﻿var Calculator = function() {
  var _step_index = 0
  
  var _optimum_height = null
  var _desired_height = null
  var _longitudinal_spacing = null
  var _transversal_spacing = null
  var _average_lux = null
  var _lsae = null
  var _watts = null
  var _candela_multiplier = null
  
  var _ies_file_type = null
  var _ies = null
  
  var _show_conforming_cells = false
  
  var _num_luminaires = 1
  
  var _google_visualization_ready = false
  var _luminance_plane_complete = false
    
  
  var change_step = function(recalculate) {
    window.location.href = '#step'+_step_index
    
    var step_nav_el = $('.nav a:eq('+_step_index+')')
    if(step_nav_el.hasClass('disabled')) return false

    var step_el = $('.step:eq('+_step_index+')')

    $('.nav .active').removeClass('active')
    step_nav_el.addClass('active')

    var change_layout = function() {
      $('#IESFileSpinner').hide()

      $('.step.active').removeClass('active')
      $(step_el).addClass('active')

      if(_step_index > 1) {
        update_history_values()
        $("#StepHistory li").hide()
        $("#StepHistory li.step"+_step_index).show()
        $('#History').toggle(true)
        if($('#StepHistory').hasClass('invisible')) $('#StepHistory').fadeTo('slow', 1).removeClass('invisible')
      }
      
      if(_step_index == 4) {
        if(!_desired_height) {
          $("#DesiredHeight").val(_optimum_height+'ft')
          $('#DesiredHeightSlider').slider('option', 'value', _optimum_height)
        }
        move_illuminance_plane_to_step('Step4')
      }

      if(step_el.attr('id') == "Summary") full_screen(true)
      
      if(recalculate !== false && _step_index > 1 && _step_index < 7 && $('.step.active table.results').hasClass('hidden')) Calculator.calculate_step(_step_index)
    }
    
    scroll_to_top_then_call(change_layout)
  }

  
  var show_step = function(step_index, recalculate) {
    if(recalculate === false && $('.nav a:eq('+step_index+')').hasClass('disabled')) return
    if($('.step.active .nextStep').hasClass('disabled') && step_index > 0) return

    if($('body').hasClass('fullscreen')) full_screen(false)

    _step_index = step_index
    
    enable_step(_step_index)
    
    // Enable printable summary link
    if(_step_index == 6) enable_step(7)

    // Create IES file if needed
    if(_step_index == 2 && !_ies) {
        $('#IESFileSpinner').show()
        
        if(_ies_file_type == 'file') {
          $('#History_iesFile').html('Uploaded File')
          $('#Summary_iesFile').html('Uploaded File')
          $('#IESFileForm').submit()
        } 
        else {
          $('#History_iesFile').html(ies_file_names[_ies_file_type])
          $('#Summary_iesFile').html(ies_file_names[_ies_file_type])
          
          _ies = new IES(ies_files[_ies_file_type])
          _watts = _ies.watts
          _candela_multiplier = _ies.candela_multiplier
          
          Calculator.calculate_distrubution_types()
          change_step(recalculate)
        }
    
    } else {
      change_step(recalculate)
    }

  }


  var scroll_to_top_then_call = function(callback) {
    $('.step.active #IlluminancePlane:visible').hide()
    $.scrollTo(0, {duration: Math.min($(window).scrollTop() * 10, 800), easing: 'swing', onAfter: callback})
  }
  
  
  var set_input_power = function(watts) {
    watts = parseFloat(watts)
    
    if(isNaN(watts) || watts <= 0) {
      $('#InputPower').val(_watts)
      return
    }
        
    _watts = watts
    reset_steps_after_active_one()
  }
  
  
  var set_candela_multiplier = function(candela_multiplier) {
    candela_multiplier = parseFloat(candela_multiplier)
    
    if(isNaN(candela_multiplier) || candela_multiplier <= 0) {
      $('#CandelaMultiplier').val(_candela_multiplier)
      return
    }
    
    candela_multiplier = Math.min(candela_multiplier, 10)
    $('#CandelaMultiplier').val(candela_multiplier)
    
    _candela_multiplier = candela_multiplier
    _ies.reparse({'candela_multiplier': _candela_multiplier})
    reset_steps_after_active_one()
  }


  var set_distribution_type = function(type, value) {
    if(type == 'lateral') {
      _lateral_type = value
    
    } else if(type == 'vertical') {
      _vertical_type = value
    }
    
    $('#VerticalType').val(_vertical_type)
    $('#LateralType').val(_lateral_type)
    
    update_history_values()
    reset_steps_after_active_one()
  }
  
  
  var set_num_luminaires = function(num) {
    var old_num = _num_luminaires
    _num_luminaires = parseInt(num)
    
    // Adjust cell size, for optimization reasons
    if(_num_luminaires != old_num) {
      _cell_size = (_num_luminaires > 1) ? 5*_mpf : 2.5*_mpf // meters
      _cell_area = _cell_size * _cell_size // m^2      
      recalculate_current_step()
    }
    
    if(_num_luminaires == 4) {
      $('#FourLuminaireWarning').show()
    } else {
        $('#FourLuminaireWarning').hide()
    }
    
    $('#History_numLuminaires').html(_num_luminaires)
    $('#Summary_numLuminaires').html(_num_luminaires)
    
  }
  
  
  var show_conforming_cells = function() {setTimeout(function() {
    _show_conforming_cells = $('#ShowConformingCells').attr('checked')
    var light_loss = parseFloat($("#LightLoss").val())
    draw_task_plane(_ies, (_desired_height / 3.2808399), light_loss)
  }, 0)}
  
  
  var load_ies = function(ies_str) {
    _ies = new IES(ies_str)
    Calculator.calculate_distrubution_types()
    setTimeout(change_step, 0)
  }


  var update_history_values = function() {
    var lateral_type = '';
    if(_lateral_type == 'type1')      lateral_type = 'I';
    else if(_lateral_type == 'type2') lateral_type = 'II';
    else if(_lateral_type == 'type3') lateral_type = 'III';
    else if(_lateral_type == 'type4') lateral_type = 'IV';
    else if(_lateral_type == 'type5') lateral_type = 'V';

    var vertical_type = _vertical_type.replace(/_/g, ' ').replace(/./, _vertical_type.slice(0, 1).toUpperCase())

    var light_loss = parseFloat($("#LightLoss").val()).toPrecision(3)
    var optimum_height = _optimum_height
    
    $('#History_lateralType').html('Type '+lateral_type)
    $('#History_verticalType').html(vertical_type)
    $('#History_lightLoss').html(light_loss)
    $('#History_optimumHeight').html((0+optimum_height).toPrecision(3)+'ft ('+(optimum_height / 3.2808399).toPrecision(3)+'m)')
    $('#History_desiredHeight').html((0+_desired_height).toPrecision(3)+'ft ('+(_desired_height / 3.2808399).toPrecision(3)+'m)')
    
    $('#Summary_lateralType').html('Type '+lateral_type)
    $('#Summary_verticalType').html(vertical_type)
    $('#Summary_lightLoss').html(light_loss)
    $('#Summary_optimumHeightFT').html((0+optimum_height).toPrecision(3)+' feet')
    $('#Summary_optimumHeightM').html((optimum_height / 3.2808399).toPrecision(3)+' meters')
    $('#Summary_desiredHeightFT').html((0+_desired_height).toPrecision(3)+' feet')
    $('#Summary_desiredHeightM').html((_desired_height / 3.2808399).toPrecision(3)+' meters')
  }


  var ies_file_chosen = function(changed_input_el, type) {
    _ies = null
    _ies_file_type = type
    reset_steps_after_active_one()
  
    $('.step.active .nextStep').fadeTo(400, 1).removeClass('disabled')
    $('.nav li:contains(Step 2)').nextAll().find('a').addClass('disabled')

    if(changed_input_el == $('#UploadedIESFile')[0]) {
      $('#UserUploadedIESFile').attr('checked', true)
      Mutex.update()
      $('#UploadedIESFile').next().addClass('active')
    }
  }


  var _recalculate_timeout = null
  
  var recalculate_current_step = function() {
    clearTimeout(_recalculate_timeout)
    
    _recalculate_timeout = setTimeout(function() {
      var active_step = $('.step.active')
      if(active_step.is(':has(table.hidden)') || !active_step.is(':has(table)')) return

      active_step.find('.nextStep').stop().css('opacity', .3).addClass('disabled')

      reset_steps_after_active_one()
      calculate_step(_step_index)
    }, 500)
  }


  var calculate_step = function(step_number) {
    // Reset a potentially queued up request to recalculate since we're going to calculate the step immediately
    clearTimeout(_recalculate_timeout)

    var active_step = $('.step.active')
    active_step.find('#IlluminancePlane:visible').hide()
    active_step.find('table.results').addClass('hidden')
    active_step.find('.spinner').show()

    var light_loss = parseFloat($("#LightLoss").val())
    
    setTimeout(function() {
      if(step_number == 2)      step2_calculation(_ies)
      else if(step_number == 3) step3_calculation(_ies, light_loss)
      else if(step_number == 4) step4_calculation(_ies, light_loss)
      else if(step_number == 5) step5_calculation()
      else if(step_number == 6) step6_calculation()      
      else show_active_results()
    }, 0)
  }


  var show_active_results = function(quickly) {
    var active_step = $('.step.active')

    active_step.find('.nextStep').stop().fadeTo(400, 1, function() {
      active_step.find('.spinner').hide()    
      active_step.find('table.results').removeClass('hidden')
    }).removeClass('disabled')
  }


  var full_screen = function(enter_full_screen) {
    if($('body :visible:animated').size()) return

    var transition_time = (enter_full_screen ? 800 : 1200)
    var calculator_el = $('#Calculator')
    var active_step = $('.step.active')
    var is_ie6 = ($.browser.msie && $.browser.version == '6.0')
    var default_header_margin = (is_ie6 ? 277 : 280)
    var default_logo_margin = (is_ie6 ? 15 : 30)

    active_step.find('.printerFriendlyVersionButton').toggleClass('hidden', enter_full_screen)
    active_step.find('.returnToCalculatorButton').toggleClass('hidden', !enter_full_screen)
    $('#Summary #IlluminancePlane:visible').hide()

    $('.header').animate({
      marginTop: (enter_full_screen ? '-60px' : '20px'),
      marginLeft: (enter_full_screen ? '140px' : default_header_margin+'px'),
      opacity: (enter_full_screen ? 0 : 1)
    }, {duration: transition_time})

    active_step.animate({
      marginLeft: (enter_full_screen ? '140px' : default_header_margin+'px')
    }, {duration: transition_time})

    $('body').toggleClass('fullscreen', enter_full_screen).animate({
      backgroundColor: (enter_full_screen ? '#EAEAEA' : '#CCC')
    }, transition_time, 'linear')

    if(enter_full_screen) {
      $('#LRCLogo, .aside').css({
        marginLeft: '-2000px'
      })
    }
    else {
      setTimeout(function() {
        $('#LRCLogo').animate({marginLeft: default_logo_margin+'px'}, {duration: 400})
        setTimeout(function() {                  
          $('.aside').animate({marginLeft: '0'}, {duration: 400})
        }, 200)
      }, transition_time)
    }
  
    setTimeout(function() {
      move_illuminance_plane_to_step('Summary')
    }, (enter_full_screen ? 1000 : 2000))
  }


  var move_illuminance_plane_to_step = function(destination_step_id) {
    var illuminance_plane = $('#IlluminancePlane')

    if(!$('#'+destination_step_id).is(':has("#IlluminancePlane")'))
      $('#'+destination_step_id+'.active .illuminancePlaneContainer').append(illuminance_plane)

    if(illuminance_plane.is(':hidden')) illuminance_plane.show()
  }


  var reset = function() {
    if(confirm('Are you sure you want to reset the calculator?\n\nAll of your calculations will be lost!\n')) 
      window.location.href = '?reset'
  }


  /***************
  PRIVATE FUNCTIONS
  ***************/
  var setup = function() {
    // If '?reset' is in the URL then start on Step 1
    if(window.location.href.indexOf('?reset') != -1) show_step(1)

    // Reset all forms so nothing persists when page is refresh
    $('form').each(function() {
      this.reset()
    })

    // Keep all forms from actually submitting
    $('form.noSubmit').bind('submit', function(e) { e.preventDefault() }) 

    // Fade in/out #LRCLogo on hover
    $('#LRCLogo a').css('opacity', 0).bind('mouseover', function() {
      $(this).fadeTo('fast', 1)
    }).bind('mouseout', function() {
      $(this).fadeTo('fast', 0)
    })

    // Setup the sliders
    new SliderWithInput('LightLoss', {value: 1})
    new SliderWithInput('DesiredHeight', {use_ints: true, value: 15, min: 1, unit: 'ft'})
    new SliderWithInput('LifeCycleYearsToConsider', {use_ints: true, min: 1, max: 50, value: 30, unit: 'yr'})
    new SliderWithInput('LightLevelAdjustBase', {value: .65, min: 0, max: 5})
    new SliderWithInput('LightLevelAdjustReflectance', {use_ints: true, value: 7, unit: '%'})
    new SliderWithInput('LightLevelAdjustAlternative', {value: 2.15, min: 0, max: 5})

    // Make changing any input set the dirty bit on the step it belongs to
    $('.step').not('#Step1').find('input').not('.doNotRecalculate').change(recalculate_current_step)    
  }
  $(document).ready(setup)
  
  // Request Google Visualization API and keep track of it's readiness state
  google.load("visualization", "1", {packages:["scatterchart"]})
  google.setOnLoadCallback(function() {
    _google_visualization_ready = true
  })


  var enable_step = function(step_index) {
    $('.nav a:eq('+step_index+')').removeClass('disabled')
  }


  var reset_steps_after_active_one = function() {
    if($('.step.active').is('#Step6')) return
    
    // For all the steps that follow this one…
    var next_steps = $('.step.active').nextAll().not('#Summary')

    // …make sure the .proceed buttons become invisible and disabled
    next_steps.find('.nextStep').css('opacity', .3).addClass('disabled')

    // …hide the .results tables
    next_steps.find('table.results').addClass('hidden')

    // …disable the link to them in the nav
    $('.nav li:has(.active)').nextAll().find('a').addClass('disabled')
  }


  
  /*  Illuminance Calculations  */
  
  var _lpf = 10.764 // lux per foot-candle
  var _mpf = 0.3048 // meters per foot

  var _cell_size = 2.5 * _mpf // meters
  var _cell_area = _cell_size * _cell_size // m^2
  
  
  // BUG ratings
  var BUG_Ratings = {
    'backlight': {
      BH: {110: 0, 500: 1, 1000: 2, 2500: 3, 5000: 4, Infinity: 5},
      BM: {220: 0, 1000: 1, 2500: 2, 5000: 3, 8500: 4, Infinity: 5},
      BL: {110: 0, 500: 1, 1000: 2, 2500: 3, 5000: 4, Infinity: 5}
    },
    
    'uplight': {
      UH: {0: 0, 10: 1, 100: 2, 500: 3, 1000: 4, Infinity: 5},
      UL: {0: 0, 10: 1, 100: 2, 500: 3, 1000: 4, Infinity: 5},
      FVH: {10: 0, 75: 1, 150: 2, Infinity: 3},
      BVH: {10: 0, 75: 1, 150: 2, Infinity: 3}
    },
    
    'glare_type1-4': {
      FVH: {10: 0, 250: 1, 375: 2, 500: 3, 750: 4, Infinity: 5},
      BVH: {10: 0, 250: 1, 375: 2, 500: 3, 750: 4, Infinity: 5},
      FH: {660: 0, 1800: 1, 5000: 2, 7500: 3, 12000: 4, Infinity: 5},
      BH: {110: 0, 500: 1, 1000: 2, 2500: 3, 5000: 4, Infinity: 5}
    },
    
    'glare_type5': {
      FVH: {10: 0, 250: 1, 375: 2, 500: 3, 750: 4, Infinity: 5},
      BVH: {10: 0, 250: 1, 375: 2, 500: 3, 750: 4, Infinity: 5},
      FH: {660: 0, 1800: 1, 5000: 2, 7500: 3, 12000: 4, Infinity: 5},
      BH: {660: 0, 1800: 1, 5000: 2, 7500: 3, 12000: 4, Infinity: 5}
    }
  }
  
  // Calculate a single BUG rating
  var single_bug_rating = function(lumens, zone, angle) {
    var rating = 0
    
    for(var max_lum in BUG_Ratings[zone][angle]) {
      rating = BUG_Ratings[zone][angle][max_lum]
      if(lumens <= max_lum) break
    }
    
    return rating
  }
  
  
  // Dimensions of the task plane, in feet
  var _centered_types = {'type1': true, 'type5': true}
  var _x_dimensions = {'very_short': 1, 'short': 2.25, 'medium': 3.75, 'long': 6}
  var _y_dimensions = {'type1': 1, 'type2': 1.75, 'type3': 2.75, 'type4': 6, 'type5': 1.75}
  
  var task_plane_dimension = function(direction, no_resize) {
    var dim_y = _y_dimensions[_lateral_type]
    var dim_x = _x_dimensions[_vertical_type]
    
    if(_num_luminaires == 4 && !no_resize) {
      dim_y = Math.max(dim_y, dim_x)
      dim_x = dim_y
    }
    
    return (direction == 'x') ? dim_x : dim_y
  }
  
  
  // Get the lateral and vertical distribution types
  _vertical_type = 'very_short'
  _lateral_type = 'type1'
  
  var calculate_distrubution_types = function() {
    
    // Check to see if it is type5
    var is_type5 = check_for_type5()
    
    var resolution =  .05 // times the height
    
    // First, find the x,y coordinates of maximum candelas
    var maximum = _ies.maximum_candelas()
    
    var tan2_ha = Math.pow(Math.tan(maximum.hangle / 57.2957795), 2)
    var tan2_va = Math.pow(Math.tan(maximum.vangle / 57.2957795), 2)
    
    var max_y = Math.sqrt(tan2_va / (1 + tan2_ha))
    var half_max_candelas = maximum.candelas / 2
    
    // Next find the largest y that contains a point with half the candelas
    var target_y = 0
    var found = false
    var candelas = 0
    
    for(y = max_y; y < 6; y += resolution) {
      found = false
      for(x = 0; x < 10; x += resolution) {
        candelas = _ies.candelas_on_plane(1, x, y)
        if(candelas >= half_max_candelas) {target_y = y; found = true; break}
      }
      if(!found) break;
    }
    
    // Next find the largest negative-y that contains a point with half the candelas
    var target_ny = 0
    
    for(y = -1*max_y; y > -6; y -= resolution) {
      found = false
      for(x = 0; x < 10; x += resolution) {
        candelas = _ies.candelas_on_plane(1, x, y)
        if(candelas >= half_max_candelas) {target_ny = y; found = true; break}
      }
      if(!found) break;
    }
    
    // Next find the x with the maximum candela value
    var target_x = 0
    var max_candelas = 0
        
    for(x = .95; x < 3.6; x += resolution) {
      found = false
      for(y = 0; y < 6; y += resolution) {
        candelas = _ies.candelas_on_plane(1, x, y)
        if(candelas >= max_candelas) {
          target_x = x
          max_candelas = candelas
        }
      }
    }
    
    // Convert point to distribution types
    if(target_x > 3.5)        _vertical_type = 'long'
    else if(target_x > 2.25)  _vertical_type = 'medium'
    else if(target_x > 1)     _vertical_type = 'short'
    else                      _vertical_type = 'very_short'
    
    if(!is_type5) {
      if(target_y > 2.75)       _lateral_type = 'type4'
      else if(target_y > 1.75)  _lateral_type = 'type3'
      else if(target_y > 1)     _lateral_type = 'type2'
      else                      _lateral_type = 'type1'
    }
    
    $('#VerticalType').val(_vertical_type)
    $('#LateralType').val(_lateral_type)
  }
  
  
  var check_for_type5 = function() {
    
    var found = function() {
      _lateral_type = 'type5'
      return true
    }
    
    // If there is only one horizontal angle
    if(_ies.horizontal_angles.length == 1) return found()
    
    // If the range of angles is 0 to 90
    if(_ies.horizontal_angles[_ies.horizontal_angles.length-1] == 90) return found()
    
    // Split horizontal angles into groups of 90 degrees
    var angle_buckets = [[]]
    var bucket_i = 0
    for(var i = 1; i < _ies.horizontal_angles.length; i++) {
      if(_ies.horizontal_angles[i] > 90*(bucket_i+1)) {
        bucket_i += 1
        angle_buckets[bucket_i] = []
      }
      angle_buckets[bucket_i].push(_ies.horizontal_angles[i])
    }
    
    // If the buckets aren't all the same length, then it can't be type5
    angle_bucket_length = angle_buckets[0].length
    for(var bucket_i = 0; bucket_i < angle_buckets.length; bucket_i++) {
      if(angle_buckets[bucket_i].length != angle_bucket_length) return false
    }
    
    // Compare the candelas at each angle in the buckets to see if they're the same
    var hi, hi2, candelas, error
    var max_error = .75
    
    for(var i = 0; i < angle_buckets[0].length; i++) {      
      hi = i + 1
      
      for(var vi = 0; vi < _ies.candelas[hi].length; vi++) {
        candelas = _ies.candelas[hi][vi]
        
        for(var bucket_i = 1; bucket_i < angle_buckets.length; bucket_i++) {
          hi2 = hi + angle_buckets[0].length
          if(!_ies.candelas[hi2]) return false
          
          var error = Math.abs((_ies.candelas[hi2][vi] - candelas) / ((_ies.candelas[hi2][vi] + candelas) / 2))
          if(error > max_error) return false
        }
      }
    }
        
    return found()
  }
  
  
  var _illuminance_range = [0.2*_lpf, 4*_lpf]
  
  var set_illuniance_criteria_inputs = function(type) {
    var old_min = _illuminance_range[0]
    var old_max = _illuminance_range[1]
    
    if(type == 'basic') {
      $('#IlluminanceRangeMin').val(0.2)
      $('#IlluminanceRangeMax').val(4)
      _illuminance_range = [0.2*_lpf, 4*_lpf]
      
    } else if(type == 'enhanced_security') {
        $('#IlluminanceRangeMin').val(0.5)
        $('#IlluminanceRangeMax').val(7.5)
        _illuminance_range = [0.5*_lpf, 7.5*_lpf]
    
    } else if(type == 'custom') {
        $('#IlluminanceRangeSelect').val('custom')
        
        var min = parseFloat($('#IlluminanceRangeMin').val()) || 0.2
        min = Math.max(0.1, Math.min(10, min))
        
        var max = parseFloat($('#IlluminanceRangeMax').val()) || 4
        max = Math.max(0.1, Math.min(20, max))
        
        $('#IlluminanceRangeMin').val(min)
        $('#IlluminanceRangeMax').val(max)
        _illuminance_range = [min*_lpf, max*_lpf]
    }
    
    $('#History_illuminanceCriteria').html($('#IlluminanceRangeMin').val()+' fc to '+$('#IlluminanceRangeMax').val()+' fc')
    $('#Summary_illuminanceCriteria').html($('#IlluminanceRangeMin').val()+' fc to '+$('#IlluminanceRangeMax').val()+' fc')
    
    if(_illuminance_range[0] != old_min || _illuminance_range[1] != old_max)
      recalculate_current_step()
  }
  
  
  var application_efficacy = function(ies, height, light_loss) {
    if(height == 0) return 0;
    
    var yf = height * task_plane_dimension('y')
    var yi = (_centered_types[_lateral_type]) ? -1 * yf : 0
    
    if(_lateral_type == 'type5') {
      var xf = yf
      var xi = yi
    } else {
      var xf = height * task_plane_dimension('x')
      var xi = -1 * xf
    }
    
    // We can forgo half or 3/4 of the coverage area if we've got multiple luminaires
    if(_num_luminaires == 2) {
      yi = 0
    } else if(_num_luminaires == 4) {
      yi = xi = 0
      var min_dim = Math.min(height * _y_dimensions[_lateral_type], height * _x_dimensions[_vertical_type])
    }
        
    // Loop through each cell and determine illuminance and conformance
    
    var n = 0 // Total number of cells
    var nc = 0 // Number of conforming cells
    var luminous_flux_conforming = 0
    var tmp_illum = 0
    
    var x_start = xi + _cell_size/2
    var y_start = yi + _cell_size/2
    var x_end = xf + _cell_size/2
    var y_end = yf + _cell_size/2
    
    // The calculation for a single luminaire per pole is simpler than with multiple
    if(_num_luminaires == 1) {
      for(var x = x_start; x <= x_end; x += _cell_size) {
        for(var y = y_start; y <= y_end; y += _cell_size) {
          tmp_illum = light_loss * _ies.illuminance_on_plane(height, x, y)
          n += 1
          if(tmp_illum >= _illuminance_range[0] && tmp_illum <= _illuminance_range[1]) {
            nc += 1
            luminous_flux_conforming += tmp_illum * _cell_area
          }
        }
      }
    
    // Multiple luminaires per pole
    } else {      
      for(var x = x_start; x <= x_end; x += _cell_size) {
        for(var y = y_start; y <= y_end; y += _cell_size) {
          
          // If there are four luminaires, make sure we're inside the cross formed by the four intersecting regions
          if(_num_luminaires == 4 && Math.abs(x) > min_dim && Math.abs(y) > min_dim) continue
          
          tmp_illum = _ies.illuminance_on_plane(height, x, y) + _ies.illuminance_on_plane(height, -1*x, -1*y)
          
          if(_num_luminaires == 4) {
            tmp_illum += _ies.illuminance_on_plane(height, -1*y, x) + _ies.illuminance_on_plane(height, y, -1*x)
          }
          
          tmp_illum *= light_loss

          n += 1
          if(tmp_illum >= _illuminance_range[0] && tmp_illum <= _illuminance_range[1]) {
            nc += 1
            luminous_flux_conforming += tmp_illum * _cell_area
          }
        }
      }
    }
    
    var lsae = luminous_flux_conforming * (nc / n) / _watts
    return lsae
  }
  
  
  
  var step2_calculation = function(ies) {
    
    $('#PhotometryType').html(ies.absolute_photometry ? 'absolute' : 'relative')
    $('#InputPower').val(_watts)
    $('#CandelaMultiplier').val(_candela_multiplier)
    
    
    var angle_size = 2.5
    var half_angle_size = angle_size / 2
    var solid_angle = Math.pow(angle_size / 360, 2) * 4 * Math.pow(Math.PI, 2) * (4 / Math.PI)
    
    var lumens_in_angle = function(vi, vf, hi, hf) {      
      var lumens = 0

      for(var va = vi+half_angle_size; va <= vf; va += angle_size) {
        for(var ha = hi+half_angle_size; ha <= hf; ha += angle_size) {
          lumens += Math.sin(va / 57.2957795) * solid_angle * ies.candelas_at_angle(va, ha)
        }
      }
      
      return lumens
    }    
    
    
	  var lumens_fl, lumens_fm, lumens_fh, lumens_fvh
	  var lumens_bl, lumens_bm, lumens_bh, lumens_bvh
	  var lumens_ul, lumens_uh
	  
    var front_total = 0
    var back_total = 0
    var up_total = 0
    
    
    // Front Low
    var calc_front_low = function() {
      lumens_fl = lumens_in_angle(0, 30, -90, 90)
      front_total += lumens_fl
      setTimeout(calc_front_medium, 0)
    }
    
    // Front Medium
    var calc_front_medium = function() {
      lumens_fm = lumens_in_angle(30, 60, -90, 90)
      front_total += lumens_fm
      setTimeout(calc_front_high, 0)
    }
    
    // Front High
    var calc_front_high = function() {
      lumens_fh = lumens_in_angle(60, 80, -90, 90)
      front_total += lumens_fh
      setTimeout(calc_front_very_high, 0)
    }
    
    // Front Very High
    var calc_front_very_high = function() {
      lumens_fvh = lumens_in_angle(80, 90, -90, 90)
      front_total += lumens_fvh
      setTimeout(calc_back_low, 0)
    }
    
    
    // Back Low
    var calc_back_low = function() {
      lumens_bl = lumens_in_angle(0, 30, 90, 270)
      back_total += lumens_bl
      setTimeout(calc_back_medium, 0)
    }
    
    // Back Medium
    var calc_back_medium = function() {
      lumens_bm = lumens_in_angle(30, 60, 90, 270)
      back_total += lumens_bm
      setTimeout(calc_back_high, 0)
    }
    
    // Back High
    var calc_back_high = function() {
      lumens_bh = lumens_in_angle(60, 80, 90, 270)
      back_total += lumens_bh
      setTimeout(calc_back_very_high, 0)
    }
    
    // Back Very High
    var calc_back_very_high = function() {
      lumens_bvh = lumens_in_angle(80, 90, 90, 270)
      back_total += lumens_bvh
      setTimeout(calc_up_low, 0)
    }
    
    
    // Up Low
    var calc_up_low = function() {
      lumens_ul = lumens_in_angle(90, 100, 0, 360)
      up_total += lumens_ul
      setTimeout(calc_up_high, 0)
    }
    
    // Up High
    var calc_up_high = function() {
      lumens_uh = lumens_in_angle(100, 180, 0, 360)
      up_total += lumens_uh
      setTimeout(finished, 0)
    }
    
        
    var finished = function() {      
      var total_lumens = front_total + back_total + up_total
      
      var bug_backlight = 'B'+Math.max(
        single_bug_rating(lumens_bh, 'backlight', 'BH'),
        single_bug_rating(lumens_bm, 'backlight', 'BM'),
        single_bug_rating(lumens_bl, 'backlight', 'BL')
      )
      
      var bug_uplight = 'U'+Math.max(
        single_bug_rating(lumens_uh, 'uplight', 'UH'),
        single_bug_rating(lumens_ul, 'uplight', 'UL'),
        single_bug_rating(lumens_fvh, 'uplight', 'FVH'),
        single_bug_rating(lumens_bvh, 'uplight', 'BVH')
      )
      
      var glare_zone = (_lateral_type == 'type5') ? 'glare_type5' : 'glare_type1-4'
      var bug_glare = 'G'+Math.max(
        single_bug_rating(lumens_fvh, glare_zone, 'FVH'),
        single_bug_rating(lumens_bvh, glare_zone, 'BVH'),
        single_bug_rating(lumens_fh, glare_zone, 'FH'),
        single_bug_rating(lumens_bh, glare_zone, 'BH')
      )
      
      
      $('#BUGRating').html(bug_backlight + ' ' + bug_uplight + ' ' + bug_glare)
      
      $('#LCS_FTotal').html((100 * front_total / total_lumens).toPrecision(3)+'%')
      $('#LCS_BTotal').html((100 * back_total / total_lumens).toPrecision(3)+'%')
      $('#LCS_UTotal').html((100 * up_total / total_lumens).toPrecision(3)+'%')
      
      $('#LCS_FL').html((100 * lumens_fl / total_lumens).toPrecision(3)+'%')
      $('#LCS_FM').html((100 * lumens_fm / total_lumens).toPrecision(3)+'%')
      $('#LCS_FH').html((100 * lumens_fh / total_lumens).toPrecision(3)+'%')
      $('#LCS_FVH').html((100 * lumens_fvh / total_lumens).toPrecision(3)+'%')
      $('#LCS_BL').html((100 * lumens_bl / total_lumens).toPrecision(3)+'%')
      $('#LCS_BM').html((100 * lumens_bm / total_lumens).toPrecision(3)+'%')
      $('#LCS_BH').html((100 * lumens_bh / total_lumens).toPrecision(3)+'%')
      $('#LCS_BVH').html((100 * lumens_bvh / total_lumens).toPrecision(3)+'%')
      $('#LCS_UL').html((100 * lumens_ul / total_lumens).toPrecision(3)+'%')
      $('#LCS_UH').html((100 * lumens_uh / total_lumens).toPrecision(3)+'%')
		  
      show_active_results()
    }
    
    
    calc_front_low()
  }
  
  
  var step3_calculation = function(ies, light_loss) {
    var points = []
    
    var max_height = 0
    var max_lsae = 0
    var height = 0
    var height_limit = 0
    
    var efficacy_step = function() {
      var tmp_height = (typeof height == 'object') ? height.pop() : height
      var lsae = application_efficacy(ies, (tmp_height / 3.2808399), light_loss)
      points.push([tmp_height, lsae])
      
      if(lsae > max_lsae) {
        max_lsae = lsae
        max_height = tmp_height
      }
      
      // If we're done, update the data
      var percent_of_max = (_num_luminaires == 1) ? 0.6 : 0.75
      if(tmp_height >= 100 || (tmp_height > 10 && lsae < (percent_of_max * max_lsae)) || (typeof height == 'object')) {
        
        // Search on either side of the maximum for a more detailed value
        if(typeof height != 'object') {
          height = [max_height - 5, max_height + 5]
          
        // Or finish up
        } else if(height.length == 0) {
          _optimum_height = max_height
          height_limit = Math.min(45, Math.ceil(1.5 * max_height))
          if(height_limit >= 30) height_limit = 45
          return step3_finished(points, max_lsae, max_height, height_limit)
        }
      
      } else {
        height += (_num_luminaires == 1) ? 5 : 10
      }
      
      setTimeout(efficacy_step, 0)
    }
    
    efficacy_step()
  }
  
  
  var step3_finished = function(points, max_lsae, max_height, height_limit) {
    points.sort(function(a, b){return a[0] - b[0]})
    
    // If the Google Visualization API isn't ready, set the 
    // function as a callback to google.setOnLoadCallback()
    if(_google_visualization_ready)
      draw_efficacy_chart(points)
    else
      google.setOnLoadCallback(function() { draw_efficacy_chart(points) })

    var max_meters = max_height / 3.2808399
    
    $('#Result_OptimumPoleHeight').html(max_height.toPrecision(3)+' feet <em>('+max_meters.toPrecision(3)+' meters)</em>')
    $('#Result_ApplicationEfficacyOptimum').html(max_lsae.toPrecision(3)+' lm/W')
    $('#Summary_lsaeAtOptimumHeight').html(max_lsae.toPrecision(3)+' lm/W')
    
    // Set this height as the max height that's choosable
    $('#DesiredHeightSlider').slider('option', 'max', height_limit)
    
    show_active_results()
  }

  
  var draw_efficacy_chart = function(points) {
    var data = new google.visualization.DataTable()
    data.addColumn('number', 'Height')
    data.addColumn('number', 'Efficacy')
    data.addRows(points.length)
    
    for(var i=0; i < points.length; i++) {
      data.setValue(i, 0, points[i][0])
      data.setValue(i, 1, points[i][1])
    }
    
    $('.efficacyAtHeights').html('')
    var chart = new google.visualization.ScatterChart($('#Step3 .efficacyAtHeights')[0])
    chart.draw(data, {width: 490, height: 240, titleX: 'Mounting Height (ft)', titleY: ' ', legend: 'none', pointSize: 0, lineSize: 2, backgroundColor: '#EAEAEA'})

    // 2nd one created into summary
    var chart = new google.visualization.ScatterChart($('#Summary .efficacyAtHeights')[0])
    chart.draw(data, {width: 490, height: 240, titleX: 'Mounting Height (ft)', titleY: ' ', legend: 'none', pointSize: 0, lineSize: 2, backgroundColor: '#EAEAEA'})
  }
  
  
  var step4_calculation = function(ies, light_loss) {
    _lsae = null; _longitudinal_spacing = null; _transversal_spacing = null; _average_lux = null
    
    _desired_height = parseFloat($("#DesiredHeight").val())
    
    draw_task_plane(ies, (_desired_height / 3.2808399), light_loss)
    calculate_spacing(ies, (_desired_height / 3.2808399), light_loss)
    
    _lsae = application_efficacy(ies, (_desired_height / 3.2808399), light_loss)
    
    $('#Result_ApplicationEfficacy').html(_lsae.toPrecision(3)+' lm/W')
    $('#Summary_lsae').html(_lsae.toPrecision(3)+' lm/W')
        
    step4_show_results()
  }
  
  
  var step4_show_results = function() {
    if(!_lsae || !_longitudinal_spacing || !_transversal_spacing || !_average_lux || !_luminance_plane_complete) return;
    show_active_results()
  }
  

  var draw_task_plane = function(ies, height, light_loss) {
    _luminance_plane_complete = false
    var containers = $('.illuminancePlaneContainer')
    var illuminance_plane = $('#IlluminancePlane').empty().hide()
    
    // Determine task plane and container dimensions
    var size_multiple = 1.1
    
    var yf = size_multiple * height * task_plane_dimension('y')
    var yi = -1 * yf
    
    if(_lateral_type == 'type5') {
      var xf = yf
      var xi = yi
    } else {
      var xf = size_multiple * height * task_plane_dimension('x')
      var xi = -1 * xf
    }
    
    var extra_num_x = extra_num_y = false
    
    var num_x = Math.round((xf - xi) / _cell_size)
    if(num_x % 2) {
      extra_num_x = true
      num_x += 1
    }
    
    var num_y = Math.round((yf - yi) / _cell_size)
    if(num_y % 2) {
      num_y += 1
      extra_num_y = true
    }
    
    var max_container_width = 490
    var box_size = Math.round(max_container_width / num_x)
    var container_width = (box_size*num_x)
    var container_height = (box_size*num_y)
    
    containers.width(container_width).height(container_height)
    

    // Loop through each cell on the task plane to determine illuminance and conformance
    // And draw the brightness chart
    
    var top = 0
    var left = 0
    var lux_x = 0
    var lux_y = 0
    var x = -1 * _cell_size
    
    var box = document.createElement('div')
  	box.className = 'box'
  	box.style.borderWidth = box_size+'px '+box_size+'px 0 0'
  	var new_box = null
  	var color, percent_of_max, tmp_illum
  	
  	var x_final = num_x
	  var y_final = num_y
  	
  	if(_num_luminaires == 2) {
    	y_final /= 2
  	} else if(_num_luminaires == 4) {
  	  x_final /= 2
  	  y_final /= 2
  	}
  	
  	
  	var draw_single_box = function(top, left, color) {
  	  new_box = box.cloneNode(false)
			new_box.style.top = top+'px'
			new_box.style.left = left+'px'
			new_box.style.borderColor = color
			illuminance_plane.append(new_box)
  	}
  	
  	
    var draw = function() {
      left = (x * box_size)
      
      for(var y = 0; y <= y_final; y++) {
        top = (y * box_size)
        
        lux_x = xi + (x*_cell_size) + _cell_size/2
        lux_y = yi + (y*_cell_size) + _cell_size/2
        tmp_illum = light_loss * _ies.illuminance_on_plane(height, lux_x, lux_y)
        
        // Add additional illumination, if there are more than one luminaires
        if(_num_luminaires > 1) {
          tmp_illum += light_loss * _ies.illuminance_on_plane(height, -1*lux_x, -1*lux_y)
          if(_num_luminaires == 4) {
            tmp_illum += light_loss * _ies.illuminance_on_plane(height, -1*lux_y, lux_x)
            tmp_illum += light_loss * _ies.illuminance_on_plane(height, lux_y, -1*lux_x)
          }
        }
                
        percent_of_max = tmp_illum / _illuminance_range[1]
        
        if(_show_conforming_cells) {
          if(tmp_illum >= _illuminance_range[0] && tmp_illum <= _illuminance_range[1]) {
            color = '#DDD'
          } else {
            color = '#000'
          }
          
        } else {
          color = Math.round(Math.min(255, 1.5 * 255 * percent_of_max))
          color = 'rgb('+color+','+color+','+color+')'
        }
        
  			draw_single_box(top, left, color)
  			
  			if(_num_luminaires > 1) {
          draw_single_box((num_y - y) * box_size, left, color)
          if(_num_luminaires == 4) {
            draw_single_box(top, (num_x - x) * box_size, color)
            draw_single_box((num_y - y) * box_size, (num_x - x) * box_size, color)
          }
        }
        
      }
      
      if(x <= x_final) {
        x += 1
        setTimeout(draw, 0)
        
      } else {
        
        // Draw task plane outlines
        var task_plane_width = 2 * box_size * height * task_plane_dimension('x', true) / _cell_size
        var task_plane_height = 2 * box_size * height * task_plane_dimension('y', true) / _cell_size
        var task_plane_left = (container_width - task_plane_width) / 2
        if(extra_num_x) task_plane_left += box_size
        
        if(_centered_types[_lateral_type]) {
          var task_plane_top = (container_height - task_plane_height) / 2
        } else {  
          task_plane_height /= 2
          var task_plane_top = container_height / 2
        }
        if(extra_num_y) task_plane_top += box_size
                
        var task_plane1 = document.createElement('div')
        task_plane1.className = 'outline'
        task_plane1.style.width = task_plane_width + 'px'
        task_plane1.style.height = task_plane_height + 'px'
        task_plane1.style.top = task_plane_top + 'px'
        task_plane1.style.left = (task_plane_left - (extra_num_x ? box_size : 0)) + 'px'
        illuminance_plane.append(task_plane1)
        
        if(_num_luminaires > 1) {
          var task_plane2 = task_plane1.cloneNode(true)
          task_plane2.style.borderBottom = '0px solid #41529A'
          task_plane2.style.top = (task_plane_top - task_plane_height) + 'px'
          illuminance_plane.append(task_plane2)
        }
        
        if(_num_luminaires == 4) {
          var task_plane3 = task_plane1.cloneNode(true)
          task_plane3.style.width = task_plane_height + 'px'
          task_plane3.style.height = task_plane_width + 'px'
          task_plane3.style.top = (task_plane_top - task_plane_width/2) + 'px'
          task_plane3.style.left = (container_width/2 - task_plane_height) + 'px'
          illuminance_plane.append(task_plane3)
          
          var task_plane4 = task_plane3.cloneNode(true)
          task_plane4.style.borderLeft= '0px solid #41529A'
          task_plane4.style.left = (container_width/2) + 'px'
          illuminance_plane.append(task_plane4)
        }
        
        illuminance_plane.show()
        
        _luminance_plane_complete = true
        step4_show_results()        
      }
    }; draw()
    
  }
  
  
  var calculate_spacing = function(ies, height, light_loss) {
    var yf = 5 * height * task_plane_dimension('y')
    var xf = 10 * height * task_plane_dimension('x') // the x-dimension is always symetrical, so we don't need to search both sides
    
    var initial_target_fc = 0.05*_lpf
    var final_target_fc = 0.1*_lpf
    
    var tmp_illum = 0
    var total_illum = 0
    var num_cells = 0
    
    var initial_xf = null
    var initial_yi = null
    var initial_yf = null
    var final_xf = null
    var final_yi = null
    var final_yf = null
    
    var x, y, bmin, bmax, blast, found
    
    
    // Find initial xf spacing
    var find_initial_xf = function() {
      found = false
      
      for(y = 0; y <= yf; y += _cell_size) {
        // if the cell has an illuminance value of at least 0.1fc, we've found our spacing
        tmp_illum = _ies.illuminance_on_plane(height, x, y)
        if(_num_luminaires >= 2) tmp_illum += _ies.illuminance_on_plane(height, -1*x, -1*y)
        if(_num_luminaires == 4) {
          tmp_illum += _ies.illuminance_on_plane(height, -1*y, x) + _ies.illuminance_on_plane(height, y, -1*x)
        }
        tmp_illum *= light_loss
        
        if(tmp_illum >= initial_target_fc) {found = true; break}
      }
      
      // Are we done?
      if(x == blast) {
        
        initial_xf = x
        
        // If there is more than one luminaire, initial_yi is the same as initial_yf,
        // so we don't need to calculate it
        if(_num_luminaires > 1) {
          y = yf; blast = 0; bmin = 0; bmax = yf
          find_initial_yf()
          
        } else {
          y = -1*yf; blast = 0; bmin = 0; bmax = -1*yf
          find_initial_yi()
        }
        
                
      } else {  
        blast = x
        
        if(found) {
          bmin = x
          x += (bmax - x) / 2
        } else {
          bmax = x
          x -= (x - bmin) / 2
        }
        x = Math.round(x / _cell_size) * _cell_size
        
        setTimeout(find_initial_xf, 0)
      }
      
    }
        
    
    // Find initial yi spacing
    var find_initial_yi = function() {
      found = false
      
      for(x = xf; x > 0; x -= _cell_size) {
        // if the cell has an illuminance value of at least 0.1fc, we've found our spacing        
        tmp_illum = _ies.illuminance_on_plane(height, x, y)
        if(_num_luminaires >= 2) tmp_illum += _ies.illuminance_on_plane(height, -1*x, -1*y)
        if(_num_luminaires == 4) {
          tmp_illum += _ies.illuminance_on_plane(height, -1*y, x) + _ies.illuminance_on_plane(height, y, -1*x)
        }
        tmp_illum *= light_loss
        
        if(tmp_illum >= initial_target_fc) {found = true; break}
      }
      
      // Are we done?
      if(y == blast) {
        initial_yi = y
        y = yf; blast = 0; bmin = 0; bmax = yf
        find_initial_yf()
        
        
      } else {  
        blast = y
        
        if(found) {
          bmin = y
          y -= (y - bmax) / 2
        } else {
          bmax = y
          y += (bmin - y) / 2
        }
        y = Math.round(y / _cell_size) * _cell_size
        
        setTimeout(find_initial_yi, 0)
      }
      
    }


    // Find initial yf spacing
    var find_initial_yf = function() {
      found = false
      
      for(x = xf; x > 0; x -= _cell_size) {
        // if the cell has an illuminance value of at least 0.1fc, we've found our spacing        
        tmp_illum = _ies.illuminance_on_plane(height, x, y)
        if(_num_luminaires >= 2) tmp_illum += _ies.illuminance_on_plane(height, -1*x, -1*y)
        if(_num_luminaires == 4) {
          tmp_illum += _ies.illuminance_on_plane(height, -1*y, x) + _ies.illuminance_on_plane(height, y, -1*x)
        }
        tmp_illum *= light_loss
        
        
        if(tmp_illum >= initial_target_fc) {found = true; break}
      }
      
      // Are we done?
      if(y == blast) {
        initial_yf = y
        if(!initial_yi) initial_yi = 0
        x = initial_xf; find_final_xf()
        
      } else {  
        blast = y
        
        if(found) {
          bmin = y
          y += (bmax - y) / 2
        } else {
          bmax = y
          y -= (y - bmin) / 2
        }
        y = Math.round(y / _cell_size) * _cell_size
        
        setTimeout(find_initial_yf, 0)
      }
      
    }
    
    
    // Find final xf spacing
    var find_final_xf = function() {
      total_illum = 0; num_cells = 0
  
      for(var y = initial_yf; y > initial_yi; y -= _cell_size) {
        tmp_illum = _ies.illuminance_on_plane(height, x, y)
        if(_num_luminaires >= 2) tmp_illum += _ies.illuminance_on_plane(height, -1*x, -1*y)
        if(_num_luminaires == 4) {
          tmp_illum += _ies.illuminance_on_plane(height, -1*y, x) + _ies.illuminance_on_plane(height, y, -1*x)
        }
        tmp_illum *= light_loss
        
        total_illum += tmp_illum
        num_cells += 1
      }
      if(total_illum / num_cells > final_target_fc) final_xf = x;
      
      // Are we done?
      if(final_xf || x <= 0) {
        y = initial_yf; find_final_yf()
        
      } else {
        x -= _cell_size
        setTimeout(find_final_xf, 0)
      }
    }
    
    
    // Find final yf spacing
    var find_final_yf = function() {
      total_illum = 0; num_cells = 0
  
      for(var x = initial_xf; x > 0; x -= _cell_size) {
        tmp_illum = _ies.illuminance_on_plane(height, x, y)
        if(_num_luminaires >= 2) tmp_illum += _ies.illuminance_on_plane(height, -1*x, -1*y)
        if(_num_luminaires == 4) {
          tmp_illum += _ies.illuminance_on_plane(height, -1*y, x) + _ies.illuminance_on_plane(height, y, -1*x)
        }
        tmp_illum *= light_loss
        
        total_illum += tmp_illum
        num_cells += 1
      }
      if(total_illum / num_cells > final_target_fc) final_yf = y;
      
      // Are we done?
      if(final_yf || y <= 0) {
        
        // Don't bother finding final_yi, if the number of luminaires is greater than 1,
        // because it is the same as final_yf
        if(_num_luminaires > 1) {
          final_yi = -1*final_yf
          finish_up()
        } else {
          y = initial_yi; find_final_yi()
        }
        
      } else {
        y -= _cell_size
        setTimeout(find_final_yf, 0)
      }
    }
    
    
    // Find final yi spacing
    var find_final_yi = function() {
      total_illum = 0; num_cells = 0
  
      for(var x = initial_xf; x > 0; x -= _cell_size) {
        tmp_illum = _ies.illuminance_on_plane(height, x, y)
        if(_num_luminaires >= 2) tmp_illum += _ies.illuminance_on_plane(height, -1*x, -1*y)
        if(_num_luminaires == 4) {
          tmp_illum += _ies.illuminance_on_plane(height, -1*y, x) + _ies.illuminance_on_plane(height, y, -1*x)
        }
        tmp_illum *= light_loss
        
        total_illum += tmp_illum
        num_cells += 1
      }
      if(total_illum / num_cells > final_target_fc) final_yi = y;
      
      // Are we done?
      if(final_yi || y >= 0) {
        finish_up()
        
      } else {
        y += _cell_size
        setTimeout(find_final_yi, 0)
      }
    }
    
    
    var finish_up = function() {
      _longitudinal_spacing = 2 * Math.abs(final_xf)
      _transversal_spacing = Math.abs(final_yi) + Math.abs(final_yf)
      
      var power_densityM = _num_luminaires * _watts / (_longitudinal_spacing * _transversal_spacing)
      var power_densityFT = power_densityM / (3.2808399*3.2808399)
      
      $('#Result_longitudinalSpacingFT').html((_longitudinal_spacing * 3.2808399).toPrecision(3)+' feet')
      $('#Result_longitudinalSpacingM').html(_longitudinal_spacing.toPrecision(3)+' meters')
      $('#Result_transversalSpacingFT').html((_transversal_spacing * 3.2808399).toPrecision(3)+' feet')
      $('#Result_transversalSpacingM').html(_transversal_spacing.toPrecision(3)+' meters')
      $('#Result_AveragePowerDensityFT').html(power_densityFT.toPrecision(3)+' W/ft&sup2;')
      $('#Result_AveragePowerDensityM').html(power_densityM.toPrecision(3)+' W/m&sup2;')
      
      $('#Summary_longitudinalSpacingFT').html((_longitudinal_spacing * 3.2808399).toPrecision(3)+' feet')
      $('#Summary_longitudinalSpacingM').html(_longitudinal_spacing.toPrecision(3)+' meters')
      $('#Summary_transversalSpacingFT').html((_transversal_spacing * 3.2808399).toPrecision(3)+' feet')
      $('#Summary_transversalSpacingM').html(_transversal_spacing.toPrecision(3)+' meters')
      $('#Summary_AveragePowerDensityFT').html(power_densityFT.toPrecision(3)+' W/ft&sup2;')
      $('#Summary_AveragePowerDensityM').html(power_densityM.toPrecision(3)+' W/m&sup2;')
      
      calculate_avg_illuminance(ies, height, light_loss)
    }
    
    
    x = xf; blast = 0; bmin = 0; bmax = xf
    find_initial_xf()
  }
  
  
  var calculate_avg_illuminance = function(ies, height, light_loss) {
    var total_lux = 0
    var num_cells = 0
    
    for(var x = _cell_size/2; x <= _longitudinal_spacing / 2; x += _cell_size) {
      for(var y = _cell_size/2; y <= _transversal_spacing; y += _cell_size) {
        total_lux += 2 * light_loss * (_ies.illuminance_on_plane(height, x, y) + _ies.illuminance_on_plane(height, -1*x, -1*y))
        num_cells += 1
      }
    }
    
    _average_lux = total_lux / num_cells
    
    $('#Result_AverageIlluminanceLux').html(_average_lux.toPrecision(3)+' lx')
    $('#Result_AverageIlluminanceFC').html((_average_lux / _lpf).toPrecision(3)+' fc')
    $('#Summary_AverageIlluminanceLux').html(_average_lux.toPrecision(3)+' lx')
    $('#Summary_AverageIlluminanceFC').html((_average_lux / _lpf).toPrecision(3)+' fc')
    
    step4_show_results()
  }
  
  
  var step5_calculation = function() {
    var luminaire_price = parseFloat($('#LifeCycleLuminairePrice').val())
    var installation_cost_per_pole = parseFloat($('#LifeCycleInstallationCost').val())
    var lamp_life_hours = parseFloat($('#LifeCycleLampLife').val())
    var hours_per_day = parseFloat($('#LifeCycleHoursOfOperation').val())
    var replacement_cost = parseFloat($('#LifeCycleReplacementCost').val())
    var electricity_cost = parseFloat($('#LifeCycleElectricityCost').val()) / 100 // $/kWh
    var interest_rate = parseFloat($('#LifeCycleInterestRate').val()) / 100
    var num_years = parseFloat($('#LifeCycleYearsToConsider').val())
    
    var luminaires_per_pole = 2
    
    var initial_cost = luminaires_per_pole * luminaire_price + installation_cost_per_pole
    
    var days_between_replacements = lamp_life_hours / hours_per_day
    var annual_replacement_cost = luminaires_per_pole * replacement_cost * (365/days_between_replacements)
    
    var annual_kilowatt_hours = 365 * hours_per_day * (_watts / 1000)
    var annual_electricity_cost = luminaires_per_pole * electricity_cost * annual_kilowatt_hours
    
    var annual_cost = annual_replacement_cost + annual_electricity_cost
    
    var life_cycle_cost = initial_cost
    for(var t = 1; t <= num_years; t++) {
      life_cycle_cost += annual_cost / Math.pow(1+interest_rate, t)
    }
    
    var area = _transversal_spacing * _longitudinal_spacing
    var avg_cost_m = life_cycle_cost / area
    var avg_cost_ft = avg_cost_m * (_mpf*_mpf)
    
    if(avg_cost_ft < 1) {
      avg_cost_ft = (avg_cost_ft * 100).toPrecision(3) + '&cent;'
    } else {
      avg_cost_ft = '$'+avg_cost_ft.toPrecision(3)
    }
    
    if(avg_cost_m < 1) {
      avg_cost_m = (avg_cost_m * 100).toPrecision(3) + '&cent;'
    } else {
      avg_cost_m = '$'+avg_cost_m.toPrecision(3)
    }
    
    $('#AverageLifeCycleCostFT').html(avg_cost_ft)
    $('#AverageLifeCycleCostM').html(avg_cost_m)
    $('#LifeCycleCostPerPole').html('$'+addCommas(Math.round(life_cycle_cost)))
    
    $('#Summary_luminairePrice').html('$'+addCommas(Math.round(luminaire_price)))
    $('#Summary_installationCostPerPole').html('$'+addCommas(Math.round(installation_cost_per_pole)))
    $('#Summary_lampLifeHours').html(addCommas(Math.round(lamp_life_hours)))
    $('#Summary_hoursPerDay').html(Math.round(hours_per_day))
    $('#Summary_lampReplacementCost').html('$'+addCommas(Math.round(replacement_cost)))
    $('#Summary_electricityCost').html(Math.round(100*electricity_cost)+ '&cent;/kWh')
    $('#Summary_interestRate').html(Math.round(100*interest_rate)+ '%')
    $('#Summary_numYears').html(num_years+' years')
    $('#Summary_lifeCycleCostPerPole').html('$'+addCommas(Math.round(life_cycle_cost)))
    $('#Summary_averageLifeCycleCostFT').html(avg_cost_ft)
    $('#Summary_averageLifeCycleCostM').html(avg_cost_m)
    
    show_active_results()
  }
  
  
  var step6_calculation = function() {
    
    var reflectance = parseFloat($('#LightLevelAdjustReflectance').val()) / 100
    var base_sp = parseFloat($('#LightLevelAdjustBase').val())
    var alternative_sp = parseFloat($('#LightLevelAdjustAlternative').val())
    
    // Are we outside the mesopic region?
    var photopic_luminance = _average_lux * reflectance / Math.PI
    if(photopic_luminance< .001 || photopic_luminance > .6) {
      $('#InsideMesopic').hide()
      $('#OutsideMesopic').show()
      return show_active_results()
    }
    else {
      $('#InsideMesopic').show()
      $('#OutsideMesopic').hide()
    }
    
    var target_ul = unified_luminance(_average_lux, reflectance, base_sp)
    var alternative_lux = find_lux_for_ul(target_ul, alternative_sp, reflectance, 0.01, _average_lux/2, 0, 100*_average_lux)
    
    var p1 = _average_lux * reflectance / Math.PI
    var p2 = alternative_lux * reflectance / Math.PI
    
    var percent_less = 100*(1 - alternative_lux/_average_lux)
    
    $("#IlluminanceReducedFC").html((alternative_lux / _lpf).toPrecision(3) + ' fc')
    $("#IlluminanceReducedLux").html(alternative_lux.toPrecision(3) + ' lx')
    $("#IlluminanceReducedPercent").html(percent_less.toPrecision(3) + '%')
    
    $('#Summary_baseSP').html(base_sp)
    $('#Summary_reflectance').html(Math.round(100*reflectance)+ '%')
    $('#Summary_alternativeSP').html(alternative_sp)
    $("#Summary_illuminanceReducedFC").html((alternative_lux / _lpf).toPrecision(3) + ' fc')
    $("#Summary_illuminanceReducedLux").html(alternative_lux.toPrecision(3) + ' lx')
    $("#Summary_illuminanceReducedPercent").html(percent_less.toPrecision(3) + '%')
    
    show_active_results()
  }
  
  
  var find_lux_for_ul = function(target_ul, alternative_sp, reflectance, within, lux, min_lux, max_lux) {
    var ul = unified_luminance(lux, reflectance, alternative_sp)
    
    var ratio = ul/target_ul
    
    if(Math.abs(1 - ratio) <= within) return lux
    if(ratio > 1) max_lux = lux; else min_lux = lux;
    
    lux = min_lux + (max_lux - min_lux) / 2
    return find_lux_for_ul(target_ul, alternative_sp, reflectance, within, lux, min_lux, max_lux)
  }
  
  
  var unified_luminance = function(lux, reflectance, sp_ratio) {
    var p = lux * reflectance / Math.PI
    var s = sp_ratio * p
    return 0.834*p - 0.335*s - 0.2 + Math.sqrt(0.696*p*p - 0.333*p - 0.56*p*s + 0.113*s*s + 0.537*s + 0.04)
  }
  
  var addCommas = function(str) {
    str += ''
    x = str.split('.')
    x1 = x[0]
    x2 = x.length > 1 ? '.' + x[1] : ''
    var rgx = /(\d+)(\d{3})/
    while (rgx.test(x1)) {
      x1 = x1.replace(rgx, '$1' + ',' + '$2')
    }
    return x1 + x2
  }
  
  
  
  $(window).hashchange(function() {
    var hash = window.location.hash
    if(!hash || hash == '#intro') return
    
    var step = parseInt(window.location.hash.replace('#step', ''))
    if(step == _step_index) return
    
    show_step(step, false)
  });
  
  $(window).load(function() {window.location.hash = '#intro'})
  

  return {
    show_step: show_step,
    set_input_power: set_input_power,
    set_candela_multiplier: set_candela_multiplier,
    set_distribution_type: set_distribution_type,
    set_illuniance_criteria_inputs: set_illuniance_criteria_inputs,
    set_num_luminaires: set_num_luminaires,
    show_conforming_cells: show_conforming_cells,
    load_ies: load_ies,
    recalculate_current_step: recalculate_current_step,
    ies_file_chosen: ies_file_chosen,
    calculate_step: calculate_step,
    full_screen: full_screen,
    reset: reset,
    calculate_distrubution_types: calculate_distrubution_types
  }
  
}()


