<commit_before>var stops_arr = [];
var stops_dict = {};
var shortened_stops = {};
var cached_schedStopPairs = {};
var cached_routeInfo = {};
var replacementText = "____ ";

// utility function
function getKeyForValue(dict, val) {
    for (key in dict) {
        if (dict[key] == val) {
            return key;
        }
    }
}

$("document").ready(function() {
    // Initialize datepicker
    $(".hasDatepicker").datepicker("setDate", new Date());
    // Get stop data
    $.getJSON("https://transit.land//api/v1/stops?identifier_starts_with=gtfs://f-drt8-nps~boha~ferries",
            function (data) {
                // caches stop data for easier use
                data.stops.forEach(function (e) {
                    stops_arr.push({"name":e.name, "osid":e.onestop_id});
                    var route_ids = [];
                    // saves only the salient information about each route – the route_onestop_id
                    e.routes_serving_stop.forEach(function (e) {route_ids.push(e.route_onestop_id);});
                    stops_dict[e.name] = {"oid":e.onestop_id, "coordinates":{"lng":e.geometry.coordinates[0], "lat":e.geometry.coordinates[1]}, "routes":route_ids};
                });

                // populate initial drop downs
                var ulTemplateFront_stops = "
____
"
                stops_arr.forEach(function (e) {
                    $(".From").append((ulTemplateFront_stops.replace("____", e.name)).replace("startorstop", "start"));
                    $(".To").append((ulTemplateFront_stops.replace("____", e.name)).replace("startorstop", "stop"));
                    var splitText = e.name.split(" ");
                    var short_name = "";
                    // trims the last word off the name
                    for (var i = 0; i < splitText.length - 1; i++) {
                            short_name += splitText[i] + " ";
                    }
                    shortened_stops[e.name] = short_name.trim();
                });

                // add click trigger for dropdowns to populate main box when something has been selected
                // also GETs and caches direct journey's from selected stop
                $(".selection").click(function() {
                    var dropdown_text = $(this).parent().prev();
                    var short_name = shortened_stops[this.innerText.trim()];
                    dropdown_text.html(replacementText.replace("____", short_name));
                    if ($(this).hasClass("start")) {
                        // caching direct schedule-stop pairs for origin
                        var this_name = $(this).context.firstChild.innerText;
                        var this_osid = stops_dict[this_name].oid;
                        $.getJSON("https://transit.land//api/v1/schedule_stop_pairs?origin_onestop_id="+this_osid+"&date=2016-06-29",
                              function (data) {
                                    cached_schedStopPairs[this_name] = data;
                              }
                        );
                        // clears the 'To' and 'Times' dropdowns whenever a new 'From' is selected
                        dropdown_text.parent().parent().next().children().children(".btn").html(replacementText.replace("____", "To"));
                        empty_times($(this));
                    }
                    else if ($(this).hasClass("stop")){
                        var from_shortName = dropdown_text.parent().parent().prev().children().children(".btn").text().trim();
                        var from_fullName = getKeyForValue(shortened_stops, from_shortName);
                        var to_fullName = getKeyForValue(shortened_stops, short_name);
                        var to_avail_routes = stops_dict[to_fullName].routes;
                        var available_trips = cached_schedStopPairs[from_fullName].schedule_stop_pairs.filter(function (e) {
                            if (to_avail_routes.includes(e.route_onestop_id)) return true;
                        });
                        if(available_trips.length > 0) {
                            populate_times(available_trips, $(this));
                        }
                        else {
                            alert("Sorry, there are no direct trips from " + from_fullName + " to " + to_fullName);
                            empty_times($(this));
                        }
                    }
                });
            }
    );
    $.getJSON("https://transit.land//api/v1/routes?operated_by=o-drt8-bostonharborislandsnationalandstatepark",
            function (data) {
                data.routes.forEach(function (e) {
                    cached_routeInfo[e.onestop_id] = {
                        "name": e.name,
                        "shape": create_polyline(e.geometry.coordinates)
                    }
                });
            }
    );
});

