text: // Global config
  var GRAPHIC_DEFAULT_WIDTH = 600;
  var MOBILE_THRESHOLD = 500;
  
  // Global vars
  var pymChild = null;
  var isMobile = false;
  var graphicData = null;
  var medicalData = [];
  var ageGroups = [];
  
  /*
   * Initialize the graphic.
   */
  var onWindowLoaded = function() {
      if (Modernizr.svg) {
          loadLocalData(GRAPHIC_DATA);
          //loadCSV('data.csv')
      } else {
          pymChild = new pym.Child({});
      }
  }
  
  /*
   * Load graphic data from a local source.
   */
  var loadLocalData = function(data) {
      graphicData = data;
  
      formatData();
  
      pymChild = new pym.Child({
          renderCallback: render
      });
  }
  
  /*
   * Load graphic data from a CSV.
   */
  var loadCSV = function(url) {
      d3.csv(GRAPHIC_DATA_URL, function(error, data) {
          graphicData = data;
  
          formatData();
  
          pymChild = new pym.Child({
              renderCallback: render
          });
      });
  }
  
  /*
   * Format graphic data for processing by D3.
   */
  var formatData = function() {
      graphicData.forEach(function(d) {
          d['amt'] = +d['amt'];
      });
  
      ageGroups = _.pluck(graphicData, 'age_group');
      ageGroups = d3.set(ageGroups).values();
      
      MEDICAL_DATA.forEach(function(d) {
          var ageGroup = d['age_group'];
          var description = d['description'];
          medicalData[ageGroup] = description;
      });
  }
  
  /*
   * Render the graphic(s). Called by pym with the container width.
   */
  var render = function(containerWidth) {
      if (!containerWidth) {
          containerWidth = GRAPHIC_DEFAULT_WIDTH;
      }
  
      var graphicWidth = containerWidth;
  
      if (containerWidth <= MOBILE_THRESHOLD) {
          isMobile = true;
      } else {
          isMobile = false;
      }
  
      // Render the chart!
      var containerElement = d3.select('#graphic');
      containerElement.html('');
  
      ageGroups.forEach(function(d, i) {
          var groupData = graphicData.filter(function(c) {
              return c['age_group'] == d;
          });
  
          var groupContainer = containerElement.append('div')
              .attr('class', 'age-group g-' + classify(d));
          
          groupContainer.append('h3');
  
          renderBarChart({
              container: '.g-' + classify(d),
              width: graphicWidth,
              data: groupData,
              ageGroup: d,
              pollTitle: HDR_POLL,
              recTitle: HDR_REC,
              rec: medicalData[d]
          });
      });
  
      // Update iframe
      if (pymChild) {
          pymChild.sendHeight();
      }
  }
  
  /*
   * Render a bar chart.
   */
  var renderBarChart = function(config) {
      /*
       * Setup
       */
      var labelColumn = 'label';
      var valueColumn = 'amt';
  
      var barHeight = 20;
      var barGap = 3;
      var labelWidth = 100;
      var labelMargin = 6;
      var valueGap = 6;
      
      var pollChartWidth = config['width'];
      var infoWidth = config['width'];
  
      if (!isMobile) {
          pollChartWidth = Math.floor((config['width'] - 22 - 1 - 22) * .7);
          infoWidth = Math.floor((config['width'] - 22 - 1 - 22) * .3);
      }
      
      var margins = {
          top: 0,
          right: 15,
          bottom: 20,
          left: (labelWidth + labelMargin)
      };
  
      var ticksX = 4;
      var roundTicksFactor = 5;
  
      // Calculate actual chart dimensions
      var chartWidth = pollChartWidth - margins['left'] - margins['right'];
      var chartHeight = ((barHeight + barGap) * config['data'].length);
  
      // Clear existing graphic (for redraw)
      var containerElement = d3.select(config['container']);
      containerElement.html('');
  
      /*
       * Set up containing divs
       */
      containerElement.append('h3')
          .text(config['ageGroup']);
  
      var rec = containerElement.append('div')
          .attr('class', 'recommendation')
          .attr('style', function() {
              if (!isMobile) {
                  var s = 'width: ' + infoWidth + 'px; ';
                  return s;
              }
          });
      rec.append('h4')
          .text(config['recTitle']);
      rec.append('p')
          .html(config['rec']);
      
      var chartOuterWrapper = containerElement.append('div')
          .attr('class', 'graphic-outer-wrapper')
          .attr('style', function() {
              if (!isMobile) {
                  var s = 'width: ' + pollChartWidth + 'px; ';
                  return s;
              }
          });
  
      chartOuterWrapper.append('h4')
          .text(config['pollTitle']);
  
      var chartWrapper = chartOuterWrapper.append('div')
          .attr('class', 'graphic-wrapper');
  
      /*
       * Create the root SVG element.
       */
  
      var chartElement = chartWrapper.append('svg')
          .attr('width', chartWidth + margins['left'] + margins['right'])
          .attr('height', chartHeight + margins['top'] + margins['bottom'])
          .append('g')
          .attr('transform', 'translate(' + margins['left'] + ',' + margins['top'] + ')');
  
      /*
       * Create D3 scale objects.
       */
      var xScale = d3.scale.linear()
          .domain([ 0, 80 ])
          .range([0, chartWidth]);
  
      /*
       * Create D3 axes.
       */
      var xAxis = d3.svg.axis()
          .scale(xScale)
          .orient('bottom')
          .ticks(ticksX)
          .tickFormat(function(d) {
              return d.toFixed(0) + '%';
          });
  
      /*
       * Render axes to chart.
       */
      chartElement.append('g')
          .attr('class', 'x axis')
          .attr('transform', makeTranslate(0, chartHeight))
          .call(xAxis);
  
      /*
       * Render grid to chart.
       */
      var xAxisGrid = function() {
          return xAxis;
      };
  
      chartElement.append('g')
          .attr('class', 'x grid')
          .attr('transform', makeTranslate(0, chartHeight))
          .call(xAxisGrid()
              .tickSize(-chartHeight, 0, 0)
              .tickFormat('')
          );
  
      /*
       * Render bars to chart.
       */
      chartElement.append('g')
          .attr('class', 'bars')
          .selectAll('rect')
          .data(config['data'])
          .enter()
          .append('rect')
              .attr('x', function(d) {
                  if (d[valueColumn] >= 0) {
                      return xScale(0);
                  }
  
                  return xScale(d[valueColumn]);
              })
              .attr('width', function(d) {
                  return Math.abs(xScale(0) - xScale(d[valueColumn]));
              })
              .attr('y', function(d, i) {
                  return i * (barHeight + barGap);
              })
              .attr('height', barHeight)
              .attr('class', function(d, i) {
                  return 'bar-' + i + ' ' + classify(d[labelColumn]);
              });
  
      /*
       * Render bar labels.
       */
      chartWrapper.append('ul')
          .attr('class', 'labels')
          .attr('style', formatStyle({
              'width': labelWidth + 'px',
              'top': margins['top'] + 'px',
              'left': '0'
          }))
          .selectAll('li')
          .data(config['data'])
          .enter()
          .append('li')
              .attr('style', function(d, i) {
                  return formatStyle({
                      'width': labelWidth + 'px',
                      'height': barHeight + 'px',
                      'left': '0px',
                      'top': (i * (barHeight + barGap)) + 'px;'
                  });
              })
              .attr('class', function(d) {
                  return classify(d[labelColumn]);
              })
              .append('span')
                  .html(function(d) {
                      return d[labelColumn];
                  });
  
      /*
       * Render bar values.
       */
      chartElement.append('g')
          .attr('class', 'value')
          .selectAll('text')
          .data(config['data'])
          .enter()
          .append('text')
              .text(function(d) {
                  return d[valueColumn].toFixed(0) + '%';
              })
              .attr('x', function(d) {
                  return xScale(d[valueColumn]);
              })
              .attr('y', function(d, i) {
                  return i * (barHeight + barGap);
              })
              .attr('dx', function(d) {
                  var xStart = xScale(d[valueColumn]);
                  var textWidth = this.getComputedTextLength()
  
                  // Negative case
                  if (d[valueColumn] < 0) {
                      var outsideOffset = -(valueGap + textWidth);
  
                      if (xStart + outsideOffset < 0) {
                          d3.select(this).classed('in', true)
                          return valueGap;
                      } else {
                          d3.select(this).classed('out', true)
                          return outsideOffset;
                      }
                  // Positive case
                  } else {
                      if (xStart + valueGap + textWidth > chartWidth) {
                          d3.select(this).classed('in', true)
                          return -(valueGap + textWidth);
                      } else {
                          d3.select(this).classed('out', true)
                          return valueGap;
                      }
                  }
              })
              .attr('dy', (barHeight / 2) + 3);
  }
  
  /*
   * Initially load the graphic
   * (NB: Use window.load to ensure all images have loaded)
   */
  window.onload = onWindowLoaded;
  