diff --git a/apis/charts_graphs_amcharts/INSTALL.TXT b/apis/charts_graphs_amcharts/INSTALL.TXT
deleted file mode 100644
index deae3bd..0000000
--- a/apis/charts_graphs_amcharts/INSTALL.TXT
+++ /dev/null
@@ -1,24 +0,0 @@
-You need to download amCharts files from: 
-http://www.amcharts.com/download
-
-At http://www.amcharts.com/download choose the 2.x amCharts Flash & JavaScript 
-bundle to download.
-
-From it you have to extrac the following files (they are at amcharts/flash):
-* amcolumn.swf
-* amline.swf
-* ampie.swf
-
-Place them in the charts_graphs/apis/charts_graphs_amcharts/downloaded</em> 
-folder of Charts and Graphs module directly, without any folder structure inside 
-the downloaded folder.
-
-Sorry for the inconvenience, but there's really nothing we
-can do about it due to licenses restrictions and Drupal policy
-to not ship anything non-GPL with the module code.
-
-CAUTION: Do NOT assume you don't need swfobject.js since
-charts_graphs already requires swfobject Drupal module. Unfortunately,
-the versions of the two js files are different, so you can
-not re-use swfobject from the module file for amCharts the way
-you can re-use it for OFC2.
diff --git a/apis/charts_graphs_amcharts/charts_graphs_amcharts.class.inc b/apis/charts_graphs_amcharts/charts_graphs_amcharts.class.inc
deleted file mode 100644
index 6200f3b..0000000
--- a/apis/charts_graphs_amcharts/charts_graphs_amcharts.class.inc
+++ /dev/null
@@ -1,581 +0,0 @@
-<?php
-
-/**
- * @file
- *   Implementation of abstract class ChartsGraphsFlashCanvas for amCharts library.
- *
- */
-
-require_once DRUPAL_ROOT . '/' . dirname(__FILE__) . '/../../charts_graphs_flash_canvas.class.inc';
-
-/**
- * Implementation of abstract class ChartsGraphsFlashCanvas for amCharts library.
- */
-class ChartsGraphsAmcharts extends ChartsGraphsFlashCanvas {
-
-  /**
-   * Array defined by the user to be placed in the pie section of the data file
-   * of the chart.
-   *
-   * @var <array>
-   */
-  var $slices = array();
-
-  /**
-   * Array defined by the user to be placed in the series subsection of the data
-   * file of the chart.
-   *
-   * @var <array>
-   */
-  var $chart_series = array();
-
-  /**
-   * Array defined by the user to be placed in the graphs subsection of the data
-   * file of the chart.
-   *
-   * @var <array>
-   */
-  var $chart_graphs = array();
-
-  /**
-   * Array defined by the user to be placed in the settings section of the
-   * settings file of the chart.
-   *
-   * @var <array>
-   */
-  var $settings = array();
-
-  function _preprocess_values() {
-    if (in_array($this->type, array('pie', 'donut', 'pie_3d', 'donut_3d'))) {
-      $this->_preprocess_values_pie();
-    }
-    else {
-      $this->_preprocess_values_not_pie();
-    }
-  }
-
-  function _preprocess_values_pie() {
-    $pie_data = array();
-    $first_series = reset($this->series);
-    $idx = 0;
-    $max_val = max($first_series);
-    $max_idx = -1;
-    $x_labels_keys = array_keys($this->x_labels);
-    if (is_array($first_series)) {
-      foreach ($first_series as $val) {
-        $pie_data[$this->x_labels[$x_labels_keys[$idx]]] = $val;
-        if ($val == $max_val) {
-          $max_idx = $idx;
-        }
-        $idx++;
-      }
-    }
-
-    $slices = array();
-    if (is_array($pie_data)) {
-      $idx = 0;
-      foreach ($pie_data as $label => $point) {
-        $slice = array(
-          '#id' => 'slice',
-          '#attributes' => array(
-            'title' => $this->encode_for_xml($label),
-          ),
-          '#value' => $this->encode_for_xml($point),
-        );
-        if ($idx == $max_idx) {
-          $slice['#attributes']['pull_out'] = 'true';
-        }
-        $slices[] = $slice;
-        $idx++;
-      }
-    }
-
-    $slices = $this->merge_xml_values($slices, $this->slices);
-
-    $pie = array(
-      '#id' => 'pie',
-      '#children' => $slices,
-    );
-    $this->data_to_use = array($pie);
-  }
-
-  function _preprocess_values_not_pie() {
-    $series = array();
-    if (is_array($this->x_labels)) {
-      $i = 1;
-      /**
-       * Making amCharts side bar graphs have the same orientation of side bar
-       * graphs made with Bluff and Google Charts.
-       */
-      $x_labels = ($this->type == 'side_bar') ?
-        array_reverse($this->x_labels) :
-        $this->x_labels;
-      foreach ($x_labels as $label) {
-        $series[] = array(
-          '#id' => 'value',
-          '#value' => $this->encode_for_xml($label),
-          '#attributes' => array(
-            'xid' => $i,
-          ),
-        );
-        $i++;
-      }
-    }
-
-    $graphs = array();
-    if (is_array($this->series)) {
-      /**
-       * Making amCharts side bar graphs have the same orientation of side bar
-       * graphs made with Bluff and Google Charts.
-       */
-      $ordered_series = ($this->type == 'side_bar') ?
-        array_reverse($this->series, TRUE) :
-        $this->series;
-
-      $gid = 0;
-      foreach ($ordered_series as $name => $graph) {
-        if (!is_array($graph)) {
-          continue;
-        }
-        $j = 1;
-        $values = array();
-
-        /**
-         * Making amCharts side bar graphs have the same orientation of side bar
-         * graphs made with Bluff and Google Charts.
-         */
-        $ordered_graph = ($this->type == 'side_bar') ?
-          array_reverse($graph, TRUE) :
-          $graph;
-
-        foreach ($ordered_graph as $val) {
-          $values[] = array(
-            '#id' => 'value',
-            '#value' => $this->encode_for_xml($val),
-            '#attributes' => array(
-              'xid' => $j,
-            ),
-          );
-          $j++;
-        }
-        $new_graph = array(
-          '#id' => 'graph',
-          '#attributes' => array(
-            'title' => $this->encode_for_xml($name),
-            'bullet' => 'round',
-            'gid' => $gid,
-          ),
-          '#children' => $values,
-        );
-        if (strpos($this->type, 'area') !== FALSE) {
-          $new_graph['#attributes']['fill_alpha'] = 50;
-        }
-        $graphs[] = $new_graph;
-        $gid++;
-      }
-    }
-
-    $series = $this->merge_xml_values($series, $this->chart_series);
-    $graphs = $this->merge_xml_values($graphs, $this->chart_graphs);
-    $series = array(
-      '#id' => 'series',
-      '#children' => $series,
-    );
-    $graphs = array(
-      '#id' => 'graphs',
-      '#children' => $graphs,
-    );
-
-    $chart = array(
-      '#id' => 'chart',
-      '#children' => array($series, $graphs),
-    );
-
-    $this->data_to_use = array($chart);
-  }
-
-  function get_chart() {
-    $unique = charts_graphs_random_hash();
-
-    $am_column_type = NULL;
-    $am_y_axe_type = NULL;
-    $inner_radius = NULL;
-    $angle_pie_3d = NULL;
-    $height_pie_3d = NULL;
-
-    switch ($this->type) {
-      case 'bar':
-        $am_category = 'amcolumn';
-        $am_type = 'column';
-        break;
-
-      case 'stacked_bar':
-        $am_category = 'amcolumn';
-        $am_type = 'column';
-        $am_column_type = 'stacked';
-        break;
-
-      case '100_stacked_bar':
-        $am_category = 'amcolumn';
-        $am_type = 'column';
-        $am_column_type = '100% stacked';
-        break;
-
-      case 'bar_3d':
-        $am_category = 'amcolumn';
-        $am_type = 'column';
-        $am_column_type = '3d column';
-        break;
-
-      case 'side_bar':
-        $am_category = 'amcolumn';
-        $am_type = 'bar';
-        break;
-
-      case 'stacked_side_bar':
-        $am_category = 'amcolumn';
-        $am_type = 'bar';
-        $am_column_type = 'stacked';
-        break;
-
-      case '100_stacked_side_bar':
-        $am_category = 'amcolumn';
-        $am_type = 'bar';
-        $am_column_type = '100% stacked';
-        break;
-
-      case 'side_bar_3d':
-        $am_category = 'amcolumn';
-        $am_type = 'bar';
-        $am_column_type = '3d column';
-        break;
-
-      case 'line':
-        $am_category = 'amline';
-        $am_type = 'line';
-        break;
-
-      case 'area':
-        $am_category = 'amline';
-        $am_type = 'line';
-        break;
-
-      case 'stacked_area':
-        $am_category = 'amline';
-        $am_type = 'line';
-        $am_y_axe_type = 'stacked';
-        break;
-
-      case '100_stacked_area':
-        $am_category = 'amline';
-        $am_type = 'line';
-        $am_y_axe_type = '100% stacked';
-        break;
-
-      case 'pie':
-        $am_category = 'ampie';
-        $am_type = 'pie';
-        break;
-
-      case 'donut':
-        $am_category = 'ampie';
-        $am_type = 'pie';
-        $inner_radius = '30%';
-        break;
-
-      case 'pie_3d':
-        $am_category = 'ampie';
-        $am_type = 'pie';
-        $angle_pie_3d = 30;
-        $height_pie_3d = 20;
-        break;
-
-      case 'donut_3d':
-        $am_category = 'ampie';
-        $am_type = 'pie';
-        $inner_radius = '30%';
-        $angle_pie_3d = 30;
-        $height_pie_3d = 20;
-        break;
-
-    }
-
-    $width = $this->width;
-    $height = $this->height;
-
-    $data = $this->_preprocess_values();
-
-    $settings = array(
-      array(
-        '#id' => 'type',
-        '#value' => $am_type,
-      ),
-      array(
-        '#id' => 'depth',
-        '#value' => 5,
-      ),
-      array(
-        '#id' => 'js_enabled',
-        '#value' => 'false',
-      ),
-      array(
-        '#id' => 'redraw',
-        '#value' => 'true',
-      ),
-      array(
-        '#id' => 'data_labels',
-        '#children' => array(
-          array(
-            '#id' => 'show',
-            '#cdata' => '{title}: {value}',
-          ),
-          array(
-            '#id' => 'line_color',
-            '#value' => '#FFFFFF',
-          ),
-          array(
-            '#id' => 'line_alpha',
-            '#value' => 40,
-          ),
-        ),
-      ),
-    );
-
-    /**
-     * Applying background colour setting if available.
-     */
-    if (isset($this->colour) && !empty($this->colour)) {
-      $settings[] = array(
-        '#id' => 'background',
-        '#children' => array(
-          array(
-            '#id' => 'color',
-            '#value' => $this->encode_for_xml($this->colour),
-          ),
-          array(
-            '#id' => 'alpha',
-            '#value' => 100,
-          ),
-        ),
-      );
-    }
-
-    /**
-     * Applying user defined min and max y axis values.
-     */
-    if ((($this->type == 'bar') || ($this->type == 'line')) &&
-      (isset($this->y_min) || isset($this->y_max))) {
-
-      $children = array(array(
-          '#id' => 'strict_min_max',
-          '#value' => 'true',
-        ));
-      if (isset($this->y_min)) {
-        $children[] = array(
-          '#id' => 'min',
-          '#value' => $this->y_min,
-        );
-      }
-      if (isset($this->y_max)) {
-        $children[] = array(
-          '#id' => 'max',
-          '#value' => $this->y_max,
-        );
-      }
-      $y_axis_limits_container = ($this->type == 'bar') ? 'value' : 'y_left';
-      $settings[] = array(
-        '#id' => 'values',
-        '#children' => array(
-          array(
-            '#id' => $y_axis_limits_container,
-            '#children' => $children,
-          ),
-        ),
-      );
-    }
-
-    if (isset($this->y_legend)) {
-      $label = array(
-        array(
-          '#id' => 'x',
-          '#value' => '2%',
-        ),
-        array(
-          '#id' => 'y',
-          '#value' => '100%',
-        ),
-        array(
-          '#id' => 'align',
-          '#value' => 'center',
-        ),
-        array(
-          '#id' => 'rotate',
-          '#value' => 'true',
-        ),
-        array(
-          '#id' => 'text',
-          '#value' => strip_tags($this->y_legend),
-        ),
-      );
-      $settings[] = array(
-        '#id' => 'labels',
-        '#children' => $label,
-      );
-    }
-
-    if (isset($am_column_type)) {
-      $column = array(
-        '#id' => 'column',
-        '#children' => array(
-          '#id' => 'type',
-          '#value' => $am_column_type,
-        ),
-      );
-      $settings[] = $column;
-    }
-
-    if (isset($am_y_axe_type)) {
-      $y_axe_type = array(
-        '#id' => 'axes',
-        '#value' => array(
-          '#id' => 'y_left',
-          '#value' => array(
-            '#id' => 'type',
-            '#value' => $am_y_axe_type,
-          ),
-        ),
-      );
-      $settings[] = $y_axe_type;
-    }
-
-    if ($am_type == 'pie') {
-      $pie = array(
-        array(
-          '#id' => 'hover_brightness',
-          '#value' => -20,
-        ),
-        array(
-          '#id' => 'gradient',
-          '#value' => 'linear',
-        ),
-        array(
-          '#id' => 'gradient_ratio',
-          '#value' => '-10,60',
-        ),
-      );
-      if ($inner_radius !== NULL) {
-        $pie[] = array(
-          '#id' => 'inner_radius',
-          '#value' => $inner_radius,
-        );
-      }
-      if ($angle_pie_3d !== NULL) {
-        $pie[] = array(
-          '#id' => 'angle',
-          '#value' => $angle_pie_3d,
-        );
-      }
-      if ($height_pie_3d !== NULL) {
-        $pie[] = array(
-          '#id' => 'height',
-          '#value' => $height_pie_3d,
-        );
-      }
-      $colors = array_slice(
-        $this->series_colours(),
-        0,
-        count(reset($this->series))
-      );
-      $pie[] = array(
-        '#id' => 'colors',
-        '#value' => implode(',', $colors),
-      );
-
-      $pie = array(
-        '#id' => 'pie',
-        '#children' => $pie,
-      );
-      $settings[] = $pie;
-    }
-    else {
-      $colors = array_slice($this->series_colours(), 0, count($this->series));
-      $settings[] = array(
-        '#id' => 'colors',
-        '#value' => implode(',', $colors),
-      );
-    }
-
-    $settings = $this->merge_xml_values($settings, $this->settings);
-    $settings = array(
-      '#id' => 'settings',
-      '#children' => $settings,
-    );
-
-    $this->settings_to_use = array($settings);
-
-    $wmode = $this->get_wmode();
-
-    $mod_path = drupal_get_path('module', $this->getModuleName());
-    // TODO The second parameter to this function call should be an array.
-    $file = url(
-      "${mod_path}/downloaded/${am_category}.swf",
-      array('absolute' => TRUE)
-    );
-
-    //-- Prepare URLs that javascript will retrieve data from, using cache:
-    $unique = charts_graphs_random_hash();
-    $arr = (array) $this;
-    $tocache = new stdClass();
-    $tocache->settings = $this->get_xml_file_from_array($this->settings_to_use);
-    $tocache->data = $this->get_xml_file_from_array($this->data_to_use);
-    cache_set($unique, $tocache, 'cache', REQUEST_TIME + 30); //Keep for at least 30 seconds;
-
-    $settings_url_query = sprintf('cid=%s', $unique);
-    // TODO The second parameter to this function call should be an array.
-    $settings_url = url(
-      'charts_graphs_amcharts/getdata/settings',
-      array(
-      'absolute' => TRUE,
-      'query' => $settings_url_query,
-    )
-    );
-
-    $data_url_query = sprintf('cid=%s', $unique);
-    // TODO The second parameter to this function call should be an array.
-    $data_url = url(
-      'charts_graphs_amcharts/getdata/data',
-      array(
-      'absolute' => TRUE,
-      'query' => $data_url_query,
-    )
-    );
-
-    $flashvars = array(
-      'settings_file' => 'SWFSETTINGSURL',
-      'data_file' => 'SWFDATAURL',
-      'preloader_color' => '#999999',
-      'wmode' => $wmode,
-    );
-    if (isset($this->key) && !empty($this->key)) {
-      $flashvars['key'] = $this->key;
-    }
-
-    $args = array(
-      'params' => array(
-        'width' => $width,
-        'height' => $height,
-        'wmode' => $wmode,
-      ),
-      'flashvars' => $flashvars,
-    );
-
-    $out = swf($file, $args);
-    $out = str_replace('SWFSETTINGSURL', $settings_url, $out);
-    $out = str_replace('SWFDATAURL', $data_url, $out);
-
-    $element = array(
-      '#markup' => $out,
-    );
-    return $element;
-  }
-}
diff --git a/apis/charts_graphs_amcharts/charts_graphs_amcharts.info b/apis/charts_graphs_amcharts/charts_graphs_amcharts.info
deleted file mode 100644
index b4c3c43..0000000
--- a/apis/charts_graphs_amcharts/charts_graphs_amcharts.info
+++ /dev/null
@@ -1,9 +0,0 @@
-
-name = "Charts and Graphs: amCharts"
-description = "amCharts implementation for Charts and Graphs."
-dependencies[] = charts_graphs
-dependencies[] = swftools
-package = "Charts"
-core = 7.x
-php = 5.1
-
diff --git a/apis/charts_graphs_amcharts/charts_graphs_amcharts.install b/apis/charts_graphs_amcharts/charts_graphs_amcharts.install
deleted file mode 100644
index 05a2dac..0000000
--- a/apis/charts_graphs_amcharts/charts_graphs_amcharts.install
+++ /dev/null
@@ -1,88 +0,0 @@
-<?php
-
-/**
- * @file
- *   Install file for amCharts submodule.
- *
- */
-
-/**
- * Implements hook_requirements().
- */
-function charts_graphs_amcharts_requirements($phase) {
-  $requirements = array();
-
-  // Ensure translations don't break at install time.
-  $t = get_t();
-
-  if ($phase == 'runtime') {
-    $path = dirname(realpath((__FILE__))) . '/downloaded/';
-    $installation_instructions_path = module_exists('advanced_help') ?
-      'help/charts_graphs/amcharts' :
-      'http://drupal.org/node/681928';
-
-    $file = 'amcolumn.swf';
-    if (!file_exists($path . $file)) {
-      $requirements['amcharts_' . $file] = array(
-        'title' => $t('amCharts %file file', array('%file' => $file)),
-        'description' => $t('amCharts for Charts and Graphs needs the %file file
-          to work properly. Please review amCharts !installation_instructions.',
-          array(
-          '%file' => $file,
-          '!installation_instructions' => l(t('installation instructions'), $installation_instructions_path),
-        )
-        ),
-        'severity' => REQUIREMENT_ERROR,
-        'value' => $t('Unavailable'),
-      );
-    }
-
-    $file = 'amline.swf';
-    if (!file_exists($path . $file)) {
-      $requirements['amcharts_' . $file] = array(
-        'title' => $t('amCharts %file file', array('%file' => $file)),
-        'description' => $t('amCharts for Charts and Graphs needs the %file file
-          to work properly. Please review amCharts !installation_instructions.',
-          array(
-          '%file' => $file,
-          '!installation_instructions' => l(t('installation instructions'), $installation_instructions_path),
-        )
-        ),
-        'severity' => REQUIREMENT_ERROR,
-        'value' => $t('Unavailable'),
-      );
-    }
-
-    $file = 'ampie.swf';
-    if (!file_exists($path . $file)) {
-      $requirements['amcharts_' . $file] = array(
-        'title' => $t('amCharts %file file', array('%file' => $file)),
-        'description' => $t('amCharts for Charts and Graphsneeds the %file file
-          to work properly. Please review amCharts !installation_instructions.',
-          array(
-          '%file' => $file,
-          '!installation_instructions' => l(t('installation instructions'), $installation_instructions_path),
-        )
-        ),
-        'severity' => REQUIREMENT_ERROR,
-        'value' => $t('Unavailable'),
-      );
-    }
-
-    if (!class_exists('DOMDocument')) {
-      $requirements['amcharts_dom_support'] = array(
-        'title' => $t('DOM support in PHP'),
-        'description' => $t('amCharts for Charts and Graphs needs DOM support in
-          PHP. Please review amCharts !installation_instructions and enable it.',
-          array(
-          '!installation_instructions' => l(t('installation instructions'), $installation_instructions_path),
-        )
-        ),
-        'severity' => REQUIREMENT_ERROR,
-        'value' => $t('Unavailable'),
-      );
-    }
-  }
-
-  return $requirements;
-}
diff --git a/apis/charts_graphs_amcharts/charts_graphs_amcharts.module b/apis/charts_graphs_amcharts/charts_graphs_amcharts.module
deleted file mode 100644
index e12436b..0000000
--- a/apis/charts_graphs_amcharts/charts_graphs_amcharts.module
+++ /dev/null
@@ -1,80 +0,0 @@
-<?php
-
-/**
- * @file drupal module file implementing amcharts.
- */
-
-/**
- * Implements hook_chartgraph_provider().
- **/
-function charts_graphs_amcharts_chartgraph_provider() {
-  $provider =  array(
-    'path' => drupal_get_path('module', 'charts_graphs_amcharts') . '/charts_graphs_amcharts.class.inc', // must be full path
-    'clazz' => 'ChartsGraphsAmcharts', // implementation class' name
-    'name' => 'amcharts', // name used when invoking through a factory method
-    'nice_name' => 'amCharts',
-    'chart_types' => array(
-      'line' => t('Line'),
-      'area' => t('Area'),
-      'donut' => t('Donut'),
-      'donut_3d' => t('3D Donut'),
-      'side_bar' => t('Side Bar'),
-      'bar' => t('Bar'),
-      'pie' => t('Pie'),
-      'pie_3d' => t('3D Pie'),
-      'stacked_area' => t('Stacked Area'),
-      'stacker_bar' => t('Stacked Bar'),
-      'stacked_side_bar' => t('Stacked Side Bar'),
-      '100_stacked_bar' => t('100% Stacked Bar'),
-      'bar_3d' => t('3D Bar'),
-      '100_stacked_side_bar' => t('100% Stacked Side Bar'),
-      'side_bar_3d' => t('3D Side Bar'),
-    ),
-    'themes' => array(),
-  );
-
-  return (object) $provider;
-}
-
-/**
- * @todo Please document this function.
- * @see http://drupal.org/node/1354
- */
-function charts_graphs_amcharts_menu() {
-  $items = array();
-
-  $items['charts_graphs_amcharts/getdata'] = array(
-    'page callback' => 'charts_graphs_amcharts_get_data',
-    'access arguments' => array('access content'),
-    'type' => MENU_CALLBACK,
-  );
-
-  return $items;
-}
-
-/**
- * @todo Please document this function.
- * @see http://drupal.org/node/1354
- */
-function charts_graphs_amcharts_get_data() {
-  $cid = check_plain($_GET['cid']);
-  $op = check_plain(arg(2));
-
-  if ($op != 'settings' && $op != 'data') {
-    drupal_not_found();
-    exit();
-  }
-
-  $cache = cache_get($cid);
-  if (!$cache || empty($cache->data)) {
-    drupal_not_found();
-    exit();
-  }
-
-  $obj = $cache->data;
-
-  $ret = $obj->$op;
-  drupal_add_http_header('Content-Type', 'text/xml; charset=utf-8');
-  print $ret;
-  exit();
-}
diff --git a/apis/charts_graphs_amcharts/downloaded/README.txt b/apis/charts_graphs_amcharts/downloaded/README.txt
deleted file mode 100644
index e9cc64e..0000000
--- a/apis/charts_graphs_amcharts/downloaded/README.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-
-This is where amCharts downloaded swf files go into.
diff --git a/apis/charts_graphs_bluff/INSTALL.TXT b/apis/charts_graphs_bluff/INSTALL.TXT
deleted file mode 100644
index 72c9c01..0000000
--- a/apis/charts_graphs_bluff/INSTALL.TXT
+++ /dev/null
@@ -1,15 +0,0 @@
-
-Since version 3.6.1 Bluff is dual licensed - MIT and GPL - so it can be
-distributed together with Charts and Graphs code.
-
-Unfortunately, to implement IE support Bluff needs excanvas.js from Google and
-excanvas.js is licensed under the Apache License so excanvas.js can't be 
-distributed with Charts and Graphs code.
-
-If you want IE support, please grab the excanvas_r3.zip file available at
-http://code.google.com/p/explorercanvas/downloads/list.
-
-From this zipped file take excanvas.js or excanvas.compiled.js and place it at
-the DV_MODULE_PATH/apis/charts_graphs_bluff/bluff directory. Please remember to
-rename excanvas.compiled.js file to excanvas.js if you choose to use 
-excanvas.compiled.js.
diff --git a/apis/charts_graphs_bluff/bluff-src.js b/apis/charts_graphs_bluff/bluff-src.js
deleted file mode 100644
index eb8de9c..0000000
--- a/apis/charts_graphs_bluff/bluff-src.js
+++ /dev/null
@@ -1,2992 +0,0 @@
-(function ($) {
-/**
- * Bluff - beautiful graphs in JavaScript
- * ======================================
- * 
- * Get the latest version and docs at http://bluff.jcoglan.com
- * Based on Gruff by Geoffrey Grosenbach: http://github.com/topfunky/gruff
- * 
- * Copyright (C) 2008-2010 James Coglan
- * 
- * Released under the MIT license and the GPL v2.
- * http://www.opensource.org/licenses/mit-license.php
- * http://www.gnu.org/licenses/gpl-2.0.txt
- **/
-
-Bluff = {
-  // This is the version of Bluff you are using.
-  VERSION: '0.3.6',
-  
-  array: function(list) {
-    if (list.length === undefined) return [list];
-    var ary = [], i = list.length;
-    while (i--) ary[i] = list[i];
-    return ary;
-  },
-  
-  array_new: function(length, filler) {
-    var ary = [];
-    while (length--) ary.push(filler);
-    return ary;
-  },
-  
-  each: function(list, block, context) {
-    for (var i = 0, n = list.length; i < n; i++) {
-      block.call(context || null, list[i], i);
-    }
-  },
-  
-  index: function(list, needle) {
-    for (var i = 0, n = list.length; i < n; i++) {
-      if (list[i] === needle) return i;
-    }
-    return -1;
-  },
-  
-  keys: function(object) {
-    var ary = [], key;
-    for (key in object) ary.push(key);
-    return ary;
-  },
-  
-  map: function(list, block, context) {
-    var results = [];
-    this.each(list, function(item) {
-      results.push(block.call(context || null, item));
-    });
-    return results;
-  },
-  
-  reverse_each: function(list, block, context) {
-    var i = list.length;
-    while (i--) block.call(context || null, list[i], i);
-  },
-  
-  sum: function(list) {
-    var sum = 0, i = list.length;
-    while (i--) sum += list[i];
-    return sum;
-  },
-  
-  Mini: {}
-};
-
-Bluff.Base = new JS.Class({
-  extend: {
-    // Draw extra lines showing where the margins and text centers are
-    DEBUG: false,
-    
-    // Used for navigating the array of data to plot
-    DATA_LABEL_INDEX: 0,
-    DATA_VALUES_INDEX: 1,
-    DATA_COLOR_INDEX: 2,
-    
-    // Space around text elements. Mostly used for vertical spacing
-    LEGEND_MARGIN: 20,
-    TITLE_MARGIN: 20,
-    LABEL_MARGIN: 10,
-    DEFAULT_MARGIN: 20,
-    
-    DEFAULT_TARGET_WIDTH:  800,
-    
-    THOUSAND_SEPARATOR: ','
-  },
-  
-  // Blank space above the graph
-  top_margin: null,
-  
-  // Blank space below the graph
-  bottom_margin: null,
-  
-  // Blank space to the right of the graph
-  right_margin: null,
-  
-  // Blank space to the left of the graph
-  left_margin: null,
-  
-  // Blank space below the title
-  title_margin: null,
-  
-  // Blank space below the legend
-  legend_margin: null,
-  
-  // A hash of names for the individual columns, where the key is the array
-  // index for the column this label represents.
-  //
-  // Not all columns need to be named.
-  //
-  // Example: {0: 2005, 3: 2006, 5: 2007, 7: 2008}
-  labels: null,
-  
-  // Used internally for spacing.
-  //
-  // By default, labels are centered over the point they represent.
-  center_labels_over_point: null,
-  
-  // Used internally for horizontal graph types.
-  has_left_labels: null,
-  
-  // A label for the bottom of the graph
-  x_axis_label: null,
-  
-  // A label for the left side of the graph
-  y_axis_label: null,
-  
-  // x_axis_increment: null,
-  
-  // Manually set increment of the horizontal marking lines
-  y_axis_increment: null,
-  
-  // Get or set the list of colors that will be used to draw the bars or lines.
-  colors: null,
-  
-  // The large title of the graph displayed at the top
-  title: null,
-  
-  // Font used for titles, labels, etc.
-  font: null,
-  
-  font_color: null,
-  
-  // Prevent drawing of line markers
-  hide_line_markers: null,
-  
-  // Prevent drawing of the legend
-  hide_legend: null,
-  
-  // Prevent drawing of the title
-  hide_title: null,
-  
-  // Prevent drawing of line numbers
-  hide_line_numbers: null,
-  
-  // Message shown when there is no data. Fits up to 20 characters. Defaults
-  // to "No Data."
-  no_data_message: null,
-  
-  // The font size of the large title at the top of the graph
-  title_font_size: null,
-  
-  // Optionally set the size of the font. Based on an 800x600px graph.
-  // Default is 20.
-  //
-  // Will be scaled down if graph is smaller than 800px wide.
-  legend_font_size: null,
-  
-  // The font size of the labels around the graph
-  marker_font_size: null,
-  
-  // The color of the auxiliary lines
-  marker_color: null,
-  
-  // The number of horizontal lines shown for reference
-  marker_count: null,
-  
-  // You can manually set a minimum value instead of having the values
-  // guessed for you.
-  //
-  // Set it after you have given all your data to the graph object.
-  minimum_value: null,
-  
-  // You can manually set a maximum value, such as a percentage-based graph
-  // that always goes to 100.
-  //
-  // If you use this, you must set it after you have given all your data to
-  // the graph object.
-  maximum_value: null,
-  
-  // Set to false if you don't want the data to be sorted with largest avg
-  // values at the back.
-  sort: null,
-  
-  // Experimental
-  additional_line_values: null,
-  
-  // Experimental
-  stacked: null,
-  
-  // Optionally set the size of the colored box by each item in the legend.
-  // Default is 20.0
-  //
-  // Will be scaled down if graph is smaller than 800px wide.
-  legend_box_size: null,
-  
-  // Set to true to enable tooltip displays
-  tooltips: false,
-  
-  // If one numerical argument is given, the graph is drawn at 4/3 ratio
-  // according to the given width (800 results in 800x600, 400 gives 400x300,
-  // etc.).
-  //
-  // Or, send a geometry string for other ratios ('800x400', '400x225').
-  initialize: function(renderer, target_width) {
-    this._d = new Bluff.Renderer(renderer);
-    target_width = target_width || this.klass.DEFAULT_TARGET_WIDTH;
-    
-    var geo;
-    
-    if (typeof target_width !== 'number') {
-      geo = target_width.split('x');
-      this._columns = parseFloat(geo[0]);
-      this._rows = parseFloat(geo[1]);
-    } else {
-      this._columns = parseFloat(target_width);
-      this._rows = this._columns * 0.75;
-    }
-    
-    this.initialize_ivars();
-    
-    this._reset_themes();
-    this.theme_keynote();
-    
-    this._listeners = {};
-  },
-  
-  // Set instance variables for this object.
-  //
-  // Subclasses can override this, call super, then set values separately.
-  //
-  // This makes it possible to set defaults in a subclass but still allow
-  // developers to change this values in their program.
-  initialize_ivars: function() {
-    // Internal for calculations
-    this._raw_columns = 800;
-    this._raw_rows = 800 * (this._rows/this._columns);
-    this._column_count = 0;
-    this.marker_count = null;
-    this.maximum_value = this.minimum_value = null;
-    this._has_data = false;
-    this._data = [];
-    this.labels = {};
-    this._labels_seen = {};
-    this.sort = true;
-    this.title = null;
-    
-    this._scale = this._columns / this._raw_columns;
-    
-    this.marker_font_size = 21.0;
-    this.legend_font_size = 20.0;
-    this.title_font_size = 36.0;
-    
-    this.top_margin = this.bottom_margin =
-    this.left_margin = this.right_margin = this.klass.DEFAULT_MARGIN;
-    
-    this.legend_margin = this.klass.LEGEND_MARGIN;
-    this.title_margin = this.klass.TITLE_MARGIN;
-    
-    this.legend_box_size = 20.0;
-    
-    this.no_data_message = "No Data";
-    
-    this.hide_line_markers = this.hide_legend = this.hide_title = this.hide_line_numbers = false;
-    this.center_labels_over_point = true;
-    this.has_left_labels = false;
-    
-    this.additional_line_values = [];
-    this._additional_line_colors = [];
-    this._theme_options = {};
-    
-    this.x_axis_label = this.y_axis_label = null;
-    this.y_axis_increment = null;
-    this.stacked = null;
-    this._norm_data = null;
-  },
-  
-  // Sets the top, bottom, left and right margins to +margin+.
-  set_margins: function(margin) {
-    this.top_margin = this.left_margin = this.right_margin = this.bottom_margin = margin;
-  },
-  
-  // Sets the font for graph text to the font at +font_path+.
-  set_font: function(font_path) {
-    this.font = font_path;
-    this._d.font = this.font;
-  },
-  
-  // Add a color to the list of available colors for lines.
-  //
-  // Example:
-  //  add_color('#c0e9d3')
-  add_color: function(colorname) {
-    this.colors.push(colorname);
-  },
-  
-  // Replace the entire color list with a new array of colors. Also
-  // aliased as the colors= setter method.
-  //
-  // If you specify fewer colors than the number of datasets you intend
-  // to draw, 'increment_color' will cycle through the array, reusing
-  // colors as needed.
-  //
-  // Note that (as with the 'set_theme' method), you should set up the color
-  // list before you send your data (via the 'data' method). Calls to the
-  // 'data' method made prior to this call will use whatever color scheme
-  // was in place at the time data was called.
-  //
-  // Example:
-  //  replace_colors ['#cc99cc', '#d9e043', '#34d8a2']
-  replace_colors: function(color_list) {
-    this.colors = color_list || [];
-    this._color_index = 0;
-  },
-  
-  // You can set a theme manually. Assign a hash to this method before you
-  // send your data.
-  //
-  //  graph.set_theme({
-  //    colors: ['orange', 'purple', 'green', 'white', 'red'],
-  //    marker_color: 'blue',
-  //    background_colors: ['black', 'grey']
-  //  })
-  //
-  // background_image: 'squirrel.png' is also possible.
-  //
-  // (Or hopefully something better looking than that.)
-  //
-  set_theme: function(options) {
-    this._reset_themes();
-    
-    this._theme_options = {
-      colors: ['black', 'white'],
-      additional_line_colors: [],
-      marker_color: 'white',
-      font_color: 'black',
-      background_colors: null,
-      background_image: null
-    };
-    for (var key in options) this._theme_options[key] = options[key];
-    
-    this.colors = this._theme_options.colors;
-    this.marker_color = this._theme_options.marker_color;
-    this.font_color = this._theme_options.font_color || this.marker_color;
-    this._additional_line_colors = this._theme_options.additional_line_colors;
-    
-    this._render_background();
-  },
-  
-  // Set just the background colors
-  set_background: function(options) {
-    if (options.colors)
-      this._theme_options.background_colors = options.colors;
-    if (options.image)
-      this._theme_options.background_image = options.image;
-    this._render_background();
-  },
-  
-  // A color scheme similar to the popular presentation software.
-  theme_keynote: function() {
-    // Colors
-    this._blue = '#6886B4';
-    this._yellow = '#FDD84E';
-    this._green = '#72AE6E';
-    this._red = '#D1695E';
-    this._purple = '#8A6EAF';
-    this._orange = '#EFAA43';
-    this._white = 'white';
-    this.colors = [this._yellow, this._blue, this._green, this._red, this._purple, this._orange, this._white];
-    
-    this.set_theme({
-      colors: this.colors,
-      marker_color: 'white',
-      font_color: 'white',
-      background_colors: ['black', '#4a465a']
-    });
-  },
-  
-  // A color scheme plucked from the colors on the popular usability blog.
-  theme_37signals: function() {
-    // Colors
-    this._green = '#339933';
-    this._purple = '#cc99cc';
-    this._blue = '#336699';
-    this._yellow = '#FFF804';
-    this._red = '#ff0000';
-    this._orange = '#cf5910';
-    this._black = 'black';
-    this.colors = [this._yellow, this._blue, this._green, this._red, this._purple, this._orange, this._black];
-    
-    this.set_theme({
-      colors: this.colors,
-      marker_color: 'black',
-      font_color: 'black',
-      background_colors: ['#d1edf5', 'white']
-    });
-  },
-  
-  // A color scheme from the colors used on the 2005 Rails keynote
-  // presentation at RubyConf.
-  theme_rails_keynote: function() {
-    // Colors
-    this._green = '#00ff00';
-    this._grey = '#333333';
-    this._orange = '#ff5d00';
-    this._red = '#f61100';
-    this._white = 'white';
-    this._light_grey = '#999999';
-    this._black = 'black';
-    this.colors = [this._green, this._grey, this._orange, this._red, this._white, this._light_grey, this._black];
-    
-    this.set_theme({
-      colors: this.colors,
-      marker_color: 'white',
-      font_color: 'white',
-      background_colors: ['#0083a3', '#0083a3']
-    });
-  },
-  
-  // A color scheme similar to that used on the popular podcast site.
-  theme_odeo: function() {
-    // Colors
-    this._grey = '#202020';
-    this._white = 'white';
-    this._dark_pink = '#a21764';
-    this._green = '#8ab438';
-    this._light_grey = '#999999';
-    this._dark_blue = '#3a5b87';
-    this._black = 'black';
-    this.colors = [this._grey, this._white, this._dark_blue, this._dark_pink, this._green, this._light_grey, this._black];
-    
-    this.set_theme({
-      colors: this.colors,
-      marker_color: 'white',
-      font_color: 'white',
-      background_colors: ['#ff47a4', '#ff1f81']
-    });
-  },
-  
-  // A pastel theme
-  theme_pastel: function() {
-    // Colors
-    this.colors = [
-                    '#a9dada', // blue
-                    '#aedaa9', // green
-                    '#daaea9', // peach
-                    '#dadaa9', // yellow
-                    '#a9a9da', // dk purple
-                    '#daaeda', // purple
-                    '#dadada' // grey
-                  ];
-    
-    this.set_theme({
-      colors: this.colors,
-      marker_color: '#aea9a9', // Grey
-      font_color: 'black',
-      background_colors: 'white'
-    });
-  },
-  
-  // A greyscale theme
-  theme_greyscale: function() {
-    // Colors
-    this.colors = [
-                    '#282828', // 
-                    '#383838', // 
-                    '#686868', // 
-                    '#989898', // 
-                    '#c8c8c8', // 
-                    '#e8e8e8' // 
-                  ];
-    
-    this.set_theme({
-      colors: this.colors,
-      marker_color: '#aea9a9', // Grey
-      font_color: 'black',
-      background_colors: 'white'
-    });
-  },
-  
-  // Parameters are an array where the first element is the name of the dataset
-  // and the value is an array of values to plot.
-  //
-  // Can be called multiple times with different datasets for a multi-valued
-  // graph.
-  //
-  // If the color argument is nil, the next color from the default theme will
-  // be used.
-  //
-  // NOTE: If you want to use a preset theme, you must set it before calling
-  // data().
-  //
-  // Example:
-  //   data("Bart S.", [95, 45, 78, 89, 88, 76], '#ffcc00')
-  data: function(name, data_points, color) {
-    data_points = (data_points === undefined) ? [] : data_points;
-    color = color || null;
-    
-    data_points = Bluff.array(data_points); // make sure it's an array
-    this._data.push([name, data_points, (color || this._increment_color())]);
-    // Set column count if this is larger than previous counts
-    this._column_count = (data_points.length > this._column_count) ? data_points.length : this._column_count;
-    
-    // Pre-normalize
-    Bluff.each(data_points, function(data_point, index) {
-      if (data_point === undefined) return;
-      
-      // Setup max/min so spread starts at the low end of the data points
-      if (this.maximum_value === null && this.minimum_value === null)
-        this.maximum_value = this.minimum_value = data_point;
-      
-      // TODO Doesn't work with stacked bar graphs
-      // Original: @maximum_value = _larger_than_max?(data_point, index) ? max(data_point, index) : @maximum_value
-      this.maximum_value = this._larger_than_max(data_point) ? data_point : this.maximum_value;
-      if (this.maximum_value >= 0) this._has_data = true;
-      
-      this.minimum_value = this._less_than_min(data_point) ? data_point : this.minimum_value;
-      if (this.minimum_value < 0) this._has_data = true;
-    }, this);
-  },
-  
-  // Overridden by subclasses to do the actual plotting of the graph.
-  //
-  // Subclasses should start by calling super() for this method.
-  draw: function() {
-    if (this.stacked) this._make_stacked();
-    this._setup_drawing();
-    
-    this._debug(function() {
-      // Outer margin
-      this._d.rectangle(this.left_margin, this.top_margin,
-                        this._raw_columns - this.right_margin, this._raw_rows - this.bottom_margin);
-      // Graph area box
-      this._d.rectangle(this._graph_left, this._graph_top, this._graph_right, this._graph_bottom);
-    });
-  },
-  
-  clear: function() {
-    this._render_background();
-  },
-  
-  on: function(eventType, callback, context) {
-    var list = this._listeners[eventType] = this._listeners[eventType] || [];
-    list.push([callback, context]);
-  },
-  
-  trigger: function(eventType, data) {
-    var list = this._listeners[eventType];
-    if (!list) return;
-    Bluff.each(list, function(listener) {
-      listener[0].call(listener[1], data);
-    });
-  },
-  
-  // Calculates size of drawable area and draws the decorations.
-  //
-  // * line markers
-  // * legend
-  // * title
-  _setup_drawing: function() {
-    // Maybe should be done in one of the following functions for more granularity.
-    if (!this._has_data) return this._draw_no_data();
-    
-    this._normalize();
-    this._setup_graph_measurements();
-    if (this.sort) this._sort_norm_data();
-    
-    this._draw_legend();
-    this._draw_line_markers();
-    this._draw_axis_labels();
-    this._draw_title();
-  },
-  
-  // Make copy of data with values scaled between 0-100
-  _normalize: function(force) {
-    if (this._norm_data === null || force === true) {
-      this._norm_data = [];
-      if (!this._has_data) return;
-      
-      this._calculate_spread();
-      
-      Bluff.each(this._data, function(data_row) {
-        var norm_data_points = [];
-        Bluff.each(data_row[this.klass.DATA_VALUES_INDEX], function(data_point) {
-          if (data_point === null || data_point === undefined)
-            norm_data_points.push(null);
-          else
-            norm_data_points.push((data_point - this.minimum_value) / this._spread);
-        }, this);
-        this._norm_data.push([data_row[this.klass.DATA_LABEL_INDEX], norm_data_points, data_row[this.klass.DATA_COLOR_INDEX]]);
-      }, this);
-    }
-  },
-  
-  _calculate_spread: function() {
-    this._spread = this.maximum_value - this.minimum_value;
-    this._spread = this._spread > 0 ? this._spread : 1;
-    
-    var power = Math.round(Math.LOG10E*Math.log(this._spread));
-    this._significant_digits = Math.pow(10, 3 - power);
-  },
-  
-  // Calculates size of drawable area, general font dimensions, etc.
-  _setup_graph_measurements: function() {
-    this._marker_caps_height = this.hide_line_markers ? 0 :
-      this._calculate_caps_height(this.marker_font_size);
-    this._title_caps_height = this.hide_title ? 0 :
-      this._calculate_caps_height(this.title_font_size);
-    this._legend_caps_height = this.hide_legend ? 0 :
-      this._calculate_caps_height(this.legend_font_size);
-    
-    var longest_label,
-        longest_left_label_width,
-        line_number_width,
-        last_label,
-        extra_room_for_long_label,
-        x_axis_label_height,
-        key;
-    
-    if (this.hide_line_markers) {
-      this._graph_left = this.left_margin;
-      this._graph_right_margin = this.right_margin;
-      this._graph_bottom_margin = this.bottom_margin;
-    } else {
-      longest_left_label_width = 0;
-      if (this.has_left_labels) {
-        longest_label = '';
-        for (key in this.labels) {
-          longest_label = longest_label.length > this.labels[key].length
-              ? longest_label
-              : this.labels[key];
-        }
-        longest_left_label_width = this._calculate_width(this.marker_font_size, longest_label) * 1.25;
-      } else {
-        longest_left_label_width = this._calculate_width(this.marker_font_size, this._label(this.maximum_value));
-      }
-      
-      // Shift graph if left line numbers are hidden
-      line_number_width = this.hide_line_numbers && !this.has_left_labels ?
-      0.0 :
-        longest_left_label_width + this.klass.LABEL_MARGIN * 2;
-      
-      this._graph_left = this.left_margin +
-        line_number_width +
-        (this.y_axis_label === null ? 0.0 : this._marker_caps_height + this.klass.LABEL_MARGIN * 2);
-      
-      // Make space for half the width of the rightmost column label.
-      // Might be greater than the number of columns if between-style bar markers are used.
-      last_label = -Infinity;
-      for (key in this.labels)
-        last_label = last_label > Number(key) ? last_label : Number(key);
-      last_label = Math.round(last_label);
-      extra_room_for_long_label = (last_label >= (this._column_count-1) && this.center_labels_over_point) ?
-      this._calculate_width(this.marker_font_size, this.labels[last_label]) / 2 :
-        0;
-      this._graph_right_margin  = this.right_margin + extra_room_for_long_label;
-      
-      this._graph_bottom_margin = this.bottom_margin +
-        this._marker_caps_height + this.klass.LABEL_MARGIN;
-    }
-    
-    this._graph_right = this._raw_columns - this._graph_right_margin;
-    this._graph_width = this._raw_columns - this._graph_left - this._graph_right_margin;
-    
-    // When hide_title, leave a title_margin space for aesthetics.
-    // Same with hide_legend
-    this._graph_top = this.top_margin +
-      (this.hide_title  ? this.title_margin  : this._title_caps_height  + this.title_margin ) +
-      (this.hide_legend ? this.legend_margin : this._legend_caps_height + this.legend_margin);
-    
-    x_axis_label_height = (this.x_axis_label === null) ? 0.0 :
-      this._marker_caps_height + this.klass.LABEL_MARGIN;
-    this._graph_bottom = this._raw_rows - this._graph_bottom_margin - x_axis_label_height;
-    this._graph_height = this._graph_bottom - this._graph_top;
-  },
-  
-  // Draw the optional labels for the x axis and y axis.
-  _draw_axis_labels: function() {
-    if (this.x_axis_label) {
-      // X Axis
-      // Centered vertically and horizontally by setting the
-      // height to 1.0 and the width to the width of the graph.
-      var x_axis_label_y_coordinate = this._graph_bottom + this.klass.LABEL_MARGIN * 2 + this._marker_caps_height;
-      
-      // TODO Center between graph area
-      this._d.fill = this.font_color;
-      if (this.font) this._d.font = this.font;
-      this._d.stroke = 'transparent';
-      this._d.pointsize = this._scale_fontsize(this.marker_font_size);
-      this._d.gravity = 'north';
-      this._d.annotate_scaled(
-                              this._raw_columns, 1.0,
-                              0.0, x_axis_label_y_coordinate,
-                              this.x_axis_label, this._scale);
-      this._debug(function() {
-        this._d.line(0.0, x_axis_label_y_coordinate, this._raw_columns, x_axis_label_y_coordinate);
-      });
-    }
-    
-    // TODO Y label (not generally possible in browsers)
-  },
-  
-  // Draws horizontal background lines and labels
-  _draw_line_markers: function() {
-    if (this.hide_line_markers) return;
-    
-    if (this.y_axis_increment === null) {
-      // Try to use a number of horizontal lines that will come out even.
-      //
-      // TODO Do the same for larger numbers...100, 75, 50, 25
-      if (this.marker_count === null) {
-        Bluff.each([3,4,5,6,7], function(lines) {
-          if (!this.marker_count && this._spread % lines === 0)
-            this.marker_count = lines;
-        }, this);
-        this.marker_count = this.marker_count || 4;
-      }
-      this._increment = (this._spread > 0) ? this._significant(this._spread / this.marker_count) : 1;
-    } else {
-      // TODO Make this work for negative values
-      this.maximum_value = Math.max(Math.ceil(this.maximum_value), this.y_axis_increment);
-      this.minimum_value = Math.floor(this.minimum_value);
-      this._calculate_spread();
-      this._normalize(true);
-      
-      this.marker_count = Math.round(this._spread / this.y_axis_increment);
-      this._increment = this.y_axis_increment;
-    }
-    this._increment_scaled = this._graph_height / (this._spread / this._increment);
-    
-    // Draw horizontal line markers and annotate with numbers
-    var index, n, y, marker_label;
-    for (index = 0, n = this.marker_count; index <= n; index++) {
-      y = this._graph_top + this._graph_height - index * this._increment_scaled;
-      
-      this._d.stroke = this.marker_color;
-      this._d.stroke_width = 1;
-      this._d.line(this._graph_left, y, this._graph_right, y);
-      
-      marker_label = index * this._increment + this.minimum_value;
-      
-      if (!this.hide_line_numbers) {
-        this._d.fill = this.font_color;
-        if (this.font) this._d.font = this.font;
-        this._d.font_weight = 'normal';
-        this._d.stroke = 'transparent';
-        this._d.pointsize = this._scale_fontsize(this.marker_font_size);
-        this._d.gravity = 'east';
-        
-        // Vertically center with 1.0 for the height
-        this._d.annotate_scaled(this._graph_left - this.klass.LABEL_MARGIN,
-                                1.0, 0.0, y,
-                                this._label(marker_label), this._scale);
-      }
-    }
-  },
-  
-  _center: function(size) {
-    return (this._raw_columns - size) / 2;
-  },
-  
-  // Draws a legend with the names of the datasets matched to the colors used
-  // to draw them.
-  _draw_legend: function() {
-    if (this.hide_legend) return;
-    
-    this._legend_labels = Bluff.map(this._data, function(item) {
-      return item[this.klass.DATA_LABEL_INDEX];
-    }, this);
-    
-    var legend_square_width = this.legend_box_size; // small square with color of this item
-    
-    // May fix legend drawing problem at small sizes
-    if (this.font) this._d.font = this.font;
-    this._d.pointsize = this.legend_font_size;
-    
-    var label_widths = [[]]; // Used to calculate line wrap
-    Bluff.each(this._legend_labels, function(label) {
-      var last = label_widths.length - 1;
-      var metrics = this._d.get_type_metrics(label);
-      var label_width = metrics.width + legend_square_width * 2.7;
-      label_widths[last].push(label_width);
-      
-      if (Bluff.sum(label_widths[last]) > (this._raw_columns * 0.9))
-        label_widths.push([label_widths[last].pop()]);
-    }, this);
-    
-    var current_x_offset = this._center(Bluff.sum(label_widths[0]));
-    var current_y_offset = this.hide_title ?
-    this.top_margin + this.title_margin :
-      this.top_margin + this.title_margin + this._title_caps_height;
-    
-    this._debug(function() {
-      this._d.stroke_width = 1;
-      this._d.line(0, current_y_offset, this._raw_columns, current_y_offset);
-    });
-    
-    Bluff.each(this._legend_labels, function(legend_label, index) {
-      
-      // Draw label
-      this._d.fill = this.font_color;
-      if (this.font) this._d.font = this.font;
-      this._d.pointsize = this._scale_fontsize(this.legend_font_size);
-      this._d.stroke = 'transparent';
-      this._d.font_weight = 'normal';
-      this._d.gravity = 'west';
-      this._d.annotate_scaled(this._raw_columns, 1.0,
-                              current_x_offset + (legend_square_width * 1.7), current_y_offset,
-                              legend_label, this._scale);
-      
-      // Now draw box with color of this dataset
-      this._d.stroke = 'transparent';
-      this._d.fill = this._data[index][this.klass.DATA_COLOR_INDEX];
-      this._d.rectangle(current_x_offset,
-                        current_y_offset - legend_square_width / 2.0,
-                        current_x_offset + legend_square_width,
-                        current_y_offset + legend_square_width / 2.0);
-      
-      this._d.pointsize = this.legend_font_size;
-      var metrics = this._d.get_type_metrics(legend_label);
-      var current_string_offset = metrics.width + (legend_square_width * 2.7),
-          line_height;
-      
-      // Handle wrapping
-      label_widths[0].shift();
-      if (label_widths[0].length == 0) {
-        this._debug(function() {
-          this._d.line(0.0, current_y_offset, this._raw_columns, current_y_offset);
-        });
-        
-        label_widths.shift();
-        if (label_widths.length > 0) current_x_offset = this._center(Bluff.sum(label_widths[0]));
-        line_height = Math.max(this._legend_caps_height, legend_square_width) + this.legend_margin;
-        if (label_widths.length > 0) {
-          // Wrap to next line and shrink available graph dimensions
-          current_y_offset += line_height;
-          this._graph_top += line_height;
-          this._graph_height = this._graph_bottom - this._graph_top;
-        }
-      } else {
-        current_x_offset += current_string_offset;
-      }
-    }, this);
-    this._color_index = 0;
-  },
-  
-  // Draws a title on the graph.
-  _draw_title: function() {
-    if (this.hide_title || !this.title) return;
-    
-    this._d.fill = this.font_color;
-    if (this.font) this._d.font = this.font;
-    this._d.pointsize = this._scale_fontsize(this.title_font_size);
-    this._d.font_weight = 'bold';
-    this._d.gravity = 'north';
-    this._d.annotate_scaled(this._raw_columns, 1.0,
-                            0, this.top_margin,
-                            this.title, this._scale);
-  },
-  
-  // Draws column labels below graph, centered over x_offset
-  //--
-  // TODO Allow WestGravity as an option
-  _draw_label: function(x_offset, index) {
-    if (this.hide_line_markers) return;
-    
-    var y_offset;
-    
-    if (this.labels[index] && !this._labels_seen[index]) {
-      y_offset = this._graph_bottom + this.klass.LABEL_MARGIN;
-      
-      this._d.fill = this.font_color;
-      if (this.font) this._d.font = this.font;
-      this._d.stroke = 'transparent';
-      this._d.font_weight = 'normal';
-      this._d.pointsize = this._scale_fontsize(this.marker_font_size);
-      this._d.gravity = 'north';
-      this._d.annotate_scaled(1.0, 1.0,
-                              x_offset, y_offset,
-                              this.labels[index], this._scale);
-      this._labels_seen[index] = true;
-      
-      this._debug(function() {
-        this._d.stroke_width = 1;
-        this._d.line(0.0, y_offset, this._raw_columns, y_offset);
-      });
-    }
-  },
-  
-  // Creates a mouse hover target rectangle for tooltip displays
-  _draw_tooltip: function(left, top, width, height, name, color, data, index) {
-    if (!this.tooltips) return;
-    var node = this._d.tooltip(left, top, width, height, name, color, data);
-    
-    Bluff.Event.observe(node, 'click', function() {
-      var point = {
-        series: name,
-        label:  this.labels[index],
-        value:  data,
-        color:  color
-      };
-      this.trigger('click:datapoint', point);
-    }, this);
-  },
-  
-  // Shows an error message because you have no data.
-  _draw_no_data: function() {
-    this._d.fill = this.font_color;
-    if (this.font) this._d.font = this.font;
-    this._d.stroke = 'transparent';
-    this._d.font_weight = 'normal';
-    this._d.pointsize = this._scale_fontsize(80);
-    this._d.gravity = 'center';
-    this._d.annotate_scaled(this._raw_columns, this._raw_rows/2,
-                            0, 10,
-                            this.no_data_message, this._scale);
-  },
-  
-  // Finds the best background to render based on the provided theme options.
-  _render_background: function() {
-    var colors = this._theme_options.background_colors;
-    switch (true) {
-      case colors instanceof Array:
-        this._render_gradiated_background.apply(this, colors);
-        break;
-      case typeof colors === 'string':
-        this._render_solid_background(colors);
-        break;
-      default:
-        this._render_image_background(this._theme_options.background_image);
-        break;
-    }
-  },
-  
-  // Make a new image at the current size with a solid +color+.
-  _render_solid_background: function(color) {
-    this._d.render_solid_background(this._columns, this._rows, color);
-  },
-  
-  // Use with a theme definition method to draw a gradiated background.
-  _render_gradiated_background: function(top_color, bottom_color) {
-    this._d.render_gradiated_background(this._columns, this._rows, top_color, bottom_color);
-  },
-  
-  // Use with a theme to use an image (800x600 original) background.
-  _render_image_background: function(image_path) {
-    // TODO
-  },
-  
-  // Resets everything to defaults (except data).
-  _reset_themes: function() {
-    this._color_index = 0;
-    this._labels_seen = {};
-    this._theme_options = {};
-    this._d.scale(this._scale, this._scale);
-  },
-  
-  _scale_value: function(value) {
-    return this._scale * value;
-  },
-  
-  // Return a comparable fontsize for the current graph.
-  _scale_fontsize: function(value) {
-    var new_fontsize = value * this._scale;
-    return new_fontsize;
-  },
-  
-  _clip_value_if_greater_than: function(value, max_value) {
-    return (value > max_value) ? max_value : value;
-  },
-  
-  // Overridden by subclasses such as stacked bar.
-  _larger_than_max: function(data_point, index) {
-    return data_point > this.maximum_value;
-  },
-  
-  _less_than_min: function(data_point, index) {
-    return data_point < this.minimum_value;
-  },
-  
-  // Overridden by subclasses that need it.
-  _max: function(data_point, index) {
-    return data_point;
-  },
-  
-  // Overridden by subclasses that need it.
-  _min: function(data_point, index) {
-    return data_point;
-  },
-  
-  _significant: function(inc) {
-    if (inc == 0) return 1.0;
-    var factor = 1.0;
-    while (inc < 10) {
-      inc *= 10;
-      factor /= 10;
-    }
-    
-    while (inc > 100) {
-      inc /= 10;
-      factor *= 10;
-    }
-    
-    return Math.floor(inc) * factor;
-  },
-  
-  // Sort with largest overall summed value at front of array so it shows up
-  // correctly in the drawn graph.
-  _sort_norm_data: function() {
-    var sums = this._sums, index = this.klass.DATA_VALUES_INDEX;
-    
-    this._norm_data.sort(function(a,b) {
-      return sums(b[index]) - sums(a[index]);
-    });
-    
-    this._data.sort(function(a,b) {
-      return sums(b[index]) - sums(a[index]);
-    });
-  },
-  
-  _sums: function(data_set) {
-    var total_sum = 0;
-    Bluff.each(data_set, function(num) { total_sum += (num || 0) });
-    return total_sum;
-  },
-  
-  _make_stacked: function() {
-    var stacked_values = [], i = this._column_count;
-    while (i--) stacked_values[i] = 0;
-    Bluff.each(this._data, function(value_set) {
-      Bluff.each(value_set[this.klass.DATA_VALUES_INDEX], function(value, index) {
-        stacked_values[index] += value;
-      }, this);
-      value_set[this.klass.DATA_VALUES_INDEX] = Bluff.array(stacked_values);
-    }, this);
-  },
-  
-  // Takes a block and draws it if DEBUG is true.
-  //
-  // Example:
-  //   debug { @d.rectangle x1, y1, x2, y2 }
-  _debug: function(block) {
-    if (this.klass.DEBUG) {
-      this._d.fill = 'transparent';
-      this._d.stroke = 'turquoise';
-      block.call(this);
-    }
-  },
-  
-  // Returns the next color in your color list.
-  _increment_color: function() {
-    var offset = this._color_index;
-    this._color_index = (this._color_index + 1) % this.colors.length;
-    return this.colors[offset];
-  },
-  
-  // Return a formatted string representing a number value that should be
-  // printed as a label.
-  _label: function(value) {
-    var sep   = this.klass.THOUSAND_SEPARATOR,
-        label = (this._spread % this.marker_count == 0 || this.y_axis_increment !== null)
-        ? String(Math.round(value))
-        : String(Math.floor(value * this._significant_digits)/this._significant_digits);
-    
-    var parts = label.split('.');
-    parts[0] = parts[0].replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1' + sep);
-    return parts.join('.');
-  },
-  
-  // Returns the height of the capital letter 'X' for the current font and
-  // size.
-  //
-  // Not scaled since it deals with dimensions that the regular scaling will
-  // handle.
-  _calculate_caps_height: function(font_size) {
-    return this._d.caps_height(font_size);
-  },
-  
-  // Returns the width of a string at this pointsize.
-  //
-  // Not scaled since it deals with dimensions that the regular 
-  // scaling will handle.
-  _calculate_width: function(font_size, text) {
-    return this._d.text_width(font_size, text);
-  }
-});
-
-
-Bluff.Area = new JS.Class(Bluff.Base, {
-  
-  draw: function() {
-    this.callSuper();
-    
-    if (!this._has_data) return;
-    
-    this._x_increment = this._graph_width / (this._column_count - 1);
-    this._d.stroke = 'transparent';
-    
-    Bluff.each(this._norm_data, function(data_row) {
-      var poly_points = [],
-          prev_x = 0.0,
-          prev_y = 0.0;
-      
-      Bluff.each(data_row[this.klass.DATA_VALUES_INDEX], function(data_point, index) {
-        // Use incremented x and scaled y
-        var new_x = this._graph_left + (this._x_increment * index);
-        var new_y = this._graph_top + (this._graph_height - data_point * this._graph_height);
-        
-        if (prev_x > 0 && prev_y > 0) {
-          poly_points.push(new_x);
-          poly_points.push(new_y);
-          
-          // this._d.polyline(prev_x, prev_y, new_x, new_y);
-        } else {
-          poly_points.push(this._graph_left);
-          poly_points.push(this._graph_bottom - 1);
-          poly_points.push(new_x);
-          poly_points.push(new_y);
-          
-          // this._d.polyline(this._graph_left, this._graph_bottom, new_x, new_y);
-        }
-        
-        this._draw_label(new_x, index);
-        
-        prev_x = new_x;
-        prev_y = new_y;
-      }, this);
-      
-      // Add closing points, draw polygon
-      poly_points.push(this._graph_right);
-      poly_points.push(this._graph_bottom - 1);
-      poly_points.push(this._graph_left);
-      poly_points.push(this._graph_bottom - 1);
-      
-      this._d.fill = data_row[this.klass.DATA_COLOR_INDEX];
-      this._d.polyline(poly_points);
-      
-    }, this);
-  }
-});
-
-
-//  This class perfoms the y coordinats conversion for the bar class.
-//
-//  There are three cases: 
-//
-//    1. Bars all go from zero in positive direction
-//    2. Bars all go from zero to negative direction  
-//    3. Bars either go from zero to positive or from zero to negative
-//
-Bluff.BarConversion = new JS.Class({
-  mode:           null,
-  zero:           null,
-  graph_top:      null,
-  graph_height:   null,
-  minimum_value:  null,
-  spread:         null,
-  
-  getLeftYRightYscaled: function(data_point, result) {
-    var val;
-    switch (this.mode) {
-      case 1: // Case one
-        // minimum value >= 0 ( only positiv values )
-        result[0] = this.graph_top + this.graph_height*(1 - data_point) + 1;
-        result[1] = this.graph_top + this.graph_height - 1;
-        break;
-      case 2:  // Case two
-        // only negativ values
-         result[0] = this.graph_top + 1;
-        result[1] = this.graph_top + this.graph_height*(1 - data_point) - 1;
-        break;
-      case 3: // Case three
-        // positiv and negativ values
-        val = data_point-this.minimum_value/this.spread;
-        if ( data_point >= this.zero ) {
-          result[0] = this.graph_top + this.graph_height*(1 - (val-this.zero)) + 1;
-          result[1] = this.graph_top + this.graph_height*(1 - this.zero) - 1;
-        } else {
-          result[0] = this.graph_top + this.graph_height*(1 - (val-this.zero)) + 1;
-          result[1] = this.graph_top + this.graph_height*(1 - this.zero) - 1;
-        }
-        break;
-      default:
-        result[0] = 0.0;
-        result[1] = 0.0;
-    }        
-  }  
-  
-});
-
-
-Bluff.Bar = new JS.Class(Bluff.Base, {
-  
-  // Spacing factor applied between bars
-  bar_spacing: 0.9,
-  
-  draw: function() {
-    // Labels will be centered over the left of the bar if
-    // there are more labels than columns. This is basically the same 
-    // as where it would be for a line graph.
-    this.center_labels_over_point = (Bluff.keys(this.labels).length > this._column_count);
-    
-    this.callSuper();
-    if (!this._has_data) return;
-    
-    this._draw_bars();
-  },
-  
-  _draw_bars: function() {
-    this._bar_width = this._graph_width / (this._column_count * this._data.length);
-    var padding = (this._bar_width * (1 - this.bar_spacing)) / 2;
-    
-    this._d.stroke_opacity = 0.0;
-    
-    // Setup the BarConversion Object
-    var conversion = new Bluff.BarConversion();
-    conversion.graph_height = this._graph_height;
-    conversion.graph_top = this._graph_top;
-    
-    // Set up the right mode [1,2,3] see BarConversion for further explanation
-    if (this.minimum_value >= 0) {
-      // all bars go from zero to positiv
-      conversion.mode = 1;
-    } else {
-      // all bars go from 0 to negativ
-      if (this.maximum_value <= 0) {
-        conversion.mode = 2;
-      } else {
-        // bars either go from zero to negativ or to positiv
-        conversion.mode = 3;
-        conversion.spread = this._spread;
-        conversion.minimum_value = this.minimum_value;
-        conversion.zero = -this.minimum_value/this._spread;
-      }
-    }
-    
-    // iterate over all normalised data
-    Bluff.each(this._norm_data, function(data_row, row_index) {
-      var raw_data = this._data[row_index][this.klass.DATA_VALUES_INDEX];
-      
-      Bluff.each(data_row[this.klass.DATA_VALUES_INDEX], function(data_point, point_index) {
-        // Use incremented x and scaled y
-        // x
-        var left_x = this._graph_left + (this._bar_width * (row_index + point_index + ((this._data.length - 1) * point_index))) + padding;
-        var right_x = left_x + this._bar_width * this.bar_spacing;
-        // y
-        var conv = [];
-        conversion.getLeftYRightYscaled(data_point, conv);
-        
-        // create new bar
-        this._d.fill = data_row[this.klass.DATA_COLOR_INDEX];
-        this._d.rectangle(left_x, conv[0], right_x, conv[1]);
-        
-        // create tooltip target
-        this._draw_tooltip(left_x, conv[0],
-                           right_x - left_x, conv[1] - conv[0],
-                           data_row[this.klass.DATA_LABEL_INDEX],
-                           data_row[this.klass.DATA_COLOR_INDEX],
-                           raw_data[point_index], point_index);
-        
-        // Calculate center based on bar_width and current row
-        var label_center = this._graph_left + 
-                          (this._data.length * this._bar_width * point_index) + 
-                          (this._data.length * this._bar_width / 2.0);
-        // Subtract half a bar width to center left if requested
-        this._draw_label(label_center - (this.center_labels_over_point ? this._bar_width / 2.0 : 0.0), point_index);
-      }, this);
-      
-    }, this);
-    
-    // Draw the last label if requested
-    if (this.center_labels_over_point) this._draw_label(this._graph_right, this._column_count);
-  }
-});
-
-
-// Here's how to make a Line graph:
-//
-//   g = new Bluff.Line('canvasId');
-//   g.title = "A Line Graph";
-//   g.data('Fries', [20, 23, 19, 8]);
-//   g.data('Hamburgers', [50, 19, 99, 29]);
-//   g.draw();
-//
-// There are also other options described below, such as #baseline_value, #baseline_color, #hide_dots, and #hide_lines.
-
-Bluff.Line = new JS.Class(Bluff.Base, {
-  // Draw a dashed line at the given value
-  baseline_value: null,
-  
-  // Color of the baseline
-  baseline_color: null,
-  
-  // Dimensions of lines and dots; calculated based on dataset size if left unspecified
-  line_width: null,
-  dot_radius: null,
-  
-  // Hide parts of the graph to fit more datapoints, or for a different appearance.
-  hide_dots: null,
-  hide_lines: null,
-  
-  // Call with target pixel width of graph (800, 400, 300), and/or 'false' to omit lines (points only).
-  //
-  //  g = new Bluff.Line('canvasId', 400) // 400px wide with lines
-  //
-  //  g = new Bluff.Line('canvasId', 400, false) // 400px wide, no lines (for backwards compatibility)
-  //
-  //  g = new Bluff.Line('canvasId', false) // Defaults to 800px wide, no lines (for backwards compatibility)
-  // 
-  // The preferred way is to call hide_dots or hide_lines instead.
-  initialize: function(renderer) {
-    if (arguments.length > 3) throw 'Wrong number of arguments';
-    if (arguments.length === 1 || (typeof arguments[1] !== 'number' && typeof arguments[1] !== 'string'))
-      this.callSuper(renderer, null);
-    else
-      this.callSuper();
-    
-    this.hide_dots = this.hide_lines = false;
-    this.baseline_color = 'red';
-    this.baseline_value = null;
-  },
-  
-  draw: function() {
-    this.callSuper();
-    
-    if (!this._has_data) return;
-    
-    // Check to see if more than one datapoint was given. NaN can result otherwise.
-    this.x_increment = (this._column_count > 1) ? (this._graph_width / (this._column_count - 1)) : this._graph_width;
-    
-    var level;
-    
-    if (this._norm_baseline !== undefined) {
-      level = this._graph_top + (this._graph_height - this._norm_baseline * this._graph_height);
-      this._d.push();
-      this._d.stroke = this.baseline_color;
-      this._d.fill_opacity = 0.0;
-      // this._d.stroke_dasharray(10, 20);
-      this._d.stroke_width = 3.0;
-      this._d.line(this._graph_left, level, this._graph_left + this._graph_width, level);
-      this._d.pop();
-    }
-    
-    Bluff.each(this._norm_data, function(data_row, row_index) {
-      var prev_x = null, prev_y = null;
-      var raw_data = this._data[row_index][this.klass.DATA_VALUES_INDEX];
-      
-      this._one_point = this._contains_one_point_only(data_row);
-      
-      Bluff.each(data_row[this.klass.DATA_VALUES_INDEX], function(data_point, index) {
-        var new_x = this._graph_left + (this.x_increment * index);
-        if (typeof data_point !== 'number') return;
-        
-        this._draw_label(new_x, index);
-        
-        var new_y = this._graph_top + (this._graph_height - data_point * this._graph_height);
-        
-        // Reset each time to avoid thin-line errors
-        this._d.stroke = data_row[this.klass.DATA_COLOR_INDEX];
-        this._d.fill = data_row[this.klass.DATA_COLOR_INDEX];
-        this._d.stroke_opacity = 1.0;
-        this._d.stroke_width = this.line_width ||
-          this._clip_value_if_greater_than(this._columns / (this._norm_data[0][this.klass.DATA_VALUES_INDEX].length * 6), 3.0);
-        
-        var circle_radius = this.dot_radius ||
-          this._clip_value_if_greater_than(this._columns / (this._norm_data[0][this.klass.DATA_VALUES_INDEX].length * 2), 7.0);
-        
-        if (!this.hide_lines && prev_x !== null && prev_y !== null) {
-          this._d.line(prev_x, prev_y, new_x, new_y);
-        } else if (this._one_point) {
-          // Show a circle if there's just one point
-          this._d.circle(new_x, new_y, new_x - circle_radius, new_y);
-        }
-        
-        if (!this.hide_dots) this._d.circle(new_x, new_y, new_x - circle_radius, new_y);
-        
-        this._draw_tooltip(new_x - circle_radius, new_y - circle_radius,
-                           2 * circle_radius, 2 *circle_radius,
-                           data_row[this.klass.DATA_LABEL_INDEX],
-                           data_row[this.klass.DATA_COLOR_INDEX],
-                           raw_data[index], index);
-        
-        prev_x = new_x;
-        prev_y = new_y;
-      }, this);
-    }, this);
-  },
-  
-  _normalize: function() {
-    this.maximum_value = Math.max(this.maximum_value, this.baseline_value);
-    this.callSuper();
-    if (this.baseline_value !== null) this._norm_baseline = this.baseline_value / this.maximum_value;
-  },
-  
-  _contains_one_point_only: function(data_row) {
-    // Spin through data to determine if there is just one value present.
-    var count = 0;
-    Bluff.each(data_row[this.klass.DATA_VALUES_INDEX], function(data_point) {
-      if (data_point !== undefined) count += 1;
-    });
-    return count === 1;
-  }
-});
-
-
-// Graph with dots and labels along a vertical access
-// see: 'Creating More Effective Graphs' by Robbins
-
-Bluff.Dot = new JS.Class(Bluff.Base, {
-  
-  draw: function() {
-    this.has_left_labels = true;
-    this.callSuper();
-    
-    if (!this._has_data) return;
-    
-    // Setup spacing.
-    //
-    var spacing_factor = 1.0;
-    
-    this._items_width = this._graph_height / this._column_count;
-    this._item_width = this._items_width * spacing_factor / this._norm_data.length;
-    this._d.stroke_opacity = 0.0;
-    var height = Bluff.array_new(this._column_count, 0),
-        length = Bluff.array_new(this._column_count, this._graph_left),
-        padding = (this._items_width * (1 - spacing_factor)) / 2;
-    
-    Bluff.each(this._norm_data, function(data_row, row_index) {
-      Bluff.each(data_row[this.klass.DATA_VALUES_INDEX], function(data_point, point_index) {
-        
-        var x_pos = this._graph_left + (data_point * this._graph_width) - Math.round(this._item_width/6.0);
-        var y_pos = this._graph_top + (this._items_width * point_index) + padding + Math.round(this._item_width/2.0);
-        
-        if (row_index === 0) {
-          this._d.stroke = this.marker_color;
-          this._d.stroke_width = 1.0;
-          this._d.opacity = 0.1;
-          this._d.line(this._graph_left, y_pos, this._graph_left + this._graph_width, y_pos);
-        }
-        
-        this._d.fill = data_row[this.klass.DATA_COLOR_INDEX];
-        this._d.stroke = 'transparent';
-        this._d.circle(x_pos, y_pos, x_pos + Math.round(this._item_width/3.0), y_pos);
-        
-        // Calculate center based on item_width and current row
-        var label_center = this._graph_top + (this._items_width * point_index + this._items_width / 2) + padding;
-        this._draw_label(label_center, point_index);
-      }, this);
-      
-    }, this);
-  },
-  
-  // Instead of base class version, draws vertical background lines and label
-  _draw_line_markers: function() {
-    
-    if (this.hide_line_markers) return;
-    
-    this._d.stroke_antialias = false;
-    
-    // Draw horizontal line markers and annotate with numbers
-    this._d.stroke_width = 1;
-    var number_of_lines = 5;
-    
-    // TODO Round maximum marker value to a round number like 100, 0.1, 0.5, etc.
-    var increment = this._significant(this.maximum_value / number_of_lines);
-    for (var index = 0; index <= number_of_lines; index++) {
-      
-      var line_diff    = (this._graph_right - this._graph_left) / number_of_lines,
-          x            = this._graph_right - (line_diff * index) - 1,
-          diff         = index - number_of_lines,
-          marker_label = Math.abs(diff) * increment;
-      
-      this._d.stroke = this.marker_color;
-      this._d.line(x, this._graph_bottom, x, this._graph_bottom + 0.5 * this.klass.LABEL_MARGIN);
-      
-      if (!this.hide_line_numbers) {
-        this._d.fill      = this.font_color;
-        if (this.font) this._d.font = this.font;
-        this._d.stroke    = 'transparent';
-        this._d.pointsize = this._scale_fontsize(this.marker_font_size);
-        this._d.gravity   = 'center';
-        // TODO Center text over line
-        this._d.annotate_scaled(0, 0, // Width of box to draw text in
-                                x, this._graph_bottom + (this.klass.LABEL_MARGIN * 2.0), // Coordinates of text
-                                marker_label, this._scale);
-      }
-      this._d.stroke_antialias = true;
-    }
-  },
-  
-  // Draw on the Y axis instead of the X
-  _draw_label: function(y_offset, index) {
-    if (this.labels[index] && !this._labels_seen[index]) {
-      this._d.fill             = this.font_color;
-      if (this.font) this._d.font = this.font;
-      this._d.stroke           = 'transparent';
-      this._d.font_weight      = 'normal';
-      this._d.pointsize        = this._scale_fontsize(this.marker_font_size);
-      this._d.gravity          = 'east';
-      this._d.annotate_scaled(1, 1,
-                              this._graph_left - this.klass.LABEL_MARGIN * 2.0, y_offset,
-                              this.labels[index], this._scale);
-      this._labels_seen[index] = true;
-    }
-  }
-});
-
-
-// Experimental!!! See also the Spider graph.
-Bluff.Net = new JS.Class(Bluff.Base, {
-  
-  // Hide parts of the graph to fit more datapoints, or for a different appearance.
-  hide_dots: null,
-  
-  //Dimensions of lines and dots; calculated based on dataset size if left unspecified
-  line_width: null,
-  dot_radius: null,
-  
-  initialize: function() {
-    this.callSuper();
-    
-    this.hide_dots = false;
-    this.hide_line_numbers = true;
-  },
-  
-  draw: function() {
-    
-    this.callSuper();
-    
-    if (!this._has_data) return;
-    
-    this._radius = this._graph_height / 2.0;
-    this._center_x = this._graph_left + (this._graph_width / 2.0);
-    this._center_y = this._graph_top + (this._graph_height / 2.0) - 10; // Move graph up a bit
-    
-    this._x_increment = this._graph_width / (this._column_count - 1);
-    var circle_radius = this.dot_radius ||
-      this._clip_value_if_greater_than(this._columns / (this._norm_data[0][this.klass.DATA_VALUES_INDEX].length * 2.5), 7.0);
-    
-    this._d.stroke_opacity = 1.0;
-    this._d.stroke_width = this.line_width ||
-      this._clip_value_if_greater_than(this._columns / (this._norm_data[0][this.klass.DATA_VALUES_INDEX].length * 4), 3.0);
-    
-    var level;
-    
-    if (this._norm_baseline !== undefined) {
-      level = this._graph_top + (this._graph_height - this._norm_baseline * this._graph_height);
-      this._d.push();
-      this._d.stroke_color  = this.baseline_color;
-      this._d.fill_opacity = 0.0;
-      // this._d.stroke_dasharray(10, 20);
-      this._d.stroke_width = 5;
-      this._d.line(this._graph_left, level, this._graph_left + this._graph_width, level);
-      this._d.pop();
-    }
-    
-    Bluff.each(this._norm_data, function(data_row) {
-      var prev_x = null, prev_y = null;
-      
-      Bluff.each(data_row[this.klass.DATA_VALUES_INDEX], function(data_point, index) {
-        if (data_point === undefined) return;
-        
-        var rad_pos = index * Math.PI * 2 / this._column_count,
-            point_distance = data_point * this._radius,
-            start_x = this._center_x + Math.sin(rad_pos) * point_distance,
-            start_y = this._center_y - Math.cos(rad_pos) * point_distance,
-            
-            next_index = (index + 1 < data_row[this.klass.DATA_VALUES_INDEX].length) ? index + 1 : 0,
-            
-            next_rad_pos = next_index * Math.PI * 2 / this._column_count,
-            next_point_distance = data_row[this.klass.DATA_VALUES_INDEX][next_index] * this._radius,
-            end_x = this._center_x + Math.sin(next_rad_pos) * next_point_distance,
-            end_y = this._center_y - Math.cos(next_rad_pos) * next_point_distance;
-        
-        this._d.stroke = data_row[this.klass.DATA_COLOR_INDEX];
-        this._d.fill = data_row[this.klass.DATA_COLOR_INDEX];
-        this._d.line(start_x, start_y, end_x, end_y);
-        
-        if (!this.hide_dots) this._d.circle(start_x, start_y, start_x - circle_radius, start_y);
-      }, this);
-      
-    }, this);
-  },
-  
-  // the lines connecting in the center, with the first line vertical
-  _draw_line_markers: function() {
-    if (this.hide_line_markers) return;
-    
-    // have to do this here (AGAIN)... see draw() in this class
-    // because this funtion is called before the @radius, @center_x and @center_y are set
-    this._radius = this._graph_height / 2.0;
-    this._center_x = this._graph_left + (this._graph_width / 2.0);
-    this._center_y = this._graph_top + (this._graph_height / 2.0) - 10; // Move graph up a bit
-    
-    var rad_pos, marker_label;
-    
-    for (var index = 0, n = this._column_count; index < n; index++) {
-      rad_pos = index * Math.PI * 2 / this._column_count;
-      
-      // Draw horizontal line markers and annotate with numbers
-      this._d.stroke = this.marker_color;
-      this._d.stroke_width = 1;
-      
-      this._d.line(this._center_x, this._center_y, this._center_x + Math.sin(rad_pos) * this._radius, this._center_y - Math.cos(rad_pos) * this._radius);
-      
-      marker_label = this.labels[index] ? this.labels[index] : '000';
-      
-      this._draw_label(this._center_x, this._center_y, rad_pos * 360 / (2 * Math.PI), this._radius, marker_label);
-    }
-  },
-  
-  _draw_label: function(center_x, center_y, angle, radius, amount) {
-    var r_offset = 1.1,
-        x_offset = center_x, // + 15 // The label points need to be tweaked slightly
-        y_offset = center_y, // + 0  // This one doesn't though
-        rad_pos = angle * Math.PI / 180,
-        x = x_offset + (radius * r_offset * Math.sin(rad_pos)),
-        y = y_offset - (radius * r_offset * Math.cos(rad_pos));
-    
-    // Draw label
-    this._d.fill = this.marker_color;
-    if (this.font) this._d.font = this.font;
-    this._d.pointsize = this._scale_fontsize(20);
-    this._d.stroke = 'transparent';
-    this._d.font_weight = 'bold';
-    this._d.gravity = 'center';
-    this._d.annotate_scaled(0, 0, x, y, amount, this._scale);
-  }
-});
-
-
-// Here's how to make a Pie graph:
-//
-//   g = new Bluff.Pie('canvasId');
-//   g.title = "Visual Pie Graph Test";
-//   g.data('Fries', 20);
-//   g.data('Hamburgers', 50);
-//   g.draw();
-//
-// To control where the pie chart starts creating slices, use #zero_degree.
-
-Bluff.Pie = new JS.Class(Bluff.Base, {
-  extend: {
-    TEXT_OFFSET_PERCENTAGE: 0.08
-  },
-  
-  // Can be used to make the pie start cutting slices at the top (-90.0)
-  // or at another angle. Default is 0.0, which starts at 3 o'clock.
-  zero_degreee: null,
-  
-  // Do not show labels for slices that are less than this percent. Use 0 to always show all labels.
-  hide_labels_less_than: null,
-  
-  initialize_ivars: function() {
-    this.callSuper();
-    this.zero_degree = 0.0;
-    this.hide_labels_less_than = 0.0;
-  },
-  
-  draw: function() {
-    this.hide_line_markers = true;
-    
-    this.callSuper();
-    
-    if (!this._has_data) return;
-    
-    var diameter = this._graph_height,
-        radius = (Math.min(this._graph_width, this._graph_height) / 2.0) * 0.8,
-        top_x = this._graph_left + (this._graph_width - diameter) / 2.0,
-        center_x = this._graph_left + (this._graph_width / 2.0),
-        center_y = this._graph_top + (this._graph_height / 2.0) - 10, // Move graph up a bit
-        total_sum = this._sums_for_pie(),
-        prev_degrees = this.zero_degree,
-        index = this.klass.DATA_VALUES_INDEX;
-    
-    // Use full data since we can easily calculate percentages
-    if (this.sort) this._data.sort(function(a,b) { return a[index][0] - b[index][0]; });
-    Bluff.each(this._data, function(data_row, i) {
-      if (data_row[this.klass.DATA_VALUES_INDEX][0] > 0) {
-        this._d.fill = data_row[this.klass.DATA_COLOR_INDEX];
-        
-        var current_degrees = (data_row[this.klass.DATA_VALUES_INDEX][0] / total_sum) * 360;
-        
-        // Gruff uses ellipse() here, but canvas doesn't seem to support it.
-        // circle() is fine for our purposes here.
-        this._d.circle(center_x, center_y,
-                    center_x + radius, center_y,
-                    prev_degrees, prev_degrees + current_degrees + 0.5); // <= +0.5 'fudge factor' gets rid of the ugly gaps
-        
-        var half_angle = prev_degrees + ((prev_degrees + current_degrees) - prev_degrees) / 2,
-            label_val = Math.round((data_row[this.klass.DATA_VALUES_INDEX][0] / total_sum) * 100.0),
-            label_string;
-        
-        if (label_val >= this.hide_labels_less_than) {
-          label_string = this._label(data_row[this.klass.DATA_VALUES_INDEX][0]);
-          this._draw_label(center_x, center_y, half_angle,
-                            radius + (radius * this.klass.TEXT_OFFSET_PERCENTAGE),
-                            label_string,
-                            data_row, i);
-        }
-        
-        prev_degrees += current_degrees;
-      }
-    }, this);
-    
-    // TODO debug a circle where the text is drawn...
-  },
-  
-  // Labels are drawn around a slightly wider ellipse to give room for 
-  // labels on the left and right.
-  _draw_label: function(center_x, center_y, angle, radius, amount, data_row, i) {
-    // TODO Don't use so many hard-coded numbers
-    var r_offset = 20.0,      // The distance out from the center of the pie to get point
-        x_offset = center_x,  // + 15.0 # The label points need to be tweaked slightly
-        y_offset = center_y,  // This one doesn't though
-        radius_offset = radius + r_offset,
-        ellipse_factor = radius_offset * 0.15,
-        x = x_offset + ((radius_offset + ellipse_factor) * Math.cos(angle * Math.PI/180)),
-        y = y_offset + (radius_offset * Math.sin(angle * Math.PI/180));
-    
-    // Draw label
-    this._d.fill = this.font_color;
-    if (this.font) this._d.font = this.font;
-    this._d.pointsize = this._scale_fontsize(this.marker_font_size);
-    this._d.font_weight = 'bold';
-    this._d.gravity = 'center';
-    this._d.annotate_scaled(0,0, x,y, amount, this._scale);
-    
-    this._draw_tooltip(x - 20, y - 20, 40, 40,
-                       data_row[this.klass.DATA_LABEL_INDEX],
-                       data_row[this.klass.DATA_COLOR_INDEX],
-                       amount, i);
-  },
-  
-  _sums_for_pie: function() {
-    var total_sum = 0;
-    Bluff.each(this._data, function(data_row) {
-      total_sum += data_row[this.klass.DATA_VALUES_INDEX][0];
-    }, this);
-    return total_sum;
-  }
-});
-
-
-// Graph with individual horizontal bars instead of vertical bars.
-
-Bluff.SideBar = new JS.Class(Bluff.Base, {
-  
-  // Spacing factor applied between bars
-  bar_spacing: 0.9,
-  
-  draw: function() {
-    this.has_left_labels = true;
-    this.callSuper();
-    
-    if (!this._has_data) return;
-    this._draw_bars();
-  },
-  
-  _draw_bars: function() {
-    this._bars_width       = this._graph_height / this._column_count;
-    this._bar_width        = this._bars_width / this._norm_data.length;
-    this._d.stroke_opacity = 0.0;
-    var height = Bluff.array_new(this._column_count, 0),
-        length = Bluff.array_new(this._column_count, this._graph_left),
-        padding = (this._bar_width * (1 - this.bar_spacing)) / 2;
-    
-    Bluff.each(this._norm_data, function(data_row, row_index) {
-      var raw_data = this._data[row_index][this.klass.DATA_VALUES_INDEX];
-      Bluff.each(data_row[this.klass.DATA_VALUES_INDEX], function(data_point, point_index) {
-        
-        // Using the original calcs from the stacked bar chart
-        // to get the difference between
-        // part of the bart chart we wish to stack.
-        var temp1      = this._graph_left + (this._graph_width - data_point * this._graph_width - height[point_index]),
-            temp2      = this._graph_left + this._graph_width - height[point_index],
-            difference = temp2 - temp1,
-        
-            left_x     = length[point_index] - 1,
-            left_y     = this._graph_top + (this._bars_width * point_index) + (this._bar_width * row_index) + padding,
-            right_x    = left_x + difference,
-            right_y    = left_y + this._bar_width * this.bar_spacing;
-        
-        height[point_index] += (data_point * this._graph_width);
-        
-        this._d.stroke = 'transparent';
-        this._d.fill = data_row[this.klass.DATA_COLOR_INDEX];
-        this._d.rectangle(left_x, left_y, right_x, right_y);
-        
-        this._draw_tooltip(left_x, left_y,
-                           right_x - left_x, right_y - left_y,
-                           data_row[this.klass.DATA_LABEL_INDEX],
-                           data_row[this.klass.DATA_COLOR_INDEX],
-                           raw_data[point_index], point_index);
-        
-        // Calculate center based on bar_width and current row
-        var label_center = this._graph_top + (this._bars_width * point_index + this._bars_width / 2);
-        this._draw_label(label_center, point_index);
-      }, this)
-      
-    }, this);
-  },
-  
-  // Instead of base class version, draws vertical background lines and label
-  _draw_line_markers: function() {
-    
-    if (this.hide_line_markers) return;
-    
-    this._d.stroke_antialias = false;
-    
-    // Draw horizontal line markers and annotate with numbers
-    this._d.stroke_width = 1;
-    var number_of_lines = 5;
-    
-    // TODO Round maximum marker value to a round number like 100, 0.1, 0.5, etc.
-    var increment = this._significant(this._spread / number_of_lines),
-        line_diff, x, diff, marker_label;
-    for (var index = 0; index <= number_of_lines; index++) {
-      
-      line_diff    = (this._graph_right - this._graph_left) / number_of_lines;
-      x            = this._graph_right - (line_diff * index) - 1;
-      diff         = index - number_of_lines;
-      marker_label = Math.abs(diff) * increment + this.minimum_value;
-      
-      this._d.stroke = this.marker_color;
-      this._d.line(x, this._graph_bottom, x, this._graph_top);
-      
-      if (!this.hide_line_numbers) {
-        this._d.fill      = this.font_color;
-        if (this.font) this._d.font = this.font;
-        this._d.stroke    = 'transparent';
-        this._d.pointsize = this._scale_fontsize(this.marker_font_size);
-        this._d.gravity   = 'center';
-        // TODO Center text over line
-        this._d.annotate_scaled(
-                          0, 0, // Width of box to draw text in
-                          x, this._graph_bottom + (this.klass.LABEL_MARGIN * 2.0), // Coordinates of text
-                          this._label(marker_label), this._scale);
-      }
-    }
-  },
-  
-  // Draw on the Y axis instead of the X
-  _draw_label: function(y_offset, index) {
-    if (this.labels[index] && !this._labels_seen[index]) {
-      this._d.fill             = this.font_color;
-      if (this.font) this._d.font = this.font;
-      this._d.stroke           = 'transparent';
-      this._d.font_weight      = 'normal';
-      this._d.pointsize        = this._scale_fontsize(this.marker_font_size);
-      this._d.gravity          = 'east';
-      this._d.annotate_scaled(1, 1,
-                              this._graph_left - this.klass.LABEL_MARGIN * 2.0, y_offset,
-                              this.labels[index], this._scale);
-      this._labels_seen[index] = true;
-    }
-  }
-});
-
-
-// Experimental!!! See also the Net graph.
-//
-// Submitted by Kevin Clark http://glu.ttono.us/
-Bluff.Spider = new JS.Class(Bluff.Base, {
-  
-  // Hide all text
-  hide_text: null,
-  hide_axes: null,
-  transparent_background: null,
-  
-  initialize: function(renderer, max_value, target_width) {
-    this.callSuper(renderer, target_width);
-    this._max_value = max_value;
-    this.hide_legend = true;
-  },
-  
-  draw: function() {
-    this.hide_line_markers = true;
-    
-    this.callSuper();
-    
-    if (!this._has_data) return;
-    
-    // Setup basic positioning
-    var diameter = this._graph_height,
-        radius = this._graph_height / 2.0,
-        top_x = this._graph_left + (this._graph_width - diameter) / 2.0,
-        center_x = this._graph_left + (this._graph_width / 2.0),
-        center_y = this._graph_top + (this._graph_height / 2.0) - 25; // Move graph up a bit
-    
-    this._unit_length = radius / this._max_value;
-    
-    var total_sum = this._sums_for_spider(),
-        prev_degrees = 0.0,
-        additive_angle = (2 * Math.PI) / this._data.length,
-        
-        current_angle = 0.0;
-    
-    // Draw axes
-    if (!this.hide_axes) this._draw_axes(center_x, center_y, radius, additive_angle);
-    
-    // Draw polygon
-    this._draw_polygon(center_x, center_y, additive_angle);
-  },
-  
-  _normalize_points: function(value) {
-    return value * this._unit_length;
-  },
-  
-  _draw_label: function(center_x, center_y, angle, radius, amount) {
-    var r_offset = 50,            // The distance out from the center of the pie to get point
-        x_offset = center_x,      // The label points need to be tweaked slightly
-        y_offset = center_y + 0,  // This one doesn't though
-        x = x_offset + ((radius + r_offset) * Math.cos(angle)),
-        y = y_offset + ((radius + r_offset) * Math.sin(angle));
-    
-    // Draw label
-    this._d.fill = this.marker_color;
-    if (this.font) this._d.font = this.font;
-    this._d.pointsize = this._scale_fontsize(this.legend_font_size);
-    this._d.stroke = 'transparent';
-    this._d.font_weight = 'bold';
-    this._d.gravity = 'center';
-    this._d.annotate_scaled(0, 0,
-                            x, y,
-                            amount, this._scale);
-  },
-  
-  _draw_axes: function(center_x, center_y, radius, additive_angle, line_color) {
-    if (this.hide_axes) return;
-    
-    var current_angle = 0.0;
-    
-    Bluff.each(this._data, function(data_row) {
-      this._d.stroke = line_color || data_row[this.klass.DATA_COLOR_INDEX];
-      this._d.stroke_width = 5.0;
-      
-      var x_offset = radius * Math.cos(current_angle);
-      var y_offset = radius * Math.sin(current_angle);
-      
-      this._d.line(center_x, center_y,
-                   center_x + x_offset,
-                   center_y + y_offset);
-      
-      if (!this.hide_text) this._draw_label(center_x, center_y, current_angle, radius, data_row[this.klass.DATA_LABEL_INDEX]);
-      
-      current_angle += additive_angle;
-    }, this);
-  },
-  
-  _draw_polygon: function(center_x, center_y, additive_angle, color) {
-    var points = [],
-        current_angle = 0.0;
-    Bluff.each(this._data, function(data_row) {
-      points.push(center_x + this._normalize_points(data_row[this.klass.DATA_VALUES_INDEX][0]) * Math.cos(current_angle));
-      points.push(center_y + this._normalize_points(data_row[this.klass.DATA_VALUES_INDEX][0]) * Math.sin(current_angle));
-      current_angle += additive_angle;
-    }, this);
-    
-    this._d.stroke_width = 1.0;
-    this._d.stroke = color || this.marker_color;
-    this._d.fill = color || this.marker_color;
-    this._d.fill_opacity = 0.4;
-    this._d.polyline(points);
-  },
-  
-  _sums_for_spider: function() {
-    var sum = 0.0;
-    Bluff.each(this._data, function(data_row) {
-      sum += data_row[this.klass.DATA_VALUES_INDEX][0];
-    }, this);
-    return sum;
-  }
-});
-
-
-// Used by StackedBar and child classes.
-Bluff.Base.StackedMixin = new JS.Module({
-  // Get sum of each stack
-  _get_maximum_by_stack: function() {
-    var max_hash = {};
-    Bluff.each(this._data, function(data_set) {
-      Bluff.each(data_set[this.klass.DATA_VALUES_INDEX], function(data_point, i) {
-        if (!max_hash[i]) max_hash[i] = 0.0;
-        max_hash[i] += data_point;
-      }, this);
-    }, this);
-    
-    // this.maximum_value = 0;
-    for (var key in max_hash) {
-      if (max_hash[key] > this.maximum_value) this.maximum_value = max_hash[key];
-    }
-    this.minimum_value = 0;
-  }
-});
-
-
-Bluff.StackedArea = new JS.Class(Bluff.Base, {
-  include: Bluff.Base.StackedMixin,
-  last_series_goes_on_bottom: null,
-  
-  draw: function() {
-    this._get_maximum_by_stack();
-    this.callSuper();
-    
-    if (!this._has_data) return;
-    
-    this._x_increment = this._graph_width / (this._column_count - 1);
-    this._d.stroke = 'transparent';
-    
-    var height = Bluff.array_new(this._column_count, 0);
-    
-    var data_points = null;
-    var iterator = this.last_series_goes_on_bottom ? 'reverse_each' : 'each';
-    Bluff[iterator](this._norm_data, function(data_row) {
-      var prev_data_points = data_points;
-      data_points = [];
-      
-      Bluff.each(data_row[this.klass.DATA_VALUES_INDEX], function(data_point, index) {
-        // Use incremented x and scaled y
-        var new_x = this._graph_left + (this._x_increment * index);
-        var new_y = this._graph_top + (this._graph_height - data_point * this._graph_height - height[index]);
-        
-        height[index] += (data_point * this._graph_height);
-        
-        data_points.push(new_x);
-        data_points.push(new_y);
-        
-        this._draw_label(new_x, index);
-      }, this);
-      
-      var poly_points, i, n;
-      
-      if (prev_data_points) {
-        poly_points = Bluff.array(data_points);
-        for (i = prev_data_points.length/2 - 1; i >= 0; i--) {
-          poly_points.push(prev_data_points[2*i]);
-          poly_points.push(prev_data_points[2*i+1]);
-        }
-        poly_points.push(data_points[0]);
-        poly_points.push(data_points[1]);
-      } else {
-        poly_points = Bluff.array(data_points);
-        poly_points.push(this._graph_right);
-        poly_points.push(this._graph_bottom - 1);
-        poly_points.push(this._graph_left);
-        poly_points.push(this._graph_bottom - 1);
-        poly_points.push(data_points[0]);
-        poly_points.push(data_points[1]);
-      }
-      this._d.fill = data_row[this.klass.DATA_COLOR_INDEX];
-      this._d.polyline(poly_points);
-    }, this);
-  }
-});
-
-
-Bluff.StackedBar = new JS.Class(Bluff.Base, {
-  include: Bluff.Base.StackedMixin,
-  
-  // Spacing factor applied between bars
-  bar_spacing: 0.9,
-  
-  // Draws a bar graph, but multiple sets are stacked on top of each other.
-  draw: function() {
-    this._get_maximum_by_stack();
-    this.callSuper();
-    if (!this._has_data) return;
-    
-    this._bar_width = this._graph_width / this._column_count;
-    var padding = (this._bar_width * (1 - this.bar_spacing)) / 2;
-    
-    this._d.stroke_opacity = 0.0;
-    
-    var height = Bluff.array_new(this._column_count, 0);
-    
-    Bluff.each(this._norm_data, function(data_row, row_index) {
-      var raw_data = this._data[row_index][this.klass.DATA_VALUES_INDEX];
-      
-      Bluff.each(data_row[this.klass.DATA_VALUES_INDEX], function(data_point, point_index) {
-        // Calculate center based on bar_width and current row
-        var label_center = this._graph_left + (this._bar_width * point_index) + (this._bar_width * this.bar_spacing / 2.0);
-        this._draw_label(label_center, point_index);
-        
-        if (data_point == 0) return;
-        // Use incremented x and scaled y
-        var left_x = this._graph_left + (this._bar_width * point_index) + padding;
-        var left_y = this._graph_top + (this._graph_height -
-                                        data_point * this._graph_height - 
-                                        height[point_index]) + 1;
-        var right_x = left_x + this._bar_width * this.bar_spacing;
-        var right_y = this._graph_top + this._graph_height - height[point_index] - 1;
-        
-        // update the total height of the current stacked bar
-        height[point_index] += (data_point * this._graph_height);
-        
-        this._d.fill = data_row[this.klass.DATA_COLOR_INDEX];
-        this._d.rectangle(left_x, left_y, right_x, right_y);
-        
-        this._draw_tooltip(left_x, left_y,
-                           right_x - left_x, right_y - left_y,
-                           data_row[this.klass.DATA_LABEL_INDEX],
-                           data_row[this.klass.DATA_COLOR_INDEX],
-                           raw_data[point_index], point_index);
-      }, this);
-    }, this);
-  }
-});
-
-
-// A special bar graph that shows a single dataset as a set of
-// stacked bars. The bottom bar shows the running total and 
-// the top bar shows the new value being added to the array.
-
-Bluff.AccumulatorBar = new JS.Class(Bluff.StackedBar, {
-  
-  draw: function() {
-    if (this._data.length !== 1) throw 'Incorrect number of datasets';
-    
-    var accumulator_array = [],
-        index = 0,
-        increment_array = [];
-    
-    Bluff.each(this._data[0][this.klass.DATA_VALUES_INDEX], function(value) {
-      var max = -Infinity;
-      Bluff.each(increment_array, function(x) { max = Math.max(max, x); });
-      
-      increment_array.push((index > 0) ? (value + max) : value);
-      accumulator_array.push(increment_array[index] - value);
-      index += 1;
-    }, this);
-    
-    this.data("Accumulator", accumulator_array);
-    
-    this.callSuper();
-  }
-});
-
-
-// New gruff graph type added to enable sideways stacking bar charts 
-// (basically looks like a x/y flip of a standard stacking bar chart)
-//
-// alun.eyre@googlemail.com
-
-Bluff.SideStackedBar = new JS.Class(Bluff.SideBar, {
-  include: Bluff.Base.StackedMixin,
-  
-  // Spacing factor applied between bars
-  bar_spacing: 0.9,
-  
-  draw: function() {
-    this.has_left_labels = true;
-    this._get_maximum_by_stack();
-    this.callSuper();
-  },
-  
-  _draw_bars: function() {
-    this._bar_width = this._graph_height / this._column_count;
-    var height = Bluff.array_new(this._column_count, 0),
-        length = Bluff.array_new(this._column_count, this._graph_left),
-        padding = (this._bar_width * (1 - this.bar_spacing)) / 2;
-
-    Bluff.each(this._norm_data, function(data_row, row_index) {
-      var raw_data = this._data[row_index][this.klass.DATA_VALUES_INDEX];
-      
-      Bluff.each(data_row[this.klass.DATA_VALUES_INDEX], function(data_point, point_index) {
-        
-        // using the original calcs from the stacked bar chart to get the difference between
-        // part of the bart chart we wish to stack.
-        var temp1 = this._graph_left + (this._graph_width -
-                                            data_point * this._graph_width - 
-                                            height[point_index]) + 1;
-        var temp2 = this._graph_left + this._graph_width - height[point_index] - 1;
-        var difference = temp2 - temp1;
-        
-        this._d.fill = data_row[this.klass.DATA_COLOR_INDEX];
-        
-        var left_x = length[point_index], //+ 1
-            left_y = this._graph_top + (this._bar_width * point_index) + padding,
-            right_x = left_x + difference,
-            right_y = left_y + this._bar_width * this.bar_spacing;
-        length[point_index] += difference;
-        height[point_index] += (data_point * this._graph_width - 2);
-        
-        this._d.rectangle(left_x, left_y, right_x, right_y);
-        
-        this._draw_tooltip(left_x, left_y,
-                           right_x - left_x, right_y - left_y,
-                           data_row[this.klass.DATA_LABEL_INDEX],
-                           data_row[this.klass.DATA_COLOR_INDEX],
-                           raw_data[point_index], point_index);
-        
-        // Calculate center based on bar_width and current row
-        var label_center = this._graph_top + (this._bar_width * point_index) + (this._bar_width * this.bar_spacing / 2.0);
-        this._draw_label(label_center, point_index);
-      }, this);
-    }, this);
-  },
-  
-  _larger_than_max: function(data_point, index) {
-    index = index || 0;
-    return this._max(data_point, index) > this.maximum_value;
-  },
-  
-  _max: function(data_point, index) {
-    var sum = 0;
-    Bluff.each(this._data, function(item) {
-      sum += item[this.klass.DATA_VALUES_INDEX][index];
-    }, this);
-    return sum;
-  }
-});
-
-
-Bluff.Mini.Legend = new JS.Module({
-  
-  hide_mini_legend: false,
-  
-  // The canvas needs to be bigger so we can put the legend beneath it.
-  _expand_canvas_for_vertical_legend: function() {
-    if (this.hide_mini_legend) return;
-    
-    this._legend_labels = Bluff.map(this._data, function(item) {
-      return item[this.klass.DATA_LABEL_INDEX];
-    }, this);
-    
-    var legend_height = this._scale_fontsize(
-                          this._data.length * this._calculate_line_height() +
-                          this.top_margin + this.bottom_margin);
-    
-    this._original_rows = this._raw_rows;
-    this._original_columns = this._raw_columns;
-    
-    switch (this.legend_position) {
-      case 'right':
-        this._rows = Math.max(this._rows, legend_height);
-        this._columns += this._calculate_legend_width() + this.left_margin;
-        break;
-      
-      default:
-        this._rows += legend_height;
-        break;
-    }
-    this._render_background();
-  },
-  
-  _calculate_line_height: function() {
-    return this._calculate_caps_height(this.legend_font_size) * 1.7;
-  },
-  
-  _calculate_legend_width: function() {
-    var width = 0;
-    Bluff.each(this._legend_labels, function(label) {
-      width = Math.max(this._calculate_width(this.legend_font_size, label), width);
-    }, this);
-    return this._scale_fontsize(width + 40*1.7);
-  },
-  
-  // Draw the legend beneath the existing graph.
-  _draw_vertical_legend: function() {
-    if (this.hide_mini_legend) return;
-    
-    var legend_square_width = 40.0, // small square with color of this item
-        legend_square_margin = 10.0,
-        legend_left_margin = 100.0,
-        legend_top_margin = 40.0;
-    
-    // May fix legend drawing problem at small sizes
-    if (this.font) this._d.font = this.font;
-    this._d.pointsize = this.legend_font_size;
-    
-    var current_x_offset, current_y_offset;
-    
-    switch (this.legend_position) {
-      case 'right':
-        current_x_offset = this._original_columns + this.left_margin;
-        current_y_offset = this.top_margin + legend_top_margin;
-        break;
-      
-      default:
-        current_x_offset = legend_left_margin,
-        current_y_offset = this._original_rows + legend_top_margin;
-        break;
-    }
-    
-    this._debug(function() {
-      this._d.line(0.0, current_y_offset, this._raw_columns, current_y_offset);
-    });
-    
-    Bluff.each(this._legend_labels, function(legend_label, index) {
-      
-      // Draw label
-      this._d.fill = this.font_color;
-      if (this.font) this._d.font = this.font;
-      this._d.pointsize = this._scale_fontsize(this.legend_font_size);
-      this._d.stroke = 'transparent';
-      this._d.font_weight = 'normal';
-      this._d.gravity = 'west';
-      this._d.annotate_scaled(this._raw_columns, 1.0,
-                        current_x_offset + (legend_square_width * 1.7), current_y_offset, 
-                        this._truncate_legend_label(legend_label), this._scale);
-      
-      // Now draw box with color of this dataset
-      this._d.stroke = 'transparent';
-      this._d.fill = this._data[index][this.klass.DATA_COLOR_INDEX];
-      this._d.rectangle(current_x_offset, 
-                        current_y_offset - legend_square_width / 2.0, 
-                        current_x_offset + legend_square_width, 
-                        current_y_offset + legend_square_width / 2.0);
-      
-      current_y_offset += this._calculate_line_height();
-    }, this);
-    this._color_index = 0;
-  },
-  
-  // Shorten long labels so they will fit on the canvas.
-  _truncate_legend_label: function(label) {
-    var truncated_label = String(label);
-    while (this._calculate_width(this._scale_fontsize(this.legend_font_size), truncated_label) > (this._columns - this.legend_left_margin - this.right_margin) && (truncated_label.length > 1))
-      truncated_label = truncated_label.substr(0, truncated_label.length-1);
-    return truncated_label + (truncated_label.length < String(label).length ? "..." : '');
-  }
-});
-
-
-// Makes a small bar graph suitable for display at 200px or even smaller.
-//
-Bluff.Mini.Bar = new JS.Class(Bluff.Bar, {
-  include: Bluff.Mini.Legend,
-  
-  initialize_ivars: function() {
-    this.callSuper();
-    
-    this.hide_legend = true;
-    this.hide_title = true;
-    this.hide_line_numbers = true;
-    
-    this.marker_font_size = 50.0;
-    this.minimum_value = 0.0;
-    this.maximum_value = 0.0;
-    this.legend_font_size = 60.0;
-  },
-  
-  draw: function() {
-    this._expand_canvas_for_vertical_legend();
-    
-    this.callSuper();
-    
-    this._draw_vertical_legend();
-  }
-});
-
-
-// Makes a small pie graph suitable for display at 200px or even smaller.
-//
-Bluff.Mini.Pie = new JS.Class(Bluff.Pie, {
-  include: Bluff.Mini.Legend,
-  
-  initialize_ivars: function() {
-    this.callSuper();
-    
-    this.hide_legend = true;
-    this.hide_title = true;
-    this.hide_line_numbers = true;
-    
-    this.marker_font_size = 60.0;
-    this.legend_font_size = 60.0;
-  },
-  
-  draw: function() {
-    this._expand_canvas_for_vertical_legend();
-    
-    this.callSuper();
-    
-    this._draw_vertical_legend();
-  }
-});
-
-
-// Makes a small pie graph suitable for display at 200px or even smaller.
-//
-Bluff.Mini.SideBar = new JS.Class(Bluff.SideBar, {
-  include: Bluff.Mini.Legend,
-  
-  initialize_ivars: function() {
-    this.callSuper();
-    this.hide_legend = true;
-    this.hide_title = true;
-    this.hide_line_numbers = true;
-    
-    this.marker_font_size = 50.0;
-    this.legend_font_size = 50.0;
-  },
-  
-  draw: function() {
-    this._expand_canvas_for_vertical_legend();
-    
-    this.callSuper();
-    
-    this._draw_vertical_legend();
-  }
-});
-
-
-Bluff.Renderer = new JS.Class({
-  extend: {
-    WRAPPER_CLASS:  'bluff-wrapper',
-    TEXT_CLASS:     'bluff-text',
-    TARGET_CLASS:   'bluff-tooltip-target'
-  },
-
-  font:     'Arial, Helvetica, Verdana, sans-serif',
-  gravity:  'north',
-  
-  initialize: function(canvasId) {
-    this._canvas = document.getElementById(canvasId);
-    this._ctx = this._canvas.getContext('2d');
-  },
-  
-  scale: function(sx, sy) {
-    this._sx = sx;
-    this._sy = sy || sx;
-  },
-  
-  caps_height: function(font_size) {
-    var X = this._sized_text(font_size, 'X'),
-        height = this._element_size(X).height;
-    this._remove_node(X);
-    return height;
-  },
-  
-  text_width: function(font_size, text) {
-    var element = this._sized_text(font_size, text);
-    var width = this._element_size(element).width;
-    this._remove_node(element);
-    return width;
-  },
-  
-  get_type_metrics: function(text) {
-    var node = this._sized_text(this.pointsize, text);
-    document.body.appendChild(node);
-    var size = this._element_size(node);
-    this._remove_node(node);
-    return size;
-  },
-  
-  clear: function(width, height) {
-    this._canvas.width = width;
-    this._canvas.height = height;
-    this._ctx.clearRect(0, 0, width, height);
-    var wrapper = this._text_container(), children = wrapper.childNodes, i = children.length;
-    wrapper.style.width = width + 'px';
-    wrapper.style.height = height + 'px';
-    while (i--) {
-      if (children[i].tagName.toLowerCase() !== 'canvas') {
-        Bluff.Event.stopObserving(children[i]);
-        this._remove_node(children[i]);
-      }
-    }
-  },
-  
-  push: function() {
-    this._ctx.save();
-  },
-  
-  pop: function() {
-    this._ctx.restore();
-  },
-  
-  render_gradiated_background: function(width, height, top_color, bottom_color) {
-    this.clear(width, height);
-    var gradient = this._ctx.createLinearGradient(0,0, 0,height);
-    gradient.addColorStop(0, top_color);
-    gradient.addColorStop(1, bottom_color);
-    this._ctx.fillStyle = gradient;
-    this._ctx.fillRect(0, 0, width, height);
-  },
-  
-  render_solid_background: function(width, height, color) {
-    this.clear(width, height);
-    this._ctx.fillStyle = color;
-    this._ctx.fillRect(0, 0, width, height);
-  },
-  
-  annotate_scaled: function(width, height, x, y, text, scale) {
-    var scaled_width = (width * scale) >= 1 ? (width * scale) : 1;
-    var scaled_height = (height * scale) >= 1 ? (height * scale) : 1;
-    var text = this._sized_text(this.pointsize, text);
-    text.style.color = this.fill;
-    text.style.cursor = 'default';
-    text.style.fontWeight = this.font_weight;
-    text.style.textAlign = 'center';
-    text.style.left = (this._sx * x + this._left_adjustment(text, scaled_width)) + 'px';
-    text.style.top = (this._sy * y + this._top_adjustment(text, scaled_height)) + 'px';
-  },
-  
-  tooltip: function(left, top, width, height, name, color, data) {
-    if (width < 0) left += width;
-    if (height < 0) top += height;
-    
-    var wrapper = this._canvas.parentNode,
-        target = document.createElement('div');
-    target.className = this.klass.TARGET_CLASS;
-    target.style.cursor = 'default';
-    target.style.position = 'absolute';
-    target.style.left = (this._sx * left - 3) + 'px';
-    target.style.top = (this._sy * top - 3) + 'px';
-    target.style.width = (this._sx * Math.abs(width) + 5) + 'px';
-    target.style.height = (this._sy * Math.abs(height) + 5) + 'px';
-    target.style.fontSize = 0;
-    target.style.overflow = 'hidden';
-    
-    Bluff.Event.observe(target, 'mouseover', function(node) {
-      Bluff.Tooltip.show(name, color, data);
-    });
-    Bluff.Event.observe(target, 'mouseout', function(node) {
-      Bluff.Tooltip.hide();
-    });
-    
-    wrapper.appendChild(target);
-    return target;
-  },
-  
-  circle: function(origin_x, origin_y, perim_x, perim_y, arc_start, arc_end) {
-    var radius = Math.sqrt(Math.pow(perim_x - origin_x, 2) + Math.pow(perim_y - origin_y, 2));
-    var alpha = 0, beta = 2 * Math.PI; // radians to full circle
-    
-    this._ctx.fillStyle = this.fill;
-    this._ctx.beginPath();
-    
-    if (arc_start !== undefined && arc_end !== undefined &&
-        Math.abs(Math.floor(arc_end - arc_start)) !== 360) {
-      alpha = arc_start * Math.PI/180;
-      beta  = arc_end   * Math.PI/180;
-      
-      this._ctx.moveTo(this._sx * (origin_x + radius * Math.cos(beta)), this._sy * (origin_y + radius * Math.sin(beta)));
-      this._ctx.lineTo(this._sx * origin_x, this._sy * origin_y);
-      this._ctx.lineTo(this._sx * (origin_x + radius * Math.cos(alpha)), this._sy * (origin_y + radius * Math.sin(alpha)));
-    }
-    this._ctx.arc(this._sx * origin_x, this._sy * origin_y, this._sx * radius, alpha, beta, false); // draw it clockwise
-    this._ctx.fill();
-  },
-  
-  line: function(sx, sy, ex, ey) {
-    this._ctx.strokeStyle = this.stroke;
-    this._ctx.lineWidth = this.stroke_width;
-    this._ctx.beginPath();
-    this._ctx.moveTo(this._sx * sx, this._sy * sy);
-    this._ctx.lineTo(this._sx * ex, this._sy * ey);
-    this._ctx.stroke();
-  },
-  
-  polyline: function(points) {
-    this._ctx.fillStyle = this.fill;
-    this._ctx.globalAlpha = this.fill_opacity || 1;
-    try { this._ctx.strokeStyle = this.stroke; } catch (e) {}
-    var x = points.shift(), y = points.shift();
-    this._ctx.beginPath();
-    this._ctx.moveTo(this._sx * x, this._sy * y);
-    while (points.length > 0) {
-      x = points.shift(); y = points.shift();
-      this._ctx.lineTo(this._sx * x, this._sy * y);
-    }
-    this._ctx.fill();
-  },
-  
-  rectangle: function(ax, ay, bx, by) {
-    var temp;
-    if (ax > bx) { temp = ax; ax = bx; bx = temp; }
-    if (ay > by) { temp = ay; ay = by; by = temp; }
-    try {
-      this._ctx.fillStyle = this.fill;
-      this._ctx.fillRect(this._sx * ax, this._sy * ay, this._sx * (bx-ax), this._sy * (by-ay));
-    } catch (e) {}
-    try {
-      this._ctx.strokeStyle = this.stroke;
-      if (this.stroke !== 'transparent')
-        this._ctx.strokeRect(this._sx * ax, this._sy * ay, this._sx * (bx-ax), this._sy * (by-ay));
-    } catch (e) {}
-  },
-  
-  _left_adjustment: function(node, width) {
-    var w = this._element_size(node).width;
-    switch (this.gravity) {
-      case 'west':    return 0;
-      case 'east':    return width - w;
-      case 'north': case 'south': case 'center':
-        return (width - w) / 2;
-    }
-  },
-  
-  _top_adjustment: function(node, height) {
-    var h = this._element_size(node).height;
-    switch (this.gravity) {
-      case 'north':   return 0;
-      case 'south':   return height - h;
-      case 'west': case 'east': case 'center':
-        return (height - h) / 2;
-    }
-  },
-  
-  _text_container: function() {
-    var wrapper = this._canvas.parentNode;
-    if (wrapper.className === this.klass.WRAPPER_CLASS) return wrapper;
-    wrapper = document.createElement('div');
-    wrapper.className = this.klass.WRAPPER_CLASS;
-    
-    wrapper.style.position = 'relative';
-    wrapper.style.border = 'none';
-    wrapper.style.padding = '0 0 0 0';
-    
-    this._canvas.parentNode.insertBefore(wrapper, this._canvas);
-    wrapper.appendChild(this._canvas);
-    return wrapper;
-  },
-  
-  _sized_text: function(size, content) {
-    var text = this._text_node(content);
-    text.style.fontFamily = this.font;
-    text.style.fontSize = (typeof size === 'number') ? size + 'px' : size;
-    return text;
-  },
-  
-  _text_node: function(content) {
-    var div = document.createElement('div');
-    div.className = this.klass.TEXT_CLASS;
-    div.style.position = 'absolute';
-    div.appendChild(document.createTextNode(content));
-    this._text_container().appendChild(div);
-    return div;
-  },
-  
-  _remove_node: function(node) {
-    node.parentNode.removeChild(node);
-    if (node.className === this.klass.TARGET_CLASS)
-      Bluff.Event.stopObserving(node);
-  },
-  
-  _element_size: function(element) {
-    var display = element.style.display;
-    return (display && display !== 'none')
-        ? {width: element.offsetWidth, height: element.offsetHeight}
-        : {width: element.clientWidth, height: element.clientHeight};
-  }
-});
-
-
-// DOM event module, adapted from Prototype
-// Copyright (c) 2005-2008 Sam Stephenson
-
-Bluff.Event = {
-  _cache: [],
-  
-  _isIE: (window.attachEvent && navigator.userAgent.indexOf('Opera') === -1),
-  
-  observe: function(element, eventName, callback, scope) {
-    var handlers = Bluff.map(this._handlersFor(element, eventName),
-                      function(entry) { return entry._handler });
-    if (Bluff.index(handlers, callback) !== -1) return;
-    
-    var responder = function(event) {
-      callback.call(scope || null, element, Bluff.Event._extend(event));
-    };
-    this._cache.push({_node: element, _name: eventName,
-                      _handler: callback, _responder: responder});
-    
-    if (element.addEventListener)
-      element.addEventListener(eventName, responder, false);
-    else
-      element.attachEvent('on' + eventName, responder);
-  },
-  
-  stopObserving: function(element) {
-    var handlers = element ? this._handlersFor(element) : this._cache;
-    Bluff.each(handlers, function(entry) {
-      if (entry._node.removeEventListener)
-        entry._node.removeEventListener(entry._name, entry._responder, false);
-      else
-        entry._node.detachEvent('on' + entry._name, entry._responder);
-    });
-  },
-  
-  _handlersFor: function(element, eventName) {
-    var results = [];
-    Bluff.each(this._cache, function(entry) {
-      if (element && entry._node !== element) return;
-      if (eventName && entry._name !== eventName) return;
-      results.push(entry);
-    });
-    return results;
-  },
-  
-  _extend: function(event) {
-    if (!this._isIE) return event;
-    if (!event) return false;
-    if (event._extendedByBluff) return event;
-    event._extendedByBluff = true;
-    
-    var pointer = this._pointer(event);
-    event.target = event.srcElement;
-    event.pageX = pointer.x;
-    event.pageY = pointer.y;
-    
-    return event;
-  },
-  
-  _pointer: function(event) {
-    var docElement = document.documentElement,
-        body = document.body || { scrollLeft: 0, scrollTop: 0 };
-    return {
-      x: event.pageX || (event.clientX +
-                        (docElement.scrollLeft || body.scrollLeft) -
-                        (docElement.clientLeft || 0)),
-      y: event.pageY || (event.clientY +
-                        (docElement.scrollTop || body.scrollTop) -
-                        (docElement.clientTop || 0))
-    };
-  }
-};
-
-if (Bluff.Event._isIE)
-  window.attachEvent('onunload', function() {
-    Bluff.Event.stopObserving();
-    Bluff.Event._cache = null;
-  });
-
-if (navigator.userAgent.indexOf('AppleWebKit/') > -1)
-  window.addEventListener('unload', function() {}, false);
-
-
-Bluff.Tooltip = new JS.Singleton({
-  LEFT_OFFSET:  20,
-  TOP_OFFSET:   -6,
-  DATA_LENGTH:  8,
-  
-  CLASS_NAME:   'bluff-tooltip',
-  
-  setup: function() {
-    this._tip = document.createElement('div');
-    this._tip.className = this.CLASS_NAME;
-    this._tip.style.position = 'absolute';
-    this.hide();
-    document.body.appendChild(this._tip);
-    
-    Bluff.Event.observe(document.body, 'mousemove', function(body, event) {
-      this._tip.style.left = (event.pageX + this.LEFT_OFFSET) + 'px';
-      this._tip.style.top = (event.pageY + this.TOP_OFFSET) + 'px';
-    }, this);
-  },
-  
-  show: function(name, color, data) {
-    data = Number(String(data).substr(0, this.DATA_LENGTH));
-    this._tip.innerHTML = '<span class="color" style="background: ' + color + ';">&nbsp;</span> ' +
-                          '<span class="label">' + name + '</span> ' +
-                          '<span class="data">' + data + '</span>';
-    this._tip.style.display = '';
-  },
-  
-  hide: function() {
-    this._tip.style.display = 'none';
-  }
-});
-
-Bluff.Event.observe(window, 'load', Bluff.Tooltip.method('setup'));
-
-
-Bluff.TableReader = new JS.Class({
-  
-  NUMBER_FORMAT: /\-?(0|[1-9]\d*)(\.\d+)?(e[\+\-]?\d+)?/i,
-  
-  initialize: function(table, options) {
-    this._options = options || {};
-    this._orientation = this._options.orientation || 'auto';
-    
-    this._table = (typeof table === 'string')
-        ? document.getElementById(table)
-        : table;
-  },
-  
-  // Get array of data series from the table
-  get_data: function() {
-    if (!this._data) this._read();
-    return this._data;
-  },
-  
-  // Get set of axis labels to use for the graph
-  get_labels: function() {
-    if (!this._labels) this._read();
-    return this._labels;
-  },
-  
-  // Get the title from the table's caption
-  get_title: function() {
-    return this._title;
-  },
-  
-  // Return series number i
-  get_series: function(i) {
-    if (this._data[i]) return this._data[i];
-    return this._data[i] = {points: []};
-  },
-  
-  // Gather data by reading from the table
-  _read: function() {
-    this._row = this._col = 0;
-    this._row_offset = this._col_offset = 0;
-    this._data = [];
-    this._labels = {};
-    this._row_headings = [];
-    this._col_headings = [];
-    this._skip_rows = [];
-    this._skip_cols = [];
-    
-    this._walk(this._table);
-    this._cleanup();
-    this._orient();
-    
-    Bluff.each(this._col_headings, function(heading, i) {
-      this.get_series(i - this._col_offset).name = heading;
-    }, this);
-    
-    Bluff.each(this._row_headings, function(heading, i) {
-      this._labels[i - this._row_offset] = heading;
-    }, this);
-  },
-  
-  // Walk the table's DOM tree
-  _walk: function(node) {
-    this._visit(node);
-    var i, children = node.childNodes, n = children.length;
-    for (i = 0; i < n; i++) this._walk(children[i]);
-  },
-  
-  // Read a single DOM node from the table
-  _visit: function(node) {
-    if (!node.tagName) return;
-    var content = this._strip_tags(node.innerHTML), x, y;
-    switch (node.tagName.toUpperCase()) {
-    
-      case 'TR':
-        if (!this._has_data) this._row_offset = this._row;
-        this._row += 1;
-        this._col = 0;
-        break;
-      
-      case 'TD':
-        if (!this._has_data) this._col_offset = this._col;
-        this._has_data = true;
-        this._col += 1;
-        content = content.match(this.NUMBER_FORMAT);
-        if (content === null) {
-          this.get_series(x).points[y] = null;
-        } else {
-          x = this._col - this._col_offset - 1;
-          y = this._row - this._row_offset - 1;
-          this.get_series(x).points[y] = parseFloat(content[0]);
-        }
-        break;
-      
-      case 'TH':
-        this._col += 1;
-        if (this._ignore(node)) {
-          this._skip_cols.push(this._col);
-          this._skip_rows.push(this._row);
-        }
-        if (this._col === 1 && this._row === 1)
-          this._row_headings[0] = this._col_headings[0] = content;
-        else if (node.scope === "row" || this._col === 1)
-          this._row_headings[this._row - 1] = content;
-        else
-          this._col_headings[this._col - 1] = content;
-        break;
-      
-      case 'CAPTION':
-        this._title = content;
-        break;
-    }
-  },
-  
-  _ignore: function(node) {
-    if (!this._options.except) return false;
-    
-    var content = this._strip_tags(node.innerHTML),
-        classes = (node.className || '').split(/\s+/),
-        list = [].concat(this._options.except);
-    
-    if (Bluff.index(list, content) >= 0) return true;
-    var i = classes.length;
-    while (i--) {
-      if (Bluff.index(list, classes[i]) >= 0) return true;
-    }
-    return false;
-  },
-  
-  _cleanup: function() {
-    var i = this._skip_cols.length, index;
-    while (i--) {
-      index = this._skip_cols[i];
-      if (index <= this._col_offset) continue;
-      this._col_headings.splice(index - 1, 1);
-      if (index >= this._col_offset)
-        this._data.splice(index - 1 - this._col_offset, 1);
-    }
-    
-    var i = this._skip_rows.length, index;
-    while (i--) {
-      index = this._skip_rows[i];
-      if (index <= this._row_offset) continue;
-      this._row_headings.splice(index - 1, 1);
-      Bluff.each(this._data, function(series) {
-        if (index >= this._row_offset)
-          series.points.splice(index - 1 - this._row_offset, 1);
-      }, this);
-    }
-  },
-  
-  _orient: function() {
-    switch (this._orientation) {
-      case 'auto':
-        if ((this._row_headings.length > 1 && this._col_headings.length === 1) ||
-            this._row_headings.length < this._col_headings.length) {
-          this._transpose();
-        }
-        break;
-        
-      case 'rows':
-        this._transpose();
-        break;
-    }
-  },
-  
-  // Transpose data in memory
-  _transpose: function() {
-    var data = this._data, tmp;
-    this._data = [];
-    
-    Bluff.each(data, function(row, i) {
-      Bluff.each(row.points, function(point, p) {
-        this.get_series(p).points[i] = point;
-      }, this);
-    }, this);
-    
-    tmp = this._row_headings;
-    this._row_headings = this._col_headings;
-    this._col_headings = tmp;
-    
-    tmp = this._row_offset;
-    this._row_offset = this._col_offset;
-    this._col_offset = tmp;
-  },
-  
-  // Remove HTML from a string
-  _strip_tags: function(string) {
-    return string.replace(/<\/?[^>]+>/gi, '');
-  },
-  
-  extend: {
-    Mixin: new JS.Module({
-      data_from_table: function(table, options) {
-        var reader    = new Bluff.TableReader(table, options),
-            data_rows = reader.get_data();
-        
-        Bluff.each(data_rows, function(row) {
-          this.data(row.name, row.points);
-        }, this);
-        
-        this.labels = reader.get_labels();
-        this.title  = reader.get_title() || this.title;
-      }
-    })
-  }
-});
-
-Bluff.Base.include(Bluff.TableReader.Mixin);
-})(jQuery);
diff --git a/apis/charts_graphs_bluff/bluff/CHANGELOG.txt b/apis/charts_graphs_bluff/bluff/CHANGELOG.txt
deleted file mode 100644
index 931d1ce..0000000
--- a/apis/charts_graphs_bluff/bluff/CHANGELOG.txt
+++ /dev/null
@@ -1,93 +0,0 @@
-Version 0.3.6.2
-January 3 2011
-================================================================
-
-* Let Pie charts support tooltips.
-
-* Add an 'orientation' option to data_from_table() that takes
-  'auto', 'rows' or 'cols'.
-
-* Add options to data_from_table() to exclude certain rows or
-  columns, based on title or DOM class.
-
-* Provide an event handler interface for when the user clicks
-  on tooltips.
-
-* Add a set_background() method to configure the background
-  without changing the whole theme.
-
-* Fix axis data-range bug in SideBar, respecting the minimum
-  value if set by the user.
-
-* Apply bar_spacing correctly to SideBar graphs.
-
-
-Version 0.3.6.1
-July 25 2010
-================================================================
-
-* Allow Mini.* to have their legends rendered on the right hand
-  side using the legend_position option.
-
-* Fix bugs with drawing full circles in pie and line graphs.
-
-* Stop colours being repeated prematurely.
-
-
-Version 0.3.6
-September 14 2009
-================================================================
-
-* Tooltips are now available on line and bar graphs. Thanks
-  to CrimsonJet, makers of Appstatz.com, for sponsoring this
-  feature's development.
-
-* New graph type ported from Gruff: Bluff.Dot.
-
-* New options available: title_margin, legend_margin, dot_radius,
-  line_width, bar_spacing, hide_labels_less_than.
-
-* JS.Class updated to 2.1.
-
-* Improved handling of data labels; values are truncated to
-  a few significant decimal places and formatted with thousand
-  delimiters.
-
-* TableReader handles non-numeric/empty cells more elegantly.
-
-* Fixes text rendering bugs relating to font weighting and
-  automatic size detection.
-
-* Allows plotting to proceed if all data is zero.
-
-
-Version 0.3.4.2
-October 27 2008
-================================================================
-
-* Fixes bug caused in normalization methods triggered by zero
-  values given to Base#data().
-
-
-Version 0.3.4.1
-October 1 2008
-================================================================
-
-* Upgrades JS.Class to 2.0.2.
-
-* Text nodes are now rendered inside a div that wraps the canvas
-  instead of just inside the <body> element. This improves
-  behaviour with respect to page zooming and relative positioning.
-
-* Fixes bugs in label rounding and zero-value handling.
-
-
-Version 0.3.4
-September 15 2008
-================================================================
-
-* Initial release, based on Gruff 0.3.4. Includes AccumulatorBar,
-  Area, Bar, Line, Net, Pie, SideBar, SideStackedBar, Spider,
-  StackedArea, StackedBar, Mini.Bar, Mini.Pie and Mini.SideBar,
-  plus ability to pull data from HTML tables.
-
diff --git a/apis/charts_graphs_bluff/bluff/GPL-LICENSE.txt b/apis/charts_graphs_bluff/bluff/GPL-LICENSE.txt
deleted file mode 100644
index d159169..0000000
--- a/apis/charts_graphs_bluff/bluff/GPL-LICENSE.txt
+++ /dev/null
@@ -1,339 +0,0 @@
-                    GNU GENERAL PUBLIC LICENSE
-                       Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-                            Preamble
-
-  The licenses for most software are designed to take away your
-freedom to share and change it.  By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users.  This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it.  (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.)  You can apply it to
-your programs, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
-  To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have.  You must make sure that they, too, receive or can get the
-source code.  And you must show them these terms so they know their
-rights.
-
-  We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
-  Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software.  If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
-  Finally, any free program is threatened constantly by software
-patents.  We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary.  To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-
-                    GNU GENERAL PUBLIC LICENSE
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-  0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License.  The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language.  (Hereinafter, translation is included without limitation in
-the term "modification".)  Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope.  The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
-  1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
-  2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
-    a) You must cause the modified files to carry prominent notices
-    stating that you changed the files and the date of any change.
-
-    b) You must cause any work that you distribute or publish, that in
-    whole or in part contains or is derived from the Program or any
-    part thereof, to be licensed as a whole at no charge to all third
-    parties under the terms of this License.
-
-    c) If the modified program normally reads commands interactively
-    when run, you must cause it, when started running for such
-    interactive use in the most ordinary way, to print or display an
-    announcement including an appropriate copyright notice and a
-    notice that there is no warranty (or else, saying that you provide
-    a warranty) and that users may redistribute the program under
-    these conditions, and telling the user how to view a copy of this
-    License.  (Exception: if the Program itself is interactive but
-    does not normally print such an announcement, your work based on
-    the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole.  If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works.  But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
-  3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
-    a) Accompany it with the complete corresponding machine-readable
-    source code, which must be distributed under the terms of Sections
-    1 and 2 above on a medium customarily used for software interchange; or,
-
-    b) Accompany it with a written offer, valid for at least three
-    years, to give any third party, for a charge no more than your
-    cost of physically performing source distribution, a complete
-    machine-readable copy of the corresponding source code, to be
-    distributed under the terms of Sections 1 and 2 above on a medium
-    customarily used for software interchange; or,
-
-    c) Accompany it with the information you received as to the offer
-    to distribute corresponding source code.  (This alternative is
-    allowed only for noncommercial distribution and only if you
-    received the program in object code or executable form with such
-    an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it.  For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable.  However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
-  4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License.  Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
-  5. You are not required to accept this License, since you have not
-signed it.  However, nothing else grants you permission to modify or
-distribute the Program or its derivative works.  These actions are
-prohibited by law if you do not accept this License.  Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
-  6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions.  You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
-  7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all.  For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices.  Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
-  8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded.  In such case, this License incorporates
-the limitation as if written in the body of this License.
-
-  9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time.  Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number.  If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation.  If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
-  10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission.  For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this.  Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
-                            NO WARRANTY
-
-  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
-  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
-                     END OF TERMS AND CONDITIONS
-
-            How to Apply These Terms to Your New Programs
-
-  If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
-  To do so, attach the following notices to the program.  It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) <year>  <name of author>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License along
-    with this program; if not, write to the Free Software Foundation, Inc.,
-    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
-    Gnomovision version 69, Copyright (C) year name of author
-    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License.  Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary.  Here is a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
-  `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
-  <signature of Ty Coon>, 1 April 1989
-  Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs.  If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library.  If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
diff --git a/apis/charts_graphs_bluff/bluff/MIT-LICENSE.txt b/apis/charts_graphs_bluff/bluff/MIT-LICENSE.txt
deleted file mode 100644
index b2304b6..0000000
--- a/apis/charts_graphs_bluff/bluff/MIT-LICENSE.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-Bluff -- Beautiful graphs in JavaScript
-http://bluff.jcoglan.com
-
-Copyright (c) 2008-2010 James Coglan
-
-Original Ruby version (c) 2005-2010 Topfunky Corporation boss@topfunky.com
- 
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
- 
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
- 
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/apis/charts_graphs_bluff/bluff/README.txt b/apis/charts_graphs_bluff/bluff/README.txt
deleted file mode 100644
index 8e6a7ff..0000000
--- a/apis/charts_graphs_bluff/bluff/README.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-
-This folder is where Bluff javascripts reside:
-
-bluff-min.js
-excanvas.js
-js-class.js
diff --git a/apis/charts_graphs_bluff/bluff/bluff-min.js b/apis/charts_graphs_bluff/bluff/bluff-min.js
deleted file mode 100644
index 4f8ad93..0000000
--- a/apis/charts_graphs_bluff/bluff/bluff-min.js
+++ /dev/null
@@ -1,3 +0,0 @@
-(function ($) {
-Bluff={VERSION:'0.3.6',array:function(c){if(c.length===undefined)return[c];var d=[],f=c.length;while(f--)d[f]=c[f];return d},array_new:function(c,d){var f=[];while(c--)f.push(d);return f},each:function(c,d,f){for(var g=0,h=c.length;g<h;g++){d.call(f||null,c[g],g)}},index:function(c,d){for(var f=0,g=c.length;f<g;f++){if(c[f]===d)return f}return-1},keys:function(c){var d=[],f;for(f in c)d.push(f);return d},map:function(d,f,g){var h=[];this.each(d,function(c){h.push(f.call(g||null,c))});return h},reverse_each:function(c,d,f){var g=c.length;while(g--)d.call(f||null,c[g],g)},sum:function(c){var d=0,f=c.length;while(f--)d+=c[f];return d},Mini:{}};Bluff.Base=new JS.Class({extend:{DEBUG:false,DATA_LABEL_INDEX:0,DATA_VALUES_INDEX:1,DATA_COLOR_INDEX:2,LEGEND_MARGIN:20,TITLE_MARGIN:20,LABEL_MARGIN:10,DEFAULT_MARGIN:20,DEFAULT_TARGET_WIDTH:800,THOUSAND_SEPARATOR:','},top_margin:null,bottom_margin:null,right_margin:null,left_margin:null,title_margin:null,legend_margin:null,labels:null,center_labels_over_point:null,has_left_labels:null,x_axis_label:null,y_axis_label:null,y_axis_increment:null,colors:null,title:null,font:null,font_color:null,hide_line_markers:null,hide_legend:null,hide_title:null,hide_line_numbers:null,no_data_message:null,title_font_size:null,legend_font_size:null,marker_font_size:null,marker_color:null,marker_count:null,minimum_value:null,maximum_value:null,sort:null,additional_line_values:null,stacked:null,legend_box_size:null,tooltips:false,initialize:function(c,d){this._0=new Bluff.Renderer(c);d=d||this.klass.DEFAULT_TARGET_WIDTH;var f;if(typeof d!=='number'){f=d.split('x');this._j=parseFloat(f[0]);this._t=parseFloat(f[1])}else{this._j=parseFloat(d);this._t=this._j*0.75}this.initialize_ivars();this._1j();this.theme_keynote();this._10={}},initialize_ivars:function(){this._b=800;this._L=800*(this._t/this._j);this._5=0;this.marker_count=null;this.maximum_value=this.minimum_value=null;this._c=false;this._1=[];this.labels={};this._u={};this.sort=true;this.title=null;this._a=this._j/this._b;this.marker_font_size=21.0;this.legend_font_size=20.0;this.title_font_size=36.0;this.top_margin=this.bottom_margin=this.left_margin=this.right_margin=this.klass.DEFAULT_MARGIN;this.legend_margin=this.klass.LEGEND_MARGIN;this.title_margin=this.klass.TITLE_MARGIN;this.legend_box_size=20.0;this.no_data_message="No Data";this.hide_line_markers=this.hide_legend=this.hide_title=this.hide_line_numbers=false;this.center_labels_over_point=true;this.has_left_labels=false;this.additional_line_values=[];this._1C=[];this._k={};this.x_axis_label=this.y_axis_label=null;this.y_axis_increment=null;this.stacked=null;this._9=null},set_margins:function(c){this.top_margin=this.left_margin=this.right_margin=this.bottom_margin=c},set_font:function(c){this.font=c;this._0.font=this.font},add_color:function(c){this.colors.push(c)},replace_colors:function(c){this.colors=c||[];this._w=0},set_theme:function(c){this._1j();this._k={colors:['black','white'],additional_line_colors:[],marker_color:'white',font_color:'black',background_colors:null,background_image:null};for(var d in c)this._k[d]=c[d];this.colors=this._k.colors;this.marker_color=this._k.marker_color;this.font_color=this._k.font_color||this.marker_color;this._1C=this._k.additional_line_colors;this._M()},set_background:function(c){if(c.colors)this._k.background_colors=c.colors;if(c.image)this._k.background_image=c.image;this._M()},theme_keynote:function(){this._11='#6886B4';this._12='#FDD84E';this._v='#72AE6E';this._D='#D1695E';this._13='#8A6EAF';this._E='#EFAA43';this._F='white';this.colors=[this._12,this._11,this._v,this._D,this._13,this._E,this._F];this.set_theme({colors:this.colors,marker_color:'white',font_color:'white',background_colors:['black','#4a465a']})},theme_37signals:function(){this._v='#339933';this._13='#cc99cc';this._11='#336699';this._12='#FFF804';this._D='#ff0000';this._E='#cf5910';this._G='black';this.colors=[this._12,this._11,this._v,this._D,this._13,this._E,this._G];this.set_theme({colors:this.colors,marker_color:'black',font_color:'black',background_colors:['#d1edf5','white']})},theme_rails_keynote:function(){this._v='#00ff00';this._14='#333333';this._E='#ff5d00';this._D='#f61100';this._F='white';this._15='#999999';this._G='black';this.colors=[this._v,this._14,this._E,this._D,this._F,this._15,this._G];this.set_theme({colors:this.colors,marker_color:'white',font_color:'white',background_colors:['#0083a3','#0083a3']})},theme_odeo:function(){this._14='#202020';this._F='white';this._1D='#a21764';this._v='#8ab438';this._15='#999999';this._1E='#3a5b87';this._G='black';this.colors=[this._14,this._F,this._1E,this._1D,this._v,this._15,this._G];this.set_theme({colors:this.colors,marker_color:'white',font_color:'white',background_colors:['#ff47a4','#ff1f81']})},theme_pastel:function(){this.colors=['#a9dada','#aedaa9','#daaea9','#dadaa9','#a9a9da','#daaeda','#dadada'];this.set_theme({colors:this.colors,marker_color:'#aea9a9',font_color:'black',background_colors:'white'})},theme_greyscale:function(){this.colors=['#282828','#383838','#686868','#989898','#c8c8c8','#e8e8e8'];this.set_theme({colors:this.colors,marker_color:'#aea9a9',font_color:'black',background_colors:'white'})},data:function(f,g,h){g=(g===undefined)?[]:g;h=h||null;g=Bluff.array(g);this._1.push([f,g,(h||this._1F())]);this._5=(g.length>this._5)?g.length:this._5;Bluff.each(g,function(c,d){if(c===undefined)return;if(this.maximum_value===null&&this.minimum_value===null)this.maximum_value=this.minimum_value=c;this.maximum_value=this._1k(c)?c:this.maximum_value;if(this.maximum_value>=0)this._c=true;this.minimum_value=this._1G(c)?c:this.minimum_value;if(this.minimum_value<0)this._c=true},this)},draw:function(){if(this.stacked)this._1H();this._1I();this._x(function(){this._0.rectangle(this.left_margin,this.top_margin,this._b-this.right_margin,this._L-this.bottom_margin);this._0.rectangle(this._2,this._7,this._l,this._g)})},clear:function(){this._M()},on:function(c,d,f){var g=this._10[c]=this._10[c]||[];g.push([d,f])},trigger:function(d,f){var g=this._10[d];if(!g)return;Bluff.each(g,function(c){c[0].call(c[1],f)})},_1I:function(){if(!this._c)return this._1J();this._16();this._1K();if(this.sort)this._1L();this._1M();this._N();this._1N();this._1O()},_16:function(g){if(this._9===null||g===true){this._9=[];if(!this._c)return;this._1l();Bluff.each(this._1,function(d){var f=[];Bluff.each(d[this.klass.DATA_VALUES_INDEX],function(c){if(c===null||c===undefined)f.push(null);else f.push((c-this.minimum_value)/this._i)},this);this._9.push([d[this.klass.DATA_LABEL_INDEX],f,d[this.klass.DATA_COLOR_INDEX]])},this)}},_1l:function(){this._i=this.maximum_value-this.minimum_value;this._i=this._i>0?this._i:1;var c=Math.round(Math.LOG10E*Math.log(this._i));this._1m=Math.pow(10,3-c)},_1K:function(){this._O=this.hide_line_markers?0:this._P(this.marker_font_size);this._1n=this.hide_title?0:this._P(this.title_font_size);this._1o=this.hide_legend?0:this._P(this.legend_font_size);var c,d,f,g,h,i,j;if(this.hide_line_markers){this._2=this.left_margin;this._17=this.right_margin;this._1p=this.bottom_margin}else{d=0;if(this.has_left_labels){c='';for(j in this.labels){c=c.length>this.labels[j].length?c:this.labels[j]}d=this._H(this.marker_font_size,c)*1.25}else{d=this._H(this.marker_font_size,this._Q(this.maximum_value))}f=this.hide_line_numbers&&!this.has_left_labels?0.0:d+this.klass.LABEL_MARGIN*2;this._2=this.left_margin+f+(this.y_axis_label===null?0.0:this._O+this.klass.LABEL_MARGIN*2);g=-Infinity;for(j in this.labels)g=g>Number(j)?g:Number(j);g=Math.round(g);h=(g>=(this._5-1)&&this.center_labels_over_point)?this._H(this.marker_font_size,this.labels[g])/2:0;this._17=this.right_margin+h;this._1p=this.bottom_margin+this._O+this.klass.LABEL_MARGIN}this._l=this._b-this._17;this._6=this._b-this._2-this._17;this._7=this.top_margin+(this.hide_title?this.title_margin:this._1n+this.title_margin)+(this.hide_legend?this.legend_margin:this._1o+this.legend_margin);i=(this.x_axis_label===null)?0.0:this._O+this.klass.LABEL_MARGIN;this._g=this._L-this._1p-i;this._3=this._g-this._7},_1N:function(){if(this.x_axis_label){var c=this._g+this.klass.LABEL_MARGIN*2+this._O;this._0.fill=this.font_color;if(this.font)this._0.font=this.font;this._0.stroke='transparent';this._0.pointsize=this._d(this.marker_font_size);this._0.gravity='north';this._0.annotate_scaled(this._b,1.0,0.0,c,this.x_axis_label,this._a);this._x(function(){this._0.line(0.0,c,this._b,c)})}},_N:function(){if(this.hide_line_markers)return;if(this.y_axis_increment===null){if(this.marker_count===null){Bluff.each([3,4,5,6,7],function(c){if(!this.marker_count&&this._i%c===0)this.marker_count=c},this);this.marker_count=this.marker_count||4}this._18=(this._i>0)?this._19(this._i/this.marker_count):1}else{this.maximum_value=Math.max(Math.ceil(this.maximum_value),this.y_axis_increment);this.minimum_value=Math.floor(this.minimum_value);this._1l();this._16(true);this.marker_count=Math.round(this._i/this.y_axis_increment);this._18=this.y_axis_increment}this._1P=this._3/(this._i/this._18);var d,f,g,h;for(d=0,f=this.marker_count;d<=f;d++){g=this._7+this._3-d*this._1P;this._0.stroke=this.marker_color;this._0.stroke_width=1;this._0.line(this._2,g,this._l,g);h=d*this._18+this.minimum_value;if(!this.hide_line_numbers){this._0.fill=this.font_color;if(this.font)this._0.font=this.font;this._0.font_weight='normal';this._0.stroke='transparent';this._0.pointsize=this._d(this.marker_font_size);this._0.gravity='east';this._0.annotate_scaled(this._2-this.klass.LABEL_MARGIN,1.0,0.0,g,this._Q(h),this._a)}}},_1q:function(c){return(this._b-c)/2},_1M:function(){if(this.hide_legend)return;this._I=Bluff.map(this._1,function(c){return c[this.klass.DATA_LABEL_INDEX]},this);var i=this.legend_box_size;if(this.font)this._0.font=this.font;this._0.pointsize=this.legend_font_size;var j=[[]];Bluff.each(this._I,function(c){var d=j.length-1;var f=this._0.get_type_metrics(c);var g=f.width+i*2.7;j[d].push(g);if(Bluff.sum(j[d])>(this._b*0.9))j.push([j[d].pop()])},this);var k=this._1q(Bluff.sum(j[0]));var m=this.hide_title?this.top_margin+this.title_margin:this.top_margin+this.title_margin+this._1n;this._x(function(){this._0.stroke_width=1;this._0.line(0,m,this._b,m)});Bluff.each(this._I,function(c,d){this._0.fill=this.font_color;if(this.font)this._0.font=this.font;this._0.pointsize=this._d(this.legend_font_size);this._0.stroke='transparent';this._0.font_weight='normal';this._0.gravity='west';this._0.annotate_scaled(this._b,1.0,k+(i*1.7),m,c,this._a);this._0.stroke='transparent';this._0.fill=this._1[d][this.klass.DATA_COLOR_INDEX];this._0.rectangle(k,m-i/2.0,k+i,m+i/2.0);this._0.pointsize=this.legend_font_size;var f=this._0.get_type_metrics(c);var g=f.width+(i*2.7),h;j[0].shift();if(j[0].length==0){this._x(function(){this._0.line(0.0,m,this._b,m)});j.shift();if(j.length>0)k=this._1q(Bluff.sum(j[0]));h=Math.max(this._1o,i)+this.legend_margin;if(j.length>0){m+=h;this._7+=h;this._3=this._g-this._7}}else{k+=g}},this);this._w=0},_1O:function(){if(this.hide_title||!this.title)return;this._0.fill=this.font_color;if(this.font)this._0.font=this.font;this._0.pointsize=this._d(this.title_font_size);this._0.font_weight='bold';this._0.gravity='north';this._0.annotate_scaled(this._b,1.0,0,this.top_margin,this.title,this._a)},_e:function(c,d){if(this.hide_line_markers)return;var f;if(this.labels[d]&&!this._u[d]){f=this._g+this.klass.LABEL_MARGIN;this._0.fill=this.font_color;if(this.font)this._0.font=this.font;this._0.stroke='transparent';this._0.font_weight='normal';this._0.pointsize=this._d(this.marker_font_size);this._0.gravity='north';this._0.annotate_scaled(1.0,1.0,c,f,this.labels[d],this._a);this._u[d]=true;this._x(function(){this._0.stroke_width=1;this._0.line(0.0,f,this._b,f)})}},_y:function(d,f,g,h,i,j,k,m){if(!this.tooltips)return;var n=this._0.tooltip(d,f,g,h,i,j,k);Bluff.Event.observe(n,'click',function(){var c={series:i,label:this.labels[m],value:k,color:j};this.trigger('click:datapoint',c)},this)},_1J:function(){this._0.fill=this.font_color;if(this.font)this._0.font=this.font;this._0.stroke='transparent';this._0.font_weight='normal';this._0.pointsize=this._d(80);this._0.gravity='center';this._0.annotate_scaled(this._b,this._L/2,0,10,this.no_data_message,this._a)},_M:function(){var c=this._k.background_colors;switch(true){case c instanceof Array:this._1Q.apply(this,c);break;case typeof c==='string':this._1R(c);break;default:this._1S(this._k.background_image);break}},_1R:function(c){this._0.render_solid_background(this._j,this._t,c)},_1Q:function(c,d){this._0.render_gradiated_background(this._j,this._t,c,d)},_1S:function(c){},_1j:function(){this._w=0;this._u={};this._k={};this._0.scale(this._a,this._a)},_2k:function(c){return this._a*c},_d:function(c){var d=c*this._a;return d},_R:function(c,d){return(c>d)?d:c},_1k:function(c,d){return c>this.maximum_value},_1G:function(c,d){return c<this.minimum_value},_1r:function(c,d){return c},_2l:function(c,d){return c},_19:function(c){if(c==0)return 1.0;var d=1.0;while(c<10){c*=10;d/=10}while(c>100){c/=10;d*=10}return Math.floor(c)*d},_1L:function(){var f=this._1T,g=this.klass.DATA_VALUES_INDEX;this._9.sort(function(c,d){return f(d[g])-f(c[g])});this._1.sort(function(c,d){return f(d[g])-f(c[g])})},_1T:function(d){var f=0;Bluff.each(d,function(c){f+=(c||0)});return f},_1H:function(){var g=[],h=this._5;while(h--)g[h]=0;Bluff.each(this._1,function(f){Bluff.each(f[this.klass.DATA_VALUES_INDEX],function(c,d){g[d]+=c},this);f[this.klass.DATA_VALUES_INDEX]=Bluff.array(g)},this)},_x:function(c){if(this.klass.DEBUG){this._0.fill='transparent';this._0.stroke='turquoise';c.call(this)}},_1F:function(){var c=this._w;this._w=(this._w+1)%this.colors.length;return this.colors[c]},_Q:function(c){var d=this.klass.THOUSAND_SEPARATOR,f=(this._i%this.marker_count==0||this.y_axis_increment!==null)?String(Math.round(c)):String(Math.floor(c*this._1m)/this._1m);var g=f.split('.');g[0]=g[0].replace(/(\d)(?=(\d\d\d)+(?!\d))/g,'$1'+d);return g.join('.')},_P:function(c){return this._0.caps_height(c)},_H:function(c,d){return this._0.text_width(c,d)}});Bluff.Area=new JS.Class(Bluff.Base,{draw:function(){this.callSuper();if(!this._c)return;this._S=this._6/(this._5-1);this._0.stroke='transparent';Bluff.each(this._9,function(h){var i=[],j=0.0,k=0.0;Bluff.each(h[this.klass.DATA_VALUES_INDEX],function(c,d){var f=this._2+(this._S*d);var g=this._7+(this._3-c*this._3);if(j>0&&k>0){i.push(f);i.push(g)}else{i.push(this._2);i.push(this._g-1);i.push(f);i.push(g)}this._e(f,d);j=f;k=g},this);i.push(this._l);i.push(this._g-1);i.push(this._2);i.push(this._g-1);this._0.fill=h[this.klass.DATA_COLOR_INDEX];this._0.polyline(i)},this)}});Bluff.BarConversion=new JS.Class({mode:null,zero:null,graph_top:null,graph_height:null,minimum_value:null,spread:null,getLeftYRightYscaled:function(c,d){var f;switch(this.mode){case 1:d[0]=this.graph_top+this.graph_height*(1-c)+1;d[1]=this.graph_top+this.graph_height-1;break;case 2:d[0]=this.graph_top+1;d[1]=this.graph_top+this.graph_height*(1-c)-1;break;case 3:f=c-this.minimum_value/this.spread;if(c>=this.zero){d[0]=this.graph_top+this.graph_height*(1-(f-this.zero))+1;d[1]=this.graph_top+this.graph_height*(1-this.zero)-1}else{d[0]=this.graph_top+this.graph_height*(1-(f-this.zero))+1;d[1]=this.graph_top+this.graph_height*(1-this.zero)-1}break;default:d[0]=0.0;d[1]=0.0}}});Bluff.Bar=new JS.Class(Bluff.Base,{bar_spacing:0.9,draw:function(){this.center_labels_over_point=(Bluff.keys(this.labels).length>this._5);this.callSuper();if(!this._c)return;this._T()},_T:function(){this._8=this._6/(this._5*this._1.length);var n=(this._8*(1-this.bar_spacing))/2;this._0.stroke_opacity=0.0;var l=new Bluff.BarConversion();l.graph_height=this._3;l.graph_top=this._7;if(this.minimum_value>=0){l.mode=1}else{if(this.maximum_value<=0){l.mode=2}else{l.mode=3;l.spread=this._i;l.minimum_value=this.minimum_value;l.zero=-this.minimum_value/this._i}}Bluff.each(this._9,function(j,k){var m=this._1[k][this.klass.DATA_VALUES_INDEX];Bluff.each(j[this.klass.DATA_VALUES_INDEX],function(c,d){var f=this._2+(this._8*(k+d+((this._1.length-1)*d)))+n;var g=f+this._8*this.bar_spacing;var h=[];l.getLeftYRightYscaled(c,h);this._0.fill=j[this.klass.DATA_COLOR_INDEX];this._0.rectangle(f,h[0],g,h[1]);this._y(f,h[0],g-f,h[1]-h[0],j[this.klass.DATA_LABEL_INDEX],j[this.klass.DATA_COLOR_INDEX],m[d],d);var i=this._2+(this._1.length*this._8*d)+(this._1.length*this._8/2.0);this._e(i-(this.center_labels_over_point?this._8/2.0:0.0),d)},this)},this);if(this.center_labels_over_point)this._e(this._l,this._5)}});Bluff.Line=new JS.Class(Bluff.Base,{baseline_value:null,baseline_color:null,line_width:null,dot_radius:null,hide_dots:null,hide_lines:null,initialize:function(c){if(arguments.length>3)throw'Wrong number of arguments';if(arguments.length===1||(typeof arguments[1]!=='number'&&typeof arguments[1]!=='string'))this.callSuper(c,null);else this.callSuper();this.hide_dots=this.hide_lines=false;this.baseline_color='red';this.baseline_value=null},draw:function(){this.callSuper();if(!this._c)return;this.x_increment=(this._5>1)?(this._6/(this._5-1)):this._6;var l;if(this._U!==undefined){l=this._7+(this._3-this._U*this._3);this._0.push();this._0.stroke=this.baseline_color;this._0.fill_opacity=0.0;this._0.stroke_width=3.0;this._0.line(this._2,l,this._2+this._6,l);this._0.pop()}Bluff.each(this._9,function(i,j){var k=null,m=null;var n=this._1[j][this.klass.DATA_VALUES_INDEX];this._1U=this._1V(i);Bluff.each(i[this.klass.DATA_VALUES_INDEX],function(c,d){var f=this._2+(this.x_increment*d);if(typeof c!=='number')return;this._e(f,d);var g=this._7+(this._3-c*this._3);this._0.stroke=i[this.klass.DATA_COLOR_INDEX];this._0.fill=i[this.klass.DATA_COLOR_INDEX];this._0.stroke_opacity=1.0;this._0.stroke_width=this.line_width||this._R(this._j/(this._9[0][this.klass.DATA_VALUES_INDEX].length*6),3.0);var h=this.dot_radius||this._R(this._j/(this._9[0][this.klass.DATA_VALUES_INDEX].length*2),7.0);if(!this.hide_lines&&k!==null&&m!==null){this._0.line(k,m,f,g)}else if(this._1U){this._0.circle(f,g,f-h,g)}if(!this.hide_dots)this._0.circle(f,g,f-h,g);this._y(f-h,g-h,2*h,2*h,i[this.klass.DATA_LABEL_INDEX],i[this.klass.DATA_COLOR_INDEX],n[d],d);k=f;m=g},this)},this)},_16:function(){this.maximum_value=Math.max(this.maximum_value,this.baseline_value);this.callSuper();if(this.baseline_value!==null)this._U=this.baseline_value/this.maximum_value},_1V:function(d){var f=0;Bluff.each(d[this.klass.DATA_VALUES_INDEX],function(c){if(c!==undefined)f+=1});return f===1}});Bluff.Dot=new JS.Class(Bluff.Base,{draw:function(){this.has_left_labels=true;this.callSuper();if(!this._c)return;var k=1.0;this._J=this._3/this._5;this._1a=this._J*k/this._9.length;this._0.stroke_opacity=0.0;var m=Bluff.array_new(this._5,0),n=Bluff.array_new(this._5,this._2),l=(this._J*(1-k))/2;Bluff.each(this._9,function(i,j){Bluff.each(i[this.klass.DATA_VALUES_INDEX],function(c,d){var f=this._2+(c*this._6)-Math.round(this._1a/6.0);var g=this._7+(this._J*d)+l+Math.round(this._1a/2.0);if(j===0){this._0.stroke=this.marker_color;this._0.stroke_width=1.0;this._0.opacity=0.1;this._0.line(this._2,g,this._2+this._6,g)}this._0.fill=i[this.klass.DATA_COLOR_INDEX];this._0.stroke='transparent';this._0.circle(f,g,f+Math.round(this._1a/3.0),g);var h=this._7+(this._J*d+this._J/2)+l;this._e(h,d)},this)},this)},_N:function(){if(this.hide_line_markers)return;this._0.stroke_antialias=false;this._0.stroke_width=1;var c=5;var d=this._19(this.maximum_value/c);for(var f=0;f<=c;f++){var g=(this._l-this._2)/c,h=this._l-(g*f)-1,i=f-c,j=Math.abs(i)*d;this._0.stroke=this.marker_color;this._0.line(h,this._g,h,this._g+0.5*this.klass.LABEL_MARGIN);if(!this.hide_line_numbers){this._0.fill=this.font_color;if(this.font)this._0.font=this.font;this._0.stroke='transparent';this._0.pointsize=this._d(this.marker_font_size);this._0.gravity='center';this._0.annotate_scaled(0,0,h,this._g+(this.klass.LABEL_MARGIN*2.0),j,this._a)}this._0.stroke_antialias=true}},_e:function(c,d){if(this.labels[d]&&!this._u[d]){this._0.fill=this.font_color;if(this.font)this._0.font=this.font;this._0.stroke='transparent';this._0.font_weight='normal';this._0.pointsize=this._d(this.marker_font_size);this._0.gravity='east';this._0.annotate_scaled(1,1,this._2-this.klass.LABEL_MARGIN*2.0,c,this.labels[d],this._a);this._u[d]=true}}});Bluff.Net=new JS.Class(Bluff.Base,{hide_dots:null,line_width:null,dot_radius:null,initialize:function(){this.callSuper();this.hide_dots=false;this.hide_line_numbers=true},draw:function(){this.callSuper();if(!this._c)return;this._z=this._3/2.0;this._A=this._2+(this._6/2.0);this._B=this._7+(this._3/2.0)-10;this._S=this._6/(this._5-1);var s=this.dot_radius||this._R(this._j/(this._9[0][this.klass.DATA_VALUES_INDEX].length*2.5),7.0);this._0.stroke_opacity=1.0;this._0.stroke_width=this.line_width||this._R(this._j/(this._9[0][this.klass.DATA_VALUES_INDEX].length*4),3.0);var r;if(this._U!==undefined){r=this._7+(this._3-this._U*this._3);this._0.push();this._0.stroke_color=this.baseline_color;this._0.fill_opacity=0.0;this._0.stroke_width=5;this._0.line(this._2,r,this._2+this._6,r);this._0.pop()}Bluff.each(this._9,function(o){var p=null,q=null;Bluff.each(o[this.klass.DATA_VALUES_INDEX],function(c,d){if(c===undefined)return;var f=d*Math.PI*2/this._5,g=c*this._z,h=this._A+Math.sin(f)*g,i=this._B-Math.cos(f)*g,j=(d+1<o[this.klass.DATA_VALUES_INDEX].length)?d+1:0,k=j*Math.PI*2/this._5,m=o[this.klass.DATA_VALUES_INDEX][j]*this._z,n=this._A+Math.sin(k)*m,l=this._B-Math.cos(k)*m;this._0.stroke=o[this.klass.DATA_COLOR_INDEX];this._0.fill=o[this.klass.DATA_COLOR_INDEX];this._0.line(h,i,n,l);if(!this.hide_dots)this._0.circle(h,i,h-s,i)},this)},this)},_N:function(){if(this.hide_line_markers)return;this._z=this._3/2.0;this._A=this._2+(this._6/2.0);this._B=this._7+(this._3/2.0)-10;var c,d;for(var f=0,g=this._5;f<g;f++){c=f*Math.PI*2/this._5;this._0.stroke=this.marker_color;this._0.stroke_width=1;this._0.line(this._A,this._B,this._A+Math.sin(c)*this._z,this._B-Math.cos(c)*this._z);d=this.labels[f]?this.labels[f]:'000';this._e(this._A,this._B,c*360/(2*Math.PI),this._z,d)}},_e:function(c,d,f,g,h){var i=1.1,j=c,k=d,m=f*Math.PI/180,n=j+(g*i*Math.sin(m)),l=k-(g*i*Math.cos(m));this._0.fill=this.marker_color;if(this.font)this._0.font=this.font;this._0.pointsize=this._d(20);this._0.stroke='transparent';this._0.font_weight='bold';this._0.gravity='center';this._0.annotate_scaled(0,0,n,l,h,this._a)}});Bluff.Pie=new JS.Class(Bluff.Base,{extend:{TEXT_OFFSET_PERCENTAGE:0.08},zero_degreee:null,hide_labels_less_than:null,initialize_ivars:function(){this.callSuper();this.zero_degree=0.0;this.hide_labels_less_than=0.0},draw:function(){this.hide_line_markers=true;this.callSuper();if(!this._c)return;var j=this._3,k=(Math.min(this._6,this._3)/2.0)*0.8,m=this._2+(this._6-j)/2.0,n=this._2+(this._6/2.0),l=this._7+(this._3/2.0)-10,o=this._1W(),p=this.zero_degree,q=this.klass.DATA_VALUES_INDEX;if(this.sort)this._1.sort(function(a,b){return a[q][0]-b[q][0]});Bluff.each(this._1,function(c,d){if(c[this.klass.DATA_VALUES_INDEX][0]>0){this._0.fill=c[this.klass.DATA_COLOR_INDEX];var f=(c[this.klass.DATA_VALUES_INDEX][0]/o)*360;this._0.circle(n,l,n+k,l,p,p+f+0.5);var g=p+((p+f)-p)/2,h=Math.round((c[this.klass.DATA_VALUES_INDEX][0]/o)*100.0),i;if(h>=this.hide_labels_less_than){i=this._Q(c[this.klass.DATA_VALUES_INDEX][0]);this._e(n,l,g,k+(k*this.klass.TEXT_OFFSET_PERCENTAGE),i,c,d)}p+=f}},this)},_e:function(c,d,f,g,h,i,j){var k=20.0,m=c,n=d,l=g+k,o=l*0.15,p=m+((l+o)*Math.cos(f*Math.PI/180)),q=n+(l*Math.sin(f*Math.PI/180));this._0.fill=this.font_color;if(this.font)this._0.font=this.font;this._0.pointsize=this._d(this.marker_font_size);this._0.font_weight='bold';this._0.gravity='center';this._0.annotate_scaled(0,0,p,q,h,this._a);this._y(p-20,q-20,40,40,i[this.klass.DATA_LABEL_INDEX],i[this.klass.DATA_COLOR_INDEX],h,j)},_1W:function(){var d=0;Bluff.each(this._1,function(c){d+=c[this.klass.DATA_VALUES_INDEX][0]},this);return d}});Bluff.SideBar=new JS.Class(Bluff.Base,{bar_spacing:0.9,draw:function(){this.has_left_labels=true;this.callSuper();if(!this._c)return;this._T()},_T:function(){this._V=this._3/this._5;this._8=this._V/this._9.length;this._0.stroke_opacity=0.0;var q=Bluff.array_new(this._5,0),s=Bluff.array_new(this._5,this._2),r=(this._8*(1-this.bar_spacing))/2;Bluff.each(this._9,function(l,o){var p=this._1[o][this.klass.DATA_VALUES_INDEX];Bluff.each(l[this.klass.DATA_VALUES_INDEX],function(c,d){var f=this._2+(this._6-c*this._6-q[d]),g=this._2+this._6-q[d],h=g-f,i=s[d]-1,j=this._7+(this._V*d)+(this._8*o)+r,k=i+h,m=j+this._8*this.bar_spacing;q[d]+=(c*this._6);this._0.stroke='transparent';this._0.fill=l[this.klass.DATA_COLOR_INDEX];this._0.rectangle(i,j,k,m);this._y(i,j,k-i,m-j,l[this.klass.DATA_LABEL_INDEX],l[this.klass.DATA_COLOR_INDEX],p[d],d);var n=this._7+(this._V*d+this._V/2);this._e(n,d)},this)},this)},_N:function(){if(this.hide_line_markers)return;this._0.stroke_antialias=false;this._0.stroke_width=1;var c=5;var d=this._19(this._i/c),f,g,h,i;for(var j=0;j<=c;j++){f=(this._l-this._2)/c;g=this._l-(f*j)-1;h=j-c;i=Math.abs(h)*d+this.minimum_value;this._0.stroke=this.marker_color;this._0.line(g,this._g,g,this._7);if(!this.hide_line_numbers){this._0.fill=this.font_color;if(this.font)this._0.font=this.font;this._0.stroke='transparent';this._0.pointsize=this._d(this.marker_font_size);this._0.gravity='center';this._0.annotate_scaled(0,0,g,this._g+(this.klass.LABEL_MARGIN*2.0),this._Q(i),this._a)}}},_e:function(c,d){if(this.labels[d]&&!this._u[d]){this._0.fill=this.font_color;if(this.font)this._0.font=this.font;this._0.stroke='transparent';this._0.font_weight='normal';this._0.pointsize=this._d(this.marker_font_size);this._0.gravity='east';this._0.annotate_scaled(1,1,this._2-this.klass.LABEL_MARGIN*2.0,c,this.labels[d],this._a);this._u[d]=true}}});Bluff.Spider=new JS.Class(Bluff.Base,{hide_text:null,hide_axes:null,transparent_background:null,initialize:function(c,d,f){this.callSuper(c,f);this._1X=d;this.hide_legend=true},draw:function(){this.hide_line_markers=true;this.callSuper();if(!this._c)return;var c=this._3,d=this._3/2.0,f=this._2+(this._6-c)/2.0,g=this._2+(this._6/2.0),h=this._7+(this._3/2.0)-25;this._1Y=d/this._1X;var i=this._1Z(),j=0.0,k=(2*Math.PI)/this._1.length,m=0.0;if(!this.hide_axes)this._20(g,h,d,k);this._21(g,h,k)},_1s:function(c){return c*this._1Y},_e:function(c,d,f,g,h){var i=50,j=c,k=d+0,m=j+((g+i)*Math.cos(f)),n=k+((g+i)*Math.sin(f));this._0.fill=this.marker_color;if(this.font)this._0.font=this.font;this._0.pointsize=this._d(this.legend_font_size);this._0.stroke='transparent';this._0.font_weight='bold';this._0.gravity='center';this._0.annotate_scaled(0,0,m,n,h,this._a)},_20:function(g,h,i,j,k){if(this.hide_axes)return;var m=0.0;Bluff.each(this._1,function(c){this._0.stroke=k||c[this.klass.DATA_COLOR_INDEX];this._0.stroke_width=5.0;var d=i*Math.cos(m);var f=i*Math.sin(m);this._0.line(g,h,g+d,h+f);if(!this.hide_text)this._e(g,h,m,i,c[this.klass.DATA_LABEL_INDEX]);m+=j},this)},_21:function(d,f,g,h){var i=[],j=0.0;Bluff.each(this._1,function(c){i.push(d+this._1s(c[this.klass.DATA_VALUES_INDEX][0])*Math.cos(j));i.push(f+this._1s(c[this.klass.DATA_VALUES_INDEX][0])*Math.sin(j));j+=g},this);this._0.stroke_width=1.0;this._0.stroke=h||this.marker_color;this._0.fill=h||this.marker_color;this._0.fill_opacity=0.4;this._0.polyline(i)},_1Z:function(){var d=0.0;Bluff.each(this._1,function(c){d+=c[this.klass.DATA_VALUES_INDEX][0]},this);return d}});Bluff.Base.StackedMixin=new JS.Module({_1b:function(){var g={};Bluff.each(this._1,function(f){Bluff.each(f[this.klass.DATA_VALUES_INDEX],function(c,d){if(!g[d])g[d]=0.0;g[d]+=c},this)},this);for(var h in g){if(g[h]>this.maximum_value)this.maximum_value=g[h]}this.minimum_value=0}});Bluff.StackedArea=new JS.Class(Bluff.Base,{include:Bluff.Base.StackedMixin,last_series_goes_on_bottom:null,draw:function(){this._1b();this.callSuper();if(!this._c)return;this._S=this._6/(this._5-1);this._0.stroke='transparent';var n=Bluff.array_new(this._5,0);var l=null;var o=this.last_series_goes_on_bottom?'reverse_each':'each';Bluff[o](this._9,function(h){var i=l;l=[];Bluff.each(h[this.klass.DATA_VALUES_INDEX],function(c,d){var f=this._2+(this._S*d);var g=this._7+(this._3-c*this._3-n[d]);n[d]+=(c*this._3);l.push(f);l.push(g);this._e(f,d)},this);var j,k,m;if(i){j=Bluff.array(l);for(k=i.length/2-1;k>=0;k--){j.push(i[2*k]);j.push(i[2*k+1])}j.push(l[0]);j.push(l[1])}else{j=Bluff.array(l);j.push(this._l);j.push(this._g-1);j.push(this._2);j.push(this._g-1);j.push(l[0]);j.push(l[1])}this._0.fill=h[this.klass.DATA_COLOR_INDEX];this._0.polyline(j)},this)}});Bluff.StackedBar=new JS.Class(Bluff.Base,{include:Bluff.Base.StackedMixin,bar_spacing:0.9,draw:function(){this._1b();this.callSuper();if(!this._c)return;this._8=this._6/this._5;var l=(this._8*(1-this.bar_spacing))/2;this._0.stroke_opacity=0.0;var o=Bluff.array_new(this._5,0);Bluff.each(this._9,function(k,m){var n=this._1[m][this.klass.DATA_VALUES_INDEX];Bluff.each(k[this.klass.DATA_VALUES_INDEX],function(c,d){var f=this._2+(this._8*d)+(this._8*this.bar_spacing/2.0);this._e(f,d);if(c==0)return;var g=this._2+(this._8*d)+l;var h=this._7+(this._3-c*this._3-o[d])+1;var i=g+this._8*this.bar_spacing;var j=this._7+this._3-o[d]-1;o[d]+=(c*this._3);this._0.fill=k[this.klass.DATA_COLOR_INDEX];this._0.rectangle(g,h,i,j);this._y(g,h,i-g,j-h,k[this.klass.DATA_LABEL_INDEX],k[this.klass.DATA_COLOR_INDEX],n[d],d)},this)},this)}});Bluff.AccumulatorBar=new JS.Class(Bluff.StackedBar,{draw:function(){if(this._1.length!==1)throw'Incorrect number of datasets';var g=[],h=0,i=[];Bluff.each(this._1[0][this.klass.DATA_VALUES_INDEX],function(d){var f=-Infinity;Bluff.each(i,function(c){f=Math.max(f,c)});i.push((h>0)?(d+f):d);g.push(i[h]-d);h+=1},this);this.data("Accumulator",g);this.callSuper()}});Bluff.SideStackedBar=new JS.Class(Bluff.SideBar,{include:Bluff.Base.StackedMixin,bar_spacing:0.9,draw:function(){this.has_left_labels=true;this._1b();this.callSuper()},_T:function(){this._8=this._3/this._5;var q=Bluff.array_new(this._5,0),s=Bluff.array_new(this._5,this._2),r=(this._8*(1-this.bar_spacing))/2;Bluff.each(this._9,function(l,o){var p=this._1[o][this.klass.DATA_VALUES_INDEX];Bluff.each(l[this.klass.DATA_VALUES_INDEX],function(c,d){var f=this._2+(this._6-c*this._6-q[d])+1;var g=this._2+this._6-q[d]-1;var h=g-f;this._0.fill=l[this.klass.DATA_COLOR_INDEX];var i=s[d],j=this._7+(this._8*d)+r,k=i+h,m=j+this._8*this.bar_spacing;s[d]+=h;q[d]+=(c*this._6-2);this._0.rectangle(i,j,k,m);this._y(i,j,k-i,m-j,l[this.klass.DATA_LABEL_INDEX],l[this.klass.DATA_COLOR_INDEX],p[d],d);var n=this._7+(this._8*d)+(this._8*this.bar_spacing/2.0);this._e(n,d)},this)},this)},_1k:function(c,d){d=d||0;return this._1r(c,d)>this.maximum_value},_1r:function(d,f){var g=0;Bluff.each(this._1,function(c){g+=c[this.klass.DATA_VALUES_INDEX][f]},this);return g}});Bluff.Mini.Legend=new JS.Module({hide_mini_legend:false,_1c:function(){if(this.hide_mini_legend)return;this._I=Bluff.map(this._1,function(c){return c[this.klass.DATA_LABEL_INDEX]},this);var d=this._d(this._1.length*this._1t()+this.top_margin+this.bottom_margin);this._22=this._L;this._23=this._b;switch(this.legend_position){case'right':this._t=Math.max(this._t,d);this._j+=this._24()+this.left_margin;break;default:this._t+=d;break}this._M()},_1t:function(){return this._P(this.legend_font_size)*1.7},_24:function(){var d=0;Bluff.each(this._I,function(c){d=Math.max(this._H(this.legend_font_size,c),d)},this);return this._d(d+40*1.7)},_1d:function(){if(this.hide_mini_legend)return;var f=40.0,g=10.0,h=100.0,i=40.0;if(this.font)this._0.font=this.font;this._0.pointsize=this.legend_font_size;var j,k;switch(this.legend_position){case'right':j=this._23+this.left_margin;k=this.top_margin+i;break;default:j=h,k=this._22+i;break}this._x(function(){this._0.line(0.0,k,this._b,k)});Bluff.each(this._I,function(c,d){this._0.fill=this.font_color;if(this.font)this._0.font=this.font;this._0.pointsize=this._d(this.legend_font_size);this._0.stroke='transparent';this._0.font_weight='normal';this._0.gravity='west';this._0.annotate_scaled(this._b,1.0,j+(f*1.7),k,this._25(c),this._a);this._0.stroke='transparent';this._0.fill=this._1[d][this.klass.DATA_COLOR_INDEX];this._0.rectangle(j,k-f/2.0,j+f,k+f/2.0);k+=this._1t()},this);this._w=0},_25:function(c){var d=String(c);while(this._H(this._d(this.legend_font_size),d)>(this._j-this.legend_left_margin-this.right_margin)&&(d.length>1))d=d.substr(0,d.length-1);return d+(d.length<String(c).length?"...":'')}});Bluff.Mini.Bar=new JS.Class(Bluff.Bar,{include:Bluff.Mini.Legend,initialize_ivars:function(){this.callSuper();this.hide_legend=true;this.hide_title=true;this.hide_line_numbers=true;this.marker_font_size=50.0;this.minimum_value=0.0;this.maximum_value=0.0;this.legend_font_size=60.0},draw:function(){this._1c();this.callSuper();this._1d()}});Bluff.Mini.Pie=new JS.Class(Bluff.Pie,{include:Bluff.Mini.Legend,initialize_ivars:function(){this.callSuper();this.hide_legend=true;this.hide_title=true;this.hide_line_numbers=true;this.marker_font_size=60.0;this.legend_font_size=60.0},draw:function(){this._1c();this.callSuper();this._1d()}});Bluff.Mini.SideBar=new JS.Class(Bluff.SideBar,{include:Bluff.Mini.Legend,initialize_ivars:function(){this.callSuper();this.hide_legend=true;this.hide_title=true;this.hide_line_numbers=true;this.marker_font_size=50.0;this.legend_font_size=50.0},draw:function(){this._1c();this.callSuper();this._1d()}});Bluff.Renderer=new JS.Class({extend:{WRAPPER_CLASS:'bluff-wrapper',TEXT_CLASS:'bluff-text',TARGET_CLASS:'bluff-tooltip-target'},font:'Arial, Helvetica, Verdana, sans-serif',gravity:'north',initialize:function(c){this._n=document.getElementById(c);this._4=this._n.getContext('2d')},scale:function(c,d){this._f=c;this._h=d||c},caps_height:function(c){var d=this._W(c,'X'),f=this._K(d).height;this._X(d);return f},text_width:function(c,d){var f=this._W(c,d);var g=this._K(f).width;this._X(f);return g},get_type_metrics:function(c){var d=this._W(this.pointsize,c);document.body.appendChild(d);var f=this._K(d);this._X(d);return f},clear:function(c,d){this._n.width=c;this._n.height=d;this._4.clearRect(0,0,c,d);var f=this._1u(),g=f.childNodes,h=g.length;f.style.width=c+'px';f.style.height=d+'px';while(h--){if(g[h].tagName.toLowerCase()!=='canvas'){Bluff.Event.stopObserving(g[h]);this._X(g[h])}}},push:function(){this._4.save()},pop:function(){this._4.restore()},render_gradiated_background:function(c,d,f,g){this.clear(c,d);var h=this._4.createLinearGradient(0,0,0,d);h.addColorStop(0,f);h.addColorStop(1,g);this._4.fillStyle=h;this._4.fillRect(0,0,c,d)},render_solid_background:function(c,d,f){this.clear(c,d);this._4.fillStyle=f;this._4.fillRect(0,0,c,d)},annotate_scaled:function(c,d,f,g,h,i){var j=(c*i)>=1?(c*i):1;var k=(d*i)>=1?(d*i):1;var h=this._W(this.pointsize,h);h.style.color=this.fill;h.style.cursor='default';h.style.fontWeight=this.font_weight;h.style.textAlign='center';h.style.left=(this._f*f+this._26(h,j))+'px';h.style.top=(this._h*g+this._27(h,k))+'px'},tooltip:function(d,f,g,h,i,j,k){if(g<0)d+=g;if(h<0)f+=h;var m=this._n.parentNode,n=document.createElement('div');n.className=this.klass.TARGET_CLASS;n.style.cursor='default';n.style.position='absolute';n.style.left=(this._f*d-3)+'px';n.style.top=(this._h*f-3)+'px';n.style.width=(this._f*Math.abs(g)+5)+'px';n.style.height=(this._h*Math.abs(h)+5)+'px';n.style.fontSize=0;n.style.overflow='hidden';Bluff.Event.observe(n,'mouseover',function(c){Bluff.Tooltip.show(i,j,k)});Bluff.Event.observe(n,'mouseout',function(c){Bluff.Tooltip.hide()});m.appendChild(n);return n},circle:function(c,d,f,g,h,i){var j=Math.sqrt(Math.pow(f-c,2)+Math.pow(g-d,2));var k=0,m=2*Math.PI;this._4.fillStyle=this.fill;this._4.beginPath();if(h!==undefined&&i!==undefined&&Math.abs(Math.floor(i-h))!==360){k=h*Math.PI/180;m=i*Math.PI/180;this._4.moveTo(this._f*(c+j*Math.cos(m)),this._h*(d+j*Math.sin(m)));this._4.lineTo(this._f*c,this._h*d);this._4.lineTo(this._f*(c+j*Math.cos(k)),this._h*(d+j*Math.sin(k)))}this._4.arc(this._f*c,this._h*d,this._f*j,k,m,false);this._4.fill()},line:function(c,d,f,g){this._4.strokeStyle=this.stroke;this._4.lineWidth=this.stroke_width;this._4.beginPath();this._4.moveTo(this._f*c,this._h*d);this._4.lineTo(this._f*f,this._h*g);this._4.stroke()},polyline:function(c){this._4.fillStyle=this.fill;this._4.globalAlpha=this.fill_opacity||1;try{this._4.strokeStyle=this.stroke}catch(e){}var d=c.shift(),f=c.shift();this._4.beginPath();this._4.moveTo(this._f*d,this._h*f);while(c.length>0){d=c.shift();f=c.shift();this._4.lineTo(this._f*d,this._h*f)}this._4.fill()},rectangle:function(c,d,f,g){var h;if(c>f){h=c;c=f;f=h}if(d>g){h=d;d=g;g=h}try{this._4.fillStyle=this.fill;this._4.fillRect(this._f*c,this._h*d,this._f*(f-c),this._h*(g-d))}catch(e){}try{this._4.strokeStyle=this.stroke;if(this.stroke!=='transparent')this._4.strokeRect(this._f*c,this._h*d,this._f*(f-c),this._h*(g-d))}catch(e){}},_26:function(c,d){var f=this._K(c).width;switch(this.gravity){case'west':return 0;case'east':return d-f;case'north':case'south':case'center':return(d-f)/2}},_27:function(c,d){var f=this._K(c).height;switch(this.gravity){case'north':return 0;case'south':return d-f;case'west':case'east':case'center':return(d-f)/2}},_1u:function(){var c=this._n.parentNode;if(c.className===this.klass.WRAPPER_CLASS)return c;c=document.createElement('div');c.className=this.klass.WRAPPER_CLASS;c.style.position='relative';c.style.border='none';c.style.padding='0 0 0 0';this._n.parentNode.insertBefore(c,this._n);c.appendChild(this._n);return c},_W:function(c,d){var f=this._28(d);f.style.fontFamily=this.font;f.style.fontSize=(typeof c==='number')?c+'px':c;return f},_28:function(c){var d=document.createElement('div');d.className=this.klass.TEXT_CLASS;d.style.position='absolute';d.appendChild(document.createTextNode(c));this._1u().appendChild(d);return d},_X:function(c){c.parentNode.removeChild(c);if(c.className===this.klass.TARGET_CLASS)Bluff.Event.stopObserving(c)},_K:function(c){var d=c.style.display;return(d&&d!=='none')?{width:c.offsetWidth,height:c.offsetHeight}:{width:c.clientWidth,height:c.clientHeight}}});Bluff.Event={_Y:[],_1v:(window.attachEvent&&navigator.userAgent.indexOf('Opera')===-1),observe:function(d,f,g,h){var i=Bluff.map(this._1w(d,f),function(c){return c._29});if(Bluff.index(i,g)!==-1)return;var j=function(c){g.call(h||null,d,Bluff.Event._2a(c))};this._Y.push({_Z:d,_1e:f,_29:g,_1x:j});if(d.addEventListener)d.addEventListener(f,j,false);else d.attachEvent('on'+f,j)},stopObserving:function(d){var f=d?this._1w(d):this._Y;Bluff.each(f,function(c){if(c._Z.removeEventListener)c._Z.removeEventListener(c._1e,c._1x,false);else c._Z.detachEvent('on'+c._1e,c._1x)})},_1w:function(d,f){var g=[];Bluff.each(this._Y,function(c){if(d&&c._Z!==d)return;if(f&&c._1e!==f)return;g.push(c)});return g},_2a:function(c){if(!this._1v)return c;if(!c)return false;if(c._2b)return c;c._2b=true;var d=this._2c(c);c.target=c.srcElement;c.pageX=d.x;c.pageY=d.y;return c},_2c:function(c){var d=document.documentElement,f=document.body||{scrollLeft:0,scrollTop:0};return{x:c.pageX||(c.clientX+(d.scrollLeft||f.scrollLeft)-(d.clientLeft||0)),y:c.pageY||(c.clientY+(d.scrollTop||f.scrollTop)-(d.clientTop||0))}}};if(Bluff.Event._1v)window.attachEvent('onunload',function(){Bluff.Event.stopObserving();Bluff.Event._Y=null});if(navigator.userAgent.indexOf('AppleWebKit/')>-1)window.addEventListener('unload',function(){},false);Bluff.Tooltip=new JS.Singleton({LEFT_OFFSET:20,TOP_OFFSET:-6,DATA_LENGTH:8,CLASS_NAME:'bluff-tooltip',setup:function(){this._o=document.createElement('div');this._o.className=this.CLASS_NAME;this._o.style.position='absolute';this.hide();document.body.appendChild(this._o);Bluff.Event.observe(document.body,'mousemove',function(c,d){this._o.style.left=(d.pageX+this.LEFT_OFFSET)+'px';this._o.style.top=(d.pageY+this.TOP_OFFSET)+'px'},this)},show:function(c,d,f){f=Number(String(f).substr(0,this.DATA_LENGTH));this._o.innerHTML='<span class="color" style="background: '+d+';">&nbsp;</span> <span class="label">'+c+'</span> <span class="data">'+f+'</span>';this._o.style.display=''},hide:function(){this._o.style.display='none'}});Bluff.Event.observe(window,'load',Bluff.Tooltip.method('setup'));Bluff.TableReader=new JS.Class({NUMBER_FORMAT:/\-?(0|[1-9]\d*)(\.\d+)?(e[\+\-]?\d+)?/i,initialize:function(c,d){this._1f=d||{};this._2d=this._1f.orientation||'auto';this._2e=(typeof c==='string')?document.getElementById(c):c},get_data:function(){if(!this._1)this._1y();return this._1},get_labels:function(){if(!this._1g)this._1y();return this._1g},get_title:function(){return this._2f},get_series:function(c){if(this._1[c])return this._1[c];return this._1[c]={points:[]}},_1y:function(){this._C=this._m=0;this._p=this._q=0;this._1=[];this._1g={};this._r=[];this._s=[];this._1h=[];this._1i=[];this._1z(this._2e);this._2g();this._2h();Bluff.each(this._s,function(c,d){this.get_series(d-this._q).name=c},this);Bluff.each(this._r,function(c,d){this._1g[d-this._p]=c},this)},_1z:function(c){this._2i(c);var d,f=c.childNodes,g=f.length;for(d=0;d<g;d++)this._1z(f[d])},_2i:function(c){if(!c.tagName)return;var d=this._1A(c.innerHTML),f,g;switch(c.tagName.toUpperCase()){case'TR':if(!this._c)this._p=this._C;this._C+=1;this._m=0;break;case'TD':if(!this._c)this._q=this._m;this._c=true;this._m+=1;d=d.match(this.NUMBER_FORMAT);if(d===null){this.get_series(f).points[g]=null}else{f=this._m-this._q-1;g=this._C-this._p-1;this.get_series(f).points[g]=parseFloat(d[0])}break;case'TH':this._m+=1;if(this._2j(c)){this._1i.push(this._m);this._1h.push(this._C)}if(this._m===1&&this._C===1)this._r[0]=this._s[0]=d;else if(c.scope==="row"||this._m===1)this._r[this._C-1]=d;else this._s[this._m-1]=d;break;case'CAPTION':this._2f=d;break}},_2j:function(c){if(!this._1f.except)return false;var d=this._1A(c.innerHTML),f=(c.className||'').split(/\s+/),g=[].concat(this._1f.except);if(Bluff.index(g,d)>=0)return true;var h=f.length;while(h--){if(Bluff.index(g,f[h])>=0)return true}return false},_2g:function(){var d=this._1i.length,f;while(d--){f=this._1i[d];if(f<=this._q)continue;this._s.splice(f-1,1);if(f>=this._q)this._1.splice(f-1-this._q,1)}var d=this._1h.length,f;while(d--){f=this._1h[d];if(f<=this._p)continue;this._r.splice(f-1,1);Bluff.each(this._1,function(c){if(f>=this._p)c.points.splice(f-1-this._p,1)},this)}},_2h:function(){switch(this._2d){case'auto':if((this._r.length>1&&this._s.length===1)||this._r.length<this._s.length){this._1B()}break;case'rows':this._1B();break}},_1B:function(){var h=this._1,i;this._1=[];Bluff.each(h,function(f,g){Bluff.each(f.points,function(c,d){this.get_series(d).points[g]=c},this)},this);i=this._r;this._r=this._s;this._s=i;i=this._p;this._p=this._q;this._q=i},_1A:function(c){return c.replace(/<\/?[^>]+>/gi,'')},extend:{Mixin:new JS.Module({data_from_table:function(d,f){var g=new Bluff.TableReader(d,f),h=g.get_data();Bluff.each(h,function(c){this.data(c.name,c.points)},this);this.labels=g.get_labels();this.title=g.get_title()||this.title}})}});Bluff.Base.include(Bluff.TableReader.Mixin);
-})(jQuery);
diff --git a/apis/charts_graphs_bluff/bluff/bluff-src.js b/apis/charts_graphs_bluff/bluff/bluff-src.js
deleted file mode 100644
index 832ce16..0000000
--- a/apis/charts_graphs_bluff/bluff/bluff-src.js
+++ /dev/null
@@ -1,2990 +0,0 @@
-/**
- * Bluff - beautiful graphs in JavaScript
- * ======================================
- * 
- * Get the latest version and docs at http://bluff.jcoglan.com
- * Based on Gruff by Geoffrey Grosenbach: http://github.com/topfunky/gruff
- * 
- * Copyright (C) 2008-2010 James Coglan
- * 
- * Released under the MIT license and the GPL v2.
- * http://www.opensource.org/licenses/mit-license.php
- * http://www.gnu.org/licenses/gpl-2.0.txt
- **/
-
-Bluff = {
-  // This is the version of Bluff you are using.
-  VERSION: '0.3.6',
-  
-  array: function(list) {
-    if (list.length === undefined) return [list];
-    var ary = [], i = list.length;
-    while (i--) ary[i] = list[i];
-    return ary;
-  },
-  
-  array_new: function(length, filler) {
-    var ary = [];
-    while (length--) ary.push(filler);
-    return ary;
-  },
-  
-  each: function(list, block, context) {
-    for (var i = 0, n = list.length; i < n; i++) {
-      block.call(context || null, list[i], i);
-    }
-  },
-  
-  index: function(list, needle) {
-    for (var i = 0, n = list.length; i < n; i++) {
-      if (list[i] === needle) return i;
-    }
-    return -1;
-  },
-  
-  keys: function(object) {
-    var ary = [], key;
-    for (key in object) ary.push(key);
-    return ary;
-  },
-  
-  map: function(list, block, context) {
-    var results = [];
-    this.each(list, function(item) {
-      results.push(block.call(context || null, item));
-    });
-    return results;
-  },
-  
-  reverse_each: function(list, block, context) {
-    var i = list.length;
-    while (i--) block.call(context || null, list[i], i);
-  },
-  
-  sum: function(list) {
-    var sum = 0, i = list.length;
-    while (i--) sum += list[i];
-    return sum;
-  },
-  
-  Mini: {}
-};
-
-Bluff.Base = new JS.Class({
-  extend: {
-    // Draw extra lines showing where the margins and text centers are
-    DEBUG: false,
-    
-    // Used for navigating the array of data to plot
-    DATA_LABEL_INDEX: 0,
-    DATA_VALUES_INDEX: 1,
-    DATA_COLOR_INDEX: 2,
-    
-    // Space around text elements. Mostly used for vertical spacing
-    LEGEND_MARGIN: 20,
-    TITLE_MARGIN: 20,
-    LABEL_MARGIN: 10,
-    DEFAULT_MARGIN: 20,
-    
-    DEFAULT_TARGET_WIDTH:  800,
-    
-    THOUSAND_SEPARATOR: ','
-  },
-  
-  // Blank space above the graph
-  top_margin: null,
-  
-  // Blank space below the graph
-  bottom_margin: null,
-  
-  // Blank space to the right of the graph
-  right_margin: null,
-  
-  // Blank space to the left of the graph
-  left_margin: null,
-  
-  // Blank space below the title
-  title_margin: null,
-  
-  // Blank space below the legend
-  legend_margin: null,
-  
-  // A hash of names for the individual columns, where the key is the array
-  // index for the column this label represents.
-  //
-  // Not all columns need to be named.
-  //
-  // Example: {0: 2005, 3: 2006, 5: 2007, 7: 2008}
-  labels: null,
-  
-  // Used internally for spacing.
-  //
-  // By default, labels are centered over the point they represent.
-  center_labels_over_point: null,
-  
-  // Used internally for horizontal graph types.
-  has_left_labels: null,
-  
-  // A label for the bottom of the graph
-  x_axis_label: null,
-  
-  // A label for the left side of the graph
-  y_axis_label: null,
-  
-  // x_axis_increment: null,
-  
-  // Manually set increment of the horizontal marking lines
-  y_axis_increment: null,
-  
-  // Get or set the list of colors that will be used to draw the bars or lines.
-  colors: null,
-  
-  // The large title of the graph displayed at the top
-  title: null,
-  
-  // Font used for titles, labels, etc.
-  font: null,
-  
-  font_color: null,
-  
-  // Prevent drawing of line markers
-  hide_line_markers: null,
-  
-  // Prevent drawing of the legend
-  hide_legend: null,
-  
-  // Prevent drawing of the title
-  hide_title: null,
-  
-  // Prevent drawing of line numbers
-  hide_line_numbers: null,
-  
-  // Message shown when there is no data. Fits up to 20 characters. Defaults
-  // to "No Data."
-  no_data_message: null,
-  
-  // The font size of the large title at the top of the graph
-  title_font_size: null,
-  
-  // Optionally set the size of the font. Based on an 800x600px graph.
-  // Default is 20.
-  //
-  // Will be scaled down if graph is smaller than 800px wide.
-  legend_font_size: null,
-  
-  // The font size of the labels around the graph
-  marker_font_size: null,
-  
-  // The color of the auxiliary lines
-  marker_color: null,
-  
-  // The number of horizontal lines shown for reference
-  marker_count: null,
-  
-  // You can manually set a minimum value instead of having the values
-  // guessed for you.
-  //
-  // Set it after you have given all your data to the graph object.
-  minimum_value: null,
-  
-  // You can manually set a maximum value, such as a percentage-based graph
-  // that always goes to 100.
-  //
-  // If you use this, you must set it after you have given all your data to
-  // the graph object.
-  maximum_value: null,
-  
-  // Set to false if you don't want the data to be sorted with largest avg
-  // values at the back.
-  sort: null,
-  
-  // Experimental
-  additional_line_values: null,
-  
-  // Experimental
-  stacked: null,
-  
-  // Optionally set the size of the colored box by each item in the legend.
-  // Default is 20.0
-  //
-  // Will be scaled down if graph is smaller than 800px wide.
-  legend_box_size: null,
-  
-  // Set to true to enable tooltip displays
-  tooltips: false,
-  
-  // If one numerical argument is given, the graph is drawn at 4/3 ratio
-  // according to the given width (800 results in 800x600, 400 gives 400x300,
-  // etc.).
-  //
-  // Or, send a geometry string for other ratios ('800x400', '400x225').
-  initialize: function(renderer, target_width) {
-    this._d = new Bluff.Renderer(renderer);
-    target_width = target_width || this.klass.DEFAULT_TARGET_WIDTH;
-    
-    var geo;
-    
-    if (typeof target_width !== 'number') {
-      geo = target_width.split('x');
-      this._columns = parseFloat(geo[0]);
-      this._rows = parseFloat(geo[1]);
-    } else {
-      this._columns = parseFloat(target_width);
-      this._rows = this._columns * 0.75;
-    }
-    
-    this.initialize_ivars();
-    
-    this._reset_themes();
-    this.theme_keynote();
-    
-    this._listeners = {};
-  },
-  
-  // Set instance variables for this object.
-  //
-  // Subclasses can override this, call super, then set values separately.
-  //
-  // This makes it possible to set defaults in a subclass but still allow
-  // developers to change this values in their program.
-  initialize_ivars: function() {
-    // Internal for calculations
-    this._raw_columns = 800;
-    this._raw_rows = 800 * (this._rows/this._columns);
-    this._column_count = 0;
-    this.marker_count = null;
-    this.maximum_value = this.minimum_value = null;
-    this._has_data = false;
-    this._data = [];
-    this.labels = {};
-    this._labels_seen = {};
-    this.sort = true;
-    this.title = null;
-    
-    this._scale = this._columns / this._raw_columns;
-    
-    this.marker_font_size = 21.0;
-    this.legend_font_size = 20.0;
-    this.title_font_size = 36.0;
-    
-    this.top_margin = this.bottom_margin =
-    this.left_margin = this.right_margin = this.klass.DEFAULT_MARGIN;
-    
-    this.legend_margin = this.klass.LEGEND_MARGIN;
-    this.title_margin = this.klass.TITLE_MARGIN;
-    
-    this.legend_box_size = 20.0;
-    
-    this.no_data_message = "No Data";
-    
-    this.hide_line_markers = this.hide_legend = this.hide_title = this.hide_line_numbers = false;
-    this.center_labels_over_point = true;
-    this.has_left_labels = false;
-    
-    this.additional_line_values = [];
-    this._additional_line_colors = [];
-    this._theme_options = {};
-    
-    this.x_axis_label = this.y_axis_label = null;
-    this.y_axis_increment = null;
-    this.stacked = null;
-    this._norm_data = null;
-  },
-  
-  // Sets the top, bottom, left and right margins to +margin+.
-  set_margins: function(margin) {
-    this.top_margin = this.left_margin = this.right_margin = this.bottom_margin = margin;
-  },
-  
-  // Sets the font for graph text to the font at +font_path+.
-  set_font: function(font_path) {
-    this.font = font_path;
-    this._d.font = this.font;
-  },
-  
-  // Add a color to the list of available colors for lines.
-  //
-  // Example:
-  //  add_color('#c0e9d3')
-  add_color: function(colorname) {
-    this.colors.push(colorname);
-  },
-  
-  // Replace the entire color list with a new array of colors. Also
-  // aliased as the colors= setter method.
-  //
-  // If you specify fewer colors than the number of datasets you intend
-  // to draw, 'increment_color' will cycle through the array, reusing
-  // colors as needed.
-  //
-  // Note that (as with the 'set_theme' method), you should set up the color
-  // list before you send your data (via the 'data' method). Calls to the
-  // 'data' method made prior to this call will use whatever color scheme
-  // was in place at the time data was called.
-  //
-  // Example:
-  //  replace_colors ['#cc99cc', '#d9e043', '#34d8a2']
-  replace_colors: function(color_list) {
-    this.colors = color_list || [];
-    this._color_index = 0;
-  },
-  
-  // You can set a theme manually. Assign a hash to this method before you
-  // send your data.
-  //
-  //  graph.set_theme({
-  //    colors: ['orange', 'purple', 'green', 'white', 'red'],
-  //    marker_color: 'blue',
-  //    background_colors: ['black', 'grey']
-  //  })
-  //
-  // background_image: 'squirrel.png' is also possible.
-  //
-  // (Or hopefully something better looking than that.)
-  //
-  set_theme: function(options) {
-    this._reset_themes();
-    
-    this._theme_options = {
-      colors: ['black', 'white'],
-      additional_line_colors: [],
-      marker_color: 'white',
-      font_color: 'black',
-      background_colors: null,
-      background_image: null
-    };
-    for (var key in options) this._theme_options[key] = options[key];
-    
-    this.colors = this._theme_options.colors;
-    this.marker_color = this._theme_options.marker_color;
-    this.font_color = this._theme_options.font_color || this.marker_color;
-    this._additional_line_colors = this._theme_options.additional_line_colors;
-    
-    this._render_background();
-  },
-  
-  // Set just the background colors
-  set_background: function(options) {
-    if (options.colors)
-      this._theme_options.background_colors = options.colors;
-    if (options.image)
-      this._theme_options.background_image = options.image;
-    this._render_background();
-  },
-  
-  // A color scheme similar to the popular presentation software.
-  theme_keynote: function() {
-    // Colors
-    this._blue = '#6886B4';
-    this._yellow = '#FDD84E';
-    this._green = '#72AE6E';
-    this._red = '#D1695E';
-    this._purple = '#8A6EAF';
-    this._orange = '#EFAA43';
-    this._white = 'white';
-    this.colors = [this._yellow, this._blue, this._green, this._red, this._purple, this._orange, this._white];
-    
-    this.set_theme({
-      colors: this.colors,
-      marker_color: 'white',
-      font_color: 'white',
-      background_colors: ['black', '#4a465a']
-    });
-  },
-  
-  // A color scheme plucked from the colors on the popular usability blog.
-  theme_37signals: function() {
-    // Colors
-    this._green = '#339933';
-    this._purple = '#cc99cc';
-    this._blue = '#336699';
-    this._yellow = '#FFF804';
-    this._red = '#ff0000';
-    this._orange = '#cf5910';
-    this._black = 'black';
-    this.colors = [this._yellow, this._blue, this._green, this._red, this._purple, this._orange, this._black];
-    
-    this.set_theme({
-      colors: this.colors,
-      marker_color: 'black',
-      font_color: 'black',
-      background_colors: ['#d1edf5', 'white']
-    });
-  },
-  
-  // A color scheme from the colors used on the 2005 Rails keynote
-  // presentation at RubyConf.
-  theme_rails_keynote: function() {
-    // Colors
-    this._green = '#00ff00';
-    this._grey = '#333333';
-    this._orange = '#ff5d00';
-    this._red = '#f61100';
-    this._white = 'white';
-    this._light_grey = '#999999';
-    this._black = 'black';
-    this.colors = [this._green, this._grey, this._orange, this._red, this._white, this._light_grey, this._black];
-    
-    this.set_theme({
-      colors: this.colors,
-      marker_color: 'white',
-      font_color: 'white',
-      background_colors: ['#0083a3', '#0083a3']
-    });
-  },
-  
-  // A color scheme similar to that used on the popular podcast site.
-  theme_odeo: function() {
-    // Colors
-    this._grey = '#202020';
-    this._white = 'white';
-    this._dark_pink = '#a21764';
-    this._green = '#8ab438';
-    this._light_grey = '#999999';
-    this._dark_blue = '#3a5b87';
-    this._black = 'black';
-    this.colors = [this._grey, this._white, this._dark_blue, this._dark_pink, this._green, this._light_grey, this._black];
-    
-    this.set_theme({
-      colors: this.colors,
-      marker_color: 'white',
-      font_color: 'white',
-      background_colors: ['#ff47a4', '#ff1f81']
-    });
-  },
-  
-  // A pastel theme
-  theme_pastel: function() {
-    // Colors
-    this.colors = [
-                    '#a9dada', // blue
-                    '#aedaa9', // green
-                    '#daaea9', // peach
-                    '#dadaa9', // yellow
-                    '#a9a9da', // dk purple
-                    '#daaeda', // purple
-                    '#dadada' // grey
-                  ];
-    
-    this.set_theme({
-      colors: this.colors,
-      marker_color: '#aea9a9', // Grey
-      font_color: 'black',
-      background_colors: 'white'
-    });
-  },
-  
-  // A greyscale theme
-  theme_greyscale: function() {
-    // Colors
-    this.colors = [
-                    '#282828', // 
-                    '#383838', // 
-                    '#686868', // 
-                    '#989898', // 
-                    '#c8c8c8', // 
-                    '#e8e8e8' // 
-                  ];
-    
-    this.set_theme({
-      colors: this.colors,
-      marker_color: '#aea9a9', // Grey
-      font_color: 'black',
-      background_colors: 'white'
-    });
-  },
-  
-  // Parameters are an array where the first element is the name of the dataset
-  // and the value is an array of values to plot.
-  //
-  // Can be called multiple times with different datasets for a multi-valued
-  // graph.
-  //
-  // If the color argument is nil, the next color from the default theme will
-  // be used.
-  //
-  // NOTE: If you want to use a preset theme, you must set it before calling
-  // data().
-  //
-  // Example:
-  //   data("Bart S.", [95, 45, 78, 89, 88, 76], '#ffcc00')
-  data: function(name, data_points, color) {
-    data_points = (data_points === undefined) ? [] : data_points;
-    color = color || null;
-    
-    data_points = Bluff.array(data_points); // make sure it's an array
-    this._data.push([name, data_points, (color || this._increment_color())]);
-    // Set column count if this is larger than previous counts
-    this._column_count = (data_points.length > this._column_count) ? data_points.length : this._column_count;
-    
-    // Pre-normalize
-    Bluff.each(data_points, function(data_point, index) {
-      if (data_point === undefined) return;
-      
-      // Setup max/min so spread starts at the low end of the data points
-      if (this.maximum_value === null && this.minimum_value === null)
-        this.maximum_value = this.minimum_value = data_point;
-      
-      // TODO Doesn't work with stacked bar graphs
-      // Original: @maximum_value = _larger_than_max?(data_point, index) ? max(data_point, index) : @maximum_value
-      this.maximum_value = this._larger_than_max(data_point) ? data_point : this.maximum_value;
-      if (this.maximum_value >= 0) this._has_data = true;
-      
-      this.minimum_value = this._less_than_min(data_point) ? data_point : this.minimum_value;
-      if (this.minimum_value < 0) this._has_data = true;
-    }, this);
-  },
-  
-  // Overridden by subclasses to do the actual plotting of the graph.
-  //
-  // Subclasses should start by calling super() for this method.
-  draw: function() {
-    if (this.stacked) this._make_stacked();
-    this._setup_drawing();
-    
-    this._debug(function() {
-      // Outer margin
-      this._d.rectangle(this.left_margin, this.top_margin,
-                        this._raw_columns - this.right_margin, this._raw_rows - this.bottom_margin);
-      // Graph area box
-      this._d.rectangle(this._graph_left, this._graph_top, this._graph_right, this._graph_bottom);
-    });
-  },
-  
-  clear: function() {
-    this._render_background();
-  },
-  
-  on: function(eventType, callback, context) {
-    var list = this._listeners[eventType] = this._listeners[eventType] || [];
-    list.push([callback, context]);
-  },
-  
-  trigger: function(eventType, data) {
-    var list = this._listeners[eventType];
-    if (!list) return;
-    Bluff.each(list, function(listener) {
-      listener[0].call(listener[1], data);
-    });
-  },
-  
-  // Calculates size of drawable area and draws the decorations.
-  //
-  // * line markers
-  // * legend
-  // * title
-  _setup_drawing: function() {
-    // Maybe should be done in one of the following functions for more granularity.
-    if (!this._has_data) return this._draw_no_data();
-    
-    this._normalize();
-    this._setup_graph_measurements();
-    if (this.sort) this._sort_norm_data();
-    
-    this._draw_legend();
-    this._draw_line_markers();
-    this._draw_axis_labels();
-    this._draw_title();
-  },
-  
-  // Make copy of data with values scaled between 0-100
-  _normalize: function(force) {
-    if (this._norm_data === null || force === true) {
-      this._norm_data = [];
-      if (!this._has_data) return;
-      
-      this._calculate_spread();
-      
-      Bluff.each(this._data, function(data_row) {
-        var norm_data_points = [];
-        Bluff.each(data_row[this.klass.DATA_VALUES_INDEX], function(data_point) {
-          if (data_point === null || data_point === undefined)
-            norm_data_points.push(null);
-          else
-            norm_data_points.push((data_point - this.minimum_value) / this._spread);
-        }, this);
-        this._norm_data.push([data_row[this.klass.DATA_LABEL_INDEX], norm_data_points, data_row[this.klass.DATA_COLOR_INDEX]]);
-      }, this);
-    }
-  },
-  
-  _calculate_spread: function() {
-    this._spread = this.maximum_value - this.minimum_value;
-    this._spread = this._spread > 0 ? this._spread : 1;
-    
-    var power = Math.round(Math.LOG10E*Math.log(this._spread));
-    this._significant_digits = Math.pow(10, 3 - power);
-  },
-  
-  // Calculates size of drawable area, general font dimensions, etc.
-  _setup_graph_measurements: function() {
-    this._marker_caps_height = this.hide_line_markers ? 0 :
-      this._calculate_caps_height(this.marker_font_size);
-    this._title_caps_height = this.hide_title ? 0 :
-      this._calculate_caps_height(this.title_font_size);
-    this._legend_caps_height = this.hide_legend ? 0 :
-      this._calculate_caps_height(this.legend_font_size);
-    
-    var longest_label,
-        longest_left_label_width,
-        line_number_width,
-        last_label,
-        extra_room_for_long_label,
-        x_axis_label_height,
-        key;
-    
-    if (this.hide_line_markers) {
-      this._graph_left = this.left_margin;
-      this._graph_right_margin = this.right_margin;
-      this._graph_bottom_margin = this.bottom_margin;
-    } else {
-      longest_left_label_width = 0;
-      if (this.has_left_labels) {
-        longest_label = '';
-        for (key in this.labels) {
-          longest_label = longest_label.length > this.labels[key].length
-              ? longest_label
-              : this.labels[key];
-        }
-        longest_left_label_width = this._calculate_width(this.marker_font_size, longest_label) * 1.25;
-      } else {
-        longest_left_label_width = this._calculate_width(this.marker_font_size, this._label(this.maximum_value));
-      }
-      
-      // Shift graph if left line numbers are hidden
-      line_number_width = this.hide_line_numbers && !this.has_left_labels ?
-      0.0 :
-        longest_left_label_width + this.klass.LABEL_MARGIN * 2;
-      
-      this._graph_left = this.left_margin +
-        line_number_width +
-        (this.y_axis_label === null ? 0.0 : this._marker_caps_height + this.klass.LABEL_MARGIN * 2);
-      
-      // Make space for half the width of the rightmost column label.
-      // Might be greater than the number of columns if between-style bar markers are used.
-      last_label = -Infinity;
-      for (key in this.labels)
-        last_label = last_label > Number(key) ? last_label : Number(key);
-      last_label = Math.round(last_label);
-      extra_room_for_long_label = (last_label >= (this._column_count-1) && this.center_labels_over_point) ?
-      this._calculate_width(this.marker_font_size, this.labels[last_label]) / 2 :
-        0;
-      this._graph_right_margin  = this.right_margin + extra_room_for_long_label;
-      
-      this._graph_bottom_margin = this.bottom_margin +
-        this._marker_caps_height + this.klass.LABEL_MARGIN;
-    }
-    
-    this._graph_right = this._raw_columns - this._graph_right_margin;
-    this._graph_width = this._raw_columns - this._graph_left - this._graph_right_margin;
-    
-    // When hide_title, leave a title_margin space for aesthetics.
-    // Same with hide_legend
-    this._graph_top = this.top_margin +
-      (this.hide_title  ? this.title_margin  : this._title_caps_height  + this.title_margin ) +
-      (this.hide_legend ? this.legend_margin : this._legend_caps_height + this.legend_margin);
-    
-    x_axis_label_height = (this.x_axis_label === null) ? 0.0 :
-      this._marker_caps_height + this.klass.LABEL_MARGIN;
-    this._graph_bottom = this._raw_rows - this._graph_bottom_margin - x_axis_label_height;
-    this._graph_height = this._graph_bottom - this._graph_top;
-  },
-  
-  // Draw the optional labels for the x axis and y axis.
-  _draw_axis_labels: function() {
-    if (this.x_axis_label) {
-      // X Axis
-      // Centered vertically and horizontally by setting the
-      // height to 1.0 and the width to the width of the graph.
-      var x_axis_label_y_coordinate = this._graph_bottom + this.klass.LABEL_MARGIN * 2 + this._marker_caps_height;
-      
-      // TODO Center between graph area
-      this._d.fill = this.font_color;
-      if (this.font) this._d.font = this.font;
-      this._d.stroke = 'transparent';
-      this._d.pointsize = this._scale_fontsize(this.marker_font_size);
-      this._d.gravity = 'north';
-      this._d.annotate_scaled(
-                              this._raw_columns, 1.0,
-                              0.0, x_axis_label_y_coordinate,
-                              this.x_axis_label, this._scale);
-      this._debug(function() {
-        this._d.line(0.0, x_axis_label_y_coordinate, this._raw_columns, x_axis_label_y_coordinate);
-      });
-    }
-    
-    // TODO Y label (not generally possible in browsers)
-  },
-  
-  // Draws horizontal background lines and labels
-  _draw_line_markers: function() {
-    if (this.hide_line_markers) return;
-    
-    if (this.y_axis_increment === null) {
-      // Try to use a number of horizontal lines that will come out even.
-      //
-      // TODO Do the same for larger numbers...100, 75, 50, 25
-      if (this.marker_count === null) {
-        Bluff.each([3,4,5,6,7], function(lines) {
-          if (!this.marker_count && this._spread % lines === 0)
-            this.marker_count = lines;
-        }, this);
-        this.marker_count = this.marker_count || 4;
-      }
-      this._increment = (this._spread > 0) ? this._significant(this._spread / this.marker_count) : 1;
-    } else {
-      // TODO Make this work for negative values
-      this.maximum_value = Math.max(Math.ceil(this.maximum_value), this.y_axis_increment);
-      this.minimum_value = Math.floor(this.minimum_value);
-      this._calculate_spread();
-      this._normalize(true);
-      
-      this.marker_count = Math.round(this._spread / this.y_axis_increment);
-      this._increment = this.y_axis_increment;
-    }
-    this._increment_scaled = this._graph_height / (this._spread / this._increment);
-    
-    // Draw horizontal line markers and annotate with numbers
-    var index, n, y, marker_label;
-    for (index = 0, n = this.marker_count; index <= n; index++) {
-      y = this._graph_top + this._graph_height - index * this._increment_scaled;
-      
-      this._d.stroke = this.marker_color;
-      this._d.stroke_width = 1;
-      this._d.line(this._graph_left, y, this._graph_right, y);
-      
-      marker_label = index * this._increment + this.minimum_value;
-      
-      if (!this.hide_line_numbers) {
-        this._d.fill = this.font_color;
-        if (this.font) this._d.font = this.font;
-        this._d.font_weight = 'normal';
-        this._d.stroke = 'transparent';
-        this._d.pointsize = this._scale_fontsize(this.marker_font_size);
-        this._d.gravity = 'east';
-        
-        // Vertically center with 1.0 for the height
-        this._d.annotate_scaled(this._graph_left - this.klass.LABEL_MARGIN,
-                                1.0, 0.0, y,
-                                this._label(marker_label), this._scale);
-      }
-    }
-  },
-  
-  _center: function(size) {
-    return (this._raw_columns - size) / 2;
-  },
-  
-  // Draws a legend with the names of the datasets matched to the colors used
-  // to draw them.
-  _draw_legend: function() {
-    if (this.hide_legend) return;
-    
-    this._legend_labels = Bluff.map(this._data, function(item) {
-      return item[this.klass.DATA_LABEL_INDEX];
-    }, this);
-    
-    var legend_square_width = this.legend_box_size; // small square with color of this item
-    
-    // May fix legend drawing problem at small sizes
-    if (this.font) this._d.font = this.font;
-    this._d.pointsize = this.legend_font_size;
-    
-    var label_widths = [[]]; // Used to calculate line wrap
-    Bluff.each(this._legend_labels, function(label) {
-      var last = label_widths.length - 1;
-      var metrics = this._d.get_type_metrics(label);
-      var label_width = metrics.width + legend_square_width * 2.7;
-      label_widths[last].push(label_width);
-      
-      if (Bluff.sum(label_widths[last]) > (this._raw_columns * 0.9))
-        label_widths.push([label_widths[last].pop()]);
-    }, this);
-    
-    var current_x_offset = this._center(Bluff.sum(label_widths[0]));
-    var current_y_offset = this.hide_title ?
-    this.top_margin + this.title_margin :
-      this.top_margin + this.title_margin + this._title_caps_height;
-    
-    this._debug(function() {
-      this._d.stroke_width = 1;
-      this._d.line(0, current_y_offset, this._raw_columns, current_y_offset);
-    });
-    
-    Bluff.each(this._legend_labels, function(legend_label, index) {
-      
-      // Draw label
-      this._d.fill = this.font_color;
-      if (this.font) this._d.font = this.font;
-      this._d.pointsize = this._scale_fontsize(this.legend_font_size);
-      this._d.stroke = 'transparent';
-      this._d.font_weight = 'normal';
-      this._d.gravity = 'west';
-      this._d.annotate_scaled(this._raw_columns, 1.0,
-                              current_x_offset + (legend_square_width * 1.7), current_y_offset,
-                              legend_label, this._scale);
-      
-      // Now draw box with color of this dataset
-      this._d.stroke = 'transparent';
-      this._d.fill = this._data[index][this.klass.DATA_COLOR_INDEX];
-      this._d.rectangle(current_x_offset,
-                        current_y_offset - legend_square_width / 2.0,
-                        current_x_offset + legend_square_width,
-                        current_y_offset + legend_square_width / 2.0);
-      
-      this._d.pointsize = this.legend_font_size;
-      var metrics = this._d.get_type_metrics(legend_label);
-      var current_string_offset = metrics.width + (legend_square_width * 2.7),
-          line_height;
-      
-      // Handle wrapping
-      label_widths[0].shift();
-      if (label_widths[0].length == 0) {
-        this._debug(function() {
-          this._d.line(0.0, current_y_offset, this._raw_columns, current_y_offset);
-        });
-        
-        label_widths.shift();
-        if (label_widths.length > 0) current_x_offset = this._center(Bluff.sum(label_widths[0]));
-        line_height = Math.max(this._legend_caps_height, legend_square_width) + this.legend_margin;
-        if (label_widths.length > 0) {
-          // Wrap to next line and shrink available graph dimensions
-          current_y_offset += line_height;
-          this._graph_top += line_height;
-          this._graph_height = this._graph_bottom - this._graph_top;
-        }
-      } else {
-        current_x_offset += current_string_offset;
-      }
-    }, this);
-    this._color_index = 0;
-  },
-  
-  // Draws a title on the graph.
-  _draw_title: function() {
-    if (this.hide_title || !this.title) return;
-    
-    this._d.fill = this.font_color;
-    if (this.font) this._d.font = this.font;
-    this._d.pointsize = this._scale_fontsize(this.title_font_size);
-    this._d.font_weight = 'bold';
-    this._d.gravity = 'north';
-    this._d.annotate_scaled(this._raw_columns, 1.0,
-                            0, this.top_margin,
-                            this.title, this._scale);
-  },
-  
-  // Draws column labels below graph, centered over x_offset
-  //--
-  // TODO Allow WestGravity as an option
-  _draw_label: function(x_offset, index) {
-    if (this.hide_line_markers) return;
-    
-    var y_offset;
-    
-    if (this.labels[index] && !this._labels_seen[index]) {
-      y_offset = this._graph_bottom + this.klass.LABEL_MARGIN;
-      
-      this._d.fill = this.font_color;
-      if (this.font) this._d.font = this.font;
-      this._d.stroke = 'transparent';
-      this._d.font_weight = 'normal';
-      this._d.pointsize = this._scale_fontsize(this.marker_font_size);
-      this._d.gravity = 'north';
-      this._d.annotate_scaled(1.0, 1.0,
-                              x_offset, y_offset,
-                              this.labels[index], this._scale);
-      this._labels_seen[index] = true;
-      
-      this._debug(function() {
-        this._d.stroke_width = 1;
-        this._d.line(0.0, y_offset, this._raw_columns, y_offset);
-      });
-    }
-  },
-  
-  // Creates a mouse hover target rectangle for tooltip displays
-  _draw_tooltip: function(left, top, width, height, name, color, data, index) {
-    if (!this.tooltips) return;
-    var node = this._d.tooltip(left, top, width, height, name, color, data);
-    
-    Bluff.Event.observe(node, 'click', function() {
-      var point = {
-        series: name,
-        label:  this.labels[index],
-        value:  data,
-        color:  color
-      };
-      this.trigger('click:datapoint', point);
-    }, this);
-  },
-  
-  // Shows an error message because you have no data.
-  _draw_no_data: function() {
-    this._d.fill = this.font_color;
-    if (this.font) this._d.font = this.font;
-    this._d.stroke = 'transparent';
-    this._d.font_weight = 'normal';
-    this._d.pointsize = this._scale_fontsize(80);
-    this._d.gravity = 'center';
-    this._d.annotate_scaled(this._raw_columns, this._raw_rows/2,
-                            0, 10,
-                            this.no_data_message, this._scale);
-  },
-  
-  // Finds the best background to render based on the provided theme options.
-  _render_background: function() {
-    var colors = this._theme_options.background_colors;
-    switch (true) {
-      case colors instanceof Array:
-        this._render_gradiated_background.apply(this, colors);
-        break;
-      case typeof colors === 'string':
-        this._render_solid_background(colors);
-        break;
-      default:
-        this._render_image_background(this._theme_options.background_image);
-        break;
-    }
-  },
-  
-  // Make a new image at the current size with a solid +color+.
-  _render_solid_background: function(color) {
-    this._d.render_solid_background(this._columns, this._rows, color);
-  },
-  
-  // Use with a theme definition method to draw a gradiated background.
-  _render_gradiated_background: function(top_color, bottom_color) {
-    this._d.render_gradiated_background(this._columns, this._rows, top_color, bottom_color);
-  },
-  
-  // Use with a theme to use an image (800x600 original) background.
-  _render_image_background: function(image_path) {
-    // TODO
-  },
-  
-  // Resets everything to defaults (except data).
-  _reset_themes: function() {
-    this._color_index = 0;
-    this._labels_seen = {};
-    this._theme_options = {};
-    this._d.scale(this._scale, this._scale);
-  },
-  
-  _scale_value: function(value) {
-    return this._scale * value;
-  },
-  
-  // Return a comparable fontsize for the current graph.
-  _scale_fontsize: function(value) {
-    var new_fontsize = value * this._scale;
-    return new_fontsize;
-  },
-  
-  _clip_value_if_greater_than: function(value, max_value) {
-    return (value > max_value) ? max_value : value;
-  },
-  
-  // Overridden by subclasses such as stacked bar.
-  _larger_than_max: function(data_point, index) {
-    return data_point > this.maximum_value;
-  },
-  
-  _less_than_min: function(data_point, index) {
-    return data_point < this.minimum_value;
-  },
-  
-  // Overridden by subclasses that need it.
-  _max: function(data_point, index) {
-    return data_point;
-  },
-  
-  // Overridden by subclasses that need it.
-  _min: function(data_point, index) {
-    return data_point;
-  },
-  
-  _significant: function(inc) {
-    if (inc == 0) return 1.0;
-    var factor = 1.0;
-    while (inc < 10) {
-      inc *= 10;
-      factor /= 10;
-    }
-    
-    while (inc > 100) {
-      inc /= 10;
-      factor *= 10;
-    }
-    
-    return Math.floor(inc) * factor;
-  },
-  
-  // Sort with largest overall summed value at front of array so it shows up
-  // correctly in the drawn graph.
-  _sort_norm_data: function() {
-    var sums = this._sums, index = this.klass.DATA_VALUES_INDEX;
-    
-    this._norm_data.sort(function(a,b) {
-      return sums(b[index]) - sums(a[index]);
-    });
-    
-    this._data.sort(function(a,b) {
-      return sums(b[index]) - sums(a[index]);
-    });
-  },
-  
-  _sums: function(data_set) {
-    var total_sum = 0;
-    Bluff.each(data_set, function(num) { total_sum += (num || 0) });
-    return total_sum;
-  },
-  
-  _make_stacked: function() {
-    var stacked_values = [], i = this._column_count;
-    while (i--) stacked_values[i] = 0;
-    Bluff.each(this._data, function(value_set) {
-      Bluff.each(value_set[this.klass.DATA_VALUES_INDEX], function(value, index) {
-        stacked_values[index] += value;
-      }, this);
-      value_set[this.klass.DATA_VALUES_INDEX] = Bluff.array(stacked_values);
-    }, this);
-  },
-  
-  // Takes a block and draws it if DEBUG is true.
-  //
-  // Example:
-  //   debug { @d.rectangle x1, y1, x2, y2 }
-  _debug: function(block) {
-    if (this.klass.DEBUG) {
-      this._d.fill = 'transparent';
-      this._d.stroke = 'turquoise';
-      block.call(this);
-    }
-  },
-  
-  // Returns the next color in your color list.
-  _increment_color: function() {
-    var offset = this._color_index;
-    this._color_index = (this._color_index + 1) % this.colors.length;
-    return this.colors[offset];
-  },
-  
-  // Return a formatted string representing a number value that should be
-  // printed as a label.
-  _label: function(value) {
-    var sep   = this.klass.THOUSAND_SEPARATOR,
-        label = (this._spread % this.marker_count == 0 || this.y_axis_increment !== null)
-        ? String(Math.round(value))
-        : String(Math.floor(value * this._significant_digits)/this._significant_digits);
-    
-    var parts = label.split('.');
-    parts[0] = parts[0].replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1' + sep);
-    return parts.join('.');
-  },
-  
-  // Returns the height of the capital letter 'X' for the current font and
-  // size.
-  //
-  // Not scaled since it deals with dimensions that the regular scaling will
-  // handle.
-  _calculate_caps_height: function(font_size) {
-    return this._d.caps_height(font_size);
-  },
-  
-  // Returns the width of a string at this pointsize.
-  //
-  // Not scaled since it deals with dimensions that the regular 
-  // scaling will handle.
-  _calculate_width: function(font_size, text) {
-    return this._d.text_width(font_size, text);
-  }
-});
-
-
-Bluff.Area = new JS.Class(Bluff.Base, {
-  
-  draw: function() {
-    this.callSuper();
-    
-    if (!this._has_data) return;
-    
-    this._x_increment = this._graph_width / (this._column_count - 1);
-    this._d.stroke = 'transparent';
-    
-    Bluff.each(this._norm_data, function(data_row) {
-      var poly_points = [],
-          prev_x = 0.0,
-          prev_y = 0.0;
-      
-      Bluff.each(data_row[this.klass.DATA_VALUES_INDEX], function(data_point, index) {
-        // Use incremented x and scaled y
-        var new_x = this._graph_left + (this._x_increment * index);
-        var new_y = this._graph_top + (this._graph_height - data_point * this._graph_height);
-        
-        if (prev_x > 0 && prev_y > 0) {
-          poly_points.push(new_x);
-          poly_points.push(new_y);
-          
-          // this._d.polyline(prev_x, prev_y, new_x, new_y);
-        } else {
-          poly_points.push(this._graph_left);
-          poly_points.push(this._graph_bottom - 1);
-          poly_points.push(new_x);
-          poly_points.push(new_y);
-          
-          // this._d.polyline(this._graph_left, this._graph_bottom, new_x, new_y);
-        }
-        
-        this._draw_label(new_x, index);
-        
-        prev_x = new_x;
-        prev_y = new_y;
-      }, this);
-      
-      // Add closing points, draw polygon
-      poly_points.push(this._graph_right);
-      poly_points.push(this._graph_bottom - 1);
-      poly_points.push(this._graph_left);
-      poly_points.push(this._graph_bottom - 1);
-      
-      this._d.fill = data_row[this.klass.DATA_COLOR_INDEX];
-      this._d.polyline(poly_points);
-      
-    }, this);
-  }
-});
-
-
-//  This class perfoms the y coordinats conversion for the bar class.
-//
-//  There are three cases: 
-//
-//    1. Bars all go from zero in positive direction
-//    2. Bars all go from zero to negative direction  
-//    3. Bars either go from zero to positive or from zero to negative
-//
-Bluff.BarConversion = new JS.Class({
-  mode:           null,
-  zero:           null,
-  graph_top:      null,
-  graph_height:   null,
-  minimum_value:  null,
-  spread:         null,
-  
-  getLeftYRightYscaled: function(data_point, result) {
-    var val;
-    switch (this.mode) {
-      case 1: // Case one
-        // minimum value >= 0 ( only positiv values )
-        result[0] = this.graph_top + this.graph_height*(1 - data_point) + 1;
-        result[1] = this.graph_top + this.graph_height - 1;
-        break;
-      case 2:  // Case two
-        // only negativ values
-         result[0] = this.graph_top + 1;
-        result[1] = this.graph_top + this.graph_height*(1 - data_point) - 1;
-        break;
-      case 3: // Case three
-        // positiv and negativ values
-        val = data_point-this.minimum_value/this.spread;
-        if ( data_point >= this.zero ) {
-          result[0] = this.graph_top + this.graph_height*(1 - (val-this.zero)) + 1;
-          result[1] = this.graph_top + this.graph_height*(1 - this.zero) - 1;
-        } else {
-          result[0] = this.graph_top + this.graph_height*(1 - (val-this.zero)) + 1;
-          result[1] = this.graph_top + this.graph_height*(1 - this.zero) - 1;
-        }
-        break;
-      default:
-        result[0] = 0.0;
-        result[1] = 0.0;
-    }        
-  }  
-  
-});
-
-
-Bluff.Bar = new JS.Class(Bluff.Base, {
-  
-  // Spacing factor applied between bars
-  bar_spacing: 0.9,
-  
-  draw: function() {
-    // Labels will be centered over the left of the bar if
-    // there are more labels than columns. This is basically the same 
-    // as where it would be for a line graph.
-    this.center_labels_over_point = (Bluff.keys(this.labels).length > this._column_count);
-    
-    this.callSuper();
-    if (!this._has_data) return;
-    
-    this._draw_bars();
-  },
-  
-  _draw_bars: function() {
-    this._bar_width = this._graph_width / (this._column_count * this._data.length);
-    var padding = (this._bar_width * (1 - this.bar_spacing)) / 2;
-    
-    this._d.stroke_opacity = 0.0;
-    
-    // Setup the BarConversion Object
-    var conversion = new Bluff.BarConversion();
-    conversion.graph_height = this._graph_height;
-    conversion.graph_top = this._graph_top;
-    
-    // Set up the right mode [1,2,3] see BarConversion for further explanation
-    if (this.minimum_value >= 0) {
-      // all bars go from zero to positiv
-      conversion.mode = 1;
-    } else {
-      // all bars go from 0 to negativ
-      if (this.maximum_value <= 0) {
-        conversion.mode = 2;
-      } else {
-        // bars either go from zero to negativ or to positiv
-        conversion.mode = 3;
-        conversion.spread = this._spread;
-        conversion.minimum_value = this.minimum_value;
-        conversion.zero = -this.minimum_value/this._spread;
-      }
-    }
-    
-    // iterate over all normalised data
-    Bluff.each(this._norm_data, function(data_row, row_index) {
-      var raw_data = this._data[row_index][this.klass.DATA_VALUES_INDEX];
-      
-      Bluff.each(data_row[this.klass.DATA_VALUES_INDEX], function(data_point, point_index) {
-        // Use incremented x and scaled y
-        // x
-        var left_x = this._graph_left + (this._bar_width * (row_index + point_index + ((this._data.length - 1) * point_index))) + padding;
-        var right_x = left_x + this._bar_width * this.bar_spacing;
-        // y
-        var conv = [];
-        conversion.getLeftYRightYscaled(data_point, conv);
-        
-        // create new bar
-        this._d.fill = data_row[this.klass.DATA_COLOR_INDEX];
-        this._d.rectangle(left_x, conv[0], right_x, conv[1]);
-        
-        // create tooltip target
-        this._draw_tooltip(left_x, conv[0],
-                           right_x - left_x, conv[1] - conv[0],
-                           data_row[this.klass.DATA_LABEL_INDEX],
-                           data_row[this.klass.DATA_COLOR_INDEX],
-                           raw_data[point_index], point_index);
-        
-        // Calculate center based on bar_width and current row
-        var label_center = this._graph_left + 
-                          (this._data.length * this._bar_width * point_index) + 
-                          (this._data.length * this._bar_width / 2.0);
-        // Subtract half a bar width to center left if requested
-        this._draw_label(label_center - (this.center_labels_over_point ? this._bar_width / 2.0 : 0.0), point_index);
-      }, this);
-      
-    }, this);
-    
-    // Draw the last label if requested
-    if (this.center_labels_over_point) this._draw_label(this._graph_right, this._column_count);
-  }
-});
-
-
-// Here's how to make a Line graph:
-//
-//   g = new Bluff.Line('canvasId');
-//   g.title = "A Line Graph";
-//   g.data('Fries', [20, 23, 19, 8]);
-//   g.data('Hamburgers', [50, 19, 99, 29]);
-//   g.draw();
-//
-// There are also other options described below, such as #baseline_value, #baseline_color, #hide_dots, and #hide_lines.
-
-Bluff.Line = new JS.Class(Bluff.Base, {
-  // Draw a dashed line at the given value
-  baseline_value: null,
-  
-  // Color of the baseline
-  baseline_color: null,
-  
-  // Dimensions of lines and dots; calculated based on dataset size if left unspecified
-  line_width: null,
-  dot_radius: null,
-  
-  // Hide parts of the graph to fit more datapoints, or for a different appearance.
-  hide_dots: null,
-  hide_lines: null,
-  
-  // Call with target pixel width of graph (800, 400, 300), and/or 'false' to omit lines (points only).
-  //
-  //  g = new Bluff.Line('canvasId', 400) // 400px wide with lines
-  //
-  //  g = new Bluff.Line('canvasId', 400, false) // 400px wide, no lines (for backwards compatibility)
-  //
-  //  g = new Bluff.Line('canvasId', false) // Defaults to 800px wide, no lines (for backwards compatibility)
-  // 
-  // The preferred way is to call hide_dots or hide_lines instead.
-  initialize: function(renderer) {
-    if (arguments.length > 3) throw 'Wrong number of arguments';
-    if (arguments.length === 1 || (typeof arguments[1] !== 'number' && typeof arguments[1] !== 'string'))
-      this.callSuper(renderer, null);
-    else
-      this.callSuper();
-    
-    this.hide_dots = this.hide_lines = false;
-    this.baseline_color = 'red';
-    this.baseline_value = null;
-  },
-  
-  draw: function() {
-    this.callSuper();
-    
-    if (!this._has_data) return;
-    
-    // Check to see if more than one datapoint was given. NaN can result otherwise.
-    this.x_increment = (this._column_count > 1) ? (this._graph_width / (this._column_count - 1)) : this._graph_width;
-    
-    var level;
-    
-    if (this._norm_baseline !== undefined) {
-      level = this._graph_top + (this._graph_height - this._norm_baseline * this._graph_height);
-      this._d.push();
-      this._d.stroke = this.baseline_color;
-      this._d.fill_opacity = 0.0;
-      // this._d.stroke_dasharray(10, 20);
-      this._d.stroke_width = 3.0;
-      this._d.line(this._graph_left, level, this._graph_left + this._graph_width, level);
-      this._d.pop();
-    }
-    
-    Bluff.each(this._norm_data, function(data_row, row_index) {
-      var prev_x = null, prev_y = null;
-      var raw_data = this._data[row_index][this.klass.DATA_VALUES_INDEX];
-      
-      this._one_point = this._contains_one_point_only(data_row);
-      
-      Bluff.each(data_row[this.klass.DATA_VALUES_INDEX], function(data_point, index) {
-        var new_x = this._graph_left + (this.x_increment * index);
-        if (typeof data_point !== 'number') return;
-        
-        this._draw_label(new_x, index);
-        
-        var new_y = this._graph_top + (this._graph_height - data_point * this._graph_height);
-        
-        // Reset each time to avoid thin-line errors
-        this._d.stroke = data_row[this.klass.DATA_COLOR_INDEX];
-        this._d.fill = data_row[this.klass.DATA_COLOR_INDEX];
-        this._d.stroke_opacity = 1.0;
-        this._d.stroke_width = this.line_width ||
-          this._clip_value_if_greater_than(this._columns / (this._norm_data[0][this.klass.DATA_VALUES_INDEX].length * 6), 3.0);
-        
-        var circle_radius = this.dot_radius ||
-          this._clip_value_if_greater_than(this._columns / (this._norm_data[0][this.klass.DATA_VALUES_INDEX].length * 2), 7.0);
-        
-        if (!this.hide_lines && prev_x !== null && prev_y !== null) {
-          this._d.line(prev_x, prev_y, new_x, new_y);
-        } else if (this._one_point) {
-          // Show a circle if there's just one point
-          this._d.circle(new_x, new_y, new_x - circle_radius, new_y);
-        }
-        
-        if (!this.hide_dots) this._d.circle(new_x, new_y, new_x - circle_radius, new_y);
-        
-        this._draw_tooltip(new_x - circle_radius, new_y - circle_radius,
-                           2 * circle_radius, 2 *circle_radius,
-                           data_row[this.klass.DATA_LABEL_INDEX],
-                           data_row[this.klass.DATA_COLOR_INDEX],
-                           raw_data[index], index);
-        
-        prev_x = new_x;
-        prev_y = new_y;
-      }, this);
-    }, this);
-  },
-  
-  _normalize: function() {
-    this.maximum_value = Math.max(this.maximum_value, this.baseline_value);
-    this.callSuper();
-    if (this.baseline_value !== null) this._norm_baseline = this.baseline_value / this.maximum_value;
-  },
-  
-  _contains_one_point_only: function(data_row) {
-    // Spin through data to determine if there is just one value present.
-    var count = 0;
-    Bluff.each(data_row[this.klass.DATA_VALUES_INDEX], function(data_point) {
-      if (data_point !== undefined) count += 1;
-    });
-    return count === 1;
-  }
-});
-
-
-// Graph with dots and labels along a vertical access
-// see: 'Creating More Effective Graphs' by Robbins
-
-Bluff.Dot = new JS.Class(Bluff.Base, {
-  
-  draw: function() {
-    this.has_left_labels = true;
-    this.callSuper();
-    
-    if (!this._has_data) return;
-    
-    // Setup spacing.
-    //
-    var spacing_factor = 1.0;
-    
-    this._items_width = this._graph_height / this._column_count;
-    this._item_width = this._items_width * spacing_factor / this._norm_data.length;
-    this._d.stroke_opacity = 0.0;
-    var height = Bluff.array_new(this._column_count, 0),
-        length = Bluff.array_new(this._column_count, this._graph_left),
-        padding = (this._items_width * (1 - spacing_factor)) / 2;
-    
-    Bluff.each(this._norm_data, function(data_row, row_index) {
-      Bluff.each(data_row[this.klass.DATA_VALUES_INDEX], function(data_point, point_index) {
-        
-        var x_pos = this._graph_left + (data_point * this._graph_width) - Math.round(this._item_width/6.0);
-        var y_pos = this._graph_top + (this._items_width * point_index) + padding + Math.round(this._item_width/2.0);
-        
-        if (row_index === 0) {
-          this._d.stroke = this.marker_color;
-          this._d.stroke_width = 1.0;
-          this._d.opacity = 0.1;
-          this._d.line(this._graph_left, y_pos, this._graph_left + this._graph_width, y_pos);
-        }
-        
-        this._d.fill = data_row[this.klass.DATA_COLOR_INDEX];
-        this._d.stroke = 'transparent';
-        this._d.circle(x_pos, y_pos, x_pos + Math.round(this._item_width/3.0), y_pos);
-        
-        // Calculate center based on item_width and current row
-        var label_center = this._graph_top + (this._items_width * point_index + this._items_width / 2) + padding;
-        this._draw_label(label_center, point_index);
-      }, this);
-      
-    }, this);
-  },
-  
-  // Instead of base class version, draws vertical background lines and label
-  _draw_line_markers: function() {
-    
-    if (this.hide_line_markers) return;
-    
-    this._d.stroke_antialias = false;
-    
-    // Draw horizontal line markers and annotate with numbers
-    this._d.stroke_width = 1;
-    var number_of_lines = 5;
-    
-    // TODO Round maximum marker value to a round number like 100, 0.1, 0.5, etc.
-    var increment = this._significant(this.maximum_value / number_of_lines);
-    for (var index = 0; index <= number_of_lines; index++) {
-      
-      var line_diff    = (this._graph_right - this._graph_left) / number_of_lines,
-          x            = this._graph_right - (line_diff * index) - 1,
-          diff         = index - number_of_lines,
-          marker_label = Math.abs(diff) * increment;
-      
-      this._d.stroke = this.marker_color;
-      this._d.line(x, this._graph_bottom, x, this._graph_bottom + 0.5 * this.klass.LABEL_MARGIN);
-      
-      if (!this.hide_line_numbers) {
-        this._d.fill      = this.font_color;
-        if (this.font) this._d.font = this.font;
-        this._d.stroke    = 'transparent';
-        this._d.pointsize = this._scale_fontsize(this.marker_font_size);
-        this._d.gravity   = 'center';
-        // TODO Center text over line
-        this._d.annotate_scaled(0, 0, // Width of box to draw text in
-                                x, this._graph_bottom + (this.klass.LABEL_MARGIN * 2.0), // Coordinates of text
-                                marker_label, this._scale);
-      }
-      this._d.stroke_antialias = true;
-    }
-  },
-  
-  // Draw on the Y axis instead of the X
-  _draw_label: function(y_offset, index) {
-    if (this.labels[index] && !this._labels_seen[index]) {
-      this._d.fill             = this.font_color;
-      if (this.font) this._d.font = this.font;
-      this._d.stroke           = 'transparent';
-      this._d.font_weight      = 'normal';
-      this._d.pointsize        = this._scale_fontsize(this.marker_font_size);
-      this._d.gravity          = 'east';
-      this._d.annotate_scaled(1, 1,
-                              this._graph_left - this.klass.LABEL_MARGIN * 2.0, y_offset,
-                              this.labels[index], this._scale);
-      this._labels_seen[index] = true;
-    }
-  }
-});
-
-
-// Experimental!!! See also the Spider graph.
-Bluff.Net = new JS.Class(Bluff.Base, {
-  
-  // Hide parts of the graph to fit more datapoints, or for a different appearance.
-  hide_dots: null,
-  
-  //Dimensions of lines and dots; calculated based on dataset size if left unspecified
-  line_width: null,
-  dot_radius: null,
-  
-  initialize: function() {
-    this.callSuper();
-    
-    this.hide_dots = false;
-    this.hide_line_numbers = true;
-  },
-  
-  draw: function() {
-    
-    this.callSuper();
-    
-    if (!this._has_data) return;
-    
-    this._radius = this._graph_height / 2.0;
-    this._center_x = this._graph_left + (this._graph_width / 2.0);
-    this._center_y = this._graph_top + (this._graph_height / 2.0) - 10; // Move graph up a bit
-    
-    this._x_increment = this._graph_width / (this._column_count - 1);
-    var circle_radius = this.dot_radius ||
-      this._clip_value_if_greater_than(this._columns / (this._norm_data[0][this.klass.DATA_VALUES_INDEX].length * 2.5), 7.0);
-    
-    this._d.stroke_opacity = 1.0;
-    this._d.stroke_width = this.line_width ||
-      this._clip_value_if_greater_than(this._columns / (this._norm_data[0][this.klass.DATA_VALUES_INDEX].length * 4), 3.0);
-    
-    var level;
-    
-    if (this._norm_baseline !== undefined) {
-      level = this._graph_top + (this._graph_height - this._norm_baseline * this._graph_height);
-      this._d.push();
-      this._d.stroke_color  = this.baseline_color;
-      this._d.fill_opacity = 0.0;
-      // this._d.stroke_dasharray(10, 20);
-      this._d.stroke_width = 5;
-      this._d.line(this._graph_left, level, this._graph_left + this._graph_width, level);
-      this._d.pop();
-    }
-    
-    Bluff.each(this._norm_data, function(data_row) {
-      var prev_x = null, prev_y = null;
-      
-      Bluff.each(data_row[this.klass.DATA_VALUES_INDEX], function(data_point, index) {
-        if (data_point === undefined) return;
-        
-        var rad_pos = index * Math.PI * 2 / this._column_count,
-            point_distance = data_point * this._radius,
-            start_x = this._center_x + Math.sin(rad_pos) * point_distance,
-            start_y = this._center_y - Math.cos(rad_pos) * point_distance,
-            
-            next_index = (index + 1 < data_row[this.klass.DATA_VALUES_INDEX].length) ? index + 1 : 0,
-            
-            next_rad_pos = next_index * Math.PI * 2 / this._column_count,
-            next_point_distance = data_row[this.klass.DATA_VALUES_INDEX][next_index] * this._radius,
-            end_x = this._center_x + Math.sin(next_rad_pos) * next_point_distance,
-            end_y = this._center_y - Math.cos(next_rad_pos) * next_point_distance;
-        
-        this._d.stroke = data_row[this.klass.DATA_COLOR_INDEX];
-        this._d.fill = data_row[this.klass.DATA_COLOR_INDEX];
-        this._d.line(start_x, start_y, end_x, end_y);
-        
-        if (!this.hide_dots) this._d.circle(start_x, start_y, start_x - circle_radius, start_y);
-      }, this);
-      
-    }, this);
-  },
-  
-  // the lines connecting in the center, with the first line vertical
-  _draw_line_markers: function() {
-    if (this.hide_line_markers) return;
-    
-    // have to do this here (AGAIN)... see draw() in this class
-    // because this funtion is called before the @radius, @center_x and @center_y are set
-    this._radius = this._graph_height / 2.0;
-    this._center_x = this._graph_left + (this._graph_width / 2.0);
-    this._center_y = this._graph_top + (this._graph_height / 2.0) - 10; // Move graph up a bit
-    
-    var rad_pos, marker_label;
-    
-    for (var index = 0, n = this._column_count; index < n; index++) {
-      rad_pos = index * Math.PI * 2 / this._column_count;
-      
-      // Draw horizontal line markers and annotate with numbers
-      this._d.stroke = this.marker_color;
-      this._d.stroke_width = 1;
-      
-      this._d.line(this._center_x, this._center_y, this._center_x + Math.sin(rad_pos) * this._radius, this._center_y - Math.cos(rad_pos) * this._radius);
-      
-      marker_label = this.labels[index] ? this.labels[index] : '000';
-      
-      this._draw_label(this._center_x, this._center_y, rad_pos * 360 / (2 * Math.PI), this._radius, marker_label);
-    }
-  },
-  
-  _draw_label: function(center_x, center_y, angle, radius, amount) {
-    var r_offset = 1.1,
-        x_offset = center_x, // + 15 // The label points need to be tweaked slightly
-        y_offset = center_y, // + 0  // This one doesn't though
-        rad_pos = angle * Math.PI / 180,
-        x = x_offset + (radius * r_offset * Math.sin(rad_pos)),
-        y = y_offset - (radius * r_offset * Math.cos(rad_pos));
-    
-    // Draw label
-    this._d.fill = this.marker_color;
-    if (this.font) this._d.font = this.font;
-    this._d.pointsize = this._scale_fontsize(20);
-    this._d.stroke = 'transparent';
-    this._d.font_weight = 'bold';
-    this._d.gravity = 'center';
-    this._d.annotate_scaled(0, 0, x, y, amount, this._scale);
-  }
-});
-
-
-// Here's how to make a Pie graph:
-//
-//   g = new Bluff.Pie('canvasId');
-//   g.title = "Visual Pie Graph Test";
-//   g.data('Fries', 20);
-//   g.data('Hamburgers', 50);
-//   g.draw();
-//
-// To control where the pie chart starts creating slices, use #zero_degree.
-
-Bluff.Pie = new JS.Class(Bluff.Base, {
-  extend: {
-    TEXT_OFFSET_PERCENTAGE: 0.08
-  },
-  
-  // Can be used to make the pie start cutting slices at the top (-90.0)
-  // or at another angle. Default is 0.0, which starts at 3 o'clock.
-  zero_degreee: null,
-  
-  // Do not show labels for slices that are less than this percent. Use 0 to always show all labels.
-  hide_labels_less_than: null,
-  
-  initialize_ivars: function() {
-    this.callSuper();
-    this.zero_degree = 0.0;
-    this.hide_labels_less_than = 0.0;
-  },
-  
-  draw: function() {
-    this.hide_line_markers = true;
-    
-    this.callSuper();
-    
-    if (!this._has_data) return;
-    
-    var diameter = this._graph_height,
-        radius = (Math.min(this._graph_width, this._graph_height) / 2.0) * 0.8,
-        top_x = this._graph_left + (this._graph_width - diameter) / 2.0,
-        center_x = this._graph_left + (this._graph_width / 2.0),
-        center_y = this._graph_top + (this._graph_height / 2.0) - 10, // Move graph up a bit
-        total_sum = this._sums_for_pie(),
-        prev_degrees = this.zero_degree,
-        index = this.klass.DATA_VALUES_INDEX;
-    
-    // Use full data since we can easily calculate percentages
-    if (this.sort) this._data.sort(function(a,b) { return a[index][0] - b[index][0]; });
-    Bluff.each(this._data, function(data_row, i) {
-      if (data_row[this.klass.DATA_VALUES_INDEX][0] > 0) {
-        this._d.fill = data_row[this.klass.DATA_COLOR_INDEX];
-        
-        var current_degrees = (data_row[this.klass.DATA_VALUES_INDEX][0] / total_sum) * 360;
-        
-        // Gruff uses ellipse() here, but canvas doesn't seem to support it.
-        // circle() is fine for our purposes here.
-        this._d.circle(center_x, center_y,
-                    center_x + radius, center_y,
-                    prev_degrees, prev_degrees + current_degrees + 0.5); // <= +0.5 'fudge factor' gets rid of the ugly gaps
-        
-        var half_angle = prev_degrees + ((prev_degrees + current_degrees) - prev_degrees) / 2,
-            label_val = Math.round((data_row[this.klass.DATA_VALUES_INDEX][0] / total_sum) * 100.0),
-            label_string;
-        
-        if (label_val >= this.hide_labels_less_than) {
-          label_string = this._label(data_row[this.klass.DATA_VALUES_INDEX][0]);
-          this._draw_label(center_x, center_y, half_angle,
-                            radius + (radius * this.klass.TEXT_OFFSET_PERCENTAGE),
-                            label_string,
-                            data_row, i);
-        }
-        
-        prev_degrees += current_degrees;
-      }
-    }, this);
-    
-    // TODO debug a circle where the text is drawn...
-  },
-  
-  // Labels are drawn around a slightly wider ellipse to give room for 
-  // labels on the left and right.
-  _draw_label: function(center_x, center_y, angle, radius, amount, data_row, i) {
-    // TODO Don't use so many hard-coded numbers
-    var r_offset = 20.0,      // The distance out from the center of the pie to get point
-        x_offset = center_x,  // + 15.0 # The label points need to be tweaked slightly
-        y_offset = center_y,  // This one doesn't though
-        radius_offset = radius + r_offset,
-        ellipse_factor = radius_offset * 0.15,
-        x = x_offset + ((radius_offset + ellipse_factor) * Math.cos(angle * Math.PI/180)),
-        y = y_offset + (radius_offset * Math.sin(angle * Math.PI/180));
-    
-    // Draw label
-    this._d.fill = this.font_color;
-    if (this.font) this._d.font = this.font;
-    this._d.pointsize = this._scale_fontsize(this.marker_font_size);
-    this._d.font_weight = 'bold';
-    this._d.gravity = 'center';
-    this._d.annotate_scaled(0,0, x,y, amount, this._scale);
-    
-    this._draw_tooltip(x - 20, y - 20, 40, 40,
-                       data_row[this.klass.DATA_LABEL_INDEX],
-                       data_row[this.klass.DATA_COLOR_INDEX],
-                       amount, i);
-  },
-  
-  _sums_for_pie: function() {
-    var total_sum = 0;
-    Bluff.each(this._data, function(data_row) {
-      total_sum += data_row[this.klass.DATA_VALUES_INDEX][0];
-    }, this);
-    return total_sum;
-  }
-});
-
-
-// Graph with individual horizontal bars instead of vertical bars.
-
-Bluff.SideBar = new JS.Class(Bluff.Base, {
-  
-  // Spacing factor applied between bars
-  bar_spacing: 0.9,
-  
-  draw: function() {
-    this.has_left_labels = true;
-    this.callSuper();
-    
-    if (!this._has_data) return;
-    this._draw_bars();
-  },
-  
-  _draw_bars: function() {
-    this._bars_width       = this._graph_height / this._column_count;
-    this._bar_width        = this._bars_width / this._norm_data.length;
-    this._d.stroke_opacity = 0.0;
-    var height = Bluff.array_new(this._column_count, 0),
-        length = Bluff.array_new(this._column_count, this._graph_left),
-        padding = (this._bar_width * (1 - this.bar_spacing)) / 2;
-    
-    Bluff.each(this._norm_data, function(data_row, row_index) {
-      var raw_data = this._data[row_index][this.klass.DATA_VALUES_INDEX];
-      Bluff.each(data_row[this.klass.DATA_VALUES_INDEX], function(data_point, point_index) {
-        
-        // Using the original calcs from the stacked bar chart
-        // to get the difference between
-        // part of the bart chart we wish to stack.
-        var temp1      = this._graph_left + (this._graph_width - data_point * this._graph_width - height[point_index]),
-            temp2      = this._graph_left + this._graph_width - height[point_index],
-            difference = temp2 - temp1,
-        
-            left_x     = length[point_index] - 1,
-            left_y     = this._graph_top + (this._bars_width * point_index) + (this._bar_width * row_index) + padding,
-            right_x    = left_x + difference,
-            right_y    = left_y + this._bar_width * this.bar_spacing;
-        
-        height[point_index] += (data_point * this._graph_width);
-        
-        this._d.stroke = 'transparent';
-        this._d.fill = data_row[this.klass.DATA_COLOR_INDEX];
-        this._d.rectangle(left_x, left_y, right_x, right_y);
-        
-        this._draw_tooltip(left_x, left_y,
-                           right_x - left_x, right_y - left_y,
-                           data_row[this.klass.DATA_LABEL_INDEX],
-                           data_row[this.klass.DATA_COLOR_INDEX],
-                           raw_data[point_index], point_index);
-        
-        // Calculate center based on bar_width and current row
-        var label_center = this._graph_top + (this._bars_width * point_index + this._bars_width / 2);
-        this._draw_label(label_center, point_index);
-      }, this)
-      
-    }, this);
-  },
-  
-  // Instead of base class version, draws vertical background lines and label
-  _draw_line_markers: function() {
-    
-    if (this.hide_line_markers) return;
-    
-    this._d.stroke_antialias = false;
-    
-    // Draw horizontal line markers and annotate with numbers
-    this._d.stroke_width = 1;
-    var number_of_lines = 5;
-    
-    // TODO Round maximum marker value to a round number like 100, 0.1, 0.5, etc.
-    var increment = this._significant(this._spread / number_of_lines),
-        line_diff, x, diff, marker_label;
-    for (var index = 0; index <= number_of_lines; index++) {
-      
-      line_diff    = (this._graph_right - this._graph_left) / number_of_lines;
-      x            = this._graph_right - (line_diff * index) - 1;
-      diff         = index - number_of_lines;
-      marker_label = Math.abs(diff) * increment + this.minimum_value;
-      
-      this._d.stroke = this.marker_color;
-      this._d.line(x, this._graph_bottom, x, this._graph_top);
-      
-      if (!this.hide_line_numbers) {
-        this._d.fill      = this.font_color;
-        if (this.font) this._d.font = this.font;
-        this._d.stroke    = 'transparent';
-        this._d.pointsize = this._scale_fontsize(this.marker_font_size);
-        this._d.gravity   = 'center';
-        // TODO Center text over line
-        this._d.annotate_scaled(
-                          0, 0, // Width of box to draw text in
-                          x, this._graph_bottom + (this.klass.LABEL_MARGIN * 2.0), // Coordinates of text
-                          this._label(marker_label), this._scale);
-      }
-    }
-  },
-  
-  // Draw on the Y axis instead of the X
-  _draw_label: function(y_offset, index) {
-    if (this.labels[index] && !this._labels_seen[index]) {
-      this._d.fill             = this.font_color;
-      if (this.font) this._d.font = this.font;
-      this._d.stroke           = 'transparent';
-      this._d.font_weight      = 'normal';
-      this._d.pointsize        = this._scale_fontsize(this.marker_font_size);
-      this._d.gravity          = 'east';
-      this._d.annotate_scaled(1, 1,
-                              this._graph_left - this.klass.LABEL_MARGIN * 2.0, y_offset,
-                              this.labels[index], this._scale);
-      this._labels_seen[index] = true;
-    }
-  }
-});
-
-
-// Experimental!!! See also the Net graph.
-//
-// Submitted by Kevin Clark http://glu.ttono.us/
-Bluff.Spider = new JS.Class(Bluff.Base, {
-  
-  // Hide all text
-  hide_text: null,
-  hide_axes: null,
-  transparent_background: null,
-  
-  initialize: function(renderer, max_value, target_width) {
-    this.callSuper(renderer, target_width);
-    this._max_value = max_value;
-    this.hide_legend = true;
-  },
-  
-  draw: function() {
-    this.hide_line_markers = true;
-    
-    this.callSuper();
-    
-    if (!this._has_data) return;
-    
-    // Setup basic positioning
-    var diameter = this._graph_height,
-        radius = this._graph_height / 2.0,
-        top_x = this._graph_left + (this._graph_width - diameter) / 2.0,
-        center_x = this._graph_left + (this._graph_width / 2.0),
-        center_y = this._graph_top + (this._graph_height / 2.0) - 25; // Move graph up a bit
-    
-    this._unit_length = radius / this._max_value;
-    
-    var total_sum = this._sums_for_spider(),
-        prev_degrees = 0.0,
-        additive_angle = (2 * Math.PI) / this._data.length,
-        
-        current_angle = 0.0;
-    
-    // Draw axes
-    if (!this.hide_axes) this._draw_axes(center_x, center_y, radius, additive_angle);
-    
-    // Draw polygon
-    this._draw_polygon(center_x, center_y, additive_angle);
-  },
-  
-  _normalize_points: function(value) {
-    return value * this._unit_length;
-  },
-  
-  _draw_label: function(center_x, center_y, angle, radius, amount) {
-    var r_offset = 50,            // The distance out from the center of the pie to get point
-        x_offset = center_x,      // The label points need to be tweaked slightly
-        y_offset = center_y + 0,  // This one doesn't though
-        x = x_offset + ((radius + r_offset) * Math.cos(angle)),
-        y = y_offset + ((radius + r_offset) * Math.sin(angle));
-    
-    // Draw label
-    this._d.fill = this.marker_color;
-    if (this.font) this._d.font = this.font;
-    this._d.pointsize = this._scale_fontsize(this.legend_font_size);
-    this._d.stroke = 'transparent';
-    this._d.font_weight = 'bold';
-    this._d.gravity = 'center';
-    this._d.annotate_scaled(0, 0,
-                            x, y,
-                            amount, this._scale);
-  },
-  
-  _draw_axes: function(center_x, center_y, radius, additive_angle, line_color) {
-    if (this.hide_axes) return;
-    
-    var current_angle = 0.0;
-    
-    Bluff.each(this._data, function(data_row) {
-      this._d.stroke = line_color || data_row[this.klass.DATA_COLOR_INDEX];
-      this._d.stroke_width = 5.0;
-      
-      var x_offset = radius * Math.cos(current_angle);
-      var y_offset = radius * Math.sin(current_angle);
-      
-      this._d.line(center_x, center_y,
-                   center_x + x_offset,
-                   center_y + y_offset);
-      
-      if (!this.hide_text) this._draw_label(center_x, center_y, current_angle, radius, data_row[this.klass.DATA_LABEL_INDEX]);
-      
-      current_angle += additive_angle;
-    }, this);
-  },
-  
-  _draw_polygon: function(center_x, center_y, additive_angle, color) {
-    var points = [],
-        current_angle = 0.0;
-    Bluff.each(this._data, function(data_row) {
-      points.push(center_x + this._normalize_points(data_row[this.klass.DATA_VALUES_INDEX][0]) * Math.cos(current_angle));
-      points.push(center_y + this._normalize_points(data_row[this.klass.DATA_VALUES_INDEX][0]) * Math.sin(current_angle));
-      current_angle += additive_angle;
-    }, this);
-    
-    this._d.stroke_width = 1.0;
-    this._d.stroke = color || this.marker_color;
-    this._d.fill = color || this.marker_color;
-    this._d.fill_opacity = 0.4;
-    this._d.polyline(points);
-  },
-  
-  _sums_for_spider: function() {
-    var sum = 0.0;
-    Bluff.each(this._data, function(data_row) {
-      sum += data_row[this.klass.DATA_VALUES_INDEX][0];
-    }, this);
-    return sum;
-  }
-});
-
-
-// Used by StackedBar and child classes.
-Bluff.Base.StackedMixin = new JS.Module({
-  // Get sum of each stack
-  _get_maximum_by_stack: function() {
-    var max_hash = {};
-    Bluff.each(this._data, function(data_set) {
-      Bluff.each(data_set[this.klass.DATA_VALUES_INDEX], function(data_point, i) {
-        if (!max_hash[i]) max_hash[i] = 0.0;
-        max_hash[i] += data_point;
-      }, this);
-    }, this);
-    
-    // this.maximum_value = 0;
-    for (var key in max_hash) {
-      if (max_hash[key] > this.maximum_value) this.maximum_value = max_hash[key];
-    }
-    this.minimum_value = 0;
-  }
-});
-
-
-Bluff.StackedArea = new JS.Class(Bluff.Base, {
-  include: Bluff.Base.StackedMixin,
-  last_series_goes_on_bottom: null,
-  
-  draw: function() {
-    this._get_maximum_by_stack();
-    this.callSuper();
-    
-    if (!this._has_data) return;
-    
-    this._x_increment = this._graph_width / (this._column_count - 1);
-    this._d.stroke = 'transparent';
-    
-    var height = Bluff.array_new(this._column_count, 0);
-    
-    var data_points = null;
-    var iterator = this.last_series_goes_on_bottom ? 'reverse_each' : 'each';
-    Bluff[iterator](this._norm_data, function(data_row) {
-      var prev_data_points = data_points;
-      data_points = [];
-      
-      Bluff.each(data_row[this.klass.DATA_VALUES_INDEX], function(data_point, index) {
-        // Use incremented x and scaled y
-        var new_x = this._graph_left + (this._x_increment * index);
-        var new_y = this._graph_top + (this._graph_height - data_point * this._graph_height - height[index]);
-        
-        height[index] += (data_point * this._graph_height);
-        
-        data_points.push(new_x);
-        data_points.push(new_y);
-        
-        this._draw_label(new_x, index);
-      }, this);
-      
-      var poly_points, i, n;
-      
-      if (prev_data_points) {
-        poly_points = Bluff.array(data_points);
-        for (i = prev_data_points.length/2 - 1; i >= 0; i--) {
-          poly_points.push(prev_data_points[2*i]);
-          poly_points.push(prev_data_points[2*i+1]);
-        }
-        poly_points.push(data_points[0]);
-        poly_points.push(data_points[1]);
-      } else {
-        poly_points = Bluff.array(data_points);
-        poly_points.push(this._graph_right);
-        poly_points.push(this._graph_bottom - 1);
-        poly_points.push(this._graph_left);
-        poly_points.push(this._graph_bottom - 1);
-        poly_points.push(data_points[0]);
-        poly_points.push(data_points[1]);
-      }
-      this._d.fill = data_row[this.klass.DATA_COLOR_INDEX];
-      this._d.polyline(poly_points);
-    }, this);
-  }
-});
-
-
-Bluff.StackedBar = new JS.Class(Bluff.Base, {
-  include: Bluff.Base.StackedMixin,
-  
-  // Spacing factor applied between bars
-  bar_spacing: 0.9,
-  
-  // Draws a bar graph, but multiple sets are stacked on top of each other.
-  draw: function() {
-    this._get_maximum_by_stack();
-    this.callSuper();
-    if (!this._has_data) return;
-    
-    this._bar_width = this._graph_width / this._column_count;
-    var padding = (this._bar_width * (1 - this.bar_spacing)) / 2;
-    
-    this._d.stroke_opacity = 0.0;
-    
-    var height = Bluff.array_new(this._column_count, 0);
-    
-    Bluff.each(this._norm_data, function(data_row, row_index) {
-      var raw_data = this._data[row_index][this.klass.DATA_VALUES_INDEX];
-      
-      Bluff.each(data_row[this.klass.DATA_VALUES_INDEX], function(data_point, point_index) {
-        // Calculate center based on bar_width and current row
-        var label_center = this._graph_left + (this._bar_width * point_index) + (this._bar_width * this.bar_spacing / 2.0);
-        this._draw_label(label_center, point_index);
-        
-        if (data_point == 0) return;
-        // Use incremented x and scaled y
-        var left_x = this._graph_left + (this._bar_width * point_index) + padding;
-        var left_y = this._graph_top + (this._graph_height -
-                                        data_point * this._graph_height - 
-                                        height[point_index]) + 1;
-        var right_x = left_x + this._bar_width * this.bar_spacing;
-        var right_y = this._graph_top + this._graph_height - height[point_index] - 1;
-        
-        // update the total height of the current stacked bar
-        height[point_index] += (data_point * this._graph_height);
-        
-        this._d.fill = data_row[this.klass.DATA_COLOR_INDEX];
-        this._d.rectangle(left_x, left_y, right_x, right_y);
-        
-        this._draw_tooltip(left_x, left_y,
-                           right_x - left_x, right_y - left_y,
-                           data_row[this.klass.DATA_LABEL_INDEX],
-                           data_row[this.klass.DATA_COLOR_INDEX],
-                           raw_data[point_index], point_index);
-      }, this);
-    }, this);
-  }
-});
-
-
-// A special bar graph that shows a single dataset as a set of
-// stacked bars. The bottom bar shows the running total and 
-// the top bar shows the new value being added to the array.
-
-Bluff.AccumulatorBar = new JS.Class(Bluff.StackedBar, {
-  
-  draw: function() {
-    if (this._data.length !== 1) throw 'Incorrect number of datasets';
-    
-    var accumulator_array = [],
-        index = 0,
-        increment_array = [];
-    
-    Bluff.each(this._data[0][this.klass.DATA_VALUES_INDEX], function(value) {
-      var max = -Infinity;
-      Bluff.each(increment_array, function(x) { max = Math.max(max, x); });
-      
-      increment_array.push((index > 0) ? (value + max) : value);
-      accumulator_array.push(increment_array[index] - value);
-      index += 1;
-    }, this);
-    
-    this.data("Accumulator", accumulator_array);
-    
-    this.callSuper();
-  }
-});
-
-
-// New gruff graph type added to enable sideways stacking bar charts 
-// (basically looks like a x/y flip of a standard stacking bar chart)
-//
-// alun.eyre@googlemail.com
-
-Bluff.SideStackedBar = new JS.Class(Bluff.SideBar, {
-  include: Bluff.Base.StackedMixin,
-  
-  // Spacing factor applied between bars
-  bar_spacing: 0.9,
-  
-  draw: function() {
-    this.has_left_labels = true;
-    this._get_maximum_by_stack();
-    this.callSuper();
-  },
-  
-  _draw_bars: function() {
-    this._bar_width = this._graph_height / this._column_count;
-    var height = Bluff.array_new(this._column_count, 0),
-        length = Bluff.array_new(this._column_count, this._graph_left),
-        padding = (this._bar_width * (1 - this.bar_spacing)) / 2;
-
-    Bluff.each(this._norm_data, function(data_row, row_index) {
-      var raw_data = this._data[row_index][this.klass.DATA_VALUES_INDEX];
-      
-      Bluff.each(data_row[this.klass.DATA_VALUES_INDEX], function(data_point, point_index) {
-        
-        // using the original calcs from the stacked bar chart to get the difference between
-        // part of the bart chart we wish to stack.
-        var temp1 = this._graph_left + (this._graph_width -
-                                            data_point * this._graph_width - 
-                                            height[point_index]) + 1;
-        var temp2 = this._graph_left + this._graph_width - height[point_index] - 1;
-        var difference = temp2 - temp1;
-        
-        this._d.fill = data_row[this.klass.DATA_COLOR_INDEX];
-        
-        var left_x = length[point_index], //+ 1
-            left_y = this._graph_top + (this._bar_width * point_index) + padding,
-            right_x = left_x + difference,
-            right_y = left_y + this._bar_width * this.bar_spacing;
-        length[point_index] += difference;
-        height[point_index] += (data_point * this._graph_width - 2);
-        
-        this._d.rectangle(left_x, left_y, right_x, right_y);
-        
-        this._draw_tooltip(left_x, left_y,
-                           right_x - left_x, right_y - left_y,
-                           data_row[this.klass.DATA_LABEL_INDEX],
-                           data_row[this.klass.DATA_COLOR_INDEX],
-                           raw_data[point_index], point_index);
-        
-        // Calculate center based on bar_width and current row
-        var label_center = this._graph_top + (this._bar_width * point_index) + (this._bar_width * this.bar_spacing / 2.0);
-        this._draw_label(label_center, point_index);
-      }, this);
-    }, this);
-  },
-  
-  _larger_than_max: function(data_point, index) {
-    index = index || 0;
-    return this._max(data_point, index) > this.maximum_value;
-  },
-  
-  _max: function(data_point, index) {
-    var sum = 0;
-    Bluff.each(this._data, function(item) {
-      sum += item[this.klass.DATA_VALUES_INDEX][index];
-    }, this);
-    return sum;
-  }
-});
-
-
-Bluff.Mini.Legend = new JS.Module({
-  
-  hide_mini_legend: false,
-  
-  // The canvas needs to be bigger so we can put the legend beneath it.
-  _expand_canvas_for_vertical_legend: function() {
-    if (this.hide_mini_legend) return;
-    
-    this._legend_labels = Bluff.map(this._data, function(item) {
-      return item[this.klass.DATA_LABEL_INDEX];
-    }, this);
-    
-    var legend_height = this._scale_fontsize(
-                          this._data.length * this._calculate_line_height() +
-                          this.top_margin + this.bottom_margin);
-    
-    this._original_rows = this._raw_rows;
-    this._original_columns = this._raw_columns;
-    
-    switch (this.legend_position) {
-      case 'right':
-        this._rows = Math.max(this._rows, legend_height);
-        this._columns += this._calculate_legend_width() + this.left_margin;
-        break;
-      
-      default:
-        this._rows += legend_height;
-        break;
-    }
-    this._render_background();
-  },
-  
-  _calculate_line_height: function() {
-    return this._calculate_caps_height(this.legend_font_size) * 1.7;
-  },
-  
-  _calculate_legend_width: function() {
-    var width = 0;
-    Bluff.each(this._legend_labels, function(label) {
-      width = Math.max(this._calculate_width(this.legend_font_size, label), width);
-    }, this);
-    return this._scale_fontsize(width + 40*1.7);
-  },
-  
-  // Draw the legend beneath the existing graph.
-  _draw_vertical_legend: function() {
-    if (this.hide_mini_legend) return;
-    
-    var legend_square_width = 40.0, // small square with color of this item
-        legend_square_margin = 10.0,
-        legend_left_margin = 100.0,
-        legend_top_margin = 40.0;
-    
-    // May fix legend drawing problem at small sizes
-    if (this.font) this._d.font = this.font;
-    this._d.pointsize = this.legend_font_size;
-    
-    var current_x_offset, current_y_offset;
-    
-    switch (this.legend_position) {
-      case 'right':
-        current_x_offset = this._original_columns + this.left_margin;
-        current_y_offset = this.top_margin + legend_top_margin;
-        break;
-      
-      default:
-        current_x_offset = legend_left_margin,
-        current_y_offset = this._original_rows + legend_top_margin;
-        break;
-    }
-    
-    this._debug(function() {
-      this._d.line(0.0, current_y_offset, this._raw_columns, current_y_offset);
-    });
-    
-    Bluff.each(this._legend_labels, function(legend_label, index) {
-      
-      // Draw label
-      this._d.fill = this.font_color;
-      if (this.font) this._d.font = this.font;
-      this._d.pointsize = this._scale_fontsize(this.legend_font_size);
-      this._d.stroke = 'transparent';
-      this._d.font_weight = 'normal';
-      this._d.gravity = 'west';
-      this._d.annotate_scaled(this._raw_columns, 1.0,
-                        current_x_offset + (legend_square_width * 1.7), current_y_offset, 
-                        this._truncate_legend_label(legend_label), this._scale);
-      
-      // Now draw box with color of this dataset
-      this._d.stroke = 'transparent';
-      this._d.fill = this._data[index][this.klass.DATA_COLOR_INDEX];
-      this._d.rectangle(current_x_offset, 
-                        current_y_offset - legend_square_width / 2.0, 
-                        current_x_offset + legend_square_width, 
-                        current_y_offset + legend_square_width / 2.0);
-      
-      current_y_offset += this._calculate_line_height();
-    }, this);
-    this._color_index = 0;
-  },
-  
-  // Shorten long labels so they will fit on the canvas.
-  _truncate_legend_label: function(label) {
-    var truncated_label = String(label);
-    while (this._calculate_width(this._scale_fontsize(this.legend_font_size), truncated_label) > (this._columns - this.legend_left_margin - this.right_margin) && (truncated_label.length > 1))
-      truncated_label = truncated_label.substr(0, truncated_label.length-1);
-    return truncated_label + (truncated_label.length < String(label).length ? "..." : '');
-  }
-});
-
-
-// Makes a small bar graph suitable for display at 200px or even smaller.
-//
-Bluff.Mini.Bar = new JS.Class(Bluff.Bar, {
-  include: Bluff.Mini.Legend,
-  
-  initialize_ivars: function() {
-    this.callSuper();
-    
-    this.hide_legend = true;
-    this.hide_title = true;
-    this.hide_line_numbers = true;
-    
-    this.marker_font_size = 50.0;
-    this.minimum_value = 0.0;
-    this.maximum_value = 0.0;
-    this.legend_font_size = 60.0;
-  },
-  
-  draw: function() {
-    this._expand_canvas_for_vertical_legend();
-    
-    this.callSuper();
-    
-    this._draw_vertical_legend();
-  }
-});
-
-
-// Makes a small pie graph suitable for display at 200px or even smaller.
-//
-Bluff.Mini.Pie = new JS.Class(Bluff.Pie, {
-  include: Bluff.Mini.Legend,
-  
-  initialize_ivars: function() {
-    this.callSuper();
-    
-    this.hide_legend = true;
-    this.hide_title = true;
-    this.hide_line_numbers = true;
-    
-    this.marker_font_size = 60.0;
-    this.legend_font_size = 60.0;
-  },
-  
-  draw: function() {
-    this._expand_canvas_for_vertical_legend();
-    
-    this.callSuper();
-    
-    this._draw_vertical_legend();
-  }
-});
-
-
-// Makes a small pie graph suitable for display at 200px or even smaller.
-//
-Bluff.Mini.SideBar = new JS.Class(Bluff.SideBar, {
-  include: Bluff.Mini.Legend,
-  
-  initialize_ivars: function() {
-    this.callSuper();
-    this.hide_legend = true;
-    this.hide_title = true;
-    this.hide_line_numbers = true;
-    
-    this.marker_font_size = 50.0;
-    this.legend_font_size = 50.0;
-  },
-  
-  draw: function() {
-    this._expand_canvas_for_vertical_legend();
-    
-    this.callSuper();
-    
-    this._draw_vertical_legend();
-  }
-});
-
-
-Bluff.Renderer = new JS.Class({
-  extend: {
-    WRAPPER_CLASS:  'bluff-wrapper',
-    TEXT_CLASS:     'bluff-text',
-    TARGET_CLASS:   'bluff-tooltip-target'
-  },
-
-  font:     'Arial, Helvetica, Verdana, sans-serif',
-  gravity:  'north',
-  
-  initialize: function(canvasId) {
-    this._canvas = document.getElementById(canvasId);
-    this._ctx = this._canvas.getContext('2d');
-  },
-  
-  scale: function(sx, sy) {
-    this._sx = sx;
-    this._sy = sy || sx;
-  },
-  
-  caps_height: function(font_size) {
-    var X = this._sized_text(font_size, 'X'),
-        height = this._element_size(X).height;
-    this._remove_node(X);
-    return height;
-  },
-  
-  text_width: function(font_size, text) {
-    var element = this._sized_text(font_size, text);
-    var width = this._element_size(element).width;
-    this._remove_node(element);
-    return width;
-  },
-  
-  get_type_metrics: function(text) {
-    var node = this._sized_text(this.pointsize, text);
-    document.body.appendChild(node);
-    var size = this._element_size(node);
-    this._remove_node(node);
-    return size;
-  },
-  
-  clear: function(width, height) {
-    this._canvas.width = width;
-    this._canvas.height = height;
-    this._ctx.clearRect(0, 0, width, height);
-    var wrapper = this._text_container(), children = wrapper.childNodes, i = children.length;
-    wrapper.style.width = width + 'px';
-    wrapper.style.height = height + 'px';
-    while (i--) {
-      if (children[i].tagName.toLowerCase() !== 'canvas') {
-        Bluff.Event.stopObserving(children[i]);
-        this._remove_node(children[i]);
-      }
-    }
-  },
-  
-  push: function() {
-    this._ctx.save();
-  },
-  
-  pop: function() {
-    this._ctx.restore();
-  },
-  
-  render_gradiated_background: function(width, height, top_color, bottom_color) {
-    this.clear(width, height);
-    var gradient = this._ctx.createLinearGradient(0,0, 0,height);
-    gradient.addColorStop(0, top_color);
-    gradient.addColorStop(1, bottom_color);
-    this._ctx.fillStyle = gradient;
-    this._ctx.fillRect(0, 0, width, height);
-  },
-  
-  render_solid_background: function(width, height, color) {
-    this.clear(width, height);
-    this._ctx.fillStyle = color;
-    this._ctx.fillRect(0, 0, width, height);
-  },
-  
-  annotate_scaled: function(width, height, x, y, text, scale) {
-    var scaled_width = (width * scale) >= 1 ? (width * scale) : 1;
-    var scaled_height = (height * scale) >= 1 ? (height * scale) : 1;
-    var text = this._sized_text(this.pointsize, text);
-    text.style.color = this.fill;
-    text.style.cursor = 'default';
-    text.style.fontWeight = this.font_weight;
-    text.style.textAlign = 'center';
-    text.style.left = (this._sx * x + this._left_adjustment(text, scaled_width)) + 'px';
-    text.style.top = (this._sy * y + this._top_adjustment(text, scaled_height)) + 'px';
-  },
-  
-  tooltip: function(left, top, width, height, name, color, data) {
-    if (width < 0) left += width;
-    if (height < 0) top += height;
-    
-    var wrapper = this._canvas.parentNode,
-        target = document.createElement('div');
-    target.className = this.klass.TARGET_CLASS;
-    target.style.cursor = 'default';
-    target.style.position = 'absolute';
-    target.style.left = (this._sx * left - 3) + 'px';
-    target.style.top = (this._sy * top - 3) + 'px';
-    target.style.width = (this._sx * Math.abs(width) + 5) + 'px';
-    target.style.height = (this._sy * Math.abs(height) + 5) + 'px';
-    target.style.fontSize = 0;
-    target.style.overflow = 'hidden';
-    
-    Bluff.Event.observe(target, 'mouseover', function(node) {
-      Bluff.Tooltip.show(name, color, data);
-    });
-    Bluff.Event.observe(target, 'mouseout', function(node) {
-      Bluff.Tooltip.hide();
-    });
-    
-    wrapper.appendChild(target);
-    return target;
-  },
-  
-  circle: function(origin_x, origin_y, perim_x, perim_y, arc_start, arc_end) {
-    var radius = Math.sqrt(Math.pow(perim_x - origin_x, 2) + Math.pow(perim_y - origin_y, 2));
-    var alpha = 0, beta = 2 * Math.PI; // radians to full circle
-    
-    this._ctx.fillStyle = this.fill;
-    this._ctx.beginPath();
-    
-    if (arc_start !== undefined && arc_end !== undefined &&
-        Math.abs(Math.floor(arc_end - arc_start)) !== 360) {
-      alpha = arc_start * Math.PI/180;
-      beta  = arc_end   * Math.PI/180;
-      
-      this._ctx.moveTo(this._sx * (origin_x + radius * Math.cos(beta)), this._sy * (origin_y + radius * Math.sin(beta)));
-      this._ctx.lineTo(this._sx * origin_x, this._sy * origin_y);
-      this._ctx.lineTo(this._sx * (origin_x + radius * Math.cos(alpha)), this._sy * (origin_y + radius * Math.sin(alpha)));
-    }
-    this._ctx.arc(this._sx * origin_x, this._sy * origin_y, this._sx * radius, alpha, beta, false); // draw it clockwise
-    this._ctx.fill();
-  },
-  
-  line: function(sx, sy, ex, ey) {
-    this._ctx.strokeStyle = this.stroke;
-    this._ctx.lineWidth = this.stroke_width;
-    this._ctx.beginPath();
-    this._ctx.moveTo(this._sx * sx, this._sy * sy);
-    this._ctx.lineTo(this._sx * ex, this._sy * ey);
-    this._ctx.stroke();
-  },
-  
-  polyline: function(points) {
-    this._ctx.fillStyle = this.fill;
-    this._ctx.globalAlpha = this.fill_opacity || 1;
-    try { this._ctx.strokeStyle = this.stroke; } catch (e) {}
-    var x = points.shift(), y = points.shift();
-    this._ctx.beginPath();
-    this._ctx.moveTo(this._sx * x, this._sy * y);
-    while (points.length > 0) {
-      x = points.shift(); y = points.shift();
-      this._ctx.lineTo(this._sx * x, this._sy * y);
-    }
-    this._ctx.fill();
-  },
-  
-  rectangle: function(ax, ay, bx, by) {
-    var temp;
-    if (ax > bx) { temp = ax; ax = bx; bx = temp; }
-    if (ay > by) { temp = ay; ay = by; by = temp; }
-    try {
-      this._ctx.fillStyle = this.fill;
-      this._ctx.fillRect(this._sx * ax, this._sy * ay, this._sx * (bx-ax), this._sy * (by-ay));
-    } catch (e) {}
-    try {
-      this._ctx.strokeStyle = this.stroke;
-      if (this.stroke !== 'transparent')
-        this._ctx.strokeRect(this._sx * ax, this._sy * ay, this._sx * (bx-ax), this._sy * (by-ay));
-    } catch (e) {}
-  },
-  
-  _left_adjustment: function(node, width) {
-    var w = this._element_size(node).width;
-    switch (this.gravity) {
-      case 'west':    return 0;
-      case 'east':    return width - w;
-      case 'north': case 'south': case 'center':
-        return (width - w) / 2;
-    }
-  },
-  
-  _top_adjustment: function(node, height) {
-    var h = this._element_size(node).height;
-    switch (this.gravity) {
-      case 'north':   return 0;
-      case 'south':   return height - h;
-      case 'west': case 'east': case 'center':
-        return (height - h) / 2;
-    }
-  },
-  
-  _text_container: function() {
-    var wrapper = this._canvas.parentNode;
-    if (wrapper.className === this.klass.WRAPPER_CLASS) return wrapper;
-    wrapper = document.createElement('div');
-    wrapper.className = this.klass.WRAPPER_CLASS;
-    
-    wrapper.style.position = 'relative';
-    wrapper.style.border = 'none';
-    wrapper.style.padding = '0 0 0 0';
-    
-    this._canvas.parentNode.insertBefore(wrapper, this._canvas);
-    wrapper.appendChild(this._canvas);
-    return wrapper;
-  },
-  
-  _sized_text: function(size, content) {
-    var text = this._text_node(content);
-    text.style.fontFamily = this.font;
-    text.style.fontSize = (typeof size === 'number') ? size + 'px' : size;
-    return text;
-  },
-  
-  _text_node: function(content) {
-    var div = document.createElement('div');
-    div.className = this.klass.TEXT_CLASS;
-    div.style.position = 'absolute';
-    div.appendChild(document.createTextNode(content));
-    this._text_container().appendChild(div);
-    return div;
-  },
-  
-  _remove_node: function(node) {
-    node.parentNode.removeChild(node);
-    if (node.className === this.klass.TARGET_CLASS)
-      Bluff.Event.stopObserving(node);
-  },
-  
-  _element_size: function(element) {
-    var display = element.style.display;
-    return (display && display !== 'none')
-        ? {width: element.offsetWidth, height: element.offsetHeight}
-        : {width: element.clientWidth, height: element.clientHeight};
-  }
-});
-
-
-// DOM event module, adapted from Prototype
-// Copyright (c) 2005-2008 Sam Stephenson
-
-Bluff.Event = {
-  _cache: [],
-  
-  _isIE: (window.attachEvent && navigator.userAgent.indexOf('Opera') === -1),
-  
-  observe: function(element, eventName, callback, scope) {
-    var handlers = Bluff.map(this._handlersFor(element, eventName),
-                      function(entry) { return entry._handler });
-    if (Bluff.index(handlers, callback) !== -1) return;
-    
-    var responder = function(event) {
-      callback.call(scope || null, element, Bluff.Event._extend(event));
-    };
-    this._cache.push({_node: element, _name: eventName,
-                      _handler: callback, _responder: responder});
-    
-    if (element.addEventListener)
-      element.addEventListener(eventName, responder, false);
-    else
-      element.attachEvent('on' + eventName, responder);
-  },
-  
-  stopObserving: function(element) {
-    var handlers = element ? this._handlersFor(element) : this._cache;
-    Bluff.each(handlers, function(entry) {
-      if (entry._node.removeEventListener)
-        entry._node.removeEventListener(entry._name, entry._responder, false);
-      else
-        entry._node.detachEvent('on' + entry._name, entry._responder);
-    });
-  },
-  
-  _handlersFor: function(element, eventName) {
-    var results = [];
-    Bluff.each(this._cache, function(entry) {
-      if (element && entry._node !== element) return;
-      if (eventName && entry._name !== eventName) return;
-      results.push(entry);
-    });
-    return results;
-  },
-  
-  _extend: function(event) {
-    if (!this._isIE) return event;
-    if (!event) return false;
-    if (event._extendedByBluff) return event;
-    event._extendedByBluff = true;
-    
-    var pointer = this._pointer(event);
-    event.target = event.srcElement;
-    event.pageX = pointer.x;
-    event.pageY = pointer.y;
-    
-    return event;
-  },
-  
-  _pointer: function(event) {
-    var docElement = document.documentElement,
-        body = document.body || { scrollLeft: 0, scrollTop: 0 };
-    return {
-      x: event.pageX || (event.clientX +
-                        (docElement.scrollLeft || body.scrollLeft) -
-                        (docElement.clientLeft || 0)),
-      y: event.pageY || (event.clientY +
-                        (docElement.scrollTop || body.scrollTop) -
-                        (docElement.clientTop || 0))
-    };
-  }
-};
-
-if (Bluff.Event._isIE)
-  window.attachEvent('onunload', function() {
-    Bluff.Event.stopObserving();
-    Bluff.Event._cache = null;
-  });
-
-if (navigator.userAgent.indexOf('AppleWebKit/') > -1)
-  window.addEventListener('unload', function() {}, false);
-
-
-Bluff.Tooltip = new JS.Singleton({
-  LEFT_OFFSET:  20,
-  TOP_OFFSET:   -6,
-  DATA_LENGTH:  8,
-  
-  CLASS_NAME:   'bluff-tooltip',
-  
-  setup: function() {
-    this._tip = document.createElement('div');
-    this._tip.className = this.CLASS_NAME;
-    this._tip.style.position = 'absolute';
-    this.hide();
-    document.body.appendChild(this._tip);
-    
-    Bluff.Event.observe(document.body, 'mousemove', function(body, event) {
-      this._tip.style.left = (event.pageX + this.LEFT_OFFSET) + 'px';
-      this._tip.style.top = (event.pageY + this.TOP_OFFSET) + 'px';
-    }, this);
-  },
-  
-  show: function(name, color, data) {
-    data = Number(String(data).substr(0, this.DATA_LENGTH));
-    this._tip.innerHTML = '<span class="color" style="background: ' + color + ';">&nbsp;</span> ' +
-                          '<span class="label">' + name + '</span> ' +
-                          '<span class="data">' + data + '</span>';
-    this._tip.style.display = '';
-  },
-  
-  hide: function() {
-    this._tip.style.display = 'none';
-  }
-});
-
-Bluff.Event.observe(window, 'load', Bluff.Tooltip.method('setup'));
-
-
-Bluff.TableReader = new JS.Class({
-  
-  NUMBER_FORMAT: /\-?(0|[1-9]\d*)(\.\d+)?(e[\+\-]?\d+)?/i,
-  
-  initialize: function(table, options) {
-    this._options = options || {};
-    this._orientation = this._options.orientation || 'auto';
-    
-    this._table = (typeof table === 'string')
-        ? document.getElementById(table)
-        : table;
-  },
-  
-  // Get array of data series from the table
-  get_data: function() {
-    if (!this._data) this._read();
-    return this._data;
-  },
-  
-  // Get set of axis labels to use for the graph
-  get_labels: function() {
-    if (!this._labels) this._read();
-    return this._labels;
-  },
-  
-  // Get the title from the table's caption
-  get_title: function() {
-    return this._title;
-  },
-  
-  // Return series number i
-  get_series: function(i) {
-    if (this._data[i]) return this._data[i];
-    return this._data[i] = {points: []};
-  },
-  
-  // Gather data by reading from the table
-  _read: function() {
-    this._row = this._col = 0;
-    this._row_offset = this._col_offset = 0;
-    this._data = [];
-    this._labels = {};
-    this._row_headings = [];
-    this._col_headings = [];
-    this._skip_rows = [];
-    this._skip_cols = [];
-    
-    this._walk(this._table);
-    this._cleanup();
-    this._orient();
-    
-    Bluff.each(this._col_headings, function(heading, i) {
-      this.get_series(i - this._col_offset).name = heading;
-    }, this);
-    
-    Bluff.each(this._row_headings, function(heading, i) {
-      this._labels[i - this._row_offset] = heading;
-    }, this);
-  },
-  
-  // Walk the table's DOM tree
-  _walk: function(node) {
-    this._visit(node);
-    var i, children = node.childNodes, n = children.length;
-    for (i = 0; i < n; i++) this._walk(children[i]);
-  },
-  
-  // Read a single DOM node from the table
-  _visit: function(node) {
-    if (!node.tagName) return;
-    var content = this._strip_tags(node.innerHTML), x, y;
-    switch (node.tagName.toUpperCase()) {
-    
-      case 'TR':
-        if (!this._has_data) this._row_offset = this._row;
-        this._row += 1;
-        this._col = 0;
-        break;
-      
-      case 'TD':
-        if (!this._has_data) this._col_offset = this._col;
-        this._has_data = true;
-        this._col += 1;
-        content = content.match(this.NUMBER_FORMAT);
-        if (content === null) {
-          this.get_series(x).points[y] = null;
-        } else {
-          x = this._col - this._col_offset - 1;
-          y = this._row - this._row_offset - 1;
-          this.get_series(x).points[y] = parseFloat(content[0]);
-        }
-        break;
-      
-      case 'TH':
-        this._col += 1;
-        if (this._ignore(node)) {
-          this._skip_cols.push(this._col);
-          this._skip_rows.push(this._row);
-        }
-        if (this._col === 1 && this._row === 1)
-          this._row_headings[0] = this._col_headings[0] = content;
-        else if (node.scope === "row" || this._col === 1)
-          this._row_headings[this._row - 1] = content;
-        else
-          this._col_headings[this._col - 1] = content;
-        break;
-      
-      case 'CAPTION':
-        this._title = content;
-        break;
-    }
-  },
-  
-  _ignore: function(node) {
-    if (!this._options.except) return false;
-    
-    var content = this._strip_tags(node.innerHTML),
-        classes = (node.className || '').split(/\s+/),
-        list = [].concat(this._options.except);
-    
-    if (Bluff.index(list, content) >= 0) return true;
-    var i = classes.length;
-    while (i--) {
-      if (Bluff.index(list, classes[i]) >= 0) return true;
-    }
-    return false;
-  },
-  
-  _cleanup: function() {
-    var i = this._skip_cols.length, index;
-    while (i--) {
-      index = this._skip_cols[i];
-      if (index <= this._col_offset) continue;
-      this._col_headings.splice(index - 1, 1);
-      if (index >= this._col_offset)
-        this._data.splice(index - 1 - this._col_offset, 1);
-    }
-    
-    var i = this._skip_rows.length, index;
-    while (i--) {
-      index = this._skip_rows[i];
-      if (index <= this._row_offset) continue;
-      this._row_headings.splice(index - 1, 1);
-      Bluff.each(this._data, function(series) {
-        if (index >= this._row_offset)
-          series.points.splice(index - 1 - this._row_offset, 1);
-      }, this);
-    }
-  },
-  
-  _orient: function() {
-    switch (this._orientation) {
-      case 'auto':
-        if ((this._row_headings.length > 1 && this._col_headings.length === 1) ||
-            this._row_headings.length < this._col_headings.length) {
-          this._transpose();
-        }
-        break;
-        
-      case 'rows':
-        this._transpose();
-        break;
-    }
-  },
-  
-  // Transpose data in memory
-  _transpose: function() {
-    var data = this._data, tmp;
-    this._data = [];
-    
-    Bluff.each(data, function(row, i) {
-      Bluff.each(row.points, function(point, p) {
-        this.get_series(p).points[i] = point;
-      }, this);
-    }, this);
-    
-    tmp = this._row_headings;
-    this._row_headings = this._col_headings;
-    this._col_headings = tmp;
-    
-    tmp = this._row_offset;
-    this._row_offset = this._col_offset;
-    this._col_offset = tmp;
-  },
-  
-  // Remove HTML from a string
-  _strip_tags: function(string) {
-    return string.replace(/<\/?[^>]+>/gi, '');
-  },
-  
-  extend: {
-    Mixin: new JS.Module({
-      data_from_table: function(table, options) {
-        var reader    = new Bluff.TableReader(table, options),
-            data_rows = reader.get_data();
-        
-        Bluff.each(data_rows, function(row) {
-          this.data(row.name, row.points);
-        }, this);
-        
-        this.labels = reader.get_labels();
-        this.title  = reader.get_title() || this.title;
-      }
-    })
-  }
-});
-
-Bluff.Base.include(Bluff.TableReader.Mixin);
\ No newline at end of file
diff --git a/apis/charts_graphs_bluff/bluff/excanvas.js b/apis/charts_graphs_bluff/bluff/excanvas.js
deleted file mode 100644
index a34ca1d..0000000
--- a/apis/charts_graphs_bluff/bluff/excanvas.js
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2006 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-document.createElement("canvas").getContext||(function(){var s=Math,j=s.round,F=s.sin,G=s.cos,V=s.abs,W=s.sqrt,k=10,v=k/2;function X(){return this.context_||(this.context_=new H(this))}var L=Array.prototype.slice;function Y(b,a){var c=L.call(arguments,2);return function(){return b.apply(a,c.concat(L.call(arguments)))}}var M={init:function(b){if(/MSIE/.test(navigator.userAgent)&&!window.opera){var a=b||document;a.createElement("canvas");a.attachEvent("onreadystatechange",Y(this.init_,this,a))}},init_:function(b){b.namespaces.g_vml_||
-b.namespaces.add("g_vml_","urn:schemas-microsoft-com:vml","#default#VML");b.namespaces.g_o_||b.namespaces.add("g_o_","urn:schemas-microsoft-com:office:office","#default#VML");if(!b.styleSheets.ex_canvas_){var a=b.createStyleSheet();a.owningElement.id="ex_canvas_";a.cssText="canvas{display:inline-block;overflow:hidden;text-align:left;width:300px;height:150px}g_vml_\\:*{behavior:url(#default#VML)}g_o_\\:*{behavior:url(#default#VML)}"}var c=b.getElementsByTagName("canvas"),d=0;for(;d<c.length;d++)this.initElement(c[d])},
-initElement:function(b){if(!b.getContext){b.getContext=X;b.innerHTML="";b.attachEvent("onpropertychange",Z);b.attachEvent("onresize",$);var a=b.attributes;if(a.width&&a.width.specified)b.style.width=a.width.nodeValue+"px";else b.width=b.clientWidth;if(a.height&&a.height.specified)b.style.height=a.height.nodeValue+"px";else b.height=b.clientHeight}return b}};function Z(b){var a=b.srcElement;switch(b.propertyName){case "width":a.style.width=a.attributes.width.nodeValue+"px";a.getContext().clearRect();
-break;case "height":a.style.height=a.attributes.height.nodeValue+"px";a.getContext().clearRect();break}}function $(b){var a=b.srcElement;if(a.firstChild){a.firstChild.style.width=a.clientWidth+"px";a.firstChild.style.height=a.clientHeight+"px"}}M.init();var N=[],B=0;for(;B<16;B++){var C=0;for(;C<16;C++)N[B*16+C]=B.toString(16)+C.toString(16)}function I(){return[[1,0,0],[0,1,0],[0,0,1]]}function y(b,a){var c=I(),d=0;for(;d<3;d++){var f=0;for(;f<3;f++){var h=0,g=0;for(;g<3;g++)h+=b[d][g]*a[g][f];c[d][f]=
-h}}return c}function O(b,a){a.fillStyle=b.fillStyle;a.lineCap=b.lineCap;a.lineJoin=b.lineJoin;a.lineWidth=b.lineWidth;a.miterLimit=b.miterLimit;a.shadowBlur=b.shadowBlur;a.shadowColor=b.shadowColor;a.shadowOffsetX=b.shadowOffsetX;a.shadowOffsetY=b.shadowOffsetY;a.strokeStyle=b.strokeStyle;a.globalAlpha=b.globalAlpha;a.arcScaleX_=b.arcScaleX_;a.arcScaleY_=b.arcScaleY_;a.lineScale_=b.lineScale_}function P(b){var a,c=1;b=String(b);if(b.substring(0,3)=="rgb"){var d=b.indexOf("(",3),f=b.indexOf(")",d+
-1),h=b.substring(d+1,f).split(",");a="#";var g=0;for(;g<3;g++)a+=N[Number(h[g])];if(h.length==4&&b.substr(3,1)=="a")c=h[3]}else a=b;return{color:a,alpha:c}}function aa(b){switch(b){case "butt":return"flat";case "round":return"round";case "square":default:return"square"}}function H(b){this.m_=I();this.mStack_=[];this.aStack_=[];this.currentPath_=[];this.fillStyle=this.strokeStyle="#000";this.lineWidth=1;this.lineJoin="miter";this.lineCap="butt";this.miterLimit=k*1;this.globalAlpha=1;this.canvas=b;
-var a=b.ownerDocument.createElement("div");a.style.width=b.clientWidth+"px";a.style.height=b.clientHeight+"px";a.style.overflow="hidden";a.style.position="absolute";b.appendChild(a);this.element_=a;this.lineScale_=this.arcScaleY_=this.arcScaleX_=1}var i=H.prototype;i.clearRect=function(){this.element_.innerHTML=""};i.beginPath=function(){this.currentPath_=[]};i.moveTo=function(b,a){var c=this.getCoords_(b,a);this.currentPath_.push({type:"moveTo",x:c.x,y:c.y});this.currentX_=c.x;this.currentY_=c.y};
-i.lineTo=function(b,a){var c=this.getCoords_(b,a);this.currentPath_.push({type:"lineTo",x:c.x,y:c.y});this.currentX_=c.x;this.currentY_=c.y};i.bezierCurveTo=function(b,a,c,d,f,h){var g=this.getCoords_(f,h),l=this.getCoords_(b,a),e=this.getCoords_(c,d);Q(this,l,e,g)};function Q(b,a,c,d){b.currentPath_.push({type:"bezierCurveTo",cp1x:a.x,cp1y:a.y,cp2x:c.x,cp2y:c.y,x:d.x,y:d.y});b.currentX_=d.x;b.currentY_=d.y}i.quadraticCurveTo=function(b,a,c,d){var f=this.getCoords_(b,a),h=this.getCoords_(c,d),g={x:this.currentX_+
-0.6666666666666666*(f.x-this.currentX_),y:this.currentY_+0.6666666666666666*(f.y-this.currentY_)};Q(this,g,{x:g.x+(h.x-this.currentX_)/3,y:g.y+(h.y-this.currentY_)/3},h)};i.arc=function(b,a,c,d,f,h){c*=k;var g=h?"at":"wa",l=b+G(d)*c-v,e=a+F(d)*c-v,m=b+G(f)*c-v,r=a+F(f)*c-v;if(l==m&&!h)l+=0.125;var n=this.getCoords_(b,a),o=this.getCoords_(l,e),q=this.getCoords_(m,r);this.currentPath_.push({type:g,x:n.x,y:n.y,radius:c,xStart:o.x,yStart:o.y,xEnd:q.x,yEnd:q.y})};i.rect=function(b,a,c,d){this.moveTo(b,
-a);this.lineTo(b+c,a);this.lineTo(b+c,a+d);this.lineTo(b,a+d);this.closePath()};i.strokeRect=function(b,a,c,d){var f=this.currentPath_;this.beginPath();this.moveTo(b,a);this.lineTo(b+c,a);this.lineTo(b+c,a+d);this.lineTo(b,a+d);this.closePath();this.stroke();this.currentPath_=f};i.fillRect=function(b,a,c,d){var f=this.currentPath_;this.beginPath();this.moveTo(b,a);this.lineTo(b+c,a);this.lineTo(b+c,a+d);this.lineTo(b,a+d);this.closePath();this.fill();this.currentPath_=f};i.createLinearGradient=function(b,
-a,c,d){var f=new D("gradient");f.x0_=b;f.y0_=a;f.x1_=c;f.y1_=d;return f};i.createRadialGradient=function(b,a,c,d,f,h){var g=new D("gradientradial");g.x0_=b;g.y0_=a;g.r0_=c;g.x1_=d;g.y1_=f;g.r1_=h;return g};i.drawImage=function(b){var a,c,d,f,h,g,l,e,m=b.runtimeStyle.width,r=b.runtimeStyle.height;b.runtimeStyle.width="auto";b.runtimeStyle.height="auto";var n=b.width,o=b.height;b.runtimeStyle.width=m;b.runtimeStyle.height=r;if(arguments.length==3){a=arguments[1];c=arguments[2];h=g=0;l=d=n;e=f=o}else if(arguments.length==
-5){a=arguments[1];c=arguments[2];d=arguments[3];f=arguments[4];h=g=0;l=n;e=o}else if(arguments.length==9){h=arguments[1];g=arguments[2];l=arguments[3];e=arguments[4];a=arguments[5];c=arguments[6];d=arguments[7];f=arguments[8]}else throw Error("Invalid number of arguments");var q=this.getCoords_(a,c),t=[];t.push(" <g_vml_:group",' coordsize="',k*10,",",k*10,'"',' coordorigin="0,0"',' style="width:',10,"px;height:",10,"px;position:absolute;");if(this.m_[0][0]!=1||this.m_[0][1]){var E=[];E.push("M11=",
-this.m_[0][0],",","M12=",this.m_[1][0],",","M21=",this.m_[0][1],",","M22=",this.m_[1][1],",","Dx=",j(q.x/k),",","Dy=",j(q.y/k),"");var p=q,z=this.getCoords_(a+d,c),w=this.getCoords_(a,c+f),x=this.getCoords_(a+d,c+f);p.x=s.max(p.x,z.x,w.x,x.x);p.y=s.max(p.y,z.y,w.y,x.y);t.push("padding:0 ",j(p.x/k),"px ",j(p.y/k),"px 0;filter:progid:DXImageTransform.Microsoft.Matrix(",E.join(""),", sizingmethod='clip');")}else t.push("top:",j(q.y/k),"px;left:",j(q.x/k),"px;");t.push(' ">','<g_vml_:image src="',b.src,
-'"',' style="width:',k*d,"px;"," height:",k*f,'px;"',' cropleft="',h/n,'"',' croptop="',g/o,'"',' cropright="',(n-h-l)/n,'"',' cropbottom="',(o-g-e)/o,'"'," />","</g_vml_:group>");this.element_.insertAdjacentHTML("BeforeEnd",t.join(""))};i.stroke=function(b){var a=[],c=P(b?this.fillStyle:this.strokeStyle),d=c.color,f=c.alpha*this.globalAlpha;a.push("<g_vml_:shape",' filled="',!!b,'"',' style="position:absolute;width:',10,"px;height:",10,'px;"',' coordorigin="0 0" coordsize="',k*10," ",k*10,'"',' stroked="',
-!b,'"',' path="');var h={x:null,y:null},g={x:null,y:null},l=0;for(;l<this.currentPath_.length;l++){var e=this.currentPath_[l];switch(e.type){case "moveTo":a.push(" m ",j(e.x),",",j(e.y));break;case "lineTo":a.push(" l ",j(e.x),",",j(e.y));break;case "close":a.push(" x ");e=null;break;case "bezierCurveTo":a.push(" c ",j(e.cp1x),",",j(e.cp1y),",",j(e.cp2x),",",j(e.cp2y),",",j(e.x),",",j(e.y));break;case "at":case "wa":a.push(" ",e.type," ",j(e.x-this.arcScaleX_*e.radius),",",j(e.y-this.arcScaleY_*e.radius),
-" ",j(e.x+this.arcScaleX_*e.radius),",",j(e.y+this.arcScaleY_*e.radius)," ",j(e.xStart),",",j(e.yStart)," ",j(e.xEnd),",",j(e.yEnd));break}if(e){if(h.x==null||e.x<h.x)h.x=e.x;if(g.x==null||e.x>g.x)g.x=e.x;if(h.y==null||e.y<h.y)h.y=e.y;if(g.y==null||e.y>g.y)g.y=e.y}}a.push(' ">');if(b)if(typeof this.fillStyle=="object"){var m=this.fillStyle,r=0,n={x:0,y:0},o=0,q=1;if(m.type_=="gradient"){var t=m.x1_/this.arcScaleX_,E=m.y1_/this.arcScaleY_,p=this.getCoords_(m.x0_/this.arcScaleX_,m.y0_/this.arcScaleY_),
-z=this.getCoords_(t,E);r=Math.atan2(z.x-p.x,z.y-p.y)*180/Math.PI;if(r<0)r+=360;if(r<1.0E-6)r=0}else{var p=this.getCoords_(m.x0_,m.y0_),w=g.x-h.x,x=g.y-h.y;n={x:(p.x-h.x)/w,y:(p.y-h.y)/x};w/=this.arcScaleX_*k;x/=this.arcScaleY_*k;var R=s.max(w,x);o=2*m.r0_/R;q=2*m.r1_/R-o}var u=m.colors_;u.sort(function(ba,ca){return ba.offset-ca.offset});var J=u.length,da=u[0].color,ea=u[J-1].color,fa=u[0].alpha*this.globalAlpha,ga=u[J-1].alpha*this.globalAlpha,S=[],l=0;for(;l<J;l++){var T=u[l];S.push(T.offset*q+
-o+" "+T.color)}a.push('<g_vml_:fill type="',m.type_,'"',' method="none" focus="100%"',' color="',da,'"',' color2="',ea,'"',' colors="',S.join(","),'"',' opacity="',ga,'"',' g_o_:opacity2="',fa,'"',' angle="',r,'"',' focusposition="',n.x,",",n.y,'" />')}else a.push('<g_vml_:fill color="',d,'" opacity="',f,'" />');else{var K=this.lineScale_*this.lineWidth;if(K<1)f*=K;a.push("<g_vml_:stroke",' opacity="',f,'"',' joinstyle="',this.lineJoin,'"',' miterlimit="',this.miterLimit,'"',' endcap="',aa(this.lineCap),
-'"',' weight="',K,'px"',' color="',d,'" />')}a.push("</g_vml_:shape>");this.element_.insertAdjacentHTML("beforeEnd",a.join(""))};i.fill=function(){this.stroke(true)};i.closePath=function(){this.currentPath_.push({type:"close"})};i.getCoords_=function(b,a){var c=this.m_;return{x:k*(b*c[0][0]+a*c[1][0]+c[2][0])-v,y:k*(b*c[0][1]+a*c[1][1]+c[2][1])-v}};i.save=function(){var b={};O(this,b);this.aStack_.push(b);this.mStack_.push(this.m_);this.m_=y(I(),this.m_)};i.restore=function(){O(this.aStack_.pop(),
-this);this.m_=this.mStack_.pop()};function ha(b){var a=0;for(;a<3;a++){var c=0;for(;c<2;c++)if(!isFinite(b[a][c])||isNaN(b[a][c]))return false}return true}function A(b,a,c){if(!!ha(a)){b.m_=a;if(c)b.lineScale_=W(V(a[0][0]*a[1][1]-a[0][1]*a[1][0]))}}i.translate=function(b,a){A(this,y([[1,0,0],[0,1,0],[b,a,1]],this.m_),false)};i.rotate=function(b){var a=G(b),c=F(b);A(this,y([[a,c,0],[-c,a,0],[0,0,1]],this.m_),false)};i.scale=function(b,a){this.arcScaleX_*=b;this.arcScaleY_*=a;A(this,y([[b,0,0],[0,a,
-0],[0,0,1]],this.m_),true)};i.transform=function(b,a,c,d,f,h){A(this,y([[b,a,0],[c,d,0],[f,h,1]],this.m_),true)};i.setTransform=function(b,a,c,d,f,h){A(this,[[b,a,0],[c,d,0],[f,h,1]],true)};i.clip=function(){};i.arcTo=function(){};i.createPattern=function(){return new U};function D(b){this.type_=b;this.r1_=this.y1_=this.x1_=this.r0_=this.y0_=this.x0_=0;this.colors_=[]}D.prototype.addColorStop=function(b,a){a=P(a);this.colors_.push({offset:b,color:a.color,alpha:a.alpha})};function U(){}G_vmlCanvasManager=
-M;CanvasRenderingContext2D=H;CanvasGradient=D;CanvasPattern=U})();
diff --git a/apis/charts_graphs_bluff/bluff/js-class.js b/apis/charts_graphs_bluff/bluff/js-class.js
deleted file mode 100644
index 71a672c..0000000
--- a/apis/charts_graphs_bluff/bluff/js-class.js
+++ /dev/null
@@ -1,3 +0,0 @@
-(function ($) {
-this.JS=this.JS||{};JS.extend=function(a,b){b=b||{};for(var c in b){if(a[c]===b[c])continue;a[c]=b[c]}return a};JS.extend(JS,{makeFunction:function(){return function(){return this.initialize?(this.initialize.apply(this,arguments)||this):this}},makeBridge:function(a){var b=function(){};b.prototype=a.prototype;return new b},bind:function(){var a=JS.array(arguments),b=a.shift(),c=a.shift()||null;return function(){return b.apply(c,a.concat(JS.array(arguments)))}},callsSuper:function(a){return a.SUPER===undefined?a.SUPER=/\bcallSuper\b/.test(a.toString()):a.SUPER},mask:function(a){var b=a.toString().replace(/callSuper/g,'super');a.toString=function(){return b};return a},array:function(a){if(!a)return[];if(a.toArray)return a.toArray();var b=a.length,c=[];while(b--)c[b]=a[b];return c},indexOf:function(a,b){for(var c=0,d=a.length;c<d;c++){if(a[c]===b)return c}return-1},isFn:function(a){return a instanceof Function},isType:function(a,b){if(!a||!b)return false;return(b instanceof Function&&a instanceof b)||(typeof b==='string'&&typeof a===b)||(a.isA&&a.isA(b))},ignore:function(a,b){return/^(include|extend)$/.test(a)&&typeof b==='object'}});JS.Module=JS.makeFunction();JS.extend(JS.Module.prototype,{END_WITHOUT_DOT:/([^\.])$/,initialize:function(a,b,c){this.__mod__=this;this.__inc__=[];this.__fns__={};this.__dep__=[];this.__mct__={};if(typeof a==='string'){this.__nom__=this.displayName=a}else{this.__nom__=this.displayName='';c=b;b=a}c=c||{};this.__res__=c._1||null;if(b)this.include(b,false);if(JS.Module.__chainq__)JS.Module.__chainq__.push(this)},setName:function(a){this.__nom__=this.displayName=a||'';for(var b in this.__mod__.__fns__)this.__name__(b);if(a&&this.__meta__)this.__meta__.setName(a+'.')},__name__:function(a){if(!this.__nom__)return;var b=this.__mod__.__fns__[a]||{};a=this.__nom__.replace(this.END_WITHOUT_DOT,'$1#')+a;if(JS.isFn(b.setName))return b.setName(a);if(JS.isFn(b))b.displayName=a},define:function(a,b,c,d){var f=(d||{})._0||this;this.__fns__[a]=b;this.__name__(a);if(JS.Module._0&&f&&JS.isFn(b))JS.Module._0(a,f);if(c!==false)this.resolve()},instanceMethod:function(a){var b=this.lookup(a).pop();return JS.isFn(b)?b:null},instanceMethods:function(a,b){var c=this.__mod__,b=b||[],d=c.ancestors(),f=d.length,e;for(e in c.__fns__){if(c.__fns__.hasOwnProperty(e)&&JS.isFn(c.__fns__[e])&&JS.indexOf(b,e)===-1)b.push(e)}if(a===false)return b;while(f--)d[f].instanceMethods(false,b);return b},include:function(a,b,c){b=(b!==false);if(!a)return b?this.resolve():this.uncache();c=c||{};if(a.__mod__)a=a.__mod__;var d=a.include,f=a.extend,e=c._4||this,g,h,i,j;if(a.__inc__&&a.__fns__){this.__inc__.push(a);a.__dep__.push(this);if(c._2)a.extended&&a.extended(c._2);else a.included&&a.included(e)}else{if(c._5){for(h in a){if(JS.ignore(h,a[h]))continue;this.define(h,a[h],false,{_0:e||c._2||this})}}else{if(typeof d==='object'||JS.isType(d,JS.Module)){g=[].concat(d);for(i=0,j=g.length;i<j;i++)e.include(g[i],b,c)}if(typeof f==='object'||JS.isType(f,JS.Module)){g=[].concat(f);for(i=0,j=g.length;i<j;i++)e.extend(g[i],false);e.extend()}c._5=true;return e.include(a,b,c)}}b?this.resolve():this.uncache()},includes:function(a){var b=this.__mod__,c=b.__inc__.length;if(Object===a||b===a||b.__res__===a.prototype)return true;while(c--){if(b.__inc__[c].includes(a))return true}return false},match:function(a){return a.isA&&a.isA(this)},ancestors:function(a){var b=this.__mod__,c=(a===undefined),d=(b.__res__||{}).klass,f=(d&&b.__res__===d.prototype)?d:b,e,g;if(c&&b.__anc__)return b.__anc__.slice();a=a||[];for(e=0,g=b.__inc__.length;e<g;e++)b.__inc__[e].ancestors(a);if(JS.indexOf(a,f)===-1)a.push(f);if(c)b.__anc__=a.slice();return a},lookup:function(a){var b=this.__mod__,c=b.__mct__;if(c[a])return c[a].slice();var d=b.ancestors(),f=[],e,g,h;for(e=0,g=d.length;e<g;e++){h=d[e].__mod__.__fns__[a];if(h)f.push(h)}c[a]=f.slice();return f},make:function(a,b){if(!JS.isFn(b)||!JS.callsSuper(b))return b;var c=this;return function(){return c.chain(this,a,arguments)}},chain:JS.mask(function(c,d,f){var e=this.lookup(d),g=e.length-1,h=c.callSuper,i=JS.array(f),j;c.callSuper=function(){var a=arguments.length;while(a--)i[a]=arguments[a];g-=1;var b=e[g].apply(c,i);g+=1;return b};j=e.pop().apply(c,i);h?c.callSuper=h:delete c.callSuper;return j}),resolve:function(a){var b=this.__mod__,a=a||b,c=a.__res__,d,f,e,g;if(a===b){b.uncache(false);d=b.__dep__.length;while(d--)b.__dep__[d].resolve()}if(!c)return;for(d=0,f=b.__inc__.length;d<f;d++)b.__inc__[d].resolve(a);for(e in b.__fns__){g=a.make(e,b.__fns__[e]);if(c[e]!==g)c[e]=g}},uncache:function(a){var b=this.__mod__,c=b.__dep__.length;b.__anc__=null;b.__mct__={};if(a===false)return;while(c--)b.__dep__[c].uncache()}});JS.Class=JS.makeFunction();JS.extend(JS.Class.prototype=JS.makeBridge(JS.Module),{initialize:function(a,b,c){if(typeof a==='string'){this.__nom__=this.displayName=a}else{this.__nom__=this.displayName='';c=b;b=a}var d=JS.extend(JS.makeFunction(),this);d.klass=d.constructor=this.klass;if(!JS.isFn(b)){c=b;b=Object}d.inherit(b);d.include(c,false);d.resolve();do{b.inherited&&b.inherited(d)}while(b=b.superclass);return d},inherit:function(a){this.superclass=a;if(this.__eigen__&&a.__eigen__)this.extend(a.__eigen__(),true);this.subclasses=[];(a.subclasses||[]).push(this);var b=this.prototype=JS.makeBridge(a);b.klass=b.constructor=this;this.__mod__=new JS.Module(this.__nom__,{},{_1:this.prototype});this.include(JS.Kernel,false);if(a!==Object)this.include(a.__mod__||new JS.Module(a.prototype,{_1:a.prototype}),false)},include:function(a,b,c){if(!a)return;var d=this.__mod__,c=c||{};c._4=this;return d.include(a,b,c)},define:function(a,b,c,d){var f=this.__mod__;d=d||{};d._0=this;f.define(a,b,c,d)}});JS.Module=new JS.Class('Module',JS.Module.prototype);JS.Class=new JS.Class('Class',JS.Module,JS.Class.prototype);JS.Module.klass=JS.Module.constructor=JS.Class.klass=JS.Class.constructor=JS.Class;JS.extend(JS.Module,{_3:[],__chainq__:[],methodAdded:function(a,b){this._3.push([a,b])},_0:function(a,b){var c=this._3,d=c.length;while(d--)c[d][0].call(c[d][1]||null,a,b)}});JS.Kernel=JS.extend(new JS.Module('Kernel',{__eigen__:function(){if(this.__meta__)return this.__meta__;var a=this.__nom__,b=this.klass.__nom__,c=a||(b?'#<'+b+'>':''),d=this.__meta__=new JS.Module(c?c+'.':'',{},{_1:this});d.include(this.klass.__mod__,false);return d},equals:function(a){return this===a},extend:function(a,b){return this.__eigen__().include(a,b,{_2:this})},hash:function(){return this.__hashcode__=this.__hashcode__||JS.Kernel.getHashCode()},isA:function(a){return this.__eigen__().includes(a)},method:function(a){var b=this,c=b.__mcache__=b.__mcache__||{};if((c[a]||{}).fn===b[a])return c[a].bd;return(c[a]={fn:b[a],bd:JS.bind(b[a],b)}).bd},methods:function(){return this.__eigen__().instanceMethods(true)},tap:function(a,b){a.call(b||null,this);return this}}),{__hashIndex__:0,getHashCode:function(){this.__hashIndex__+=1;return(Math.floor(new Date().getTime()/1000)+this.__hashIndex__).toString(16)}});JS.Module.include(JS.Kernel);JS.extend(JS.Module,JS.Kernel.__fns__);JS.Class.include(JS.Kernel);JS.extend(JS.Class,JS.Kernel.__fns__);JS.Interface=new JS.Class({initialize:function(d){this.test=function(a,b){var c=d.length;while(c--){if(!JS.isFn(a[d[c]]))return b?d[c]:false}return true}},extend:{ensure:function(){var a=JS.array(arguments),b=a.shift(),c,d;while(c=a.shift()){d=c.test(b,true);if(d!==true)throw new Error('object does not implement '+d+'()');}}}});JS.Singleton=new JS.Class({initialize:function(a,b,c){return new(new JS.Class(a,b,c))}});
-})(jQuery);
diff --git a/apis/charts_graphs_bluff/charts_graphs_bluff.class.inc b/apis/charts_graphs_bluff/charts_graphs_bluff.class.inc
deleted file mode 100644
index 9b60b0f..0000000
--- a/apis/charts_graphs_bluff/charts_graphs_bluff.class.inc
+++ /dev/null
@@ -1,311 +0,0 @@
-<?php
-/**
- * @file
- *   Implementation of abstract class ChartsGraphsCanvas for Bluff library.
- *
- */
-
-/**
- * Implementation of abstract class ChartsGraphsCanvas for Bluff library.
- */
-class ChartsGraphsBluff extends ChartsGraphsCanvas {
-
-  var $width = 450;
-  var $height = 200;
-  var $title = '';
-  var $title_font_size = 32;
-
-  /**
-   * Parameters set directly by the user.
-   *
-   * @var <array>
-   */
-  var $parameters = array();
-
-  /**
-   * Optional parameter.
-   *
-   * It recognizes 3 different settings:
-   * - auto: default behaviour where Bluff tries to identify the proper
-   *   data orientation;
-   * - rows: rows are mapped as data series;
-   * - columns: columns are mapped as data series.
-   *
-   * @var string
-   */
-  var $orientation = NULL;
-
-  /**
-   * Converts the standard Charts and Graphs chart type to Bluff chart type.
-   *
-   * @return string
-   */
-  protected function _get_translated_chart_type() {
-    switch ($this->type) {
-      case 'mini_bar':
-        $type = 'Mini.Bar';
-        break;
-
-      case 'mini_pie':
-        $type = 'Mini.Pie';
-        break;
-
-      case 'mini_side_bar':
-        $type = 'Mini.SideBar';
-        break;
-
-      case 'side_bar':
-        $type = 'SideBar';
-        break;
-
-      case 'stacked_side_bar':
-        $type = 'SideStackedBar';
-        break;
-
-      case 'stacked_area':
-        $type = 'StackedArea';
-        break;
-
-      case 'stacked_bar':
-        $type = 'StackedBar';
-        break;
-
-      default:
-        $type = ucfirst($this->type);
-    }
-    return $type;
-  }
-
-  protected function _initialize_final_parameters($chart_id) {
-    $parameters = array();
-    $parameters['marker_font_size'] = 20;
-    $parameters['hide_legend'] = 'true';
-    $parameters['hide_title'] = 'false';
-    $parameters['sort'] = 'false';
-    $parameters['title_font_size'] = (int) $this->title_font_size;
-    $parameters['tooltips'] = 'true';
-
-    /**
-     * Applying user defined min, max and step for y axis values.
-     */
-    if ($this->y_min) {
-      $parameters['minimum_value'] = $this->y_min;
-    }
-    if ($this->y_max) {
-      $parameters['maximum_value'] = $this->y_max;
-    }
-    if ($this->y_step) {
-      $parameters['y_axis_increment'] = $this->y_step;
-    }
-
-    if (isset($this->theme) && !empty($this->theme)) {
-      $parameters['theme_' . $this->theme] = array();
-    }
-    else {
-      $series_colours = "['" . implode("', '", $this->series_colours) . "']";
-      $marker_colour = '#aea9a9';
-      $font_colour = '#000000';
-      $background_colour = isset($this->colour) ?
-        array($this->colour, $this->colour) :
-        array(
-        '#d1edf5',
-        '#ffffff',
-      );
-      $background_colour = "['" . implode("', '", $background_colour) . "']";
-      $set_theme = sprintf(
-        "{
-          colors: %s,
-          marker_color: '%s',
-          font_color: '%s',
-          background_colors: %s
-        }",
-        $series_colours,
-        $marker_colour,
-        $font_colour,
-        $background_colour
-      );
-      $parameters['set_theme'] = array($set_theme);
-    }
-
-    $parameters['data_from_table'] = array(
-      '"' . $chart_id . '"',
-      "{orientation: '" . (($this->orientation) ? $this->orientation : 'auto') . "'}",
-    );
-
-    if (is_array($this->parameters)) {
-      foreach ($this->parameters as $user_parameter_key => $user_parameter) {
-        $parameters[$user_parameter_key] = $user_parameter;
-      }
-    }
-    $this->final_parameters = $parameters;
-  }
-
-  protected function _get_encoded_parameters() {
-    $output = "\n";
-    foreach ($this->final_parameters as $key => $value) {
-      if (is_array($value)) {
-        $function_parameters = '';
-        foreach ($value as $val) {
-          $function_parameters .= sprintf(', %s', $val);
-        }
-        if (strlen($function_parameters) > 0) {
-          $function_parameters = substr($function_parameters, 2);
-        }
-        $output .= sprintf("\tg.%s(%s);\n", $key, $function_parameters);
-      }
-      else {
-        $output .= sprintf("\tg.%s = %s;\n", $key, $value);
-      }
-    }
-    return $output;
-  }
-
-  /**
-   * Function that renders data.
-   */
-  public function get_chart() {
-    $bluff_js_files = $this->get_bluff_js_files();
-
-    foreach ($bluff_js_files as $file_path) {
-      drupal_add_js($file_path);
-    }
-
-    $bluff_path = drupal_get_path('module', 'charts_graphs_bluff');
-    drupal_add_css($bluff_path . '/charts_graphs_bluff.css');
-
-    $x_labels = $this->x_labels;
-    $series = $this->series;
-    $chart_id = 'bluffchart-' . charts_graphs_chart_id_generator();
-    $table = array();
-
-    $table[] = sprintf(<<<TABLE
-      <table id="%s" class="bluff-data-table">
-        <caption>%s</caption>
-        <thead>
-          <tr>
-            <th scope="col"></th>
-TABLE
-,
-        $chart_id,
-        $this->title
-    );
-
-    $serie_keys = array_keys($series);
-    foreach ($serie_keys as $col) {
-      $table[] = sprintf("<th scope='col'>%s</th>\n", $col);
-    }
-
-    $table[] = "</tr></thead><tbody>\n";
-
-    foreach ($x_labels as $key => $label) {
-      $table[] = "<tr>\n";
-      $cols = array($label);
-
-      foreach ($serie_keys as $serie_key) {
-        $cols[] = array_shift($series[$serie_key]);
-      }
-
-      $table[] = sprintf("<th scope='row'>%s</th>\n", array_shift($cols));
-
-      foreach ($cols as $col) {
-        $table[] = sprintf("<td>%s</td>\n", (string) $col);
-      }
-
-      $table[] = "</tr>\n";
-    }
-
-    $table[] = "</tbody></table>\n";
-
-    $is_pie_chart = ($this->type == 'pie');
-
-    if ($this->orientation === NULL) {
-      $this->orientation = $is_pie_chart ? 'rows' : 'auto';
-    }
-
-    $this->_initialize_final_parameters($chart_id);
-    $html = implode('', $table);
-
-    $javascript = '
-      <canvas id="%chart_id-graph" width="%width" height="%height"></canvas>
-      <script type="text/javascript">
-        var ChartsAndGraphs = ChartsAndGraphs || {};
-
-        ChartsAndGraphs.init = function() {
-          var g = new Bluff.%type("%chart_id-graph", "%widthx%height");
-          ';
-    $javascript .= $this->_get_encoded_parameters();
-    $javascript .= '
-          g.draw();
-
-          var g_labels = %json_encode;
-          var legend = ["<ul class=\"bluff-legend\">"];
-
-          for (var i = 0, j = 0, color; i < g_labels.length; i++, j++) {
-            if (g.colors[j]) {
-              color = g.colors[j]
-            }
-            else {
-              g.colors[(0)];
-              j = 0;
-            }
-            legend.push("<li>");
-            legend.push("<div style=\"background-color: " + color + "\"><\/div>" + g_labels[i]);
-            legend.push("<\/li>");
-          }
-
-          legend.push("<\/ul>");
-
-          jQuery("#%chart_id-graph")
-            .parent("div.bluff-wrapper")
-            .append(legend.join(""))
-            .css({height: "auto"});
-        }
-
-        jQuery(window).load(ChartsAndGraphs.init);
-
-        Drupal.behaviors.ChartsAndGraphs_init = function(context) {
-          ChartsAndGraphs.init();
-        }
-      </script>';
-
-    $javascript = strtr(
-      $javascript,
-      array(
-      '%chart_id' => $chart_id,
-      '%type' => $this->_get_translated_chart_type(),
-      '%width' => $this->width,
-      '%height' => $this->height,
-      '%json_encode' => json_encode($is_pie_chart ? $x_labels : array_keys($series)),
-    ));
-
-    $element = array(
-      '#markup' => $html . $javascript,
-    );
-    return $element;
-  }
-
-  /**
-   * Cache list of javascript files for performance.
-   */
-  function get_bluff_js_files() {
-    static $js_files = NULL;
-
-    if (is_array($js_files)) {
-      return $js_files;
-    }
-
-    $bluff_path = drupal_get_path('module', 'charts_graphs_bluff');
-    $bluff_files = array_map('basename', glob(dirname(__FILE__) . '/bluff/*.js'));
-
-    rsort($bluff_files);
-
-    $js_files = array();
-
-    foreach ($bluff_files as $bluff_file) {
-      $file_path = sprintf('%s/bluff/%s', $bluff_path, $bluff_file);
-      $js_files[] = $file_path;
-    }
-
-    return $js_files;
-  }
-}
diff --git a/apis/charts_graphs_bluff/charts_graphs_bluff.css b/apis/charts_graphs_bluff/charts_graphs_bluff.css
deleted file mode 100644
index f5e630f..0000000
--- a/apis/charts_graphs_bluff/charts_graphs_bluff.css
+++ /dev/null
@@ -1,28 +0,0 @@
-
-table.bluff-data-table {
-  left: -9999px;
-  position: absolute;
-}
-
-ul.bluff-legend {
-  list-style-type: none;
-  margin: 0;
-  padding: 0;
-}
-
-ul.bluff-legend li {
-  height: 16px;
-  line-height: 16px;
-  list-style-type: none; 
-  margin: 2px 0;
-  padding: 0 0 0 18px;
-  position: relative;
-}
-
-ul.bluff-legend li div {
-  height: 16px;
-  left: 0;    
-  position: absolute;
-  top: 0;
-  width: 16px;
-}
diff --git a/apis/charts_graphs_bluff/charts_graphs_bluff.info b/apis/charts_graphs_bluff/charts_graphs_bluff.info
deleted file mode 100644
index b0954b7..0000000
--- a/apis/charts_graphs_bluff/charts_graphs_bluff.info
+++ /dev/null
@@ -1,8 +0,0 @@
-
-name = "Charts and Graphs: Bluff"
-description = "Bluff (Beautiful Graphs in JavaScript) implementation for Charts and Graphs."
-dependencies[] = charts_graphs
-package = "Charts"
-core = 7.x
-php = 5.1
-
diff --git a/apis/charts_graphs_bluff/charts_graphs_bluff.install b/apis/charts_graphs_bluff/charts_graphs_bluff.install
deleted file mode 100644
index 7c32853..0000000
--- a/apis/charts_graphs_bluff/charts_graphs_bluff.install
+++ /dev/null
@@ -1,97 +0,0 @@
-<?php
-
-/**
- * @file
- *   Install file for Bluff submodule.
- *
- */
-
-/**
- * Implements hook_requirements().
- */
-function charts_graphs_bluff_requirements($phase) {
-  $requirements = array();
-
-  // Ensure translations don't break at install time.
-  $t = get_t();
-
-  if ($phase == 'runtime') {
-    $path = dirname(realpath((__FILE__))) . '/bluff/';
-    $installation_instructions_path = module_exists('advanced_help') ?
-      'help/charts_graphs/bluff' :
-      'http://drupal.org/node/681668';
-
-    $file = 'excanvas.js';
-    if (!file_exists($path . $file)) {
-      $requirements['charts_graphs_bluff_' . $file] = array(
-        'title' => $t('Bluff %file file', array('%file' => $file)),
-        'description' => $t('Bluff needs the %file file to work properly.
-          Please review Bluff !installation_instructions.',
-          array(
-          '%file' => $file,
-          '!installation_instructions' => l(t('installation instructions'), $installation_instructions_path),
-        )
-        ),
-        'severity' => REQUIREMENT_ERROR,
-        'value' => $t('Unavailable'),
-      );
-    }
-
-    $file = 'js-class.js';
-    if (!file_exists($path . $file)) {
-      $requirements['charts_graphs_bluff_' . $file] = array(
-        'title' => $t('Bluff %file file', array('%file' => $file)),
-        'description' => $t('Bluff needs the %file file to work properly.
-          Please review Bluff !installation_instructions.',
-          array(
-          '%file' => $file,
-          '!installation_instructions' => l(t('installation instructions'), $installation_instructions_path),
-        )
-        ),
-        'severity' => REQUIREMENT_ERROR,
-        'value' => $t('Unavailable'),
-      );
-    }
-
-    $files = array('bluff-src.js', 'bluff-min.js', 'bluff.js');
-    $bluff_count = 0;
-    foreach ($files as $file) {
-      if (file_exists($path . $file)) {
-        $bluff_count++;
-      }
-    }
-    if ($bluff_count == 0) {
-      $requirements['charts_graphs_bluff_' . $file] = array(
-        'title' => $t('Bluff %file file', array('%file' => $file)),
-        'description' => $t('Bluff needs the %file file to work properly.
-          Please review Bluff !installation_instructions.',
-          array(
-          '%file' => $file,
-          '!installation_instructions' => l(t('installation instructions'), $installation_instructions_path),
-        )
-        ),
-        'severity' => REQUIREMENT_ERROR,
-        'value' => $t('Unavailable'),
-      );
-    }
-    elseif ($bluff_count > 1) {
-      $requirements['charts_graphs_bluff_excess_bluff.js'] = array(
-        'title' => $t('Too many Bluff files'),
-        'description' => $t('Bluff needs only one of the following files to work
-          properly: %files. There are %number of them. Please leave only one.
-          You can review Bluff !installation_instructions.',
-          array(
-          '%files' => implode(', ', $files),
-          '%number' => $bluff_count,
-          '!installation_instructions' => l(t('installation instructions'), $installation_instructions_path),
-        )
-        ),
-        'severity' => REQUIREMENT_ERROR,
-        'value' => $t('%number installed', array('%number' => $bluff_count)),
-      );
-    }
-
-  }
-
-  return $requirements;
-}
diff --git a/apis/charts_graphs_bluff/charts_graphs_bluff.module b/apis/charts_graphs_bluff/charts_graphs_bluff.module
deleted file mode 100644
index ec17d9b..0000000
--- a/apis/charts_graphs_bluff/charts_graphs_bluff.module
+++ /dev/null
@@ -1,40 +0,0 @@
-<?php
-
-/**
- * @file drupal module file implementing bluff charting.
- */
-
-/**
- * Implements hook_chartgraph_provider().
- **/
-function charts_graphs_bluff_chartgraph_provider() {
-  $provider = array(
-    'path' => drupal_get_path('module', 'charts_graphs_bluff') . '/charts_graphs_bluff.class.inc', // must be full path
-    'clazz' => 'ChartsGraphsBluff', // implementation class' name
-    'name' => 'bluff', // name used when invoking through a factory method
-    'nice_name' => 'Bluff',
-    'chart_types' => array(
-      'line' => t('Line'),
-      'bar' => t('Bar'),
-      'pie' => t('Pie'),
-      'area' => t('Area'),
-      'side_bar' => t('Side Bar'),
-      'stacked_side_bar' => t('Stacked Side Bar'),
-      'stacked_area' => t('Stacked Area'),
-      'stacked_bar' => t('Stacked Bar'),
-      'mini_bar' => t('Small Bar'),
-      'mini_pie' => t('Small Pie'),
-      'mini_side_bar' => t('Small Side Bar'),
-    ),
-    'themes' => array(
-      'keynote' => t('Keynote'),
-      '37signals' => t('37 Signals'),
-      'rails_keynote' => t('Rails Keynote'),
-      'odeo' => t('Odeo'),
-      'pastel' => t('Pastel'),
-      'greyscale' => t('Greyscale'),
-    ),
-  );
-
-  return (object) $provider;
-}
diff --git a/apis/charts_graphs_google_charts/charts_graphs_google_charts.class.inc b/apis/charts_graphs_google_charts/charts_graphs_google_charts.class.inc
deleted file mode 100644
index 76887c9..0000000
--- a/apis/charts_graphs_google_charts/charts_graphs_google_charts.class.inc
+++ /dev/null
@@ -1,395 +0,0 @@
-<?php
-
-/**
- * @file
- *   Implementation of abstract class ChartsGraphsCanvas for Google Charts library.
- *
- */
-
-define('CHARTS_GRAPHS_GOOGLE_CHARTS_AREA_MARKER_STYLE', 'B');
-define('CHARTS_GRAPHS_GOOGLE_CHARTS_DATA_STARTER', 't:');
-
-define('CHARTS_GRAPHS_GOOGLE_CHARTS_DATA_PARAMETER', 'chd');
-define('CHARTS_GRAPHS_GOOGLE_CHARTS_MIN_MAX_PER_SERIE_PARAMETER', 'chds');
-define('CHARTS_GRAPHS_GOOGLE_CHARTS_VISIBLE_AXIS_PARAMETER', 'chxt');
-define('CHARTS_GRAPHS_GOOGLE_CHARTS_AXIS_RANGE_PARAMETER', 'chxr');
-define('CHARTS_GRAPHS_GOOGLE_CHARTS_CUSTOM_AXIS_LABELS', 'chxl');
-define('CHARTS_GRAPHS_GOOGLE_CHARTS_CHART_TYPE', 'cht');
-define('CHARTS_GRAPHS_GOOGLE_CHARTS_MARKER_STYLE', 'chm');
-define('CHARTS_GRAPHS_GOOGLE_CHARTS_CHART_TITLE', 'chtt');
-define('CHARTS_GRAPHS_GOOGLE_CHARTS_CHART_TITLE_COLOUR', 'chts');
-define('CHARTS_GRAPHS_GOOGLE_CHARTS_CHART_SIZE', 'chs');
-define('CHARTS_GRAPHS_GOOGLE_CHARTS_SERIES_COLOUR', 'chco');
-define('CHARTS_GRAPHS_GOOGLE_CHARTS_LABEL_POSITION', 'chxp');
-define('CHARTS_GRAPHS_GOOGLE_CHARTS_BARS_WIDTH_SPACING', 'chbh');
-define('CHARTS_GRAPHS_GOOGLE_CHARTS_LEGEND', 'chdl');
-define('CHARTS_GRAPHS_GOOGLE_CHARTS_LEGEND_POSITION', 'chdlp');
-define('CHARTS_GRAPHS_GOOGLE_CHARTS_BACKGROUND_COLOUR', 'chf');
-define('CHARTS_GRAPHS_GOOGLE_CHARTS_PIE_LABELS', 'chl');
-
-define('CHARTS_GRAPHS_GOOGLE_CHARTS_COLOUR_DEFINITION_LENGTH', 6);
-
-define('CHARTS_GRAPHS_GOOGLE_CHARTS_URL_PREFIX', 'http://chart.apis.google.com/chart?');
-
-/**
- * Implementation of abstract class ChartsGraphsCanvas for Google Charts library.
- */
-class ChartsGraphsGoogleCharts extends ChartsGraphsCanvas {
-
-  var $width = 450;
-  var $height = 200;
-  var $title = '';
-
-  /**
-   * Sets how we count how many colours must be sent.
-   *
-   * TRUE: counts the number of data series available
-   * FALSE: counts the munber of data poitns in the first serie. This last
-   * behaviour is used with pie charts.
-   *
-   * @var <bool>
-   */
-  var $colour_count_series = TRUE;
-
-  /**
-   * Parameters set directly by the user.
-   *
-   * @var <array>
-   */
-  var $parameters = array();
-
-  protected function _encode_chart_type() {
-    switch ($this->type) {
-      case 'line':
-        $type = 'lc';
-        break;
-
-      case 'area':
-        $type = 'lc';
-        break;
-
-      case 'bar':
-        $type = 'bvg';
-        break;
-
-      case 'pie':
-        $type = 'p';
-        $this->colour_count_series = FALSE;
-        break;
-
-      case 'side_bar':
-        $type = 'bhg';
-        break;
-
-      case 'queued_bar':
-        $type = 'bvo';
-        break;
-
-      case 'stacked_bar':
-        $type = 'bvs';
-        break;
-
-      case 'stacked_side_bar':
-        $type = 'bhs';
-        break;
-
-      case 'pie_3d':
-        $type = 'p3';
-        $this->colour_count_series = FALSE;
-        break;
-    }
-    $this->parameters_to_send[CHARTS_GRAPHS_GOOGLE_CHARTS_CHART_TYPE] = $type;
-  }
-
-  protected function _encode_data() {
-    $series = $this->series;
-    $is_stacked = (strpos($this->type, 'stacked') !== FALSE);
-    // Use zero as initial min to guarantee that the y axis show zero.
-    $min_y = 0;
-    $max_y = $is_stacked ? 0 : reset(reset($series));
-    $chds = '';
-    $chd = array();
-    $chdl = array();
-    $is_pie = (strpos($this->type, 'pie') !== FALSE);
-    foreach ($series as $serie_name => $serie) {
-      if (!$is_pie) {
-        $chdl[] = $serie_name;
-      }
-      $min_serie = 0;
-      $max_serie = reset($serie);
-      $serie_as_string = '';
-      foreach ($serie as $val) {
-        $serie_as_string .= ',' . drupal_encode_path($val);
-        if ($val < $min_serie) {
-          $min_serie = $val;
-        }
-        elseif ($val > $max_serie) {
-          $max_serie = $val;
-        }
-      }
-      if ($min_serie < $min_y) {
-        $min_y = $min_serie;
-      }
-      if ($is_stacked) {
-        $max_y += $max_serie;
-      }
-      else {
-        if ($max_serie > $max_y) {
-          $max_y = $max_serie;
-        }
-      }
-
-      if (strlen($serie_as_string)) {
-        $serie_as_string = substr($serie_as_string, 1);
-      }
-      $chd[] = $serie_as_string;
-    }
-
-    /**
-     * Applying user defined min and max y axis values.
-     */
-    if (isset($this->y_min)) {
-      $min_y = $this->y_min;
-    }
-    if (isset($this->y_max)) {
-      $max_y = $this->y_max;
-    }
-
-    $chds = drupal_encode_path($min_y) . ',' . drupal_encode_path($max_y);
-    if ($is_pie) {
-      $chdl = $this->x_labels;
-      $chl = reset($this->series);
-    }
-    $this->parameters_to_send[CHARTS_GRAPHS_GOOGLE_CHARTS_DATA_PARAMETER] =
-      CHARTS_GRAPHS_GOOGLE_CHARTS_DATA_STARTER . implode('|', $chd);
-    $this->parameters_to_send[CHARTS_GRAPHS_GOOGLE_CHARTS_LEGEND] = implode('|', $chdl);
-    if ($is_pie) {
-      $this->parameters_to_send[CHARTS_GRAPHS_GOOGLE_CHARTS_PIE_LABELS] =
-        implode('|', $chl);
-    }
-    else {
-      if (strpos($this->type, 'side') === FALSE) {
-        $scale_axis_identifier = 1;
-        $text_labels_axis_identifier = 0;
-        $y_legend_axis = ',y';
-      }
-      else {
-        $scale_axis_identifier = 0;
-        $text_labels_axis_identifier = 1;
-        $y_legend_axis = ',x';
-      }
-      if ($this->y_legend) {
-        $this->parameters_to_send[CHARTS_GRAPHS_GOOGLE_CHARTS_VISIBLE_AXIS_PARAMETER] .= $y_legend_axis;
-        $y_legend = '2:|' . drupal_encode_path($this->y_legend) . '|';
-        $this->parameters_to_send[CHARTS_GRAPHS_GOOGLE_CHARTS_LABEL_POSITION] = '2,50';
-      }
-      else {
-        $y_legend = '';
-      }
-      $this->parameters_to_send[CHARTS_GRAPHS_GOOGLE_CHARTS_CUSTOM_AXIS_LABELS] =
-        $y_legend . $text_labels_axis_identifier . ':' . $this->_get_encoded_text_labels();
-      $this->parameters_to_send[CHARTS_GRAPHS_GOOGLE_CHARTS_MIN_MAX_PER_SERIE_PARAMETER] = $chds;
-      $this->parameters_to_send[CHARTS_GRAPHS_GOOGLE_CHARTS_VISIBLE_AXIS_PARAMETER] = 'x,y';
-
-      /**
-       * Applying user defined min and max y axis values.
-       */
-      if (isset($this->y_min)) {
-        $min_y = $this->y_min;
-      }
-      if (isset($this->y_max)) {
-        $max_y = $this->y_max;
-      }
-      $this->parameters_to_send[CHARTS_GRAPHS_GOOGLE_CHARTS_AXIS_RANGE_PARAMETER] =
-        $scale_axis_identifier . ',' . drupal_encode_path($min_y) . ',' .
-        drupal_encode_path($max_y);
-      /**
-       * Applying user defined step for y axis values.
-       */
-      if (isset($this->y_step)) {
-        $this->parameters_to_send[CHARTS_GRAPHS_GOOGLE_CHARTS_AXIS_RANGE_PARAMETER] .= ',' . $this->y_step;
-      }
-    }
-
-    $colour_count = $this->colour_count_series ? count($series) : count(reset($series));
-    $colours = array_slice($this->series_colours(), 0, $colour_count);
-    $pure_hex_colours = array();
-    foreach ($colours as $colour) {
-      $pure_hex_colours[] = substr($colour, -6);
-    }
-    $this->parameters_to_send[CHARTS_GRAPHS_GOOGLE_CHARTS_SERIES_COLOUR] = implode(',', $pure_hex_colours);
-    if ($this->type == 'area') {
-      $fill_colour = array();
-      $i = 0;
-      foreach ($pure_hex_colours as $colour) {
-        $fill_colour[] = sprintf(
-          '%s,%s,%u,0,0',
-          CHARTS_GRAPHS_GOOGLE_CHARTS_AREA_MARKER_STYLE,
-          $colour,
-          $i
-        );
-        $i++;
-      }
-      $this->parameters_to_send[CHARTS_GRAPHS_GOOGLE_CHARTS_MARKER_STYLE] = implode('|', $fill_colour);
-    }
-
-    if ($this->legend_pos) {
-      switch ($this->legend_pos) {
-        case 'top':
-          $chdlp = 't';
-          break;
-        case 'bottom':
-          $chdlp = 'b';
-          break;
-        case 'top_vert':
-          $chdlp = 'tv';
-          break;
-        case 'bottom_vert':
-          $chdlp = 'bv';
-          break;
-        case 'left':
-          $chdlp = 'l';
-          break;
-        default:
-          $chdlp = 'r';
-      }
-      $this->parameters_to_send[CHARTS_GRAPHS_GOOGLE_CHARTS_LEGEND_POSITION] = $chdlp;
-    }
-    if ($this->title_colour) {
-      $this->parameters_to_send[CHARTS_GRAPHS_GOOGLE_CHARTS_CHART_TITLE_COLOUR] = $this->title_colour;
-    }
-  }
-
-  protected function _get_encoded_text_labels() {
-    $chxl = '';
-    if (is_array($this->x_labels)) {
-      /**
-       * Workaround a apparently Google Charts bug: data labels are inverted on
-       * side bar graphs.
-       */
-      $x_labels = ($this->type == 'side_bar') ?
-        array_reverse($this->x_labels) :
-        $this->x_labels;
-      foreach ($x_labels as $label) {
-        $chxl .= '|' . drupal_encode_path($label);
-      }
-    }
-    return $chxl;
-  }
-
-  protected function _encode_other_parameters() {
-    $this->parameters_to_send[CHARTS_GRAPHS_GOOGLE_CHARTS_CHART_TITLE] = drupal_encode_path($this->title);
-    $this->parameters_to_send[CHARTS_GRAPHS_GOOGLE_CHARTS_CHART_SIZE] = drupal_encode_path(sprintf(
-      '%ux%u',
-      $this->width,
-      $this->height
-    ));
-    if (strpos($this->type, 'bar') !== FALSE) {
-      $this->parameters_to_send[CHARTS_GRAPHS_GOOGLE_CHARTS_BARS_WIDTH_SPACING] = 'a';
-    }
-
-    /**
-     * Applying background colour setting if available.
-     */
-    if (isset($this->colour) && !empty($this->colour)) {
-      $this->parameters_to_send[CHARTS_GRAPHS_GOOGLE_CHARTS_BACKGROUND_COLOUR] = sprintf(
-        'bg,s,%s',
-        substr($this->colour, -(CHARTS_GRAPHS_GOOGLE_CHARTS_COLOUR_DEFINITION_LENGTH))
-      );
-    }
-  }
-
-  /**
-   * Pushes user defined parameters over any parameters defined by the class.
-   *
-   * I.e., the user defined parameters overwrite any parameters defined
-   * elsewhere. We don't make any processing on these parameters. They are
-   * outputed exactly as sent. The user is responsable for urlenconding this
-   * data.
-   *
-   * If the user wants to simply unset some parameter, it can do it senting the
-   * parameter with a NULL value.
-   */
-  protected function _encode_user_parameters() {
-    if (is_array($this->parameters)) {
-      foreach ($this->parameters as $key => $value) {
-        if ($value === NULL) {
-          unset($this->parameters_to_send[$key]);
-        }
-        else {
-          $this->parameters_to_send[$key] = $value;
-        }
-      }
-    }
-  }
-
-  protected function _get_encoded_value($value) {
-    if (is_array($value)) {
-      $encoded_value = '';
-      foreach ($value as $val) {
-        $encoded_value .= '|' . $this->_get_encoded_value($val);
-      }
-      if (strlen($encoded_value)) {
-        $encoded_value = substr($encoded_value, 1);
-      }
-    }
-    else {
-      $encoded_value = drupal_encode_path($value);
-    }
-    return $encoded_value;
-  }
-
-  protected function _get_query() {
-    $query = '';
-    foreach ($this->parameters_to_send as $key => $value) {
-      $query .= '&' . $key . '=' . $value;
-    }
-    if (strlen($query)) {
-      $query = substr($query, 1);
-    }
-    return $query;
-  }
-
-  protected function _get_url() {
-    $this->parameters_to_send = array();
-    $this->_encode_chart_type();
-    $this->_encode_data();
-    $this->_encode_other_parameters();
-    $this->_encode_user_parameters();
-    $url = CHARTS_GRAPHS_GOOGLE_CHARTS_URL_PREFIX . $this->_get_query();
-    return $url;
-  }
-
-  /**
-   * Function that renders data.
-   */
-  public function get_chart() {
-    $provider = charts_graphs_google_charts_chartgraph_provider();
-    $chart_id = sprintf(
-      '%s-chart-%d',
-      $this->type,
-      $this->getUnique_ID()
-    );
-    $alt_text = sprintf(
-      '%s %s chart',
-      $this->title,
-      $provider->chart_types[$this->type]
-    );
-
-    $output = sprintf(
-      '<div id="%s-wrapper" class="charts_graphs_google_chart charts_graphs_google_chart_%s">
-        <img id="%1$s" src="%s" alt="%s" />
-      </div>',
-      check_plain($chart_id),
-      check_plain($this->type),
-      $this->_get_url(),
-      check_plain($alt_text)
-    );
-
-    $element = array(
-      '#markup' => $output,
-    );
-    return $element;
-
-  }
-}
diff --git a/apis/charts_graphs_google_charts/charts_graphs_google_charts.info b/apis/charts_graphs_google_charts/charts_graphs_google_charts.info
deleted file mode 100644
index da82685..0000000
--- a/apis/charts_graphs_google_charts/charts_graphs_google_charts.info
+++ /dev/null
@@ -1,8 +0,0 @@
-
-name = "Charts and Graphs: Google Charts"
-description = "Google Charts implementation for Charts and Graphs."
-dependencies[] = charts_graphs
-package = "Charts"
-core = 7.x
-php = 5.1
-
diff --git a/apis/charts_graphs_google_charts/charts_graphs_google_charts.module b/apis/charts_graphs_google_charts/charts_graphs_google_charts.module
deleted file mode 100644
index 482e026..0000000
--- a/apis/charts_graphs_google_charts/charts_graphs_google_charts.module
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-
-/**
- * @file drupal module file implementing Google Charts charting.
- */
-
-/**
- * Implements hook_chartgraph_provider().
- **/
-function charts_graphs_google_charts_chartgraph_provider() {
-
-  drupal_get_path($type, $project);
-
-  $provider = array(
-    'path' => drupal_get_path('module', 'charts_graphs_google_charts') . '/charts_graphs_google_charts.class.inc', // must be full path
-    'clazz' => 'ChartsGraphsGoogleCharts', // implementation class' name
-    'name' => 'google-charts', // name used when invoking through a factory method
-    'nice_name' => 'Google Charts',
-    'chart_types' => array(
-      'line' => t('Line'),
-      'bar' => t('Bar'),
-      'pie' => t('Pie'),
-      'pie_3d' => t('3D Pie'),
-      'area' => t('Area'),
-      'side_bar' => t('Side Bar'),
-      'stacked_side_bar' => t('Stacked Side Bar'),
-      'queued_bar' => t('Queued Bar'),
-      'stacked_bar' => t('Stacked Bar'),
-    ),
-    'themes' => array(),
-  );
-
-  return (object) $provider;
-}
diff --git a/apis/charts_graphs_open_flash/INSTALL.TXT b/apis/charts_graphs_open_flash/INSTALL.TXT
deleted file mode 100644
index 3baf37b..0000000
--- a/apis/charts_graphs_open_flash/INSTALL.TXT
+++ /dev/null
@@ -1,5 +0,0 @@
-You need to get Open Flash Chart SWF file as it's LGPL and so can't be included 
-in this module release files. Download latest Open Flash Chart 2 release from
-http://sourceforge.net/projects/openflashchart/files/open-flash-chart/ and dump 
-the open-flash-chart.swf file into the 
-sites/all/modules/charts_graphs/apis/charts_graphs_open_flash directory.
diff --git a/apis/charts_graphs_open_flash/charts_graphs_open_flash.class.inc b/apis/charts_graphs_open_flash/charts_graphs_open_flash.class.inc
deleted file mode 100644
index 9d5a7fb..0000000
--- a/apis/charts_graphs_open_flash/charts_graphs_open_flash.class.inc
+++ /dev/null
@@ -1,275 +0,0 @@
-<?php
-
-/**
- * @file
- *   Implementation of abstract class ChartsGraphsFlashCanvas for Open Charts
- * Flash 2 library.
- *
- */
-
-require_once DRUPAL_ROOT . '/' . dirname(__FILE__) . '/../../charts_graphs_flash_canvas.class.inc';
-
-/**
- * Implementation of abstract class ChartsGraphsFlashCanvas for Open Charts
- * Flash 2 library.
- */
-class ChartsGraphsOpenFlash extends ChartsGraphsFlashCanvas {
-
-  /**
-   * Holds the type definition translated to Open Charts Flash 2 types.
-   *
-   * @var <string>
-   */
-  var $translated_type;
-
-  /**
-   * @param $cid
-   *   cache_id from which cache to retrieve the data
-   */
-  function get_data_from_cache($cid = NULL) {
-    $cache = cache_get($cid);
-    if (!$cache) {
-      drupal_not_found();
-      exit();
-    }
-    $canvas = $cache->data;
-
-    if (empty($canvas) || !is_object($canvas) ||
-      !is_array($canvas->series) || empty($canvas->type)) {
-      drupal_not_found();
-      exit();
-    }
-
-    $this->title = new stdClass();
-    $this->title->text = $canvas->title;
-    $this->title->style = 'font-size: 20px; color:#0000ff; font-family: Verdana; text-align: center;';
-
-    $this->type = $canvas->translated_type;
-
-    $is_pie = ($this->type === 'pie');
-
-    $this->y_legend = new stdClass();
-    $this->y_legend->text = $canvas->y_legend ? $canvas->y_legend : '';
-    $this->y_legend->style = '{color: #736AFF; font-size: 12px;}';
-
-    /**
-     * Applying background colour setting if available.
-     */
-    if (isset($canvas->colour) && !empty($canvas->colour)) {
-      $this->bg_colour = $canvas->colour;
-    }
-
-    $y = new stdClass();
-    $y->grid_colour = '#00ff00';
-    $y->offset = 50;
-    $this->y_axis = $y;
-
-    $x = new stdClass();
-    $x->colour = '#909090';
-    $x->grid_colour = '#00ff00';
-
-    /**
-     * Some kind of bug: if labels are not PHP "strings" they do not render.
-     * Sigh.
-     *
-     * Seizing the oportunity and also fixing x_labels arrays whoose keys aren't
-     * numeric: 0, 1, 2 etc.
-     */
-    $x_labels = array();
-    foreach ($canvas->x_labels as $key => $label) {
-      $x_labels[] = (string) $label;
-    }
-
-    $x->labels->labels = $x_labels;
-    $this->x_axis = $x;
-
-    $series_colours = array_values($canvas->series_colours);
-
-    /**
-     * Initializing $min and $max.
-     */
-    $val = reset($canvas->series);
-    $max_value = reset($val);
-    $min_value = $max_value;
-
-    $i = 0; // for colours
-    foreach ($canvas->series as $key => $val) {
-      if ($is_pie && ($i > 0)) {
-        break;
-      }
-      $obj = new stdClass();
-      $val = $this->_preprocess_values($val);
-      $obj->values = $val;
-      if ($is_pie) {
-        $obj->tip = '#label# #val# (#percent#)';
-        $obj->{'label - colour'} = '#432BAF';
-      }
-      else {
-        $max_value_arr = max($val);
-        if ($max_value < $max_value_arr) {
-          $max_value = $max_value_arr;
-        }
-        $min_value_arr = min($val);
-        if ($min_value > $min_value_arr) {
-          $min_value = $min_value_arr;
-        }
-      }
-      $obj->text = $key;
-      $obj->alpha = .5;
-      $obj->type = $canvas->type;
-      $obj->colour = $series_colours[$i];
-      $this->elements[] = $obj;
-      $i++;
-    }
-
-    if (!$is_pie) {
-      $y_step = abs(($max_value - $min_value) / 10);
-
-      $this->x_axis->{'3d'} = 5;
-      $this->y_axis->max = $max_value + $max_value / 10;
-      if ($this->y_axis->max > 10) {
-        $this->y_axis->max = (int) $this->y_axis->max;
-      }
-      $this->y_axis->min = $min_value;
-      if ($y_step > 5) {
-        $y_step = (int) $y_step;
-      }
-      $this->y_axis->steps = $y_step;
-
-      /**
-       * Applying user defined min, max and step for y axis values.
-       */
-      if (isset($canvas->y_min)) {
-        $this->y_axis->min = $canvas->y_min;
-      }
-      if (isset($canvas->y_max)) {
-        $this->y_axis->max = $canvas->y_max;
-      }
-      if (isset($canvas->y_step)) {
-        $this->y_axis->steps = $canvas->y_step;
-      }
-    }
-  }
-
-  /**
-   * Pie-chart has different format for $values array than bar chart etc.
-   * This method deals with permutations across chart types. Sigh.
-   *
-   * We also remove items with no label, while we are at it, since
-   * those can cause problems to Flash renderer.
-   */
-  function _preprocess_values($values) {
-    $labels = $this->x_axis->labels->labels;
-    $i = 0;
-
-    $series_colours = array_values($this->series_colours());
-
-    switch ($this->type) {
-      case 'pie':
-        $new_vals = array();
-        foreach ($values as $val) {
-          // An accidental empty label causes SWF to go nuts.
-          if (!empty($labels[$i]) && ($labels[$i] != 'null')) {
-            $obj = new stdClass();
-            $obj->value = $val;
-            $obj->label = $labels[$i];
-            $obj->colour = $series_colours[$i];
-            $new_vals[] = $obj;
-          }
-          $i++;
-        }
-        return $new_vals;
-
-        /**
-         * Default action is just filtering values with nulled labels (leftovers
-         * from out joins).
-         */
-      default:
-        $new_vals = array();
-        $new_labels = array();
-        foreach ($values as $val) {
-          // An accidental empty label causes SWF to go nuts.
-          if (!empty($labels[$i]) && ($labels[$i] != 'null')) {
-            $new_vals[] = $val;
-            $new_labels[] = $labels[$i];
-          }
-          $i++;
-        }
-        $this->x_axis->labels->labels = $new_labels;
-        return $new_vals;
-    }
-  }
-
-  /**
-   * Translate Charts and Graphs graph type to Open Charts Flash 2 types.
-   *
-   * It currently doesn't nothing of value but will leave it here in case some
-   * brave soul decides to implement horizontal bar or area or some other graph
-   * type.
-   *
-   * @return <string>
-   */
-  protected function _get_translated_chart_type() {
-    switch ($this->type) {
-      default:
-        $type = $this->type;
-    }
-
-    return $type;
-  }
-
-  /**
-   * Function that renders data.
-   */
-  function get_chart() {
-    global $base_url;
-    $unique = charts_graphs_random_hash();
-
-    // Make current object a StdClass() for easier de-serialization
-    $this->translated_type = $this->_get_translated_chart_type();
-    $arr = (array) $this;
-    $generic = (object) $arr;
-
-    //Keep for at least 30 seconds;
-    cache_set($unique, $generic, 'cache', REQUEST_TIME + 30);
-
-    $mod_path = drupal_get_path('module', $this->getModuleName());
-    $openflash_swf_uri = $base_url . '/' . $mod_path . '/open-flash-chart.swf';
-
-    // TODO The second parameter to this function call should be an array.
-    $data_URL = url(
-      'charts_graphs_open_flash/data/' . $unique,
-      array('absolute' => TRUE)
-    );
-
-    /** For debugging
-     * $ret = drupal_http_request( $data_URL );
-     * echo "<pre>".print_r ( $ret,true)."</pre>";
-     * exit();
-     * */
-    $wmode = $this->get_wmode();
-
-    $flashvars = array(
-      'data-file' => 'SWFDATAURL',
-      'preloader_color' => '#999999',
-      'wmode' => $wmode,
-    );
-
-    $args = array(
-      'params' => array(
-        'width' => $this->width,
-        'height' => $this->height,
-        'wmode' => $wmode,
-      ),
-      'flashvars' => $flashvars,
-    );
-
-    $out = swf($openflash_swf_uri, $args);
-    $out = str_replace('SWFDATAURL', $data_URL, $out);
-
-    $element = array(
-      '#markup' => $out,
-    );
-    return $element;
-  }
-}
diff --git a/apis/charts_graphs_open_flash/charts_graphs_open_flash.info b/apis/charts_graphs_open_flash/charts_graphs_open_flash.info
deleted file mode 100644
index da161ba..0000000
--- a/apis/charts_graphs_open_flash/charts_graphs_open_flash.info
+++ /dev/null
@@ -1,8 +0,0 @@
-name = "Charts and Graphs: Open Flash Charts 2"
-description = "Open Flash Charts 2 implementation for Charts and Graphs."
-dependencies[] = charts_graphs
-dependencies[] = swftools
-package = "Charts"
-core = 7.x
-php = 5.1
-
diff --git a/apis/charts_graphs_open_flash/charts_graphs_open_flash.module b/apis/charts_graphs_open_flash/charts_graphs_open_flash.module
deleted file mode 100644
index 1070847..0000000
--- a/apis/charts_graphs_open_flash/charts_graphs_open_flash.module
+++ /dev/null
@@ -1,71 +0,0 @@
-<?php
-
-/**
- * @file drupal module file implementing Open Flash Chart 2 charting.
- */
-
-/**
- * Implements hook_chartgraph_provider().
- **/
-function charts_graphs_open_flash_chartgraph_provider() {
-  $provider =  array(
-    'path' => drupal_get_path('module', 'charts_graphs_open_flash  ') . '/charts_graphs_open_flash.class.inc', //must be full path
-    'clazz' => 'ChartsGraphsOpenFlash', //implementation class' name
-    'name' => 'open-flash', //name used when invoking through a factroy method
-    'nice_name' => 'Open Flash Chart 2',
-    'chart_types' => array(
-      'line' => t('Line'),
-      'bar' => t('Bar'),
-      'bar_3d' => t('3D Bar'),
-      'bar_cylinder' => t('Cylinder Bar'),
-      'bar_cylinder_outline' => t('Outlined Cylinder Bar'),
-      'bar_dome' => t('Dome Bar'),
-      'bar_filled' => t('Filled Bar'),
-      'bar_glass' => t('Glass Bar'),
-      'bar_round' => t('Glass Bar with rounded tops and bottoms'),
-      'bar_round_glass' => t('Glass Bar with rounded tops'),
-      'bar_sketch' => t('Sketched Bar'),
-      'pie' => t('Pie'),
-    ),
-    'themes' => array(),
-  );
-
-  return (object) $provider;
-}
-
-/**
- * Implements hook_menu().
- */
-function charts_graphs_open_flash_menu() {
-  $items = array();
-
-  $items['charts_graphs_open_flash/data'] = array(
-    'page callback' => 'charts_graphs_open_flash_data',
-    'access arguments' => array('access content'),
-    'type' => MENU_CALLBACK,
-  );
-
-  return $items;
-}
-
-/**
- * Adds chart data as JSON.
- *
- * @param $cid
- *   cache_id from which cache to retrieve the data
- */
-function charts_graphs_open_flash_data($cid = NULL) {
-  $cache = cache_get($cid);
-  if (!$cache) {
-    drupal_not_found();
-    exit();
-  }
-  $canvas = $cache->data;
-
-  $chart = charts_graphs_get_graph('open-flash');
-
-  $chart->get_data_from_cache($cid);
-
-  drupal_json_output($chart);
-  exit();
-}
diff --git a/apis/charts_openflash/INSTALL.TXT b/apis/charts_openflash/INSTALL.TXT
deleted file mode 100644
index 78e3b88..0000000
--- a/apis/charts_openflash/INSTALL.TXT
+++ /dev/null
@@ -1,3 +0,0 @@
-Please download OFC zip from http://teethgrinder.co.uk/open-flash-chart-2/downloads.php
-extract the archive and copy open-flash-chart.swf file from the archive in the
-same directory as this readme file. Do not copy any other files. 
diff --git a/apis/charts_openflash/charts_openflash.class.inc b/apis/charts_openflash/charts_openflash.class.inc
deleted file mode 100755
index 514746b..0000000
--- a/apis/charts_openflash/charts_openflash.class.inc
+++ /dev/null
@@ -1,184 +0,0 @@
-<?php
-
-class ChartsOpenFlash extends ChartCanvas {
-
-function set_data($rows, $x_labels) {
-    
-    $this->series = $rows;
-    $this->x_labels = $x_labels;
-}
-
-/**
-* @param $cid
-*   cache_id from which cache to retrieve the data
-*/
-function get_data_from_cache($cid=null) {
-  
-  $cache = cache_get($cid);
-  if (!$cache) {
-    drupal_not_found();
-    exit();
-  }
-  $canvas = $cache->data;
-  
-  if (empty($canvas) || !is_object($canvas) || 
-      !is_array($canvas->series) || empty($canvas->type)) {
-    drupal_not_found();
-    exit();
-  }
-  
-  $this->title = new stdClass();
-  $this->title->text = $canvas->title;
-  $this->title->style="font-size: 20px; color:#0000ff; font-family: Verdana; text-align: center;";
-
-  $this->type = $canvas->type;
-
-  $this->y_legend = new stdClass();  
-  $this->y_legend->text = $canvas->y_legend;
-  $this->y_legend->style = "{color: #736AFF; font-size: 12px;}";
-  
-  $y = new stdClass();
-  $y->grid_colour = "#00ff00";
-  $y->offset = 50;
-  $this->y_axis = $y;
-  
-  $x = new stdClass();
-  $x->colour = "#909090";
-  $x->grid_colour="#00ff00";
-  $x->labels->labels  = $canvas->x_labels;
-  $this->x_axis = $x;
-  
-  $series_colors = ChartsOpenFlash::series_colors();
-  
-  /**
-  * Initializing max_value with some really small value
-  * and max_value with large value, respectively so that
-  * they get thrown away at the very first comparision.
-  */
-  $max_value = -10e10; //some really small value
-  $min_value = $canvas->y_min; //some really large value  
-
-  $i=0; // for colours
-  foreach ( $canvas->series as $key => $val ) {
-    $obj = new stdClass();
-    $val = $this->_preprocess_values($val);
-    $obj->values = $val;
-     // Determine max
-     $arr_tmp_max = array_merge ($val, array($max_value));
-     $arr_tmp_min = array_merge ($val, array($min_value));     
-     $max_value = max($arr_tmp_max);
-     $min_value = min($arr_tmp_min);
-      if ($this->type == 'pie' ) {
-        $obj->tip = '#label# #val# (#percent#)';
-        $obj->{label-colour} = '#432BAF';        
-      }    
-    $obj->text = $key;
-    $obj->alpha = .5;
-    $obj->type = $canvas->type;
-    $obj->colour = $series_colors[$i];
-    $this->elements[] = $obj;
-    $i++;
-  }
-
-  $y_step = abs(($max_value - $min_value)/10);
-  
-  $this->x_axis->{'3d'} = 5;
-  $this->y_axis->max = $max_value + $max_value/10;
-  if ($this->y_axis->max > 10) {
-    $this->y_axis->max = (int) $this->y_axis->max;
-  }
-  $this->y_axis->min = $min_value;  
-  if ($y_step > 5)  {
-    $y_step = (int) $y_step;
-  }
-  $this->y_axis->steps = $y_step; 
-
-}
-
-/**
-* Pie-chart has different format for $values array than bar chart etc. 
-* This method deals with permutations across chart types. Sigh.
-*
-* <p> We also remove items with no label, while we are at it, since
-* those can cause problems to Flash renderer.
-*/
-function _preprocess_values($values) {
-
-  $labels = $this->x_axis->labels->labels;
-  $i = 0;
-  
-  switch ($this->type) {
-    case 'pie': 
-      $new_vals = array();
-      foreach ($values as $val) {
-        if (!empty($labels[$i]) && $labels[$i] != 'null') { // An accidental empty label causes SWF to go nuts
-          $obj = new stdClass();
-          $obj->value = $val;
-          $obj->label = $labels[$i];
-          $arr = array('value'=>$val, 'label'=>$labels[$i]);
-          $new_vals[] = $obj;
-        }
-        $i++;
-      }
-      return $new_vals;
-    default: // Default action is just filtering values with nulled labels (leftovers from out joins)
-      $new_vals = array(); $new_labels = array();
-      foreach ($values as $val) {
-        if (!empty($labels[$i]) && $labels[$i] != 'null') { // An accidental empty label causes SWF to go nuts
-          $new_vals[] = $val;
-          $new_labels[] = $labels[$i];
-        }
-        $i++;
-      }
-      $this->x_axis->labels->labels = $new_labels;
-      return $new_vals;
-  }
-
-}
-
-function get_chart() {
-  
-  
- $unique = chart_graphs_random_hash();
-  // Make current object a StdClass() for easier de-serialization
-  $arr = (array) $this; $generic = (object) $arr;
- cache_set( $unique, $generic, 'cache', time() + 30 ); //Keep for at least 30 seconds;
-  
- $mod_path = drupal_get_path('module', $this->getModuleName());
- $openflash_swf_uri = base_path() . $mod_path . '/open-flash-chart.swf';
- 
- $data_URI = base_path() . 'charts_openflash/data/' . $unique ;
- $data_URL = url($data_URI, array('absolute' => TRUE ) );
- 
- /** For debugging 
- $ret = drupal_http_request( $data_URL ); 
- echo "<pre>".print_r ( $ret,true)."</pre>";
- exit();
- **/
-  
- $swfobj_mod_path = drupal_get_path('module', 'swfobject_api');
- $swfobj_js = $swfobj_mod_path . '/swfobject.js';
- $expressInst =  base_path() . $swfobj_mod_path . '/expressInstall.swf'; 
-  
- $chart_div_id = "drp_charts_graphs_" . $this->getUnique_ID(); 
- 
- drupal_add_js( $swfobj_js,1 );
-  
-return <<<HTML
-
-<script type="text/javascript">
-swfobject.embedSWF(
-  "${openflash_swf_uri}", "${chart_div_id}", "$this->width", "$this->height",
-  "9.0.0", "${expressInst}",
-  {"data-file":"$data_URI"}
-  );
-</script>
-
-<div id="${chart_div_id}"></div>
-
-HTML;
-
-}
-
-
-}
\ No newline at end of file
diff --git a/apis/charts_openflash/charts_openflash.info b/apis/charts_openflash/charts_openflash.info
deleted file mode 100755
index 4997b7e..0000000
--- a/apis/charts_openflash/charts_openflash.info
+++ /dev/null
@@ -1,8 +0,0 @@
-
-name = "Charts: OpenFlash"
-description = "Open Flash Charts."
-dependencies[]=charts_graphs
-dependencies[]=swfobject_api
-package = "Charts"
-core = 6.x
-php = 5.1
diff --git a/apis/charts_openflash/charts_openflash.module b/apis/charts_openflash/charts_openflash.module
deleted file mode 100755
index aacc6c9..0000000
--- a/apis/charts_openflash/charts_openflash.module
+++ /dev/null
@@ -1,61 +0,0 @@
-<?php
-/**
-* @file drupal module file implementing openflash charting
-*/
-
-/**
-* Implementation of hook_charts_graphs_provider 
-**/
-function charts_openflash_chartgraph_provider() {
-  $provider =  array(
-    'path' => dirname(__FILE__) . '/charts_openflash.class.inc', //must be full path
-    'clazz' => 'ChartsOpenFlash', //implementation class' name
-    'name' => 'open-flash', //name used when invoking through a factroy method
-  );    
-  
-  return (object) $provider;
-}
-
-function charts_openflash_menu() {
-  $items = array();
-
-  $items['charts_openflash/data'] = array(
-    'page callback' => 'charts_openflash_data',
-    'access arguments' => array('access content'),
-    'type' => MENU_CALLBACK,
-  );
-
-  return $items;
-}
-
-/**
-* @param $cid
-*   cache_id from which cache to retrieve the data
-*/
-function charts_openflash_data($cid=null) {
-  
-  $cache = cache_get($cid);
-  if (!$cache) {
-    drupal_not_found();
-    exit();
-  }
-  $canvas = $cache->data;
-    
-  $chart = chart_graphs_get_graph('open-flash');
-  
-  $chart->get_data_from_cache($cid); 
-  
-
-  /*$chart = <<<JSON
-  { "elements": [ { "type": "pie", "colours": [ "#77CC6D", "#FF5973", "#6D86CC" ], "border": 2, "animate": true, "label-colour": "#432BAF", "alpha": 0.75, "tip": "#label#
-$#val# (#percent#)", "on-click": "pie_slice_clicked", "values": [ { "value": 120, "label": "X" }, { "value": 99, "label": "Y" }, { "value": 21, "label": "Z", "on-click": "http:\/\/example.com" } ] } ] }';
-
-JSON;*/
-
-  //drupal_set_header('Content-Type: text/javascript; charset=utf-8');
-  //echo $chart;
-  
-  drupal_json($chart);
-  exit();
-  
-}
\ No newline at end of file