function populate_times(available_trips, point) {
    empty_times(point);
    var ulTemplateFront_times = "
____
"
    var available_times = point.parent().parent().parent().parent().children(".times").children().children("ul");
    var time_accumulator = {};
    available_trips.forEach(function (e, index, arr) {
        if(time_accumulator[e.route_onestop_id]) {
            time_accumulator[e.route_onestop_id].push(e.origin_departure_time);
        }
        else {
            time_accumulator[e.route_onestop_id] = [];
            time_accumulator[e.route_onestop_id].push(e.origin_departure_time);
        }
    });
    for (key in time_accumulator) {
        time_accumulator[key].sort(sort_times);
        time_accumulator[key].forEach(function (e) {
            var this_time = sanitize_time(e);
            available_times.append((ulTemplateFront_times.replace("____", this_time)).replace("****", key));
        });
        available_times.append("

");
    }
    $(".time").click(function () {
        var dropdown_text = $(this).parent().prev();
        var time = this.innerText;
        dropdown_text.html(replacementText.replace("____", time));
        clear_polylines();
        draw_polyline($(this));
    })
}

function sort_times(a, b) {
    var atomized = a.split(":");
    var btomized = b.split(":");
    if (parseInt(atomized[0]) < parseInt(btomized[0])) return -1;
    else if (parseInt(atomized[0]) > parseInt(btomized[0])) return 1;
    return 0;
}

function sanitize_time(dirty_time) {
    var x = dirty_time.split(":");
    var clean_time = "";
    var hour = parseInt(x[0], 10);
    if (hour > 12) hour %= 12;
    clean_time += hour.toString() + ":" + x[1];
    if ((parseInt(x[0], 10) / 12) < 1) clean_time += " am";
    else clean_time += " pm";
    return clean_time;
}

function empty_times(point) {
    var times = point.parent().parent().parent().parent().children(".times").children().children("ul");
    times.empty();
    times.parent().html("<button type='button' data-toggle='dropdown' class='btn btn-default dropdown-toggle'>Times </button>

");
    clear_polylines();
}

function create_polyline(coordinates) {
    var arr = [];
    coordinates.forEach(function (i) {
        i.forEach(function (j) {
            var obj = {"lng":j[0], "lat":j[1]};
             arr.push(obj);
        });
    });
    return new google.maps.Polyline({
        path: arr,
        geodesic: true,
        strokeColor: '#FF0000',
        strokeOpacity: 1.0,
        strokeWeight: 2
    })
}

function draw_polyline(time_li) {
    var roid = time_li.attr('data-roid');
    cached_routeInfo[roid].shape.setMap(gmap);
}

function clear_polylines() {
    for (key in cached_routeInfo) {
        cached_routeInfo[key].shape.setMap(null);
    }
}<commit_msg>cleaned up panel.js<commit_after>var stops_arr = [];
var stops_dict_by_name = {};
var stops_dict_by_oid = {};
var shortened_stops = {};
var cached_schedStopPairs = {};
var cached_routeInfo = {};
var replacementText = "____ ";
var ulTemplateFront_stops = "
____
"

// utility function
function getKeyForValue(dict, val) {
    for (key in dict) {
        if (dict[key] == val) {
            return key;
        }
    }
}

function cache_stop_data(stops) {
    stops.forEach(function (e) {
        stops_arr.push({"name":e.name, "osid":e.onestop_id});
        var route_ids = [];
        // saves only the salient information about each route – the route_onestop_id
        e.routes_serving_stop.forEach(function (e) {route_ids.push(e.route_onestop_id);});
        stops_dict_by_name[e.name] = {"oid":e.onestop_id, "coordinates":{"lng":e.geometry.coordinates[0], "lat":e.geometry.coordinates[1]}, "routes":route_ids};
        stops_dict_by_oid[e.onestop_id] = {"name":e.name};
        var splitText = e.name.split(" ");
        var short_name = "";
        // trims the last word off the name
        for (var i = 0; i < splitText.length - 1; i++) {
                short_name += splitText[i] + " ";
        }
        shortened_stops[e.name] = short_name.trim();
    });
}

function populate_dropdown(dropdown, stops, startorstop) {
    stops.forEach(function (e) {
        dropdown.append(((ulTemplateFront_stops.replace("____", e.name)).replace("startorstop", startorstop)).replace("&&&&", e.osid));
    });
}

function replace_button_text(dropdown_text, short_name) {
    dropdown_text.html(replacementText.replace("____", short_name));
}

function cache_schedStopPairs(this_name) {
    var this_osid = stops_dict_by_name[this_name].oid;
    $.getJSON("https://transit.land//api/v1/schedule_stop_pairs?origin_onestop_id="+this_osid+"&date=2016-06-29",
          function (data) {
                cached_schedStopPairs[this_name] = data;
          }
    );
}

$("document").ready(function() {
    // Initialize datepicker
    $(".hasDatepicker").datepicker("setDate", new Date());
    // Get stop data
    $.getJSON("https://transit.land//api/v1/stops?identifier_starts_with=gtfs://f-drt8-nps~boha~ferries",
            function (data) {
                // caches stop data for easier/faster use
                cache_stop_data(data.stops);

                // populate initial drop downs
                populate_dropdown($(".From"), stops_arr, "start");
                populate_dropdown($(".To"), stops_arr, "stop");

                // add click trigger for dropdowns to populate main box when something has been selected
                // also GETs and caches direct journey's from selected stop
                $(".selection").click(function() {
                    var dropdown_dom_elem = $(this).parent().prev();
                    var short_name = shortened_stops[dropdown_dom_elem.context.innerText.trim()];

                    replace_button_text(dropdown_dom_elem, short_name);

                    if ($(this).hasClass("start")) {
                        // caching direct schedule-stop pairs for origin
                        cache_schedStopPairs($(this).context.firstChild.innerText);

                        // clears the 'To' and 'Times' dropdowns whenever a new 'From' is selected
                        dropdown_dom_elem.parent().parent().next().children().children(".btn").html(replacementText.replace("____", "To"));
                        empty_times($(this));
                    }
                    else if ($(this).hasClass("stop")){
                        var from_shortName = dropdown_dom_elem.parent().parent().prev().children().children(".btn").text().trim();
                        var from_fullName = getKeyForValue(shortened_stops, from_shortName);
                        var to_fullName = getKeyForValue(shortened_stops, short_name);
                        var to_avail_routes = stops_dict_by_name[to_fullName].routes;
                        var available_trips = cached_schedStopPairs[from_fullName].schedule_stop_pairs.filter(function (e) {
                            if (to_avail_routes.includes(e.route_onestop_id)) return true;
                        });
                        if(available_trips.length > 0) {
                            populate_times(available_trips, $(this));
                        }
                        else {
                            alert("Sorry, there are no direct trips from " + from_fullName + " to " + to_fullName);
                            empty_times($(this));
                        }
                    }
                });
            }
    );
    $.getJSON("https://transit.land//api/v1/routes?operated_by=o-drt8-bostonharborislandsnationalandstatepark",
            function (data) {
                data.routes.forEach(function (e) {
                    cached_routeInfo[e.onestop_id] = {
                        "name": e.name,
                        "shape": create_polyline(e.geometry.coordinates)
                    }
                });
            }
    );
});

// unnecessary right now
function populate_to_dropdowns(stops_served) {
    console.log(stops_served);
    var stops = [];
    stops_served.schedule_stop_pairs.forEach(function (e) {
        curr_stop = stops_dict_by_oid[e.destination_onestop_id].name;
        if (stops.includes(curr_stop) == false) {
            stops.push(curr_stop);
        }
    });
    stops.sort();
    stops.forEach(function (e) {
        $(".To").append((ulTemplateFront_stops.replace("____", e)).replace("startorstop", "stop"));
    })
}

function populate_times(available_trips, point) {
    empty_times(point);
    var ulTemplateFront_times = "
____
"
    var available_times = point.parent().parent().parent().parent().children(".times").children().children("ul");
    var time_accumulator = {};
    available_trips.forEach(function (e, index, arr) {
        if(time_accumulator[e.route_onestop_id]) {
            time_accumulator[e.route_onestop_id].push(e.origin_departure_time);
        }
        else {
            time_accumulator[e.route_onestop_id] = [];
            time_accumulator[e.route_onestop_id].push(e.origin_departure_time);
        }
    });
    for (key in time_accumulator) {
        time_accumulator[key].sort(compare_times);
        time_accumulator[key].forEach(function (e) {
            var this_time = sanitize_time(e);
            available_times.append((ulTemplateFront_times.replace("____", this_time)).replace("****", key));
        });
        available_times.append("

");
    }
    $(".time").click(function () {
        var dropdown_text = $(this).parent().prev();
        var time = this.innerText;
        dropdown_text.html(replacementText.replace("____", time));
        clear_polylines();
        draw_polyline($(this));
    })
}

function compare_times(a, b) {
    var atomized = a.split(":");
    var btomized = b.split(":");
    if (parseInt(atomized[0]) < parseInt(btomized[0])) return -1;
    else if (parseInt(atomized[0]) > parseInt(btomized[0])) return 1;
    return 0;
}

function sanitize_time(dirty_time) {
    var x = dirty_time.split(":");
    var clean_time = "";
    var hour = parseInt(x[0], 10);
    if (hour > 12) hour %= 12;
    clean_time += hour.toString() + ":" + x[1];
    if ((parseInt(x[0], 10) / 12) < 1) clean_time += " am";
    else clean_time += " pm";
    return clean_time;
}

function empty_times(point) {
    var times = point.parent().parent().parent().parent().children(".times").children().children("ul");
    times.empty();
    times.parent().html("<button type='button' data-toggle='dropdown' class='btn btn-default dropdown-toggle'>Times </button>

");
    clear_polylines();
}

function create_polyline(coordinates) {
    var arr = [];
    coordinates.forEach(function (i) {
        i.forEach(function (j) {
            var obj = {"lng":j[0], "lat":j[1]};
             arr.push(obj);
        });
    });
    return new google.maps.Polyline({
        path: arr,
        geodesic: true,
        strokeColor: '#FF0000',
        strokeOpacity: 1.0,
        strokeWeight: 2
    })
}

function draw_polyline(time_li) {
    var roid = time_li.attr('data-roid');
    cached_routeInfo[roid].shape.setMap(gmap);
}

function clear_polylines() {
    for (key in cached_routeInfo) {
        cached_routeInfo[key].shape.setMap(null);
    }
}

// EDIC - Thompson stuff
/*
    var edic_thompson_roids = [stops_dict_by_name["EDIC Pier"].oid, stops_dict_by_name["Thompson Island"].oid];
    if(this_name != "EDIC Pier" && this_name != "Thompson Island") {
        edic_thompson_roids.forEach(function (e) {
            var to = dropdown_dom_elem.parent().parent().next().children().children("ul").children("[data-roid='"+e+"']");
            to.remove();
        })
    }
    else {
        var delete_all_but = "[data-roid!='"+edic_thompson_roids[0]+"'][data-roid!='"+edic_thompson_roids[1]+"']";
        var to = dropdown_dom_elem.parent().parent().next().children().children("ul").children(delete_all_but);
        to.remove();
    }
*/<|endoftext|>


<commit_before>/*

Required Variables:

  port:             StatsD listening port [default: 8125]

Graphite Required Variables:

(Leave these unset to avoid sending stats to Graphite.
 Set debug flag and leave these unset to run in 'dry' debug mode -
 useful for testing statsd clients without a Graphite server.)

  graphiteHost:     hostname or IP of Graphite server
  graphitePort:     port of Graphite server

Optional Variables:

  backends:         an array of backends to load. Each backend must exist
                    by name in the directory backends/. If not specified,
                    the default graphite backend will be loaded.
  debug:            debug flag [default: false]
  address:          address to listen on over UDP [default: 0.0.0.0]
  address_ipv6:     defines if the address is an IPv4 or IPv6 address [true or false, default: false]
  port:             port to listen for messages on over UDP [default: 8125]
  mgmt_address:     address to run the management TCP interface on
                    [default: 0.0.0.0]
  mgmt_port:        port to run the management TCP interface on [default: 8126]
  title :           Allows for overriding the process title. [default: statsd]
                    if set to false, will not override the process title and let the OS set it.
                    The length of the title has to be less than or equal to the binary name + cli arguments
                    NOTE: This does not work on Mac's with node versions prior to v0.10

  healthStatus:     default health status to be returned and statsd process starts ['up' or 'down', default: 'up']
  dumpMessages:     log all incoming messages
  flushInterval:    interval (in ms) to flush to Graphite
  percentThreshold: for time information, calculate the Nth percentile(s)
                    (can be a single value or list of floating-point values)
                    negative values mean to use "top" Nth percentile(s) values
                    [%, default: 90]
  flush_counts:     send stats_counts metrics [default: true]

  keyFlush:         log the most frequently sent keys [object, default: undefined]
    interval:       how often to log frequent keys [ms, default: 0]
    percent:        percentage of frequent keys to log [%, default: 100]
    log:            location of log file for frequent keys [default: STDOUT]
  deleteIdleStats:  don't send values to graphite for inactive counters, sets, gauges, or timeers
                    as opposed to sending 0.  For gauges, this unsets the gauge (instead of sending
                    the previous value). Can be indivdually overriden. [default: false]
  deleteGauges  :   don't send values to graphite for inactive gauges, as opposed to sending the previous value [default: false]
  deleteTimers:     don't send values to graphite for inactive timers, as opposed to sending 0 [default: false]
  deleteSets:       don't send values to graphite for inactive sets, as opposed to sending 0 [default: false]
  deleteCounters:   don't send values to graphite for inactive counters, as opposed to sending 0 [default: false]
  prefixStats:      prefix to use for the statsd statistics data for this running instance of statsd [default: statsd]
                    applies to both legacy and new namespacing

  console:
    prettyprint:    whether to prettyprint the console backend
                    output [true or false, default: true]

  log:              log settings [object, default: undefined]
    backend:        where to log: stdout or syslog [string, default: stdout]
    application:    name of the application for syslog [string, default: statsd]
    level:          log level for [node-]syslog [string, default: LOG_INFO]

  graphite:
    legacyNamespace:  use the legacy namespace [default: true]
    globalPrefix:     global prefix to use for sending stats to graphite [default: "stats"]
    prefixCounter:    graphite prefix for counter metrics [default: "counters"]
    prefixTimer:      graphite prefix for timer metrics [default: "timers"]
    prefixGauge:      graphite prefix for gauge metrics [default: "gauges"]
    prefixSet:        graphite prefix for set metrics [default: "sets"]
    globalSuffix:     global suffix to use for sending stats to graphite [default: ""]
                      This is particularly useful for sending per host stats by
                      settings this value to: require('os').hostname().split('.')[0]

  repeater:         an array of hashes of the for host: and port:
                    that details other statsd servers to which the received
                    packets should be "repeated" (duplicated to).
                    e.g. [ { host: '10.10.10.10', port: 8125 },
                           { host: 'observer', port: 88125 } ]

  repeaterProtocol: whether to use udp4 or udp6 for repeaters.
                    ["udp4" or "udp6", default: "udp4"]

  histogram:        for timers, an array of mappings of strings (to match metrics) and
                    corresponding ordered non-inclusive upper limits of bins.
                    For all matching metrics, histograms are maintained over
                    time by writing the frequencies for all bins.
                    'inf' means infinity. A lower limit of 0 is assumed.
                    default: [], meaning no histograms for any timer.
                    First match wins.  examples:
                    * histogram to only track render durations, with unequal
                      class intervals and catchall for outliers:
                      [ { metric: 'render', bins: [ 0.01, 0.1, 1, 10, 'inf'] } ]
                    * histogram for all timers except 'foo' related,
                      equal class interval and catchall for outliers:
                     [ { metric: 'foo', bins: [] },
                       { metric: '', bins: [ 50, 100, 150, 200, 'inf'] } ]

*/
{
  graphitePort: Number(process.env.GRAPHITE_PORT) || Number(process.env.GRAPHITE_PORT_2003_TCP_PORT) || 2003
, graphiteHost: process.env.GRAPHITE_HOST || process.env.GRAPHITE_PORT_2003_TCP_ADDR || undefined
, port: 8125
, backends: [ "./backends/graphite" ]
, debug: !!process.env.DEBUG
, legacyNamespace = false
}
<commit_msg>statsd: typo<commit_after>/*

Required Variables:

  port:             StatsD listening port [default: 8125]

Graphite Required Variables:

(Leave these unset to avoid sending stats to Graphite.
 Set debug flag and leave these unset to run in 'dry' debug mode -
 useful for testing statsd clients without a Graphite server.)

  graphiteHost:     hostname or IP of Graphite server
  graphitePort:     port of Graphite server

Optional Variables:

  backends:         an array of backends to load. Each backend must exist
                    by name in the directory backends/. If not specified,
                    the default graphite backend will be loaded.
  debug:            debug flag [default: false]
  address:          address to listen on over UDP [default: 0.0.0.0]
  address_ipv6:     defines if the address is an IPv4 or IPv6 address [true or false, default: false]
  port:             port to listen for messages on over UDP [default: 8125]
  mgmt_address:     address to run the management TCP interface on
                    [default: 0.0.0.0]
  mgmt_port:        port to run the management TCP interface on [default: 8126]
  title :           Allows for overriding the process title. [default: statsd]
                    if set to false, will not override the process title and let the OS set it.
                    The length of the title has to be less than or equal to the binary name + cli arguments
                    NOTE: This does not work on Mac's with node versions prior to v0.10

  healthStatus:     default health status to be returned and statsd process starts ['up' or 'down', default: 'up']
  dumpMessages:     log all incoming messages
  flushInterval:    interval (in ms) to flush to Graphite
  percentThreshold: for time information, calculate the Nth percentile(s)
                    (can be a single value or list of floating-point values)
                    negative values mean to use "top" Nth percentile(s) values
                    [%, default: 90]
  flush_counts:     send stats_counts metrics [default: true]

  keyFlush:         log the most frequently sent keys [object, default: undefined]
    interval:       how often to log frequent keys [ms, default: 0]
    percent:        percentage of frequent keys to log [%, default: 100]
    log:            location of log file for frequent keys [default: STDOUT]
  deleteIdleStats:  don't send values to graphite for inactive counters, sets, gauges, or timeers
                    as opposed to sending 0.  For gauges, this unsets the gauge (instead of sending
                    the previous value). Can be indivdually overriden. [default: false]
  deleteGauges  :   don't send values to graphite for inactive gauges, as opposed to sending the previous value [default: false]
  deleteTimers:     don't send values to graphite for inactive timers, as opposed to sending 0 [default: false]
  deleteSets:       don't send values to graphite for inactive sets, as opposed to sending 0 [default: false]
  deleteCounters:   don't send values to graphite for inactive counters, as opposed to sending 0 [default: false]
  prefixStats:      prefix to use for the statsd statistics data for this running instance of statsd [default: statsd]
                    applies to both legacy and new namespacing

  console:
    prettyprint:    whether to prettyprint the console backend
                    output [true or false, default: true]

  log:              log settings [object, default: undefined]
    backend:        where to log: stdout or syslog [string, default: stdout]
    application:    name of the application for syslog [string, default: statsd]
    level:          log level for [node-]syslog [string, default: LOG_INFO]

  graphite:
    legacyNamespace:  use the legacy namespace [default: true]
    globalPrefix:     global prefix to use for sending stats to graphite [default: "stats"]
    prefixCounter:    graphite prefix for counter metrics [default: "counters"]
    prefixTimer:      graphite prefix for timer metrics [default: "timers"]
    prefixGauge:      graphite prefix for gauge metrics [default: "gauges"]
    prefixSet:        graphite prefix for set metrics [default: "sets"]
    globalSuffix:     global suffix to use for sending stats to graphite [default: ""]
                      This is particularly useful for sending per host stats by
                      settings this value to: require('os').hostname().split('.')[0]

  repeater:         an array of hashes of the for host: and port:
                    that details other statsd servers to which the received
                    packets should be "repeated" (duplicated to).
                    e.g. [ { host: '10.10.10.10', port: 8125 },
                           { host: 'observer', port: 88125 } ]

  repeaterProtocol: whether to use udp4 or udp6 for repeaters.
                    ["udp4" or "udp6", default: "udp4"]

  histogram:        for timers, an array of mappings of strings (to match metrics) and
                    corresponding ordered non-inclusive upper limits of bins.
                    For all matching metrics, histograms are maintained over
                    time by writing the frequencies for all bins.
                    'inf' means infinity. A lower limit of 0 is assumed.
                    default: [], meaning no histograms for any timer.
                    First match wins.  examples:
                    * histogram to only track render durations, with unequal
                      class intervals and catchall for outliers:
                      [ { metric: 'render', bins: [ 0.01, 0.1, 1, 10, 'inf'] } ]
                    * histogram for all timers except 'foo' related,
                      equal class interval and catchall for outliers:
                     [ { metric: 'foo', bins: [] },
                       { metric: '', bins: [ 50, 100, 150, 200, 'inf'] } ]

*/
{
  graphitePort: Number(process.env.GRAPHITE_PORT) || Number(process.env.GRAPHITE_PORT_2003_TCP_PORT) || 2003
, graphiteHost: process.env.GRAPHITE_HOST || process.env.GRAPHITE_PORT_2003_TCP_ADDR || undefined
, port: 8125
, backends: [ "./backends/graphite" ]
, debug: !!process.env.DEBUG
, legacyNamespace: false
}
<|endoftext|>


<commit_before>$( "#artists" ).on( "click", function( event ) {
    artists.load()
})

$( "#albums" ).on( "click", function( event ) {
    albums.load()
})

$("#tracks").on("click", function(event) {
    tracks.load()
})

<commit_msg>Choosing tab clears list div<commit_after>$( "#artists" ).on( "click", function( event ) {
    $("#list").empty()
    artists.load()
})

$( "#albums" ).on( "click", function( event ) {
    $("#list").empty()
    albums.load()
})

$("#tracks").on("click", function(event) {
    $("#list").empty()
    tracks.load()
})

<|endoftext|>


<commit_before>
var dataTable;

$(function() {
  var jsonObj,
    userID = '',
    accountID = '';
  $("#lock_ids").click(function(event) {
    /* Act on the event */
    userID = $('#userID').val()
    accountID = $("#accountID").val()
  });

  function get_file() {
    data = $("#id_encrypted_file")[0].files[0]
    var reader = new FileReader()
    reader.readAsText(data)
    reader.onload = function(event) {
      jsonObj = JSON.parse(event.target.result);
    }
  }
  $("#load_file").click(function(event) {
    /* Act on the event */
    get_file()
    $("#loading").html('File is loaded')
  });
  $('#register').click(function(event) {
    /* Act on the event */
    // event.preventDefault();
    // get_file()
    sendPost(jsonObj, $(this)[0].id, register_template)
  });

  $('#start_session').click(function(event) {
    // get_file()
    // event.preventDefault();
    sendPost(jsonObj, $(this)[0].id, start_session_template)
  });
  $("#users").click(function(event) {
    /* Act on the event */
    sendPost(jsonObj, $(this)[0].id + '/' + userID + '/', ussers_template)
  });
  $("#accounts").click(function(event) {
    /* Act on the event */
    sendPost(jsonObj, $(this)[0].id + '/' + userID + '/' + accountID, accounts_template)

  });
  $("#payment").click(function(event) {
    /* Act on the event */
    sendPost(jsonObj, $(this)[0].id + '/' + userID + '/' + accountID, payments_template)

  });
  $("#card").click(function(event) {
    /* Act on the event */
    sendPost(jsonObj, $(this)[0].id + '/' + userID + '/' + accountID, card_template)

  });
  $("#mastercard_action").click(function(event) {
    /* Act on the event */
  });
  $("#export").click(function(event) {
    /* Act on the event */
    pages = $("#pages").val()
    if (dataTable) {
      curentPage = dataTable.currentPage
      if (pages) {

        dataTable.export('csv', 'Bunq-transactions', ';', '\r\n', [pages])
      }else {
        dataTable.export('csv', 'Bunq-transactions', ';', '\r\n', curentPage)

      }
    }else {
      $("#loading").html('Table is not created yet?')
    }
  });
});

function sendPost(json, action, template) {
  $('#loading').html('')
  csrftoken = Cookies.get('csrftoken')

  function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
  }
  frm = $("#encryption_form");
  $.ajax({
      url: '/API/' + action,
      type: frm.attr('method'),
      dataType: '',
      data: {
        'json': JSON.stringify(json),
        'pass': $('#id_encryption_password').val()
      },
      beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
          xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
      }
    })
    .done(function(response) {
      r = JSON.parse(response)
      // r = response
      // $("#response").html(response)
      if (r.Error !== undefined) {
             show(r.Error[0], true)
              $("#loading").html('')
            }else if (r.Response[0].Payment) {
              createTable(r.Response)
              $("#loading").html('')
            } else if (r.Response){
              show(r.Response, false, template)
              $("#loading").html('')
            }

      //
      // else {
      //   show(r, true)
      // }

})
    .fail(function() {})
    .always(function() {});
}

function show(j, error, template) {
  // var template = $('#template').html()
  // // Mustache.parse(template)
  // var rendered;
  if (error) {
    $("#response").html(j.error_description_translated)

  } else {

    // rendered = Mustache.render(template, j)
    // $("#response").html(rendered)
    $.get(template, function(template) {
      var rendered = Mustache.render(template, j)
      $('#response').html(rendered)
    })
  }
}

function createTable(input) {

    var rows = [],
        headers = [
          'Payment ID',
          'Account ID',
          'Date',
          'Ammount',
          'Account IBAN',
          'Payee IBAN',
          'Name',
          'Description',
          'Type'
        ]

    for (var i = 0; i < input.length; i++) {
        rows.push([
          input[i].Payment.id,
          input[i].Payment.monetary_account_id,
          input[i].Payment.updated,
          input[i].Payment.amount.value,
          input[i].Payment.alias.iban,
          input[i].Payment.counterparty_alias.iban,
          input[i].Payment.counterparty_alias.label_user.public_nick_name,
          input[i].Payment.description,
          input[i].Payment.type
        ])
    }
    options = {
        data: {
            'headings': headers,
            "rows": rows
        }
    }

    // Check to see if initialized
    if (dataTable) {
        // Wipe the table
        dataTable.destroy();

        // Destroy the containers
        // dataTable.wrapper.parentNode.replaceChild(dataTable.table, dataTable.wrapper);
        // dataTable.init(options)
    }

    // Initialize with the data
    dataTable = new DataTable("#response2", options);
    // dataTable.destroy()
}

function exportTable(){

}
<commit_msg>Cleaned JS<commit_after>var dataTable;

$(function() {
  var jsonObj,
    userID = '',
    accountID = '';
  $("#lock_ids").click(function(event) {
    userID = $('#userID').val()
    accountID = $("#accountID").val()
  });

  function get_file() {
    data = $("#id_encrypted_file")[0].files[0]
    var reader = new FileReader()
    reader.readAsText(data)
    reader.onload = function(event) {
      jsonObj = JSON.parse(event.target.result);
    }
  }
  $("#load_file").click(function(event) {
    get_file()
    $("#loading").html('File is loaded')
  });
  $('#register').click(function(event) {
    sendPost(jsonObj, $(this)[0].id, register_template)
  });

  $('#start_session').click(function(event) {
    sendPost(jsonObj, $(this)[0].id, start_session_template)
  });
  $("#users").click(function(event) {
    sendPost(jsonObj, $(this)[0].id + '/' + userID + '/', ussers_template)
  });
  $("#accounts").click(function(event) {
    sendPost(jsonObj, $(this)[0].id + '/' + userID + '/' + accountID, accounts_template)

  });
  $("#payment").click(function(event) {
    sendPost(jsonObj, $(this)[0].id + '/' + userID + '/' + accountID, payments_template)

  });
  $("#card").click(function(event) {
    sendPost(jsonObj, $(this)[0].id + '/' + userID + '/' + accountID, card_template)

  });
  $("#mastercard_action").click(function(event) {});
  $("#export").click(function(event) {
    pages = $("#pages").val()
    if (dataTable) {
      curentPage = dataTable.currentPage
      if (pages) {

        dataTable.export('csv', 'Bunq-transactions', ';', '\r\n', [pages])
      } else {
        dataTable.export('csv', 'Bunq-transactions', ';', '\r\n', curentPage)

      }
    } else {
      $("#loading").html('Table is not created yet?')
    }
  });
});

function sendPost(json, action, template) {
  $('#loading').html('')
  csrftoken = Cookies.get('csrftoken')

  function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
  }
  frm = $("#encryption_form");
  $.ajax({
      url: '/API/' + action,
      type: frm.attr('method'),
      dataType: '',
      data: {
        'json': JSON.stringify(json),
        'pass': $('#id_encryption_password').val()
      },
      beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
          xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
      }
    })
    .done(function(response) {
      r = JSON.parse(response)
      if (r.Error !== undefined) {
        show(r.Error[0], true)
      } else if (r.Response[0].Payment) {
        createTable(r.Response)
      } else if (r.Response) {
        show(r.Response, false, template)
      }
    })
    .fail(function() {
      e = {
        'error_description_translated': 'Something went wrong server-side. Did you input you encrypted JSON file?'
      }
      show(e, true)
    })
    .always(function() {
      $("#loading").html('')
    });
}