// Class for dealing with mutually exclusive toggles
var Mutex = function() {

  // Whenever any mutex radio button has it's state changed, call update
  var setup = function() {
    $('.mutex input[type="radio"]').click(update)
    update()
  }
  $(document).ready(setup)


  // Go through all the mutex labels and set (or remove) the
  // "active" class based on whether or not it's input is checked
  var update = function() {
    $('.mutex label').each(function() {
      var input_for_this_label = $('#' + $(this).attr('for')).get(0)
      $(this).toggleClass('active', $(input_for_this_label).attr('checked'))
    })
  }
  
  return {update: update}
  
}()


// Class for creating a slider and associating it with a text input
var SliderWithInput = function(name, options) {

  var options = options || {}
  var use_ints =  options.use_ints || false
  var unit = options.unit || ''

  $('#' + name + 'Slider').slider({
    min: options.min || 0,
    max: options.max || (use_ints ? 100 : 1),
    step: options.step || (use_ints ? 1 : .01),
    value: options.value || (use_ints ? 50 : .5),
    animate: true,
    slide: function() {
      var that = $(this)
      setTimeout(function() {
        $('#' + name).attr('value', that.slider('value') + unit)
      }, 0)
    },
    change: function() {
      Calculator.recalculate_current_step()
    }
  })

  $('#' + name).change(function(){
    var formatted_value = (use_ints ? parseInt(this.value) : this.value)
    $('#' + name + 'Slider').slider('value', formatted_value)
  })
  
}


