<commit_before>var request = require('request');
var cheerio = require('cheerio');
var _ = require('underscore');

// TODO: allow this to be configurable by API
var FORECASTS_COUNT = 4;

// return the closest N forecasts in the future to current time with the smallest time range
var closestInstantForecasts = function($, times, N) {
  N = typeof N === 'undefined' ? 24 : N;

  return _.chain(times).map(function(time){
    // map to back to cheerio'fied object so we can read attr()
    return $(time);
  }).filter(function(time){
    // filter by instantaneous forecasts only
    return time.attr("from") == time.attr("to");
  }).sortBy(function(time){
    // sort by closest to most distant time
    var from = new Date(time.attr("from"));
    return Math.abs((new Date()).getTime() - from.getTime());
  }).first(N).value();
};

// return an object with temperature in C and F and a relative ETA in hours for that temperature.
var createForecastItem = function(time){
  var tempC = parseFloat(time.find('temperature').eq(0).attr('value'));
  return {
    hoursFromNow: Math.ceil(((new Date(time.attr("from"))).getTime() - (new Date()).getTime()) / 1000 / 60 / 60),

    // Celcius is kept decimal since met.no returns a pleasant formatted value. 
    // Fahrenheit is rounded for reasons of laziness. 
    // TODO: format Fahrenheit value.
    tempC: tempC,
    tempF: Math.round((9 / 5 * tempC) + 32)
  };
};

module.exports = {

  // call done with weather forecast results for GPS location lat, lon
  getForecast: function(lat, lon, done){

    var url = "http://api.met.no/weatherapi/locationforecast/1.8/?lat=" + lat + ";lon=" + lon;

    request(url, function(error, response, body) {

      if (!error && response.statusCode == 200) {<commit_msg>Allow any 2xx or 3xx response code<commit_after>var request = require('request');
var cheerio = require('cheerio');
var _ = require('underscore');

// TODO: allow this to be configurable by API
var FORECASTS_COUNT = 4;

// return the closest N forecasts in the future to current time with the smallest time range
var closestInstantForecasts = function($, times, N) {
  N = typeof N === 'undefined' ? 24 : N;

  return _.chain(times).map(function(time){
    // map to back to cheerio'fied object so we can read attr()
    return $(time);
  }).filter(function(time){
    // filter by instantaneous forecasts only
    return time.attr("from") == time.attr("to");
  }).sortBy(function(time){
    // sort by closest to most distant time
    var from = new Date(time.attr("from"));
    return Math.abs((new Date()).getTime() - from.getTime());
  }).first(N).value();
};

// return an object with temperature in C and F and a relative ETA in hours for that temperature.
var createForecastItem = function(time){
  var tempC = parseFloat(time.find('temperature').eq(0).attr('value'));
  return {
    hoursFromNow: Math.ceil(((new Date(time.attr("from"))).getTime() - (new Date()).getTime()) / 1000 / 60 / 60),

    // Celcius is kept decimal since met.no returns a pleasant formatted value. 
    // Fahrenheit is rounded for reasons of laziness. 
    // TODO: format Fahrenheit value.
    tempC: tempC,
    tempF: Math.round((9 / 5 * tempC) + 32)
  };
};

module.exports = {

  // call done with weather forecast results for GPS location lat, lon
  getForecast: function(lat, lon, done){

    var url = "http://api.met.no/weatherapi/locationforecast/1.8/?lat=" + lat + ";lon=" + lon;

    request(url, function(error, response, body) {

      if (!error && response.statusCode < 400) {
{'fraction_non_alphanumeric': 0.14637599093997736, 'fraction_numerical': 0.01245753114382786, 'mean_word_length': 3.546975546975547, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5354054', 'n_tokens_mistral': 1125, 'n_tokens_neox': 1060, 'n_words': 364}