function show(j, error, template) {
  if (error) {
    $("#response").html(j.error_description_translated)

  } else {
    $.get(template, function(template) {
      var rendered = Mustache.render(template, j)
      $('#response').html(rendered)
    })
  }
}

function createTable(input) {

  var rows = [],
    headers = [
      'Payment ID',
      'Account ID',
      'Date',
      'Ammount',
      'Account IBAN',
      'Payee IBAN',
      'Name',
      'Description',
      'Type'
    ]

  for (var i = 0; i < input.length; i++) {
    rows.push([
      input[i].Payment.id,
      input[i].Payment.monetary_account_id,
      input[i].Payment.updated,
      input[i].Payment.amount.value,
      input[i].Payment.alias.iban,
      input[i].Payment.counterparty_alias.iban,
      input[i].Payment.counterparty_alias.label_user.public_nick_name,
      input[i].Payment.description,
      input[i].Payment.type
    ])
  }
  options = {
    data: {
      'headings': headers,
      "rows": rows
    }
  }
  if (dataTable) {
    dataTable.destroy();
  }
  dataTable = new DataTable("#response2", options);
}
<|endoftext|>


<commit_before>"use strict";

var includes      = require("../array/#/contains")
  , uniq          = require("../array/#/uniq")
  , objForEach    = require("./for-each")
  , isPlainObject = require("./is-plain-object")
  , ensureValue   = require("./valid-value");