var ies_files = {
  TypeIIIMedium150WHPS: "IESNA:LM-63-1995\n[TEST] \n[MANUFAC] \n[SEARCH] \n[LUMINAIRE] \n[DISTRIBUTION] \n[LUMCAT] \n[LAMP] \n[LAMPCAT] \n[OTHER] \n[MORE] \n[MORE] \n[MORE] \n[MORE] \n[MORE] \nTILT=NONE\n1 16000 1.6000 20 36 1 1 0.9 1.1 0.3\n1.0 1.0 183\n 0 5 15 25 35 45 55 60 62.5 65 67.5 70 72.5 75 77.5 80 82.5 85 87.5 90\n 0 5 15 25 35 45 52.5 55 57.5 62.5 65 67.5 72.5 75 77.5 82.5 85 87.5 92.5 95 97.5 102.5 105 107.5 112.5 115 117.5 122.5 125 127.5\n 135 145 155 165 175 180\n 1127 1458 1844 2046 1396 997 752 652 602 551 478 406 333 260 223 186 149 112 100 88\n 1127 1452 1821 2085 1577 1043 818 712 660 607 528 448 369 290 257 224 191 158 140 122\n 1127 1439 1775 2164 1940 1135 950 834 776 719 626 534 442 350 325 300 276 251 222 192\n 1127 1406 1709 2376 2488 1412 1089 993 945 897 780 663 546 429 404 380 355 330 292 254\n 1127 1379 1670 2475 2574 1854 1359 1214 1142 1069 932 795 658 521 476 432 388 343 300 258\n 1127 1313 1564 2409 2409 1907 1511 1534 1546 1557 1454 1352 1250 1148 952 756 560 363 308 254\n 1127 1273 1460 2053 2349 1853 1680 1901 2164 2395 2640 2818 2613 2283 1709 1095 620 370 257 185\n 1127 1260 1425 1934 2329 1835 1736 2072 2369 2765 3244 3537 3349 2838 1990 1144 607 350 248 182\n 1127 1245 1389 1823 2234 1822 1832 2244 2574 3135 3847 4256 4085 3405 2270 1194 594 337 238 178\n 1127 1216 1316 1602 2042 1795 2022 2593 3069 3926 4751 5167 5174 3913 2343 1089 528 317 231 178\n 1127 1201 1280 1491 1947 1782 2118 2666 3161 3986 4692 5150 5062 3742 2174 996 492 304 228 178\n 1127 1186 1246 1425 1891 1728 2056 2739 3253 4052 4633 5134 4949 3577 2006 904 455 297 224 178\n 1127 1157 1176 1293 1778 1618 1930 2098 2739 3062 3563 4039 3900 2917 1623 739 389 264 198 152\n 1127 1142 1142 1227 1722 1564 1868 2032 2412 2653 3036 3425 3435 2706 1564 722 376 251 185 142\n 1127 1127 1110 1201 1606 1504 1749 1967 2085 2250 2508 2811 2970 2494 1505 706 363 244 172 132\n 1127 1097 1048 1148 1376 1386 1511 1544 1604 1643 1643 1795 2032 1993 1419 706 350 218 152 112\n 1127 1082 1016 1122 1260 1326 1392 1435 1468 1465 1412 1462 1650 1689 1297 686 340 211 142 109\n 1127 1072 994 1066 1229 1262 1314 1326 1333 1293 1181 1128 1267 1392 1175 666 330 218 132 106\n 1127 1053 952 953 1166 1133 1160 1214 1175 1095 990 871 878 963 904 594 310 198 132 92\n 1127 1043 930 897 1135 1069 1082 1148 1116 1016 910 782 756 798 766 541 304 185 132 92\n 1127 1031 909 868 1084 1038 980 1082 1056 944 831 693 634 640 627 488 297 178 132 92\n 1127 1008 866 808 981 975 775 950 904 765 647 541 462 436 409 356 257 172 139 106\n 1127 996 845 779 930 944 673 894 844 699 591 492 412 376 353 306 238 172 139 112\n 1127 986 827 762 862 870 647 838 785 634 535 442 363 330 297 257 218 172 139 119\n 1127 967 790 730 728 721 594 732 673 554 455 370 330 290 264 231 198 165 145 125\n 1127 957 772 713 660 647 568 670 614 528 436 363 320 284 264 241 204 178 165 145\n 1127 950 757 703 632 616 543 607 554 502 416 356 310 284 264 251 211 198 185 165\n 1127 937 728 683 576 552 494 515 469 442 396 350 317 297 310 330 317 284 244 191\n 1127 930 713 673 548 521 469 466 422 409 390 353 336 330 360 383 366 310 248 174\n 1127 924 701 662 540 504 457 416 376 376 383 356 356 370 409 436 416 343 251 158\n 1127 904 666 627 515 455 422 360 328 297 335 373 411 449 386 324 261 198 162 126\n 1127 891 640 561 502 436 416 344 308 271 282 294 306 317 268 218 168 119 104 89\n 1127 884 620 528 495 455 455 360 312 264 251 238 224 211 194 178 162 145 136 126\n 1127 871 601 521 488 429 436 346 302 257 234 211 188 165 155 145 135 125 130 135\n 1127 864 594 502 482 389 422 340 298 257 239 221 203 185 176 168 160 152 140 129\n 1127 860 590 492 479 369 415 337 296 257 242 226 210 195 186 180 172 166 145 126",
  TypeIIIMedium250WMH: "IESNA:LM-63-1995\n[TEST] \n[MANUFAC] \n[SEARCH] \n[LUMINAIRE] \n[DISTRIBUTION] \n[LUMCAT] \n[LAMP] 1; \n[LAMPCAT] \n[OTHER] \n[MORE] \n[MORE] \n[MORE] \n[MORE] \n[MORE] \nTILT=NONE\n1 19100 19.1000 20 36 1 1 1.0 1.3 0.0\n1.0 1.0 290\n 0 5 15 25 35 45 55 60 62.5 65 67.5 70 72.5 75 77.5 80 82.5 85 87.5 90\n 0 5 15 25 35 45 52.5 55 57.5 62.5 65 67.5 72.5 75 77.5 82.5 85 87.5 92.5 95 97.5 102.5 105 107.5 112.5 115 117.5 122.5 125 127.5\n 135 145 155 165 175 180\n 126 128 135 139 139 119 194 118 80 43 35 27 19 11 8 6 3 0 0 0\n 126 128 132 136 144 124 192 118 80 43 36 28 20 12 9 6 3 0 0 0\n 126 128 132 152 206 170 211 136 99 62 50 39 28 16 12 8 4 0 0 0\n 126 128 135 176 252 204 253 176 138 100 80 60 40 20 15 10 5 0 0 0\n 126 130 136 166 222 212 293 210 168 126 100 73 46 20 15 10 5 0 0 0\n 126 130 140 166 182 245 316 271 248 226 188 149 110 72 54 36 18 1 0 0\n 126 130 144 170 178 240 313 342 338 484 598 698 547 219 38 9 4 3 1 1\n 126 130 145 171 177 239 312 365 395 549 672 820 641 252 43 10 5 3 2 1\n 126 130 146 171 179 237 306 388 452 614 746 942 735 282 48 12 6 4 3 1\n 126 132 146 172 182 233 292 358 434 500 706 708 498 222 50 12 6 5 3 1\n 126 132 147 172 184 231 286 326 378 404 540 554 376 166 42 12 6 4 2 1\n 126 132 148 172 181 226 282 295 322 308 373 399 254 110 33 11 6 4 2 1\n 126 132 151 170 174 215 272 272 307 310 396 470 292 110 31 10 5 2 0 0\n 126 132 152 170 171 210 268 282 299 314 412 518 340 129 34 10 5 2 0 0\n 126 132 153 169 168 204 246 292 291 318 428 567 388 148 38 10 5 2 0 0\n 126 134 154 167 164 190 204 270 246 263 318 444 328 134 34 8 4 2 0 0\n 126 134 155 166 161 184 182 238 214 225 250 319 238 102 28 8 4 2 0 0\n 126 134 156 162 161 180 178 206 182 187 183 194 148 71 23 8 4 1 0 0\n 126 134 156 154 160 174 172 188 162 148 120 114 88 50 20 6 3 0 0 0\n 126 134 157 150 160 170 168 184 157 134 100 88 68 40 17 6 3 0 0 0\n 126 134 157 150 162 180 174 181 152 122 80 62 47 30 14 6 3 0 0 0\n 126 134 158 148 168 200 188 180 146 110 61 42 30 20 12 6 3 0 0 0\n 126 134 158 148 170 210 194 182 146 107 56 37 26 16 11 6 3 0 0 0\n 126 134 159 150 171 206 196 184 146 103 52 32 22 14 10 6 3 1 0 0\n 126 134 161 153 173 198 198 172 141 98 51 35 22 14 9 6 3 1 0 0\n 126 134 162 155 174 194 200 173 144 104 54 38 26 16 10 6 4 1 0 0\n 126 134 160 155 175 190 195 174 147 109 58 42 29 16 10 6 4 1 0 0\n 126 132 158 156 176 184 185 167 149 112 56 38 29 19 11 6 4 1 0 0\n 126 132 156 156 177 180 180 160 146 114 56 36 28 18 12 7 4 2 0 0\n 126 132 154 156 174 173 174 154 144 114 56 34 27 19 13 8 4 2 0 0\n 126 132 150 158 166 151 156 139 130 122 97 72 46 21 16 11 6 1 0 0\n 126 132 140 156 158 144 150 140 135 130 104 78 52 25 20 14 8 2 2 1\n 126 132 134 146 161 140 168 150 141 132 105 78 52 25 19 13 7 1 0 0\n 126 132 132 136 156 130 148 131 122 114 92 71 50 28 22 15 8 2 2 1\n 126 134 134 126 155 152 106 90 82 74 61 48 36 23 18 13 8 3 2 2\n 126 135 135 121 154 163 85 70 62 54 46 36 29 20 16 12 8 4 2 2",
  TYPEIIIShort150WLED: "IESNA:LM-63-2002\n[TEST]ITL\n[TESTLAB]INDEPENDENT TESTING LABORATORIES, INC.\n[ISSUEDATE]06/18/99\n[MANUFAC]Test, INC.\n[LUMCAT]PRELIMINARY OPTIC\n[LUMINAIRE] ONE CIRCUIT \n[MORE]ONE CLEAR PLASTIC \n[LAMP]TWENTY LEDs\n[MORE]VERTICAL\n[MORE]BASE-UP POSITION.\n[OTHER]INPUT VOLTAGE = 60.8 AT 350 mA DC\n[OTHER]NOTE: DATA SHOWN IS ABSOLUTE FOR THE SAMPLE PROVIDED AT\n[MORE]CLIENT REQUESTED 350mA DC TO THE LED ASSEMBLY. \nTILT=NONE\n1 1268 7 38 22 1 1 0.130208 0.765625 0\n1 1 149.1\n0 2.5 5 7.5 10 12.5 15 17.5 20 22.5 25 27.5 30 32.5 35 37.5 40 42.5 45 47.5 50 52.5 53 55 57.5 60 62.5 65 67.5 70 72.5 75 77.5 80 82.5 85 87.5 90\n0 5 15 25 35 45 55 59 65 75 85 90 95 105 115 125 135 145 155 165 175 180\n214.00 216.00 219.00 220.00 221.00 221.00 221.00 221.00 221.00 221.00 219.00 217.00 216.00 228.00 243.00 250.00 264.00 274.00 337.00 462.00 559.00 621.00 623.00 502.00 605.00 548.00 383.00 260.00 174.00 110.00 60.00 33.00 21.00 15.00 10.00 6.00 3.00 0.00\n214.00 217.00 220.00 221.00 223.00 223.00 223.00 223.00 223.00 222.00 221.00 218.00 217.00 230.00 245.00 253.00 267.00 278.00 341.00 468.00 571.00 635.00 637.00 515.00 614.00 559.00 391.00 267.00 177.00 112.00 61.00 34.00 22.00 15.00 10.00 6.00 3.00 0.00\n214.00 217.00 220.00 222.00 223.00 223.00 223.00 223.00 223.00 222.00 223.00 223.00 224.00 233.00 249.00 259.00 269.00 285.00 346.00 474.00 590.00 668.00 666.00 538.00 625.00 572.00 418.00 284.00 186.00 118.00 65.00 37.00 23.00 16.00 11.00 6.00 3.00 0.00\n214.00 216.00 219.00 220.00 222.00 222.00 223.00 223.00 224.00 224.00 225.00 227.00 230.00 237.00 253.00 262.00 270.00 291.00 350.00 468.00 592.00 691.00 682.00 553.00 620.00 581.00 436.00 300.00 199.00 127.00 72.00 41.00 26.00 17.00 11.00 6.00 3.00 0.00\n214.00 217.00 219.00 221.00 222.00 223.00 224.00 225.00 226.00 227.00 226.00 228.00 230.00 235.00 250.00 263.00 270.00 289.00 357.00 447.00 576.00 696.00 680.00 562.00 612.00 592.00 460.00 325.00 215.00 139.00 83.00 48.00 28.00 18.00 10.00 5.00 2.00 0.00\n214.00 217.00 218.00 221.00 223.00 225.00 226.00 228.00 228.00 228.00 228.00 229.00 231.00 234.00 247.00 263.00 269.00 285.00 356.00 416.00 556.00 700.00 684.00 580.00 612.00 622.00 512.00 376.00 259.00 171.00 105.00 61.00 36.00 21.00 12.00 5.00 2.00 0.00\n214.00 216.00 218.00 220.00 223.00 225.00 227.00 228.00 229.00 228.00 229.00 231.00 232.00 234.00 248.00 265.00 271.00 284.00 337.00 390.00 529.00 702.00 699.00 598.00 601.00 641.00 574.00 461.00 346.00 243.00 163.00 102.00 62.00 36.00 20.00 9.00 3.00 \n0.00\n214.00 215.00 217.00 219.00 222.00 224.00 227.00 228.00 229.00 229.00 230.00 231.00 234.00 236.00 249.00 267.00 274.00 287.00 330.00 383.00 513.00 701.00 705.00 609.00 582.00 628.00 584.00 489.00 381.00 280.00 197.00 130.00 82.00 49.00 28.00 12.00 4.00 \n0.00\n214.00 216.00 217.00 218.00 221.00 225.00 228.00 229.00 232.00 232.00 233.00 235.00 238.00 240.00 252.00 275.00 282.00 295.00 324.00 374.00 480.00 681.00 697.00 619.00 545.00 581.00 568.00 500.00 411.00 318.00 235.00 166.00 111.00 69.00 37.00 17.00 5.00 \n0.00\n214.00 215.00 216.00 218.00 221.00 225.00 228.00 231.00 235.00 237.00 241.00 246.00 251.00 258.00 267.00 290.00 307.00 315.00 329.00 357.00 412.00 590.00 628.00 626.00 499.00 497.00 494.00 466.00 418.00 352.00 279.00 202.00 130.00 72.00 36.00 16.00 6.00 \n0.00\n214.00 214.00 214.00 216.00 219.00 223.00 228.00 232.00 238.00 246.00 254.00 264.00 277.00 291.00 304.00 321.00 342.00 349.00 348.00 352.00 362.00 418.00 444.00 489.00 446.00 419.00 411.00 385.00 336.00 276.00 205.00 127.00 65.00 29.00 12.00 5.00 2.00 \n0.00\n214.00 213.00 214.00 215.00 218.00 223.00 228.00 233.00 241.00 253.00 266.00 281.00 298.00 315.00 332.00 344.00 359.00 366.00 355.00 347.00 343.00 348.00 358.00 382.00 379.00 352.00 331.00 297.00 250.00 199.00 136.00 73.00 32.00 14.00 7.00 3.00 1.00 0.00\n214.00 214.00 213.00 214.00 217.00 222.00 228.00 236.00 248.00 265.00 284.00 306.00 327.00 345.00 358.00 363.00 368.00 365.00 352.00 335.00 319.00 306.00 304.00 300.00 294.00 274.00 247.00 215.00 176.00 129.00 77.00 36.00 16.00 9.00 6.00 3.00 1.00 0.00\n214.00 213.00 212.00 212.00 215.00 221.00 230.00 248.00 275.00 305.00 333.00 352.00 367.00 374.00 374.00 366.00 353.00 334.00 312.00 289.00 266.00 245.00 238.00 223.00 202.00 181.00 158.00 136.00 107.00 66.00 30.00 16.00 11.00 7.00 4.00 2.00 1.00 0.00\n214.00 212.00 210.00 209.00 212.00 222.00 241.00 271.00 303.00 327.00 346.00 359.00 366.00 363.00 353.00 335.00 309.00 280.00 259.00 242.00 227.00 211.00 207.00 193.00 176.00 156.00 137.00 116.00 78.00 35.00 18.00 12.00 8.00 6.00 3.00 2.00 1.00 0.00\n214.00 210.00 207.00 205.00 211.00 226.00 251.00 278.00 299.00 316.00 328.00 338.00 343.00 332.00 306.00 273.00 248.00 234.00 226.00 217.00 207.00 194.00 191.00 179.00 162.00 142.00 123.00 96.00 50.00 20.00 15.00 10.00 8.00 5.00 3.00 1.00 0.00 0.00\n214.00 210.00 206.00 204.00 211.00 229.00 249.00 268.00 281.00 292.00 304.00 308.00 307.00 280.00 243.00 222.00 214.00 211.00 209.00 205.00 198.00 188.00 185.00 172.00 154.00 133.00 114.00 79.00 32.00 18.00 14.00 10.00 8.00 5.00 3.00 1.00 0.00 0.00\n214.00 209.00 204.00 202.00 210.00 225.00 237.00 248.00 256.00 266.00 272.00 270.00 257.00 224.00 207.00 203.00 202.00 205.00 204.00 201.00 196.00 184.00 182.00 169.00 149.00 129.00 111.00 72.00 26.00 18.00 14.00 12.00 9.00 4.00 2.00 1.00 0.00 0.00\n214.00 208.00 202.00 199.00 207.00 218.00 222.00 227.00 233.00 239.00 241.00 232.00 217.00 205.00 205.00 208.00 213.00 218.00 217.00 214.00 207.00 193.00 189.00 175.00 154.00 133.00 116.00 74.00 25.00 19.00 15.00 12.00 7.00 4.00 2.00 1.00 0.00 0.00\n214.00 208.00 202.00 199.00 206.00 213.00 211.00 212.00 214.00 217.00 217.00 210.00 208.00 216.00 224.00 236.00 244.00 249.00 248.00 241.00 228.00 208.00 201.00 183.00 159.00 138.00 122.00 78.00 25.00 20.00 15.00 11.00 5.00 3.00 2.00 1.00 0.00 0.00\n214.00 208.00 202.00 198.00 204.00 209.00 204.00 202.00 200.00 202.00 201.00 201.00 212.00 228.00 241.00 256.00 268.00 275.00 277.00 268.00 246.00 217.00 209.00 184.00 157.00 139.00 124.00 83.00 25.00 20.00 15.00 9.00 5.00 3.00 2.00 1.00 0.00 0.00\n214.00 206.00 201.00 197.00 203.00 207.00 202.00 198.00 197.00 198.00 198.00 198.00 211.00 228.00 242.00 257.00 268.00 275.00 278.00 273.00 246.00 214.00 206.00 181.00 155.00 137.00 123.00 83.00 25.00 20.00 14.00 9.00 5.00 3.00 2.00 1.00 0.00 0.00\n"
}

var ies_file_names = {
  TypeIIIMedium150WHPS: 'Type III Medium 150W HPS',
  TypeIIIMedium250WMH: 'Type III Medium 250W MH',
  TYPEIIIShort150WLED: 'Type III Short 150W LED'
}