var isArray = Array.isArray, slice = Array.prototype.slice;

var deepAssign = function (target, source) {
	if (isPlainObject(target)) {
		if (!isPlainObject(source)) return source;
		objForEach(source, function (value, key) { target[key] = deepAssign(target[key], value); });
		return target;
	}
	if (isArray(target)) {
		if (!isArray(source)) return source;
		source.forEach(function (item) { if (!includes.call(target, item)) target.push(item); });
		return target;
	}
	return source;
};

module.exports = function (target/*, ...objects*/) {
	return uniq
		.call([ensureValue(target)].concat(slice.call(arguments, 1).map(ensureValue)))
		.reduce(deepAssign);
};
<commit_msg>refactor: seclude assign logic<commit_after>"use strict";

var includes      = require("../array/#/contains")
  , uniq          = require("../array/#/uniq")
  , objForEach    = require("./for-each")
  , isPlainObject = require("./is-plain-object")
  , ensureValue   = require("./valid-value");

var isArray = Array.isArray, slice = Array.prototype.slice;

var assignObject = function (target, source) {
	// eslint-disable-next-line no-use-before-define
	objForEach(source, function (value, key) { target[key] = deepAssign(target[key], value); });
};

var assignArray = function (target, source) {
	source.forEach(function (item) { if (!includes.call(target, item)) target.push(item); });
};

var deepAssign = function (target, source) {
	if (isPlainObject(target)) {
		if (!isPlainObject(source)) return source;
		assignObject(target, source);
		return target;
	}
	if (isArray(target)) {
		if (!isArray(source)) return source;
		assignArray(target, source);
		return target;
	}
	return source;
};

module.exports = function (target/*, ...objects*/) {
	return uniq
		.call([ensureValue(target)].concat(slice.call(arguments, 1).map(ensureValue)))
		.reduce(deepAssign);
};
<|endoftext|>


<commit_before>/* loading of amout of players credits */
$(document).ready(function () {
		ajax.send({
			requestId: 'CreditsAmount',
			relatedObject: 'CreditsAmount',
			data: {},
			repeatEvery: 5,
			callback: function (credits) {
				$('.creditsAmount').each(function () {
					var before = +$(this).text();
					$(this).text(credits);
					if (before && before != credits) {
						if (before > credits) {
							$(this).css('color', 'red');
						} else {
							$(this).css('color', 'green');
						}
						$(this).stop().animate({
							color: "white"
						}, 2500);
					}
				});
			}
		});
});<commit_msg>Repaired credits color changing.<commit_after>/* loading of amout of players credits */
$(document).ready(function () {
		ajax.send({
			requestId: 'CreditsAmount',
			relatedObject: 'CreditsAmount',
			data: {},
			repeatEvery: 5,
			callback: function (credits) {
				$('.creditsAmount').each(function () {
					var before = $(this).text();
					$(this).text(credits);
					if (before != '-' && before != credits) {
						if (before > credits) {
							$(this).css('color', 'red');
						} else {
							$(this).css('color', 'green');
						}
						$(this).stop().animate({
							color: "white"
						}, 2500);
					}
				});
			}
		});
});<|endoftext|>


<commit_before>import React from 'react';
import { expect } from 'chai';
import { mount, shallow } from 'enzyme';

import Controls from '../client/controls';

describe('<Controls />', () => {
  it ('should have h3 tag', () => {
		const wrapper = shallow(<Controls />);
    expect(wrapper.find('h3')).to.have.length(1);
	});
});
<commit_msg>[FEATURE] - add tests to testing suite<commit_after>import React from 'react';
import { expect } from 'chai';
import { mount, shallow } from 'enzyme';

import Controls from '../client/controls';
import Challenge from '../client/components/challenge';

describe('<Controls />', () => {
  it ('should have h3 tag', () => {
		const wrapper = shallow(<Controls />);
    expect(wrapper.find('h3')).to.have.length(1);
	});
});

describe('<Challenge />', () => {
  const wrapper = shallow(<Challenge />);
  it('should have a state', () =>{
    expect(wrapper.state()).to.be.defined;
  });

  it('should have a checkRegex function', () => {
    expect(wrapper.checkRegex).to.be.defined;
  });
});
<|endoftext|>


<commit_before>/*
 * tzmap.js - Library for working with the geography of timezones in JavaScript

 * Written in 2011 by L. David Baron <dbaron@dbaron.org>

 * To the extent possible under law, the author(s) have dedicated all
 * copyright and related and neighboring rights to this software to the
 * public domain worldwide.  This software is distributed without any
 * warranty.
 *
 * You should have received a copy of the CC0 Public Domain Dedication
 * along with this software.  If not, see
 * <http://creativecommons.org/publicdomain/zero/1.0/>.
 */
(function() {
    "use strict";

    var gXHR = null;
    var gLoadSuccessCallbacks = [];
    var gLoadErrorCallbacks = [];
    var gJSON = null;

    var public_loadData = function(path, success_callback, error_callback) {
        if (gJSON) {
            if (success_callback) {
                setTimeout(success_callback, 0);
            }
            return;
        }
        if (success_callback) {
            gLoadSuccessCallbacks.push(success_callback);
        }
        if (error_callback) {
            gLoadErrorCallbacks.push(error_callback);
        }
        if (gXHR) {
            return;
        }

        var protocol_match = path.match(/^([^/?#]+):/)
        var isHTTP;
        if (protocol_match) {
            isHTTP = protocol_match[1] == "http" ||
                     protocol_match[1] == "https";
        } else {
            isHTTP = window.location.protocol == "http:" ||
                     window.location.protocol == "https:";
        }
        path += "world-map.json";
        if (isHTTP) {
            path += ".gz";
        }

        function rsc() {
            if (gXHR.readyState != 4) {
                return;
            }

            var success = false;
            if (!isHTTP || (200 <= gXHR.status && gXHR.status < 300)) {
                var json = null;
                try {
                    if ("responseType" in gXHR) {
                        json = gXHR.response;
                    } else {
                        json = JSON.parse(gXHR.responseText);
                    }
                } catch (ex) {
                }
                if (json && json.chains && json.zones) {
                    success = true;
                    gJSON = json;
                }
            }

            var callbacks = success ? gLoadSuccessCallbacks
                                    : gLoadErrorCallbacks;

            gLoadSuccessCallbacks = [];
            gLoadErrorCallbacks = [];
            gXHR = null;

            for (var idx in callbacks) {
                callbacks[idx]();
            }
        }

        gXHR = new XMLHttpRequest();
        gXHR.onreadystatechange = rsc;
        gXHR.open("GET", path);
        if ("responseType" in gXHR) {
            gXHR.responseType = "json";
        }
        gXHR.send();
    }

    /**
     * Check if needle is in [rangea, rangeb] or [rangeb, rangea].
     */
    function in_range(needle, rangea, rangeb) {
        if (rangea < rangeb) {
            return rangea <= needle && needle <= rangeb;
        } else {
            return rangeb <= needle && needle <= rangea;
        }
    }

    function zoneContains(tzid, lat, lon) {
        var zones = gJSON.zones;
        var chains = gJSON.chains;

        var zone = zones[tzid];
        for (var polygonIdx in zone) {
            var polygon = zone[polygonIdx];

            // Since we don't need to worry about zones containing the
            // north pole (FIXME: really?), we can just count the number
            // of times that a north-south line from the north pole to
            // our point intersects the zone.
            // Furthermore, the segments are short enough that we don't
            // need to worry about whether they're great circle lines or
            // lines on an easier projection.
            var intersects = 0;
            for (var chainIdx in polygon) {
                var chainobj = polygon[chainIdx];
                var chainID = chainobj[0];
                var chainInv = chainobj[1];
                var chain = chains[chainID];
                var prevlon, prevlat;
                for (var pointIdx in chain) {
                    var pointobj = chain[pointIdx];
                    var ptlon = pointobj[0];
                    var ptlat = pointobj[1];
                    if (pointIdx > 0) {
                        if (ptlon == prevlon) {
                            // vertical line.  All we need to do is
                            // check if our point is *on* it.
                            if (ptlon == lon
                                && in_range(lat, ptlat, prevlat))
                                return true;
                        } else {
                            var alon, ptalon, prevalon;
                            if (Math.abs(ptlon - prevlon) > 180) {
                                // this segment crosses the date line,
                                // so use adjusted numbers instead
                                alon = (lon + 180) % 360;
                                ptalon = (ptlon + 180) % 360;
                                prevalon = (prevlon + 180) % 360;
                            } else {
                                alon = lon;
                                ptalon = ptlon;
                                prevalon = prevlon;
                            }

                            if (ptalon < prevalon) {
                                var tmp = ptalon;
                                ptalon = prevalon;
                                prevalon = tmp;
                            }

                            // Check the endpoint at the west end but
                            // not the east end.  This does the right
                            // thing for the intersects count, since we
                            // need to worry about both what happens
                            // when the segments turn back the opposite
                            // east/west or continue the same east/west
                            // from the boundary.  FIXME: But it's not
                            // quite right for the on-the-line check.
                            if (prevalon <= alon && alon < ptalon) {
                                var xlat = prevlat + (ptlat - prevlat) * ((alon - prevalon) / (ptalon - prevalon));
                                if (xlat == lat)
                                    // on the line
                                    return true;
                                if (xlat > lat) {
                                    ++intersects;
                                }
                            }
                        }
                    }
                    prevlon = ptlon;
                    prevlat = ptlat;
                }
            }
            if (intersects % 2 == 1) {
                return true;
            }
        }
        return false;
    }

    var public_zoneContains = function(zone, lat, lon) {
        if (lat >= 90 || lat <= -90)
            return null;
        lon = ((lon % 360) + 180) % 360 - 180;

        return zoneContains(zone, lat, lon);
    }

    var public_zoneAt = function(lat, lon) {
        if (lat >= 90 || lat <= -90)
            return null;
        lon = ((lon % 360) + 180) % 360 - 180;

        for (var tzid in gJSON.zones) {
            if (zoneContains(tzid, lat, lon)) {
                return tzid;
            }
        }
        return null;
    }

    function firstpt(chainID) {
        return gJSON.chains[chainID][0];
    }

    function lastpt(chainID) {
        var chain = gJSON.chains[chainID];
        return chain[chain.length - 1];
    }

    function pts_equal(a, b) {
        return a[0] == b[0] && a[1] == b[1];
    }

    var public_polygonsFor = function(zone_array) {
        // A set of chain IDs, except there is a useful value on the
        // value side of the hash:  whether the chain is used forwards
        // (false) or in reverse (true).
        var chains = {};

        for (var zoneIdx in zone_array) {
            var tzid = zone_array[zoneIdx];
            var zone = gJSON.zones[tzid];
            for (var polygonIdx in zone) {
                var polygon = zone[polygonIdx];
                for (var chainIdx in polygon) {
                    var chainobj = polygon[chainIdx];
                    var chainID = chainobj[0];
                    var reverse = chainobj[1];
                    if (chainID in chains) {
                        // It's a shared boundary
                        delete chains[chainID];
                    } else {
                        chains[chainID] = reverse;
                    }
                }
            }
        }

        var result = [];

        // Append the polygons that are in one chain, and put the rest
        // of the chains in a hash by their starting longitude.
        var startlons = {};
        for (var chainID in chains) {
            if (pts_equal(firstpt(chainID), lastpt(chainID))) {
                // This chain is a complete polygon.
                var reverse = chains[chainID];
                var chain = gJSON.chains[chainID];
                if (chains[chainID]) {
                    // append in reverse
                    result.push([].concat(chain).reverse());
                } else {
                    // append in forward order (without copy)
                    result.push(chain);
                }
            } else {
                var reverse = chains[chainID];
                var info = { chainID: chainID, reverse: reverse };
                var startlon = (reverse ? lastpt : firstpt)(chainID)[0];
                if (startlon in startlons) {
                    startlons[startlon].push(info);
                } else {
                    startlons[startlon] = [ info ];
                }
            }
        }
        chains = null;

        // Deal with the polygons that we hashed by starting longitude.
        function first_startlon() {
            for (var startlon in startlons) {
                return startlon;
            }
            return null;
        }
        for (;;) {
            var startlon = first_startlon();
            if (startlon === null) {
                break;
            }
            var polygon = [];
            do {
                var arr, info;
                if (polygon.length == 0) {
                    arr = startlons[startlon];
                    info = arr.pop();
                } else {
                    var startpt = polygon[polygon.length - 1];
                    startlon = startpt[0];
                    arr = startlons[startlon];
                    info = null;
                    for (var idx in arr) {
                        var testinfo = arr[idx];
                        var testpt = (testinfo.reverse ? lastpt : firstpt)(testinfo.chainID);
                        if (testpt[1] == startpt[1]) {
                            arr.splice(idx, 1);
                            info = testinfo;
                            break;
                        }
                    }
                }
                if (arr.length == 0) {
                    delete startlons[startlon];
                }
                var chain = gJSON.chains[info.chainID];
                if (info.reverse) {
                    polygon = polygon.concat([].concat(chain).reverse());
                } else {
                    polygon = polygon.concat(chain);
                }
                // Note: minimum of 2 iterations
            } while (!pts_equal(polygon[0], polygon[polygon.length - 1]));
            result.push(polygon);
        }

        return result;
    }

    // Exports:
    window.tzmap = {
        /**
         * loadData(path, success_callback, error_callback)
         *
         * This library has to load a significant amount of timezone
         * boundary data in order to work.  This function triggers the
         * loading of the data.  The path argument given is the path to
         * the directory in which the data are located (usually the same
         * as the script), which must end with a slash, and may be a
         * path relative to the document.  When the loading completes
         * successfully, success_callback is called; if it fails,
         * error_callback is called.
         *
         * Other methods of this library can be used only after
         * success_callback has been called.
         */
        loadData: public_loadData,

        /**
         * zoneContains(zone, lat, lon)
         *
         * Return whether the time zone name (e.g.,
         * "America/Los_Angeles") contains the point at the given
         * latitude and longitude or has that point on its boundary.
         * Supports the "uninhabited" zone, but not null.
         */
        zoneContains: public_zoneContains,

        /**
         * zoneAt(lat, lon)
         *
         * Return the time zone name (e.g., "America/Los_Angeles") at
         * the given latitude and longitude, "uninhabited" for land
         * areas for which no time zone is known for the location (e.g.,
         * Antarctica), or null for water areas.  If the location is
         * exactly on a time zone boundary, which time zone will be
         * returned is undefined, but one of them will be.
         */
        zoneAt: public_zoneAt,

        /**
         * polygonsFor(zone_array)
         *
         * Get the set of polygons for a set of timezones.  Each name in
         * zone_array should be an tz database timezone name.  This API
         * will return an array of non-adjacent polygons, where each
         * polygon is an array of points (the first and last being the
         * same), and each point is an array of [lon, lat] as floats.
         */
        polygonsFor: public_polygonsFor,
    };
})();
<commit_msg>Call the failure callback if gXHR.send() throws, as it does for some bad URI cases.<commit_after>/*
 * tzmap.js - Library for working with the geography of timezones in JavaScript

 * Written in 2011 by L. David Baron <dbaron@dbaron.org>

 * To the extent possible under law, the author(s) have dedicated all
 * copyright and related and neighboring rights to this software to the
 * public domain worldwide.  This software is distributed without any
 * warranty.
 *
 * You should have received a copy of the CC0 Public Domain Dedication
 * along with this software.  If not, see
 * <http://creativecommons.org/publicdomain/zero/1.0/>.
 */
(function() {
    "use strict";

    var gXHR = null;
    var gLoadSuccessCallbacks = [];
    var gLoadErrorCallbacks = [];
    var gJSON = null;

    var public_loadData = function(path, success_callback, error_callback) {
        if (gJSON) {
            if (success_callback) {
                setTimeout(success_callback, 0);
            }
            return;
        }
        if (success_callback) {
            gLoadSuccessCallbacks.push(success_callback);
        }
        if (error_callback) {
            gLoadErrorCallbacks.push(error_callback);
        }
        if (gXHR) {
            return;
        }

        var protocol_match = path.match(/^([^/?#]+):/)
        var isHTTP;
        if (protocol_match) {
            isHTTP = protocol_match[1] == "http" ||
                     protocol_match[1] == "https";
        } else {
            isHTTP = window.location.protocol == "http:" ||
                     window.location.protocol == "https:";
        }
        path += "world-map.json";
        if (isHTTP) {
            path += ".gz";
        }

        function do_notify(success) {
            var callbacks = success ? gLoadSuccessCallbacks
                                    : gLoadErrorCallbacks;

            gLoadSuccessCallbacks = [];
            gLoadErrorCallbacks = [];
            gXHR = null;

            for (var idx in callbacks) {
                callbacks[idx]();
            }
        }

        function rsc() {
            if (gXHR.readyState != 4) {
                return;
            }

            var success = false;
            if (!isHTTP || (200 <= gXHR.status && gXHR.status < 300)) {
                var json = null;
                try {
                    if ("responseType" in gXHR) {
                        json = gXHR.response;
                    } else {
                        json = JSON.parse(gXHR.responseText);
                    }
                } catch (ex) {
                }
                if (json && json.chains && json.zones) {
                    success = true;
                    gJSON = json;
                }
            }

            do_notify(success);
        }

        try {
            gXHR = new XMLHttpRequest();
            gXHR.onreadystatechange = rsc;
            gXHR.open("GET", path);
            if ("responseType" in gXHR) {
                gXHR.responseType = "json";
            }
            gXHR.send();
        } catch(ex) {
            do_notify(false);
        }
    }

    /**
     * Check if needle is in [rangea, rangeb] or [rangeb, rangea].
     */
    function in_range(needle, rangea, rangeb) {
        if (rangea < rangeb) {
            return rangea <= needle && needle <= rangeb;
        } else {
            return rangeb <= needle && needle <= rangea;
        }
    }

    function zoneContains(tzid, lat, lon) {
        var zones = gJSON.zones;
        var chains = gJSON.chains;

        var zone = zones[tzid];
        for (var polygonIdx in zone) {
            var polygon = zone[polygonIdx];

            // Since we don't need to worry about zones containing the
            // north pole (FIXME: really?), we can just count the number
            // of times that a north-south line from the north pole to
            // our point intersects the zone.
            // Furthermore, the segments are short enough that we don't
            // need to worry about whether they're great circle lines or
            // lines on an easier projection.
            var intersects = 0;
            for (var chainIdx in polygon) {
                var chainobj = polygon[chainIdx];
                var chainID = chainobj[0];
                var chainInv = chainobj[1];
                var chain = chains[chainID];
                var prevlon, prevlat;
                for (var pointIdx in chain) {
                    var pointobj = chain[pointIdx];
                    var ptlon = pointobj[0];
                    var ptlat = pointobj[1];
                    if (pointIdx > 0) {
                        if (ptlon == prevlon) {
                            // vertical line.  All we need to do is
                            // check if our point is *on* it.
                            if (ptlon == lon
                                && in_range(lat, ptlat, prevlat))
                                return true;
                        } else {
                            var alon, ptalon, prevalon;
                            if (Math.abs(ptlon - prevlon) > 180) {
                                // this segment crosses the date line,
                                // so use adjusted numbers instead
                                alon = (lon + 180) % 360;
                                ptalon = (ptlon + 180) % 360;
                                prevalon = (prevlon + 180) % 360;
                            } else {
                                alon = lon;
                                ptalon = ptlon;
                                prevalon = prevlon;
                            }

                            if (ptalon < prevalon) {
                                var tmp = ptalon;
                                ptalon = prevalon;
                                prevalon = tmp;
                            }

                            // Check the endpoint at the west end but
                            // not the east end.  This does the right
                            // thing for the intersects count, since we
                            // need to worry about both what happens
                            // when the segments turn back the opposite
                            // east/west or continue the same east/west
                            // from the boundary.  FIXME: But it's not
                            // quite right for the on-the-line check.
                            if (prevalon <= alon && alon < ptalon) {
                                var xlat = prevlat + (ptlat - prevlat) * ((alon - prevalon) / (ptalon - prevalon));
                                if (xlat == lat)
                                    // on the line
                                    return true;
                                if (xlat > lat) {
                                    ++intersects;
                                }
                            }
                        }
                    }
                    prevlon = ptlon;
                    prevlat = ptlat;
                }
            }
            if (intersects % 2 == 1) {
                return true;
            }
        }
        return false;
    }

    var public_zoneContains = function(zone, lat, lon) {
        if (lat >= 90 || lat <= -90)
            return null;
        lon = ((lon % 360) + 180) % 360 - 180;

        return zoneContains(zone, lat, lon);
    }

    var public_zoneAt = function(lat, lon) {
        if (lat >= 90 || lat <= -90)
            return null;
        lon = ((lon % 360) + 180) % 360 - 180;

        for (var tzid in gJSON.zones) {
            if (zoneContains(tzid, lat, lon)) {
                return tzid;
            }
        }
        return null;
    }

    function firstpt(chainID) {
        return gJSON.chains[chainID][0];
    }

    function lastpt(chainID) {
        var chain = gJSON.chains[chainID];
        return chain[chain.length - 1];
    }

    function pts_equal(a, b) {
        return a[0] == b[0] && a[1] == b[1];
    }

    var public_polygonsFor = function(zone_array) {
        // A set of chain IDs, except there is a useful value on the
        // value side of the hash:  whether the chain is used forwards
        // (false) or in reverse (true).
        var chains = {};

        for (var zoneIdx in zone_array) {
            var tzid = zone_array[zoneIdx];
            var zone = gJSON.zones[tzid];
            for (var polygonIdx in zone) {
                var polygon = zone[polygonIdx];
                for (var chainIdx in polygon) {
                    var chainobj = polygon[chainIdx];
                    var chainID = chainobj[0];
                    var reverse = chainobj[1];
                    if (chainID in chains) {
                        // It's a shared boundary
                        delete chains[chainID];
                    } else {
                        chains[chainID] = reverse;
                    }
                }
            }
        }

        var result = [];

        // Append the polygons that are in one chain, and put the rest
        // of the chains in a hash by their starting longitude.
        var startlons = {};
        for (var chainID in chains) {
            if (pts_equal(firstpt(chainID), lastpt(chainID))) {
                // This chain is a complete polygon.
                var reverse = chains[chainID];
                var chain = gJSON.chains[chainID];
                if (chains[chainID]) {
                    // append in reverse
                    result.push([].concat(chain).reverse());
                } else {
                    // append in forward order (without copy)
                    result.push(chain);
                }
            } else {
                var reverse = chains[chainID];
                var info = { chainID: chainID, reverse: reverse };
                var startlon = (reverse ? lastpt : firstpt)(chainID)[0];
                if (startlon in startlons) {
                    startlons[startlon].push(info);
                } else {
                    startlons[startlon] = [ info ];
                }
            }
        }
        chains = null;

        // Deal with the polygons that we hashed by starting longitude.
        function first_startlon() {
            for (var startlon in startlons) {
                return startlon;
            }
            return null;
        }
        for (;;) {
            var startlon = first_startlon();
            if (startlon === null) {
                break;
            }
            var polygon = [];
            do {
                var arr, info;
                if (polygon.length == 0) {
                    arr = startlons[startlon];
                    info = arr.pop();
                } else {
                    var startpt = polygon[polygon.length - 1];
                    startlon = startpt[0];
                    arr = startlons[startlon];
                    info = null;
                    for (var idx in arr) {
                        var testinfo = arr[idx];
                        var testpt = (testinfo.reverse ? lastpt : firstpt)(testinfo.chainID);
                        if (testpt[1] == startpt[1]) {
                            arr.splice(idx, 1);
                            info = testinfo;
                            break;
                        }
                    }
                }
                if (arr.length == 0) {
                    delete startlons[startlon];
                }
                var chain = gJSON.chains[info.chainID];
                if (info.reverse) {
                    polygon = polygon.concat([].concat(chain).reverse());
                } else {
                    polygon = polygon.concat(chain);
                }
                // Note: minimum of 2 iterations
            } while (!pts_equal(polygon[0], polygon[polygon.length - 1]));
            result.push(polygon);
        }

        return result;
    }

    // Exports:
    window.tzmap = {
        /**
         * loadData(path, success_callback, error_callback)
         *
         * This library has to load a significant amount of timezone
         * boundary data in order to work.  This function triggers the
         * loading of the data.  The path argument given is the path to
         * the directory in which the data are located (usually the same
         * as the script), which must end with a slash, and may be a
         * path relative to the document.  When the loading completes
         * successfully, success_callback is called; if it fails,
         * error_callback is called.
         *
         * Other methods of this library can be used only after
         * success_callback has been called.
         */
        loadData: public_loadData,

        /**
         * zoneContains(zone, lat, lon)
         *
         * Return whether the time zone name (e.g.,
         * "America/Los_Angeles") contains the point at the given
         * latitude and longitude or has that point on its boundary.
         * Supports the "uninhabited" zone, but not null.
         */
        zoneContains: public_zoneContains,

        /**
         * zoneAt(lat, lon)
         *
         * Return the time zone name (e.g., "America/Los_Angeles") at
         * the given latitude and longitude, "uninhabited" for land
         * areas for which no time zone is known for the location (e.g.,
         * Antarctica), or null for water areas.  If the location is
         * exactly on a time zone boundary, which time zone will be
         * returned is undefined, but one of them will be.
         */
        zoneAt: public_zoneAt,

        /**
         * polygonsFor(zone_array)
         *
         * Get the set of polygons for a set of timezones.  Each name in
         * zone_array should be an tz database timezone name.  This API
         * will return an array of non-adjacent polygons, where each
         * polygon is an array of points (the first and last being the
         * same), and each point is an array of [lon, lat] as floats.
         */
        polygonsFor: public_polygonsFor,
    };
})();
<|endoftext|>


<commit_before>// Description:
//   Build RPMs guy
//
// Commands:
//   hubot buildrpms <snappier-branch>,<snwebapi-branch>

var querystring = require('querystring');
var unirest = require('unirest');
var _ = require('lodash');
var Q = require('q');
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';

function makeRequest(jobName, queryParams) {
	var deferred = Q.defer();

	var endpoint = process.env.JENKINS_URL + '/view/WebAPI/job/' + jobName + '/buildWithParameters';

	unirest.post(endpoint)
		.auth({
			user: process.env.JENKINS_USERNAME,
			pass: process.env.JENKINS_API_KEY
		})
		.query(queryParams)
		.end(function (response) {
			deferred.resolve(response);
		});
	return deferred.promise;
}

function bundleRequests(requests) {
	var requestsToMake = [];

	_.each(requests, function(request) {
		requestsToMake.push(makeRequest(request.job, request.params));
	});

	return Q.all(requestsToMake);
}

module.exports = function(robot) {
	robot.respond(/build-dev (.*)/i, function(res) {
		var branches = res.match[1].trim().split(',');

		var snappierBranch = branches[0].trim();
		var webapiBranch = branches[0].trim();

		if (branches.length < 2) {
			res.reply('Not enough parameters supplied.  Expecting snappierbranch,webapibranch');
    	} else {
			var requests = [
				{
					job: 'SignNow_SNAppier_Dev_Deploy',
					params: {
						branch: snappierBranch
					}
				},
				{
					job: 'SignNow_WebAPI_Dev_Deploy',
					params: {
						branch: webapiBranch
					}
				}
			];

			bundleRequests(requests).then(function() {
				res.reply('Builds queued up!');
			});
    	}
	});

	robot.respond(/build-stage (.*)/i, function(res) {
		var branches = res.match[1].trim().split(',');

		var snappierBranch = branches[0].trim();
		var webapiBranch = branches[0].trim();

		if (branches.length < 2) {
			res.reply('Not enough parameters supplied.  Expecting snappierbranch,webapibranch');
    	} else {
			var requests = [
				{
					job: 'CudaSign_SNAppier_Stage_Deploy',
					params: {
						branch: snappierBranch
					}
				},
				{
					job: 'CudaSign_WebAPI_Stage_Deploy',
					params: {
						branch: webapiBranch
					}
				},
				{
					job: 'SignNow_SNAppier_Stage_Deploy',
					params: {
						branch: snappierBranch
					}
				},
				{
					job: 'SignNow_WebAPI_Stage_Deploy',
					params: {
						branch: webapiBranch
					}
				}
			];

			bundleRequests(requests).then(function() {
				res.reply('Builds queued up!');
			});
    	}
	});

	robot.respond(/build-rpms (.*)/i, function(res) {
		var branches = res.match[1].trim().split(',');

		var snappierBranch = branches[0].trim();
		var webapiBranch = branches[0].trim();

		if (branches.length < 2) {
			res.reply('Not enough parameters supplied.  Expecting snappierbranch,webapibranch');
    	} else {
			var requests = [
				{
					job: 'SNAppier_Builder_v2',
					params: {
						SNAppierBranch: snappierBranch,
						Build_Target_Env: 'qa'
					}
				},
				{
					job: 'SNAppier_Builder_v2',
					params: {
						SNAppierBranch: snappierBranch,
						Build_Target_Env: 'rc-sn'
					}
				},
				{
					job: 'WebAPI_Builder_v2',
					params: {
						WebApiBranch: snappierBranch
					}
				}
			];

			bundleRequests(requests).then(function() {
				res.reply('Builds queued up!');
			});
    	}
	});
};<commit_msg>trying to debug?<commit_after>// Description:
//   Build RPMs guy
//
// Commands:
//   hubot buildrpms <snappier-branch>,<snwebapi-branch>

var querystring = require('querystring');
var unirest = require('unirest');
var _ = require('lodash');
var Q = require('q');
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';

function makeRequest(jobName, queryParams) {
	var deferred = Q.defer();

	var endpoint = process.env.JENKINS_URL + '/view/WebAPI/job/' + jobName + '/buildWithParameters';

	unirest.post(endpoint)
		.auth({
			user: process.env.JENKINS_USERNAME,
			pass: process.env.JENKINS_API_KEY
		})
		.query(queryParams)
		.end(function (response) {
			deferred.resolve(response);
		});
	return deferred.promise;
}

function bundleRequests(requests) {
	var requestsToMake = [];

	_.each(requests, function(request) {
		requestsToMake.push(makeRequest(request.job, request.params));
	});

	return Q.all(requestsToMake);
}

module.exports = function(robot) {
	robot.respond(/build-dev (.*)/i, function(res) {
		var branches = res.match[1];

		if (!branches || branches.trim().split(',').length < 2) {
			res.reply('Not enough parameters supplied.  Expecting snappierbranch,webapibranch');
    	} else {
       		var snappierBranch = branches.trim().split(',')[0].trim();
    		var webapiBranch = branches.trim().split(',')[1].trim();

			var requests = [
				{
					job: 'SignNow_SNAppier_Dev_Deploy',
					params: {
						branch: snappierBranch
					}
				},
				{
					job: 'SignNow_WebAPI_Dev_Deploy',
					params: {
						branch: webapiBranch
					}
				}
			];

			bundleRequests(requests).then(function(response) {
				res.send(JSON.stringify(response));
				res.reply('Builds queued up!');
			});
    	}
	});

	robot.respond(/build-stage (.*)/i, function(res) {
		var branches = res.match[1];

		if (!branches || branches.trim().split(',').length < 2) {
			res.reply('Not enough parameters supplied.  Expecting snappierbranch,webapibranch');
    	} else {
    		var snappierBranch = branches.trim().split(',')[0].trim();
    		var webapiBranch = branches.trim().split(',')[1].trim();
			var requests = [
				{
					job: 'CudaSign_SNAppier_Stage_Deploy',
					params: {
						branch: snappierBranch
					}
				},
				{
					job: 'CudaSign_WebAPI_Stage_Deploy',
					params: {
						branch: webapiBranch
					}
				},
				{
					job: 'SignNow_SNAppier_Stage_Deploy',
					params: {
						branch: snappierBranch
					}
				},
				{
					job: 'SignNow_WebAPI_Stage_Deploy',
					params: {
						branch: webapiBranch
					}
				}
			];

			bundleRequests(requests).then(function() {
				res.reply('Builds queued up!');
			});
    	}
	});

	robot.respond(/build-rpms (.*)/i, function(res) {
		var branches = res.match[1];

		if (branches = undefined || !branches || branches.length < 2) {
			res.reply('Not enough parameters supplied.  Expecting snappierbranch,webapibranch');
    	} else {
    		var snappierBranch = branches.trim().split(',')[0].trim();
    		var webapiBranch = branches.trim().split(',')[1].trim();

			var requests = [
				{
					job: 'SNAppier_Builder_v2',
					params: {
						SNAppierBranch: snappierBranch,
						Build_Target_Env: 'qa'
					}
				},
				{
					job: 'SNAppier_Builder_v2',
					params: {
						SNAppierBranch: snappierBranch,
						Build_Target_Env: 'rc-sn'
					}
				},
				{
					job: 'WebAPI_Builder_v2',
					params: {
						WebApiBranch: snappierBranch
					}
				}
			];

			bundleRequests(requests).then(function() {
				res.reply('Builds queued up!');
			});
    	}
	});
};<|endoftext|>


<commit_before>'use strict';

var unmarshalJson = require('../index').unmarshalJson;

var item = {
  name: {S: 'Will Vaughn'},
  age: {N: '30'},
  employed: {BOOL: true},
  relationshipStatus: {NULL: true},
  defaultReplies: {
    L: [
      {S: 'No.'},
      {N: '42'}
    ]
  },
  appearance: {
    M: {
      height: {N: '183'},
      weight: {N: '79'},
      eyeColor: {S: 'brown'},
      ethnicity: {
        M: {
          whiteAmerican: {BOOL: true},
          nativeAmerican: {BOOL: false},
          asianAmerican: {BOOL: false},
          africanAmerican: {BOOL: false},
          nativeHawaiianOrPacificIslander: {BOOL: false},
          someOtherRace: {BOOL: false}
        }
      }
    }
  },
  favoriteFoods: {
    SS: [
      'burritos',
      'fried chicken',
      'pad kee mao'
    ]
  },
  luckyNumbers: {
    NS: ['42', '98', '777']
  }
};

// unmarshalJson() uses unmarshalItem() to do the work, but just stringifies the item to JSON for you.
console.log(unmarshalJson(item));

//{
//  "name": "Will Vaughn",
//  "age": 30,
//  "employed": true,
//  "relationshipStatus": null,
//  "defaultReplies": ["No.", 42],
//  "appearance": {
//    "height": 183,
//    "weight": 79,
//    "eyeColor": "brown",
//    "ethnicity": {
//      "whiteAmerican": true,
//      "nativeAmerican": false,
//      "asianAmerican": false,
//      "africanAmerican": false,
//      "nativeHawaiianOrPacificIslander": false,
//      "someOtherRace": false
//    }
//  },
//  "favoriteFoods": ["burritos", "fried chicken", "pad kee mao"],
//  "luckyNumbers": [42, 98, 777]
//}
<commit_msg>80 maxchar on a comment in example-unmarshal.js<commit_after>'use strict';

var unmarshalJson = require('../index').unmarshalJson;

var item = {
  name: {S: 'Will Vaughn'},
  age: {N: '30'},
  employed: {BOOL: true},
  relationshipStatus: {NULL: true},
  defaultReplies: {
    L: [
      {S: 'No.'},
      {N: '42'}
    ]
  },
  appearance: {
    M: {
      height: {N: '183'},
      weight: {N: '79'},
      eyeColor: {S: 'brown'},
      ethnicity: {
        M: {
          whiteAmerican: {BOOL: true},
          nativeAmerican: {BOOL: false},
          asianAmerican: {BOOL: false},
          africanAmerican: {BOOL: false},
          nativeHawaiianOrPacificIslander: {BOOL: false},
          someOtherRace: {BOOL: false}
        }
      }
    }
  },
  favoriteFoods: {
    SS: [
      'burritos',
      'fried chicken',
      'pad kee mao'
    ]
  },
  luckyNumbers: {
    NS: ['42', '98', '777']
  }
};

// unmarshalJson() uses unmarshalItem() to do the work.
// It just stringifies the item to JSON for you.
console.log(unmarshalJson(item));

//{
//  "name": "Will Vaughn",
//  "age": 30,
//  "employed": true,
//  "relationshipStatus": null,
//  "defaultReplies": ["No.", 42],
//  "appearance": {
//    "height": 183,
//    "weight": 79,
//    "eyeColor": "brown",
//    "ethnicity": {
//      "whiteAmerican": true,
//      "nativeAmerican": false,
//      "asianAmerican": false,
//      "africanAmerican": false,
//      "nativeHawaiianOrPacificIslander": false,
//      "someOtherRace": false
//    }
//  },
//  "favoriteFoods": ["burritos", "fried chicken", "pad kee mao"],
//  "luckyNumbers": [42, 98, 777]
//}
<|endoftext|>


<commit_before>import assert from 'assert'
import DexieRelationships from '../../src/index'

describe('simple', function () {
  var Promise = Dexie.Promise;
  var db = new Dexie('bands-simple', {addons: [DexieRelationships]});
  db.version(1).stores({
    genres: `
            id,
            name`,
    bands: `
            id,
            name,
            genreId -> genres.id`,
    albums: `
            id,
            name,
            bandId -> bands.id,
            year`
  });

  beforeEach(function() {
    return db.delete()
      .then(()=>{
        return db.open();
      }).then(()=> {
        return db.transaction('rw', db.bands, db.albums, db.genres, ()=>{
          // Genres
          db.genres.bulkAdd([{
            id: 1,
            name: "Rock"
          },{
            id: 2,
            name: "Schlager"
          }])

          // Bands
          db.bands.bulkAdd([{
            id: 1,
            name: 'Beatles',
            genreId: 1
          },{
            id: 2,
            name: 'Abba',
            genreId: 2
          }])

          // Albums
          db.albums.bulkAdd([{
            id: 1,
            name: 'Abbey Road',
            year: 1969,
            bandId: 1
          }, {
            id: 2,
            name: 'Let It Be',
            year: 1970,
            bandId: 1
          }, {
            id: 3,
            name: 'Super Trouper',
            bandId: 2,
            year: 1980
          }, {
            id: 4,
            name: 'Waterloo',
            bandId: 2,
            year: 1974
          }])
        })
      })
  })

  describe('many-to-one', function () {
    it('should be possible to retrieve an entity with a collection of referring entities attached to it', function () {
      return db.bands.where('name').equals('Beatles').with({
        albums: 'albums'
      }).then (bands => {
        assert(bands.length == 1, "Should be one Beatles")
        let beatles = bands[0]
        assert(!!beatles.albums, "Should have got the foreign albums collection")
        assert(beatles.albums.length === 2, "Should have 2 albums in this db")
        assert(beatles.albums[0].name === "Abbey Road", "First albums should be 'Abbey Roead'")
        assert(beatles.albums[1].name === "Let It Be", "Second album should be 'Let It Be'")
      })
    })
  })

  describe('one-to-one', ()=> {
    it('should be possible to retrieve entity with a foreign key to expand that foreign key', ()=>{
      return db.albums.where('year').between(1970, 1974, true, true).with ({
        band: 'bandId'
      }).then (albums => {
        assert (albums.length === 2, "Should retrieve two albums between 1970 to 1974")
        let letItBe = albums[0],
          waterloo = albums[1]
        assert (letItBe.name === "Let It Be", "First album should be 'Let It Be'")
        assert (!!letItBe.band, "Should get the band resolved with the query")
        assert (letItBe.band.name === "Beatles", "The band should be Beatles")

        assert (waterloo.name === "Waterloo", "Second album should be 'Waterloo'")
        assert (!!waterloo.band, "Should get the band resolved with the query")
        assert (waterloo.band.name === "Abba", "The band should be Abba")
      })
    })
  })

  describe('Multiple foreign keys of different kind', ()=>{
    it('Should be possible to retrieve entities with oneToOne as well as manyToOne relations', ()=> {
      return db.bands.where('name').equals('Beatles').with({
        albums: 'albums',
        genre: 'genreId'
      }).then (bands => {
        assert(bands.length == 1, "Should be one Beatles")
        let beatles = bands[0]
        assert(!!beatles.albums, "Should have got the foreign albums collection")
        assert(beatles.albums.length === 2, "Should have 2 albums in this db")
        assert(beatles.albums[0].name === "Abbey Road", "First albums should be 'Abbey Roead'")
        assert(beatles.albums[1].name === "Let It Be", "Second album should be 'Let It Be'")
        assert(!!beatles.genre, "Should have got the foreign genre entity")
        assert(beatles.genre.name === "Rock", "The genre should be 'Rock' (even though that could be questionable)");
      })
    })
  })

  describe('Navigation properties should be non-enumerable', () => {
    it('should be possible to put back an object to indexedDB after ' +
      'having retrieved it with navigation properties ' +
      'without storing the navigation properties redundantly',
      ()=>{
        return db.bands.where('name').equals('Abba').with({albums: 'albums', genre: 'genreId'})
          .then(bands => {
            assert(bands.length === 1, "Should be one Abba");
            let abba = bands[0]
            assert (!!abba.albums, "Abba should have its 'albums' foreign collection")
            assert (!!abba.genre, "Abba should have its 'genre' foreign property")
            abba.customProperty = "Hello world"
            return db.bands.put(abba)
          }).then(()=>{
            return db.bands.where('name').equals('Abba').first()
          }).then(abba => {
            assert(!abba.albums, "Abba should not have the 'albums' foreign collection stored redundantly")
            assert(!abba.genre, "Abba should not have the 'genre' foreign property stored redundantly")
          })
      })
  })

  describe('Sample from README', ()=> {
    it('should be possible to copy and paste the sample from README', ()=>{
      return db.bands
        .where('name').startsWithAnyOf('A', 'B')
        .with({albums: 'albums', genre: 'genreId'}) // Resolves foreign keys into props
        .then(rows => {
          // Print the result:
          rows.forEach (band => {
            console.log (`Band Name: ${band.name}`)
            console.log (`Genre: ${band.genre.name}`)
            console.log (`Albums: ${JSON.stringify(band.albums, null, 4)}`)
          });
        }).then(()=>{
          assert (true, "Promise resolved and no exception occured")
        }).catch (ex => {
          assert (false, "Something went wrong: " + (ex.stack || ex))
        })
    })
  })
})
<commit_msg>Add failing test for one-to-many.<commit_after>import assert from 'assert'
import DexieRelationships from '../../src/index'

describe('simple', function () {
  var Promise = Dexie.Promise;
  var db = new Dexie('bands-simple', {addons: [DexieRelationships]});
  db.version(1).stores({
    genres: `
            id,
            name`,
    bands: `
            id,
            name,
            genreId -> genres.id`,
    albums: `
            id,
            name,
            bandId -> bands.id,
            year`
  });

  beforeEach(function() {
    return db.delete()
      .then(()=>{
        return db.open();
      }).then(()=> {
        return db.transaction('rw', db.bands, db.albums, db.genres, ()=>{
          // Genres
          db.genres.bulkAdd([{
            id: 1,
            name: "Rock"
          },{
            id: 2,
            name: "Schlager"
          }])

          // Bands
          db.bands.bulkAdd([{
            id: 1,
            name: 'Beatles',
            genreId: 1
          },{
            id: 2,
            name: 'Abba',
            genreId: 2
          }])

          // Albums
          db.albums.bulkAdd([{
            id: 1,
            name: 'Abbey Road',
            year: 1969,
            bandId: 1
          }, {
            id: 2,
            name: 'Let It Be',
            year: 1970,
            bandId: 1
          }, {
            id: 3,
            name: 'Super Trouper',
            bandId: 2,
            year: 1980
          }, {
            id: 4,
            name: 'Waterloo',
            bandId: 2,
            year: 1974
          }])
        })
      })
  })

  describe('many-to-one', function () {
    it('should be possible to retrieve an entity with a collection of referring entities attached to it', function () {
      return db.bands.where('name').equals('Beatles').with({
        albums: 'albums'
      }).then (bands => {
        assert(bands.length == 1, "Should be one Beatles")
        let beatles = bands[0]
        assert(!!beatles.albums, "Should have got the foreign albums collection")
        assert(beatles.albums.length === 2, "Should have 2 albums in this db")
        assert(beatles.albums[0].name === "Abbey Road", "First albums should be 'Abbey Roead'")
        assert(beatles.albums[1].name === "Let It Be", "Second album should be 'Let It Be'")
      })
    })
  })

  describe('one-to-one', ()=> {
    it('should be possible to retrieve entity with a foreign key to expand that foreign key', ()=>{
      return db.albums.where('year').between(1970, 1974, true, true).with ({
        band: 'bandId'
      }).then (albums => {
        assert (albums.length === 2, "Should retrieve two albums between 1970 to 1974")
        let letItBe = albums[0],
          waterloo = albums[1]
        assert (letItBe.name === "Let It Be", "First album should be 'Let It Be'")
        assert (!!letItBe.band, "Should get the band resolved with the query")
        assert (letItBe.band.name === "Beatles", "The band should be Beatles")

        assert (waterloo.name === "Waterloo", "Second album should be 'Waterloo'")
        assert (!!waterloo.band, "Should get the band resolved with the query")
        assert (waterloo.band.name === "Abba", "The band should be Abba")
      })
    })
  })

  describe('one-to-many', () => {
    it('should add association to all records when more than one record has the same association', ()=>{
      return db.albums.with ({
        band: 'bandId'
      }).then (albums => {
        assert (albums.length === 4, "Should retrieve four albums")

        let bandIds = [1, 1, 2, 2];

        albums.map((album, idx) => {
          assert(album.band != null, "Each album should have a band")
          assert(album.band.id === bandIds[idx], "Each album should be assigned the correct band")
        })
      })
    })
  })

  describe('Multiple foreign keys of different kind', ()=>{
    it('Should be possible to retrieve entities with oneToOne as well as manyToOne relations', ()=> {
      return db.bands.where('name').equals('Beatles').with({
        albums: 'albums',
        genre: 'genreId'
      }).then (bands => {
        assert(bands.length == 1, "Should be one Beatles")
        let beatles = bands[0]
        assert(!!beatles.albums, "Should have got the foreign albums collection")
        assert(beatles.albums.length === 2, "Should have 2 albums in this db")
        assert(beatles.albums[0].name === "Abbey Road", "First albums should be 'Abbey Roead'")
        assert(beatles.albums[1].name === "Let It Be", "Second album should be 'Let It Be'")
        assert(!!beatles.genre, "Should have got the foreign genre entity")
        assert(beatles.genre.name === "Rock", "The genre should be 'Rock' (even though that could be questionable)");
      })
    })
  })

  describe('Navigation properties should be non-enumerable', () => {
    it('should be possible to put back an object to indexedDB after ' +
      'having retrieved it with navigation properties ' +
      'without storing the navigation properties redundantly',
      ()=>{
        return db.bands.where('name').equals('Abba').with({albums: 'albums', genre: 'genreId'})
          .then(bands => {
            assert(bands.length === 1, "Should be one Abba");
            let abba = bands[0]
            assert (!!abba.albums, "Abba should have its 'albums' foreign collection")
            assert (!!abba.genre, "Abba should have its 'genre' foreign property")
            abba.customProperty = "Hello world"
            return db.bands.put(abba)
          }).then(()=>{
            return db.bands.where('name').equals('Abba').first()
          }).then(abba => {
            assert(!abba.albums, "Abba should not have the 'albums' foreign collection stored redundantly")
            assert(!abba.genre, "Abba should not have the 'genre' foreign property stored redundantly")
          })
      })
  })

  describe('Sample from README', ()=> {
    it('should be possible to copy and paste the sample from README', ()=>{
      return db.bands
        .where('name').startsWithAnyOf('A', 'B')
        .with({albums: 'albums', genre: 'genreId'}) // Resolves foreign keys into props
        .then(rows => {
          // Print the result:
          rows.forEach (band => {
            console.log (`Band Name: ${band.name}`)
            console.log (`Genre: ${band.genre.name}`)
            console.log (`Albums: ${JSON.stringify(band.albums, null, 4)}`)
          });
        }).then(()=>{
          assert (true, "Promise resolved and no exception occured")
        }).catch (ex => {
          assert (false, "Something went wrong: " + (ex.stack || ex))
        })
    })
  })
})
<|endoftext|>