<commit_before>/**
 * Generic component that displays a list of genomic locations, along
 * with buttons to execute actions on them.
 */

define([
           'dojo/_base/declare',
           'dojo/_base/array',
           'dojo/dom-construct',
           'dijit/form/Button',
           'JBrowse/Util',
           'dgrid/Grid',
           'dgrid/extensions/DijitRegistry'
       ],
       function(
           declare,
           array,
           dom,
           dijitButton,
           Util,
           DGrid,
           DGridDijitRegistry
       ) {

var Grid = declare([DGrid,DGridDijitRegistry]);

return declare(null,{
    constructor: function( args, parent ) {
        var thisB = this;
        this.browser = args.browser;
        var columns = [];

        if( array.some( args.locations || [], function(l) { return l.label; }) )
            columns.unshift( { label: 'Name', field: 'label' } );

        if( array.some( args.locations || [], function(l) { return l.description; }) )
            columns.unshift( { label: 'Description', field: 'description' } );

        if( array.some( args.locations || [], function(l) { return l.score; }) )
            columns.unshift( { label: 'Score', field: 'score' } );

        columns.push( { label: 'Location',
                        get: function( location ) {
                            return Util.assembleLocString( location );
                        }
                      });

        if( args.locations && args.locations.length && args.locations[0].tracks )
            columns.push({
                             label: 'Track',
                             get: function(location) {
                                 var tracks = location.tracks;
                                 return array.map( array.filter( tracks, function(t) { return t; }), // remove nulls
                                                   function(t) {
                                                       return t.key || t.name || t.label || t;
                                                   })
                                             .join(', ');
                             }
                         });

        if( args.buttons ) {
            columns.push({
                             label: '',
                             className: 'goButtonColumn',
                             renderCell: function( object, value, node, options ) {
                                 var container = dom.create('div');
                                 array.forEach( args.buttons, function( button ) {
                                     var buttonArgs = dojo.mixin( {}, button );
                                     buttonArgs.onClick = function() { button.onClick( object, value, node, options ); };
                                     new dijitButton( buttonArgs ).placeAt( container );
                                 });
                                 return container;
                             }
                         });
        }

        this.grid = new Grid({ columns: columns }, parent );
        this.grid.renderArray( args.locations );
    }
});
});<commit_msg>improve the multiple-location list, making it sortable<commit_after>/**
 * Generic component that displays a list of genomic locations, along
 * with buttons to execute actions on them.
 */

define([
           'dojo/_base/declare',
           'dojo/_base/array',
           'dojo/dom-construct',
           'dijit/form/Button',
           'JBrowse/Util',
           'dojo/store/Memory',
           'dgrid/OnDemandGrid',
           'dgrid/extensions/DijitRegistry'
       ],
       function(
           declare,
           array,
           dom,
           dijitButton,
           Util,
           MemoryStore,
           DGrid,
           DGridDijitRegistry
       ) {

var Grid = declare([DGrid,DGridDijitRegistry]);

return declare(null,{
    constructor: function( args, parent ) {
        var thisB = this;
        this.browser = args.browser;

        // transform our data first, so that it's sortable.
        var locations = array.map( args.locations || [], function(l) {
            return { locstring: Util.assembleLocString( l ),
                     location: l,
                     label: l.label,
                     description: l.description,
                     score: l.score,
                     tracks: array.map( array.filter( l.tracks || [], function(t) { return t; }), // remove nulls
                                        function(t) {
                                            return t.key || t.name || t.label || t;
                                        })
                             .join(', ')
                   };
        });

        // build the column list
        var columns = [];
        if( array.some( locations, function(l) { return l.label; }) )
            columns.unshift( { label: 'Name', field: 'label' } );
        if( array.some( locations, function(l) { return l.description; }) )
            columns.unshift( { label: 'Description', field: 'description' } );
        if( array.some( locations, function(l) { return l.score; }) )
            columns.unshift( { label: 'Score', field: 'score' } );
        columns.push({ label: 'Location', field: 'locstring' });
        if( locations.length && locations[0].tracks )
            columns.push({ label: 'Track', field: 'tracks' });
        if( args.buttons ) {
            columns.push({
                             label: '',
                             className: 'goButtonColumn',
                             renderCell: function( object, value, node, options ) {
                                 var container = dom.create('div');
                                 array.forEach( args.buttons, function( button ) {
                                     var buttonArgs = dojo.mixin( {}, button );
                                     buttonArgs.onClick = function() { button.onClick( object.location, value, node, options ); };
                                     new dijitButton( buttonArgs ).placeAt( container );
                                 });
                                 return container;
                             }
                         });
        }

        // create the grid
        this.grid = new Grid({
            columns: columns,
            store: new MemoryStore({ data: locations } )
        }, parent );
    }
});
});<|endoftext|>


<commit_before>var modeRef = firebase.database().ref('mode');
modeRef.on('value', function (v) {
    var modes = v.val();
    for (mode in modes) {
        if (modes.hasOwnProperty(mode)) {
            $("#" + mode).toggleClass("inactive", !modes[mode]);
            if (mode == "chyron") {
                if (modes[mode] == "single") {
                    $("#chyronSingle").css("opacity", 1);
                    $("#chyronLeft").css("opacity", 0);
                    $("#chyronRight").css("opacity", 0);
                    $("#chyron").find(".logo").css("opacity", 0);
                } else {
                    $("#chyronSingle").css("opacity", 0);
                    $("#chyronLeft").css("opacity", 1);
                    $("#chyronRight").css("opacity", 1);
                    $("#chyron").find(".logo").css("opacity", 1);
                }
            }
        }
    }
});

var sets;
// Gatherer card images are low-res and blocky and ugly, so if we can, we want to use magiccards.info images.
// We need to translate from what Gatherer calls the set to what magiccards.info calls the set, though.
var gathererToMagiccardsInfo = [];
$.get("https://api.magicthegathering.io/v1/sets",
    function(data) {
        data.sets = _.sortBy(data.sets, function (x) {
            return (x.type == "promo" ? "p" : "") + x.releaseDate;
        });
        sets = _.map(data.sets, function (x) {
            return x.code;
        });

        gathererToMagiccardsInfo = _.object(
            sets,
            // If there's no magicCardsInfoCode, give up and return the normal code; fixes Kaladesh.
            _.map(data.sets, function(x) { return x.magicCardsInfoCode || x.code; }));
    });

function fillFeaturedCard(cardName, featuredCardSelector) {
    if (cardName != "") {
        // exact match on the name, because autocomplete in director.html should have
        // put an exact name there for us
        $.get("https://api.magicthegathering.io/v1/cards?name=\"" + cardName + "\"",
            function (data) {
                if (data.cards && data.cards.length > 0) {
                    data.cards = _.sortBy(data.cards, function (c) {
                        return sets.indexOf(c.set);
                    });
                    var card = data.cards[0];
                    var imageUrl = card.imageUrl;
                    if (card.set && card.number) {
                        // not all cards have a number (e.g. LEA Lightning Bolt)
                        imageUrl = ("http://magiccards.info/scans/en/" + gathererToMagiccardsInfo[card.set]
                                    + "/" + card.number + ".jpg").toLowerCase();
                    }
                    var setReq = Promise.resolve(null);
                    if (card.set) {
                        setReq = $.get("https://api.magicthegathering.io/v1/sets/" + card.set);
                    }
                    var img = $(featuredCardSelector).find(".img");
                    img.attr("src", imageUrl);
                    img.one("load", function () {
                        setReq.done(function (data) {
                            $(featuredCardSelector).find(".rarityAndSet").text(
                                card.rarity + ", " + card.setName +
                                (data && data.set ? " (" + data.set.releaseDate.substring(0, 4) + ")" : ""));
                            $(featuredCardSelector).removeClass("offscreen");
                        })
                    });
                    img.on("error", function () {
                        if ($(this).attr("src") != card.imageUrl) {
                            // fall back to Gatherer if we unexpectedly have to
                            $(this).attr("src", card.imageUrl)
                        } else {
                            // Gatherer failed too, sandwich time
                            $(this).attr("src", "back.jpg");
                        }
                    });
                }
            });
    } else {
        $(featuredCardSelector).addClass("offscreen");
        $(featuredCardSelector).find(".img").off("load");
        $(featuredCardSelector).find(".img").off("error");
    }
}

function updateValue(elt, newValue, toggleOnZero) {
    if (!elt.text() || elt.text() != newValue) {
        var event;
        var duration;
        if (elt.css("transition-duration") != "0s") {
            event = "transitionend";
            duration = elt.css("transition-duration");
        } else if (elt.css("animation-duration") != "0s") {
            event = "animationend";
            duration = elt.css("animation-duration");
        }
        if (event) {
            duration = parseFloat(duration.substring(0, duration.length - 1)) * 1000;
            elt.off(event);
            elt.addClass("updating");
            var fallback;
            var update = function () {
                elt.text(newValue == "inf" ? "∞" : newValue);
                elt.removeClass("updating");
                elt.off(event);
                if (toggleOnZero) {
                    elt.toggle(newValue == "inf" || !!parseInt(newValue));
                }
                clearTimeout(fallback);
            };
            fallback = setTimeout(update, duration);
            elt.on(event, update);
        } else {
            elt.text(newValue);
        }
    }
}

// Update life totals, with debouncing
var updateP1Numbers = _.debounce(function(v) {
    updateValue($(".p1.life"), v.val().life);
    updateValue($(".p1.poison"), v.val().poison, true);
    if (v.val().gamewins > 0) {
        updateValue($(".p1.wins"), v.val().gamewins);
    } else {
        $(".p1.wins").text(v.val().gamewins);
    }
}, 1000);

var updateP2Numbers = _.debounce(function(v) {
    updateValue($(".p2.life"), v.val().life);
    updateValue($(".p2.poison"), v.val().poison, true);
    if (v.val().gamewins > 0) {
        updateValue($(".p2.wins"), v.val().gamewins);
    } else {
        $(".p2.wins").text(v.val().gamewins);
    }
}, 1000);

firebase.database().ref('player1').on('value', function (v) {
    updateP1Numbers(v);
    $(".p1.name").text(v.val().name);
    var deck = $(".p1.deck");
    deck.text(v.val().deck);
    deck.removeData("Emoji");
    deck.Emoji({path: 'https://rodrigopolo.github.io/jqueryemoji/img/apple72/'});
    fillFeaturedCard(v.val().featuredcard, ".p1.featuredcard");
});
firebase.database().ref('p1deck').on('value', function (v) {
    var handElt = $(".p1.hand");
    fillHand(handElt, v.val());
    fillDeck($(".p1.sideboard"), v.val(), true);
});
firebase.database().ref('player2').on('value', function (v) {
    updateP2Numbers(v);
    $(".p2.name").text(v.val().name);
    var deck = $(".p2.deck");
    deck.text(v.val().deck);
    deck.removeData("Emoji");
    deck.Emoji({path: 'https://rodrigopolo.github.io/jqueryemoji/img/apple72/'});
    fillFeaturedCard(v.val().featuredcard, ".p2.featuredcard");
});
firebase.database().ref('p2deck').on('value', function (v) {
    var handElt = $(".p2.hand");
    fillHand(handElt, v.val());
    fillDeck($(".p2.sideboard"), v.val(), true);
});
firebase.database().ref('chyron').on('value', function (v) {
    var single = $("#chyronSingle");
    single.text(v.val().single);
    single.removeData("Emoji");
    single.Emoji({path: 'https://rodrigopolo.github.io/jqueryemoji/img/apple72/'});
    $("#chyronLeft").text(v.val().left);
    $("#chyronRight").text(v.val().right);
});
<commit_msg>Put both players' life totals on a single shared debouncer.<commit_after>var modeRef = firebase.database().ref('mode');
modeRef.on('value', function (v) {
    var modes = v.val();
    for (mode in modes) {
        if (modes.hasOwnProperty(mode)) {
            $("#" + mode).toggleClass("inactive", !modes[mode]);
            if (mode == "chyron") {
                if (modes[mode] == "single") {
                    $("#chyronSingle").css("opacity", 1);
                    $("#chyronLeft").css("opacity", 0);
                    $("#chyronRight").css("opacity", 0);
                    $("#chyron").find(".logo").css("opacity", 0);
                } else {
                    $("#chyronSingle").css("opacity", 0);
                    $("#chyronLeft").css("opacity", 1);
                    $("#chyronRight").css("opacity", 1);
                    $("#chyron").find(".logo").css("opacity", 1);
                }
            }
        }
    }
});

var sets;
// Gatherer card images are low-res and blocky and ugly, so if we can, we want to use magiccards.info images.
// We need to translate from what Gatherer calls the set to what magiccards.info calls the set, though.
var gathererToMagiccardsInfo = [];
$.get("https://api.magicthegathering.io/v1/sets",
    function(data) {
        data.sets = _.sortBy(data.sets, function (x) {
            return (x.type == "promo" ? "p" : "") + x.releaseDate;
        });
        sets = _.map(data.sets, function (x) {
            return x.code;
        });

        gathererToMagiccardsInfo = _.object(
            sets,
            // If there's no magicCardsInfoCode, give up and return the normal code; fixes Kaladesh.
            _.map(data.sets, function(x) { return x.magicCardsInfoCode || x.code; }));
    });

function fillFeaturedCard(cardName, featuredCardSelector) {
    if (cardName != "") {
        // exact match on the name, because autocomplete in director.html should have
        // put an exact name there for us
        $.get("https://api.magicthegathering.io/v1/cards?name=\"" + cardName + "\"",
            function (data) {
                if (data.cards && data.cards.length > 0) {
                    data.cards = _.sortBy(data.cards, function (c) {
                        return sets.indexOf(c.set);
                    });
                    var card = data.cards[0];
                    var imageUrl = card.imageUrl;
                    if (card.set && card.number) {
                        // not all cards have a number (e.g. LEA Lightning Bolt)
                        imageUrl = ("http://magiccards.info/scans/en/" + gathererToMagiccardsInfo[card.set]
                                    + "/" + card.number + ".jpg").toLowerCase();
                    }
                    var setReq = Promise.resolve(null);
                    if (card.set) {
                        setReq = $.get("https://api.magicthegathering.io/v1/sets/" + card.set);
                    }
                    var img = $(featuredCardSelector).find(".img");
                    img.attr("src", imageUrl);
                    img.one("load", function () {
                        setReq.done(function (data) {
                            $(featuredCardSelector).find(".rarityAndSet").text(
                                card.rarity + ", " + card.setName +
                                (data && data.set ? " (" + data.set.releaseDate.substring(0, 4) + ")" : ""));
                            $(featuredCardSelector).removeClass("offscreen");
                        })
                    });
                    img.on("error", function () {
                        if ($(this).attr("src") != card.imageUrl) {
                            // fall back to Gatherer if we unexpectedly have to
                            $(this).attr("src", card.imageUrl)
                        } else {
                            // Gatherer failed too, sandwich time
                            $(this).attr("src", "back.jpg");
                        }
                    });
                }
            });
    } else {
        $(featuredCardSelector).addClass("offscreen");
        $(featuredCardSelector).find(".img").off("load");
        $(featuredCardSelector).find(".img").off("error");
    }
}

function updateValue(elt, newValue, toggleOnZero) {
    if (!elt.text() || elt.text() != newValue) {
        var event;
        var duration;
        if (elt.css("transition-duration") != "0s") {
            event = "transitionend";
            duration = elt.css("transition-duration");
        } else if (elt.css("animation-duration") != "0s") {
            event = "animationend";
            duration = elt.css("animation-duration");
        }
        if (event) {
            duration = parseFloat(duration.substring(0, duration.length - 1)) * 1000;
            elt.off(event);
            elt.addClass("updating");
            var fallback;
            var update = function () {
                elt.text(newValue == "inf" ? "∞" : newValue);
                elt.removeClass("updating");
                elt.off(event);
                if (toggleOnZero) {
                    elt.toggle(newValue == "inf" || !!parseInt(newValue));
                }
                clearTimeout(fallback);
            };
            fallback = setTimeout(update, duration);
            elt.on(event, update);
        } else {
            elt.text(newValue);
        }
    }
}

// Update life totals, with debouncing
function updateSide(prefix, v) {
    updateValue($(prefix + ".life"), v.val().life);
    updateValue($(prefix + ".poison"), v.val().poison, true);
    if (v.val().gamewins > 0) {
        updateValue($(prefix + ".wins"), v.val().gamewins);
    } else {
        $(prefix + ".wins").text(v.val().gamewins);
    }
}

var updateAllNumbers = _.debounce(function () {
    firebase.database().ref('player1').once('value', updateSide.bind(null, ".p1"));
    firebase.database().ref('player2').once('value', updateSide.bind(null, ".p2"));
}, 1000);

firebase.database().ref('player1').on('value', function (v) {
    updateAllNumbers();
    $(".p1.name").text(v.val().name);
    var deck = $(".p1.deck");
    deck.text(v.val().deck);
    deck.removeData("Emoji");
    deck.Emoji({path: 'https://rodrigopolo.github.io/jqueryemoji/img/apple72/'});
    fillFeaturedCard(v.val().featuredcard, ".p1.featuredcard");
});
firebase.database().ref('p1deck').on('value', function (v) {
    var handElt = $(".p1.hand");
    fillHand(handElt, v.val());
    fillDeck($(".p1.sideboard"), v.val(), true);
});
firebase.database().ref('player2').on('value', function (v) {
    updateAllNumbers();
    $(".p2.name").text(v.val().name);
    var deck = $(".p2.deck");
    deck.text(v.val().deck);
    deck.removeData("Emoji");
    deck.Emoji({path: 'https://rodrigopolo.github.io/jqueryemoji/img/apple72/'});
    fillFeaturedCard(v.val().featuredcard, ".p2.featuredcard");
});
firebase.database().ref('p2deck').on('value', function (v) {
    var handElt = $(".p2.hand");
    fillHand(handElt, v.val());
    fillDeck($(".p2.sideboard"), v.val(), true);
});
firebase.database().ref('chyron').on('value', function (v) {
    var single = $("#chyronSingle");
    single.text(v.val().single);
    single.removeData("Emoji");
    single.Emoji({path: 'https://rodrigopolo.github.io/jqueryemoji/img/apple72/'});
    $("#chyronLeft").text(v.val().left);
    $("#chyronRight").text(v.val().right);
});
<|endoftext|>


<commit_before>// ==UserScript==
// @id             iitc-plugin-cross-links@mcben
// @name           IITC plugin: cross links
// @category       Layer
// @version        1.1.1.@@DATETIMEVERSION@@
// @namespace      https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL      @@UPDATEURL@@
// @downloadURL    @@DOWNLOADURL@@
// @description    [@@BUILDNAME@@-@@BUILDDATE@@] EXPERIMENTAL: Checks for existing links that cross planned links. Requires draw-tools plugin.
// @include        https://www.ingress.com/intel*
// @include        http://www.ingress.com/intel*
// @match          https://www.ingress.com/intel*
// @match          http://www.ingress.com/intel*
// @grant          none
// ==/UserScript==

@@PLUGINSTART@@

// PLUGIN START ////////////////////////////////////////////////////////

window.plugin.crossLinks = function() {};

window.plugin.crossLinks.greatCircleArcIntersect = function(a0,a1,b0,b1) {
  // based on the formula at http://williams.best.vwh.net/avform.htm#Int

  // method:
  // check to ensure no line segment is zero length - if so, cannot cross
  // check to see if either of the lines start/end at the same point. if so, then they cannot cross
  // check to see if the line segments overlap in longitude. if not, no crossing
  // if overlap, clip each line to the overlapping longitudes, then see if latitudes cross

  // anti-meridian handling. this code will not sensibly handle a case where one point is
  // close to -180 degrees and the other +180 degrees. unwrap coordinates in this case, so one point
  // is beyond +-180 degrees. this is already true in IITC
  // FIXME? if the two lines have been 'unwrapped' differently - one positive, one negative - it will fail

  // zero length line tests
  if (a0.equals(a1)) return false;
  if (b0.equals(b1)) return false;

  // lines have a common point
  if (a0.equals(b0) || a0.equals(b1)) return false;
  if (a1.equals(b0) || a1.equals(b1)) return false;

  // check for 'horizontal' overlap in lngitude
  if (Math.min(a0.lng,a1.lng) > Math.max(b0.lng,b1.lng)) return false;
  if (Math.max(a0.lng,a1.lng) < Math.min(b0.lng,b1.lng)) return false;

  // ok, our two lines have some horizontal overlap in longitude
  // 1. calculate the overlapping min/max longitude
  // 2. calculate each line latitude at each point
  // 3. if latitudes change place between overlapping range, the lines cross

  // class to hold the pre-calculated maths for a geodesic line
  // TODO: move this outside this function, so it can be pre-calculated once for each line we test
  var GeodesicLine = function(start,end) {
    var d2r = Math.PI/180.0;
    var r2d = 180.0/Math.PI;

    // maths based on http://williams.best.vwh.net/avform.htm#Int

    if (start.lng == end.lng) {
      throw 'Error: cannot calculate latitude for meridians';
    }

    // only the variables needed to calculate a latitude for a given longitude are stored in 'this'
    this.lat1 = start.lat * d2r;
    this.lat2 = end.lat * d2r;
    this.lng1 = start.lng * d2r;
    this.lng2 = end.lng * d2r;

    var dLng = this.lng1-this.lng2;

    var sinLat1 = Math.sin(this.lat1);
    var sinLat2 = Math.sin(this.lat2);
    var cosLat1 = Math.cos(this.lat1);
    var cosLat2 = Math.cos(this.lat2);

    this.sinLat1CosLat2 = sinLat1*cosLat2;
    this.sinLat2CosLat1 = sinLat2*cosLat1;

    this.cosLat1CosLat2SinDLng = cosLat1*cosLat2*Math.sin(dLng);
  }

  GeodesicLine.prototype.isMeridian = function() {
    return this.lng1 == this.lng2;
  }

  GeodesicLine.prototype.latAtLng = function(lng) {
    lng = lng * Math.PI / 180; //to radians

    var lat;
    // if we're testing the start/end point, return that directly rather than calculating
    // 1. this may be fractionally faster, no complex maths
    // 2. there's odd rounding issues that occur on some browsers (noticed on IITC MObile) for very short links - this may help
    if (lng == this.lng1) {
      lat = this.lat1;
    } else if (lng == this.lng2) {
      lat = this.lat2;
    } else {
      lat = Math.atan ( (this.sinLat1CosLat2*Math.sin(lng-this.lng2) - this.sinLat2CosLat1*Math.sin(lng-this.lng1))
                       / this.cosLat1CosLat2SinDLng);
    }
    return lat * 180 / Math.PI; // return value in degrees
  }

  // calculate the longitude of the overlapping region
  var leftLng = Math.max( Math.min(a0.lng,a1.lng), Math.min(b0.lng,b1.lng) );
  var rightLng = Math.min( Math.max(a0.lng,a1.lng), Math.max(b0.lng,b1.lng) );

  // calculate the latitudes for each line at left + right longitudes
  // NOTE: need a special case for meridians - as GeodesicLine.latAtLng method is invalid in that case
  var aLeftLat, aRightLat;
  if (a0.lng == a1.lng) {
    // 'left' and 'right' now become 'top' and 'bottom' (in some order) - which is fine for the below intersection code
    aLeftLat = a0.lat;
    aRightLat = a1.lat;
  } else {
    var aGeo = new GeodesicLine(a0,a1);
    aLeftLat = aGeo.latAtLng(leftLng);
    aRightLat = aGeo.latAtLng(rightLng);
  }

  var bLeftLat, bRightLat;
  if (b0.lng == b1.lng) {
    // 'left' and 'right' now become 'top' and 'bottom' (in some order) - which is fine for the below intersection code
    bLeftLat = b0.lat;
    bRightLat = b1.lat;
  } else {
    var bGeo = new GeodesicLine(b0,b1);
    bLeftLat = bGeo.latAtLng(leftLng);
    bRightLat = bGeo.latAtLng(rightLng);
  }

  // if both a are less or greater than both b, then lines do not cross

  if (aLeftLat < bLeftLat && aRightLat < bRightLat) return false;
  if (aLeftLat > bLeftLat && aRightLat > bRightLat) return false;

  // latitudes cross between left and right - so geodesic lines cross
  return true;
}

window.plugin.crossLinks.testPolyLine = function (polyline, link,closed) {

    var a = link.getLatLngs();
    var b = polyline.getLatLngs();

    for (var i=0;i<b.length-1;++i) {
        if (window.plugin.crossLinks.greatCircleArcIntersect(a[0],a[1],b[i],b[i+1])) return true;
    }

    if (closed) {
        if (window.plugin.crossLinks.greatCircleArcIntersect(a[0],a[1],b[b.length-1],b[0])) return true;
    }

    return false;
}

window.plugin.crossLinks.onLinkAdded = function (data) {
    if (window.plugin.crossLinks.disabled) return;

    plugin.crossLinks.testLink(data.link);
}

window.plugin.crossLinks.checkAllLinks = function() {
    if (window.plugin.crossLinks.disabled) return;

    console.debug("Cross-Links: checking all links");
    plugin.crossLinks.linkLayer.clearLayers();
    plugin.crossLinks.linkLayerGuids = {};

    $.each(window.links, function(guid, link) {
        plugin.crossLinks.testLink(link);
    });
}

window.plugin.crossLinks.testLink = function (link) {
    if (plugin.crossLinks.linkLayerGuids[link.options.guid]) return;

    for (var i in plugin.drawTools.drawnItems._layers) { // leaflet don't support breaking out of the loop
       var layer = plugin.drawTools.drawnItems._layers[i];
       if (layer instanceof L.GeodesicPolygon) {
           if (plugin.crossLinks.testPolyLine(layer, link,true)) {
               plugin.crossLinks.showLink(link);
               break;
           }
        } else if (layer instanceof L.GeodesicPolyline) {
            if (plugin.crossLinks.testPolyLine(layer, link)) {
                plugin.crossLinks.showLink(link);
                break;
            }
        }
    };
}

window.plugin.crossLinks.showLink = function(link) {

    var poly = L.geodesicPolyline(link.getLatLngs(), {
       color: '#d22',
       opacity: 0.7,
       weight: 5,
       clickable: false,
       dashArray: [8,8],

       guid: link.options.guid
    });

    poly.addTo(plugin.crossLinks.linkLayer);
    plugin.crossLinks.linkLayerGuids[link.options.guid]=poly;
}

window.plugin.crossLinks.onMapDataRefreshEnd = function () {
    if (window.plugin.crossLinks.disabled) return;

    window.plugin.crossLinks.linkLayer.bringToFront();

    window.plugin.crossLinks.testForDeletedLinks();
}

window.plugin.crossLinks.testAllLinksAgainstLayer = function (layer) {
    if (window.plugin.crossLinks.disabled) return;

    $.each(window.links, function(guid, link) {
        if (!plugin.crossLinks.linkLayerGuids[link.options.guid])
        {
            if (layer instanceof L.GeodesicPolygon) {
                if (plugin.crossLinks.testPolyLine(layer, link,true)) {
                    plugin.crossLinks.showLink(link);
                }
            } else if (layer instanceof L.GeodesicPolyline) {
                if (plugin.crossLinks.testPolyLine(layer, link)) {
                    plugin.crossLinks.showLink(link);
                }
            }
        }
    });
}

window.plugin.crossLinks.testForDeletedLinks = function () {
    window.plugin.crossLinks.linkLayer.eachLayer( function(layer) {
        var guid = layer.options.guid;
        if (!window.links[guid]) {
            console.log("link removed");
            plugin.crossLinks.linkLayer.removeLayer(layer);
            delete plugin.crossLinks.linkLayerGuids[guid];
        }
    });
}

window.plugin.crossLinks.createLayer = function() {
    window.plugin.crossLinks.linkLayer = new L.FeatureGroup();
    window.plugin.crossLinks.linkLayerGuids={};
    window.addLayerGroup('Cross Links', window.plugin.crossLinks.linkLayer, true);

    map.on('layeradd', function(obj) {
      if(obj.layer === window.plugin.crossLinks.linkLayer) {
        delete window.plugin.crossLinks.disabled;
        window.plugin.crossLinks.checkAllLinks();
      }
    });
    map.on('layerremove', function(obj) {
      if(obj.layer === window.plugin.crossLinks.linkLayer) {
        window.plugin.crossLinks.disabled = true;
        window.plugin.crossLinks.linkLayer.clearLayers();
        plugin.crossLinks.linkLayerGuids = {};
      }
    });
}

var setup = function() {
    if (window.plugin.drawTools === undefined) {
       alert("'Cross-Links' requires 'draw-tools'");
       return;
    }

    // this plugin also needs to create the draw-tools hook, in case it is initialised before draw-tools
    window.pluginCreateHook('pluginDrawTools');

    window.plugin.crossLinks.createLayer();

    // events
    window.addHook('pluginDrawTools',function(e) {
        if (e.event == 'layerCreated') {
            // we can just test the new layer in this case
            window.plugin.crossLinks.testAllLinksAgainstLayer(e.layer);
        } else {
            // all other event types - assume anything could have been modified and re-check all links
            window.plugin.crossLinks.checkAllLinks();
        }
    });

    window.addHook('linkAdded', window.plugin.crossLinks.onLinkAdded);
    window.addHook('mapDataRefreshEnd', window.plugin.crossLinks.onMapDataRefreshEnd);
}

// PLUGIN END //////////////////////////////////////////////////////////

@@PLUGINEND@@
<commit_msg>cross-links plugin: ensure disabled flag is initialised correctly for layer state fix #823<commit_after>// ==UserScript==
// @id             iitc-plugin-cross-links@mcben
// @name           IITC plugin: cross links
// @category       Layer
// @version        1.1.2.@@DATETIMEVERSION@@
// @namespace      https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL      @@UPDATEURL@@
// @downloadURL    @@DOWNLOADURL@@
// @description    [@@BUILDNAME@@-@@BUILDDATE@@] EXPERIMENTAL: Checks for existing links that cross planned links. Requires draw-tools plugin.
// @include        https://www.ingress.com/intel*
// @include        http://www.ingress.com/intel*
// @match          https://www.ingress.com/intel*
// @match          http://www.ingress.com/intel*
// @grant          none
// ==/UserScript==

@@PLUGINSTART@@

// PLUGIN START ////////////////////////////////////////////////////////

window.plugin.crossLinks = function() {};

window.plugin.crossLinks.greatCircleArcIntersect = function(a0,a1,b0,b1) {
  // based on the formula at http://williams.best.vwh.net/avform.htm#Int

  // method:
  // check to ensure no line segment is zero length - if so, cannot cross
  // check to see if either of the lines start/end at the same point. if so, then they cannot cross
  // check to see if the line segments overlap in longitude. if not, no crossing
  // if overlap, clip each line to the overlapping longitudes, then see if latitudes cross

  // anti-meridian handling. this code will not sensibly handle a case where one point is
  // close to -180 degrees and the other +180 degrees. unwrap coordinates in this case, so one point
  // is beyond +-180 degrees. this is already true in IITC
  // FIXME? if the two lines have been 'unwrapped' differently - one positive, one negative - it will fail

  // zero length line tests
  if (a0.equals(a1)) return false;
  if (b0.equals(b1)) return false;

  // lines have a common point
  if (a0.equals(b0) || a0.equals(b1)) return false;
  if (a1.equals(b0) || a1.equals(b1)) return false;

  // check for 'horizontal' overlap in lngitude
  if (Math.min(a0.lng,a1.lng) > Math.max(b0.lng,b1.lng)) return false;
  if (Math.max(a0.lng,a1.lng) < Math.min(b0.lng,b1.lng)) return false;

  // ok, our two lines have some horizontal overlap in longitude
  // 1. calculate the overlapping min/max longitude
  // 2. calculate each line latitude at each point
  // 3. if latitudes change place between overlapping range, the lines cross

  // class to hold the pre-calculated maths for a geodesic line
  // TODO: move this outside this function, so it can be pre-calculated once for each line we test
  var GeodesicLine = function(start,end) {
    var d2r = Math.PI/180.0;
    var r2d = 180.0/Math.PI;

    // maths based on http://williams.best.vwh.net/avform.htm#Int

    if (start.lng == end.lng) {
      throw 'Error: cannot calculate latitude for meridians';
    }

    // only the variables needed to calculate a latitude for a given longitude are stored in 'this'
    this.lat1 = start.lat * d2r;
    this.lat2 = end.lat * d2r;
    this.lng1 = start.lng * d2r;
    this.lng2 = end.lng * d2r;

    var dLng = this.lng1-this.lng2;

    var sinLat1 = Math.sin(this.lat1);
    var sinLat2 = Math.sin(this.lat2);
    var cosLat1 = Math.cos(this.lat1);
    var cosLat2 = Math.cos(this.lat2);

    this.sinLat1CosLat2 = sinLat1*cosLat2;
    this.sinLat2CosLat1 = sinLat2*cosLat1;

    this.cosLat1CosLat2SinDLng = cosLat1*cosLat2*Math.sin(dLng);
  }

  GeodesicLine.prototype.isMeridian = function() {
    return this.lng1 == this.lng2;
  }

  GeodesicLine.prototype.latAtLng = function(lng) {
    lng = lng * Math.PI / 180; //to radians

    var lat;
    // if we're testing the start/end point, return that directly rather than calculating
    // 1. this may be fractionally faster, no complex maths
    // 2. there's odd rounding issues that occur on some browsers (noticed on IITC MObile) for very short links - this may help
    if (lng == this.lng1) {
      lat = this.lat1;
    } else if (lng == this.lng2) {
      lat = this.lat2;
    } else {
      lat = Math.atan ( (this.sinLat1CosLat2*Math.sin(lng-this.lng2) - this.sinLat2CosLat1*Math.sin(lng-this.lng1))
                       / this.cosLat1CosLat2SinDLng);
    }
    return lat * 180 / Math.PI; // return value in degrees
  }

  // calculate the longitude of the overlapping region
  var leftLng = Math.max( Math.min(a0.lng,a1.lng), Math.min(b0.lng,b1.lng) );
  var rightLng = Math.min( Math.max(a0.lng,a1.lng), Math.max(b0.lng,b1.lng) );

  // calculate the latitudes for each line at left + right longitudes
  // NOTE: need a special case for meridians - as GeodesicLine.latAtLng method is invalid in that case
  var aLeftLat, aRightLat;
  if (a0.lng == a1.lng) {
    // 'left' and 'right' now become 'top' and 'bottom' (in some order) - which is fine for the below intersection code
    aLeftLat = a0.lat;
    aRightLat = a1.lat;
  } else {
    var aGeo = new GeodesicLine(a0,a1);
    aLeftLat = aGeo.latAtLng(leftLng);
    aRightLat = aGeo.latAtLng(rightLng);
  }

  var bLeftLat, bRightLat;
  if (b0.lng == b1.lng) {
    // 'left' and 'right' now become 'top' and 'bottom' (in some order) - which is fine for the below intersection code
    bLeftLat = b0.lat;
    bRightLat = b1.lat;
  } else {
    var bGeo = new GeodesicLine(b0,b1);
    bLeftLat = bGeo.latAtLng(leftLng);
    bRightLat = bGeo.latAtLng(rightLng);
  }

  // if both a are less or greater than both b, then lines do not cross

  if (aLeftLat < bLeftLat && aRightLat < bRightLat) return false;
  if (aLeftLat > bLeftLat && aRightLat > bRightLat) return false;

  // latitudes cross between left and right - so geodesic lines cross
  return true;
}

window.plugin.crossLinks.testPolyLine = function (polyline, link,closed) {

    var a = link.getLatLngs();
    var b = polyline.getLatLngs();

    for (var i=0;i<b.length-1;++i) {
        if (window.plugin.crossLinks.greatCircleArcIntersect(a[0],a[1],b[i],b[i+1])) return true;
    }

    if (closed) {
        if (window.plugin.crossLinks.greatCircleArcIntersect(a[0],a[1],b[b.length-1],b[0])) return true;
    }

    return false;
}

window.plugin.crossLinks.onLinkAdded = function (data) {
    if (window.plugin.crossLinks.disabled) return;

    plugin.crossLinks.testLink(data.link);
}

window.plugin.crossLinks.checkAllLinks = function() {
    if (window.plugin.crossLinks.disabled) return;

    console.debug("Cross-Links: checking all links");
    plugin.crossLinks.linkLayer.clearLayers();
    plugin.crossLinks.linkLayerGuids = {};

    $.each(window.links, function(guid, link) {
        plugin.crossLinks.testLink(link);
    });
}

window.plugin.crossLinks.testLink = function (link) {
    if (plugin.crossLinks.linkLayerGuids[link.options.guid]) return;

    for (var i in plugin.drawTools.drawnItems._layers) { // leaflet don't support breaking out of the loop
       var layer = plugin.drawTools.drawnItems._layers[i];
       if (layer instanceof L.GeodesicPolygon) {
           if (plugin.crossLinks.testPolyLine(layer, link,true)) {
               plugin.crossLinks.showLink(link);
               break;
           }
        } else if (layer instanceof L.GeodesicPolyline) {
            if (plugin.crossLinks.testPolyLine(layer, link)) {
                plugin.crossLinks.showLink(link);
                break;
            }
        }
    };
}

window.plugin.crossLinks.showLink = function(link) {

    var poly = L.geodesicPolyline(link.getLatLngs(), {
       color: '#d22',
       opacity: 0.7,
       weight: 5,
       clickable: false,
       dashArray: [8,8],

       guid: link.options.guid
    });

    poly.addTo(plugin.crossLinks.linkLayer);
    plugin.crossLinks.linkLayerGuids[link.options.guid]=poly;
}

window.plugin.crossLinks.onMapDataRefreshEnd = function () {
    if (window.plugin.crossLinks.disabled) return;

    window.plugin.crossLinks.linkLayer.bringToFront();

    window.plugin.crossLinks.testForDeletedLinks();
}

window.plugin.crossLinks.testAllLinksAgainstLayer = function (layer) {
    if (window.plugin.crossLinks.disabled) return;

    $.each(window.links, function(guid, link) {
        if (!plugin.crossLinks.linkLayerGuids[link.options.guid])
        {
            if (layer instanceof L.GeodesicPolygon) {
                if (plugin.crossLinks.testPolyLine(layer, link,true)) {
                    plugin.crossLinks.showLink(link);
                }
            } else if (layer instanceof L.GeodesicPolyline) {
                if (plugin.crossLinks.testPolyLine(layer, link)) {
                    plugin.crossLinks.showLink(link);
                }
            }
        }
    });
}

window.plugin.crossLinks.testForDeletedLinks = function () {
    window.plugin.crossLinks.linkLayer.eachLayer( function(layer) {
        var guid = layer.options.guid;
        if (!window.links[guid]) {
            console.log("link removed");
            plugin.crossLinks.linkLayer.removeLayer(layer);
            delete plugin.crossLinks.linkLayerGuids[guid];
        }
    });
}

window.plugin.crossLinks.createLayer = function() {
    window.plugin.crossLinks.linkLayer = new L.FeatureGroup();
    window.plugin.crossLinks.linkLayerGuids={};
    window.addLayerGroup('Cross Links', window.plugin.crossLinks.linkLayer, true);

    map.on('layeradd', function(obj) {
      if(obj.layer === window.plugin.crossLinks.linkLayer) {
        delete window.plugin.crossLinks.disabled;
        window.plugin.crossLinks.checkAllLinks();
      }
    });
    map.on('layerremove', function(obj) {
      if(obj.layer === window.plugin.crossLinks.linkLayer) {
        window.plugin.crossLinks.disabled = true;
        window.plugin.crossLinks.linkLayer.clearLayers();
        plugin.crossLinks.linkLayerGuids = {};
      }
    });

    // ensure 'disabled' flag is initialised
    if (!map.hasLayer(window.plugin.crossLinks.linkLayer)) {
        window.plugin.crossLinks.disabled = true;
    }
}

var setup = function() {
    if (window.plugin.drawTools === undefined) {
       alert("'Cross-Links' requires 'draw-tools'");
       return;
    }

    // this plugin also needs to create the draw-tools hook, in case it is initialised before draw-tools
    window.pluginCreateHook('pluginDrawTools');

    window.plugin.crossLinks.createLayer();

    // events
    window.addHook('pluginDrawTools',function(e) {
        if (e.event == 'layerCreated') {
            // we can just test the new layer in this case
            window.plugin.crossLinks.testAllLinksAgainstLayer(e.layer);
        } else {
            // all other event types - assume anything could have been modified and re-check all links
            window.plugin.crossLinks.checkAllLinks();
        }
    });

    window.addHook('linkAdded', window.plugin.crossLinks.onLinkAdded);
    window.addHook('mapDataRefreshEnd', window.plugin.crossLinks.onMapDataRefreshEnd);

}

// PLUGIN END //////////////////////////////////////////////////////////

@@PLUGINEND@@
<|endoftext|>


<commit_before>var debug = require('debug')('freecc:user:remote');
var blacklistedUsernames =
  require('../../server/utils/constants').blacklistedUsernames;

module.exports = function(User) {
  // NOTE(berks): user email validation currently not needed but build in. This
  // work around should let us sneak by
  // see:
  // https://github.com/strongloop/loopback/issues/1137#issuecomment-109200135
  delete User.validations.email;
  // set salt factor for passwords
  User.settings.saltWorkFactor = 5;

  // username should not be in blacklist
  User.validatesExclusionOf('username', {
    'in': blacklistedUsernames,
    message: 'is taken'
  });

  // username should be unique
  User.validatesUniquenessOf('username');

  debug('setting up user hooks');
  User.afterRemote('confirm', function(ctx) {
    ctx.req.flash('success', {
      msg: [
        'You\'re email has been confirmed!'
      ]
    });
    ctx.res.redirect('/email-signin');
  });

  User.afterRemote('login', function(ctx, user, next) {
    var res = ctx.res;
    var req = ctx.req;
    // var args = ctx.args;

    var accessToken = {};
    var config = {
      signed: !!req.signedCookies,
      maxAge: accessToken.ttl
    };
    if (accessToken && accessToken.id) {
      res.cookie('access_token', accessToken.id, config);
      res.cookie('userId', accessToken.userId, config);
    }
    debug('before pass login');
    return req.logIn(user, function(err) {
      if (err) {
        return next(err);
      }
      req.flash('success', { msg: 'Success! You are logged in.' });
      return res.redirect('/');
    });
  });

  User.afterRemoteError('login', function(ctx) {
    var res = ctx.res;
    var req = ctx.req;

    req.flash('errors', {
      msg: 'Invalid username or password.'
    });
    return res.redirect('/');
  });

  User.afterRemote('logout', function(ctx, result, next) {
    var res = ctx.result;
    res.clearCookie('access_token');
    res.clearCookie('userId');
    next();
  });

  User.doesExist = function doesExist(username, email, cb) {
    if (!username && !email) {
      return process.nextTick(function() {
        cb(null, false);
      });
    }
    debug('checking existence');

    // check to see if username is on blacklist
    if (username && blacklistedUsernames.indexOf(username) !== -1) {
      return cb(null, true);
    }

    var where = {};
    if (username) {
      where.username = username.toLowerCase();
    } else {
      where.email = email ? email.toLowerCase() : email;
    }
    debug('where', where);
    User.count(
      where,
      function(err, count) {
        if (err) {
          debug('err checking existance: ', err);
          return cb(err);
        }
        if (count > 0) {
          return cb(null, true);
        }
        return cb(null, false);
      }
    );
  };

  User.remoteMethod(
    'doesExist',
    {
      description: 'checks whether a user exists using email or username',
      accepts: [
        {
          arg: 'username',
          type: 'string'
        },
        {
          arg: 'email',
          type: 'string'
        }
      ],
      returns: [
        {
          arg: 'exists',
          type: 'boolean'
        }
      ],
      http: {
        path: '/exists',
        verb: 'get'
      }
    }
  );

  User.about = function about(username, cb) {
    if (!username) {
      // Zalgo!!
      return process.nextTick(() => {
        cb(
          new TypeError('FCC: username should be a string but got %s', username)
        );
      });
    }
    User.findOne({ where: { username } }, (err, user) => {
      if (err) {
        cb(err);
      }
      if (!user || user.username !== username) {
        cb(new Error('FCC: no user found for %s', username));
      }
      const aboutUser = {
        username: user.username,
        bio: user.bio,
        github: user.githubProfile
      };
      cb(null, aboutUser);
    });
  };

  User.remoteMethod(
    'about',
    {
      description: 'get public info about user',
      accepts: [
        {
          arg: 'username',
          type: 'string'
        }
      ],
      returns: [
        {
          arg: 'about',
          type: 'object'
        }
      ],
      http: {
        path: '/about',
        verb: 'get'
      }
    }
  );
};
<commit_msg>fix return callbacks<commit_after>var debug = require('debug')('freecc:user:remote');
var blacklistedUsernames =
  require('../../server/utils/constants').blacklistedUsernames;

module.exports = function(User) {
  // NOTE(berks): user email validation currently not needed but build in. This
  // work around should let us sneak by
  // see:
  // https://github.com/strongloop/loopback/issues/1137#issuecomment-109200135
  delete User.validations.email;
  // set salt factor for passwords
  User.settings.saltWorkFactor = 5;

  // username should not be in blacklist
  User.validatesExclusionOf('username', {
    'in': blacklistedUsernames,
    message: 'is taken'
  });

  // username should be unique
  User.validatesUniquenessOf('username');

  debug('setting up user hooks');
  User.afterRemote('confirm', function(ctx) {
    ctx.req.flash('success', {
      msg: [
        'You\'re email has been confirmed!'
      ]
    });
    ctx.res.redirect('/email-signin');
  });

  User.afterRemote('login', function(ctx, user, next) {
    var res = ctx.res;
    var req = ctx.req;
    // var args = ctx.args;

    var accessToken = {};
    var config = {
      signed: !!req.signedCookies,
      maxAge: accessToken.ttl
    };
    if (accessToken && accessToken.id) {
      res.cookie('access_token', accessToken.id, config);
      res.cookie('userId', accessToken.userId, config);
    }
    debug('before pass login');
    return req.logIn(user, function(err) {
      if (err) {
        return next(err);
      }
      req.flash('success', { msg: 'Success! You are logged in.' });
      return res.redirect('/');
    });
  });

  User.afterRemoteError('login', function(ctx) {
    var res = ctx.res;
    var req = ctx.req;

    req.flash('errors', {
      msg: 'Invalid username or password.'
    });
    return res.redirect('/');
  });

  User.afterRemote('logout', function(ctx, result, next) {
    var res = ctx.result;
    res.clearCookie('access_token');
    res.clearCookie('userId');
    next();
  });

  User.doesExist = function doesExist(username, email, cb) {
    if (!username && !email) {
      return process.nextTick(function() {
        cb(null, false);
      });
    }
    debug('checking existence');

    // check to see if username is on blacklist
    if (username && blacklistedUsernames.indexOf(username) !== -1) {
      return cb(null, true);
    }

    var where = {};
    if (username) {
      where.username = username.toLowerCase();
    } else {
      where.email = email ? email.toLowerCase() : email;
    }
    debug('where', where);
    User.count(
      where,
      function(err, count) {
        if (err) {
          debug('err checking existance: ', err);
          return cb(err);
        }
        if (count > 0) {
          return cb(null, true);
        }
        return cb(null, false);
      }
    );
  };

  User.remoteMethod(
    'doesExist',
    {
      description: 'checks whether a user exists using email or username',
      accepts: [
        {
          arg: 'username',
          type: 'string'
        },
        {
          arg: 'email',
          type: 'string'
        }
      ],
      returns: [
        {
          arg: 'exists',
          type: 'boolean'
        }
      ],
      http: {
        path: '/exists',
        verb: 'get'
      }
    }
  );

  User.about = function about(username, cb) {
    if (!username) {
      // Zalgo!!
      return process.nextTick(() => {
        cb(
          new TypeError('FCC: username should be a string but got %s', username)
        );
      });
    }
    User.findOne({ where: { username } }, (err, user) => {
      if (err) {
        return cb(err);
      }
      if (!user || user.username !== username) {
        return cb(new Error('FCC: no user found for %s', username));
      }
      const aboutUser = {
        username: user.username,
        bio: user.bio,
        github: user.githubProfile
      };
      return cb(null, aboutUser);
    });
  };

  User.remoteMethod(
    'about',
    {
      description: 'get public info about user',
      accepts: [
        {
          arg: 'username',
          type: 'string'
        }
      ],
      returns: [
        {
          arg: 'about',
          type: 'object'
        }
      ],
      http: {
        path: '/about',
        verb: 'get'
      }
    }
  );
};
<|endoftext|>


<commit_before>import * as utils from '../src/utils';
import { format } from '../src/url';
// import { config } from '../src/config';
import { registerBidder } from '../src/adapters/bidderFactory';
import find from 'core-js/library/fn/array/find';

const VERSION = '1.0';
const BIDDER_CODE = 'adyoulike';
const DEFAULT_DC = 'hb-api';

export const spec = {
  code: BIDDER_CODE,
  aliases: ['ayl'], // short code
  /**
   * Determines whether or not the given bid request is valid.
   *
   * @param {BidRequest} bid The bid params to validate.
   * @return boolean True if this is a valid bid, and false otherwise.
   */
  isBidRequestValid: function (bid) {
    const sizes = getSize(bid.sizes);
    if (!bid.params || !bid.params.placement || !sizes.width || !sizes.height) {
      return false;
    }
    return true;
  },
  /**
   * Make a server request from the list of BidRequests.
   *
   * @param {bidRequests} - bidRequests.bids[] is an array of AdUnits and bids
   * @return ServerRequest Info describing the request to the server.
   */
  buildRequests: function (bidRequests, bidderRequest) {
    const payload = {
      Version: VERSION,
      Bids: bidRequests.reduce((accumulator, bid) => {
        let size = getSize(bid.sizes);
        accumulator[bid.bidId] = {};
        accumulator[bid.bidId].PlacementID = bid.params.placement;
        accumulator[bid.bidId].TransactionID = bid.transactionId;
        accumulator[bid.bidId].Width = size.width;
        accumulator[bid.bidId].Height = size.height;
        return accumulator;
      }, {}),
      PageRefreshed: getPageRefreshed()
    };

    if (bidderRequest && bidderRequest.gdprConsent) {
      payload.gdprConsent = {
        consentString: bidderRequest.gdprConsent.consentString,
        consentRequired: (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') ? bidderRequest.gdprConsent.gdprApplies : true
      };
    }

    const data = JSON.stringify(payload);
    const options = {
      withCredentials: true
    };

    return {
      method: 'POST',
      url: createEndpoint(bidRequests, bidderRequest),
      data,
      options
    };
  },
  /**
   * Unpack the response from the server into a list of bids.
   *
   * @param {*} serverResponse A successful response from the server.
   * @return {Bid[]} An array of bids which were nested inside the server.
   */
  interpretResponse: function (serverResponse, bidRequest) {
    const bidResponses = [];
    // For this adapter, serverResponse is a list
    serverResponse.body.forEach(response => {
      const bid = createBid(response);
      if (bid) {
        bidResponses.push(bid);
      }
    });
    return bidResponses;
  }
}

/* Get hostname from bids */
function getHostname(bidderRequest) {
  let dcHostname = find(bidderRequest, bid => bid.params.DC);
  if (dcHostname) {
    return ('-' + dcHostname.params.DC);
  }
  return '';
}

/* Get current page referrer url */
function getReferrerUrl(bidderRequest) {
  let referer = '';
  if (bidderRequest && bidderRequest.refererInfo) {
    referer = encodeURIComponent(bidderRequest.refererInfo.referer);
  }
  return referer;
}

/* Get current page canonical url */
function getCanonicalUrl() {
  let link;
  if (window.self !== window.top) {
    try {
      link = window.top.document.head.querySelector('link[rel="canonical"][href]');
    } catch (e) { }
  } else {
    link = document.head.querySelector('link[rel="canonical"][href]');
  }

  if (link) {
    return link.href;
  }
  return '';
}

/* Get information on page refresh */
function getPageRefreshed() {
  try {
    if (performance && performance.navigation) {
      return performance.navigation.type === performance.navigation.TYPE_RELOAD;
    }
  } catch (e) { }
  return false;
}

/* Create endpoint url */
function createEndpoint(bidRequests, bidderRequest) {
  let host = getHostname(bidRequests);
  return format({
    protocol: 'https',
    host: `${DEFAULT_DC}${host}.omnitagjs.com`,
    pathname: '/hb-api/prebid/v1',
    search: createEndpointQS(bidderRequest)
  });
}

/* Create endpoint query string */
function createEndpointQS(bidderRequest) {
  const qs = {};

  const ref = getReferrerUrl(bidderRequest);
  if (ref) {
    qs.RefererUrl = encodeURIComponent(ref);
  }

  const can = getCanonicalUrl();
  if (can) {
    qs.CanonicalUrl = encodeURIComponent(can);
  }

  return qs;
}

/* Get parsed size from request size */
function getSize(requestSizes) {
  const parsed = {};
  const size = utils.parseSizesInput(requestSizes)[0];

  if (typeof size !== 'string') {
    return parsed;
  }

  const parsedSize = size.toUpperCase().split('X');
  const width = parseInt(parsedSize[0], 10);
  if (width) {
    parsed.width = width;
  }

  const height = parseInt(parsedSize[1], 10);
  if (height) {
    parsed.height = height;
  }

  return parsed;
}

/* Create bid from response */
function createBid(response) {
  if (!response || !response.Ad) {
    return
  }

  return {
    requestId: response.BidID,
    width: response.Width,
    height: response.Height,
    ad: response.Ad,
    ttl: 3600,
    creativeId: response.CreativeID,
    cpm: response.Price,
    netRevenue: true,
    currency: 'USD'
  };
}

registerBidder(spec);
<commit_msg> Multiple sizes handling in adYouLike adaptor (#4013)<commit_after>import * as utils from '../src/utils';
import { format } from '../src/url';
// import { config } from '../src/config';
import { registerBidder } from '../src/adapters/bidderFactory';
import find from 'core-js/library/fn/array/find';

const VERSION = '1.0';
const BIDDER_CODE = 'adyoulike';
const DEFAULT_DC = 'hb-api';

export const spec = {
  code: BIDDER_CODE,
  aliases: ['ayl'], // short code
  /**
   * Determines whether or not the given bid request is valid.
   *
   * @param {BidRequest} bid The bid params to validate.
   * @return boolean True if this is a valid bid, and false otherwise.
   */
  isBidRequestValid: function (bid) {
    const sizes = getSize(getSizeArray(bid));
    if (!bid.params || !bid.params.placement || !sizes.width || !sizes.height) {
      return false;
    }
    return true;
  },
  /**
   * Make a server request from the list of BidRequests.
   *
   * @param {bidRequests} - bidRequests.bids[] is an array of AdUnits and bids
   * @return ServerRequest Info describing the request to the server.
   */
  buildRequests: function (bidRequests, bidderRequest) {
    const payload = {
      Version: VERSION,
      Bids: bidRequests.reduce((accumulator, bid) => {
        let sizesArray = getSizeArray(bid);
        let size = getSize(sizesArray);
        accumulator[bid.bidId] = {};
        accumulator[bid.bidId].PlacementID = bid.params.placement;
        accumulator[bid.bidId].TransactionID = bid.transactionId;
        accumulator[bid.bidId].Width = size.width;
        accumulator[bid.bidId].Height = size.height;
        accumulator[bid.bidId].AvaiableSizes = sizesArray.join(',');
        return accumulator;
      }, {}),
      PageRefreshed: getPageRefreshed()
    };

    if (bidderRequest && bidderRequest.gdprConsent) {
      payload.gdprConsent = {
        consentString: bidderRequest.gdprConsent.consentString,
        consentRequired: (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') ? bidderRequest.gdprConsent.gdprApplies : true
      };
    }

    const data = JSON.stringify(payload);
    const options = {
      withCredentials: true
    };

    return {
      method: 'POST',
      url: createEndpoint(bidRequests, bidderRequest),
      data,
      options
    };
  },
  /**
   * Unpack the response from the server into a list of bids.
   *
   * @param {*} serverResponse A successful response from the server.
   * @return {Bid[]} An array of bids which were nested inside the server.
   */
  interpretResponse: function (serverResponse, bidRequest) {
    const bidResponses = [];
    // For this adapter, serverResponse is a list
    serverResponse.body.forEach(response => {
      const bid = createBid(response);
      if (bid) {
        bidResponses.push(bid);
      }
    });
    return bidResponses;
  }
}

/* Get hostname from bids */
function getHostname(bidderRequest) {
  let dcHostname = find(bidderRequest, bid => bid.params.DC);
  if (dcHostname) {
    return ('-' + dcHostname.params.DC);
  }
  return '';
}

/* Get current page referrer url */
function getReferrerUrl(bidderRequest) {
  let referer = '';
  if (bidderRequest && bidderRequest.refererInfo) {
    referer = encodeURIComponent(bidderRequest.refererInfo.referer);
  }
  return referer;
}

/* Get current page canonical url */
function getCanonicalUrl() {
  let link;
  if (window.self !== window.top) {
    try {
      link = window.top.document.head.querySelector('link[rel="canonical"][href]');
    } catch (e) { }
  } else {
    link = document.head.querySelector('link[rel="canonical"][href]');
  }

  if (link) {
    return link.href;
  }
  return '';
}

/* Get information on page refresh */
function getPageRefreshed() {
  try {
    if (performance && performance.navigation) {
      return performance.navigation.type === performance.navigation.TYPE_RELOAD;
    }
  } catch (e) { }
  return false;
}

/* Create endpoint url */
function createEndpoint(bidRequests, bidderRequest) {
  let host = getHostname(bidRequests);
  return format({
    protocol: 'https',
    host: `${DEFAULT_DC}${host}.omnitagjs.com`,
    pathname: '/hb-api/prebid/v1',
    search: createEndpointQS(bidderRequest)
  });
}

/* Create endpoint query string */
function createEndpointQS(bidderRequest) {
  const qs = {};

  const ref = getReferrerUrl(bidderRequest);
  if (ref) {
    qs.RefererUrl = encodeURIComponent(ref);
  }

  const can = getCanonicalUrl();
  if (can) {
    qs.CanonicalUrl = encodeURIComponent(can);
  }

  return qs;
}

function getSizeArray(bid) {
  let inputSize = bid.sizes;
  if (bid.mediaTypes && bid.mediaTypes.banner) {
    inputSize = bid.mediaTypes.banner.sizes;
  }

  return utils.parseSizesInput(inputSize);
}

/* Get parsed size from request size */
function getSize(sizesArray) {
  const parsed = {};
  // the main requested size is the first one
  const size = sizesArray[0];

  if (typeof size !== 'string') {
    return parsed;
  }

  const parsedSize = size.toUpperCase().split('X');
  const width = parseInt(parsedSize[0], 10);
  if (width) {
    parsed.width = width;
  }

  const height = parseInt(parsedSize[1], 10);
  if (height) {
    parsed.height = height;
  }

  return parsed;
}

/* Create bid from response */
function createBid(response) {
  if (!response || !response.Ad) {
    return
  }

  return {
    requestId: response.BidID,
    width: response.Width,
    height: response.Height,
    ad: response.Ad,
    ttl: 3600,
    creativeId: response.CreativeID,
    cpm: response.Price,
    netRevenue: true,
    currency: 'USD'
  };
}

registerBidder(spec);
<|endoftext|>


<commit_before>define([
    'underscore',
    'knockout',
    'knockout-mapping',
    'models/abstract',
    'arches'
], function(_, ko, koMapping, AbstractModel, arches) {
    return AbstractModel.extend({
        url: arches.urls.mobile_survey_designer,

        initialize: function(options) {
            var self = this;
            self.identities = options.identities || [];
            self._mobilesurvey = ko.observable('{}');
            self.name = ko.observable('');
            self.description = ko.observable('');
            self.startdate = ko.observable(null);
            self.enddate = ko.observable(null);
            self.active = ko.observable(false);
            self.createdby = ko.observable(null);
            self.lasteditedby = ko.observable(null);
            self.users = ko.observableArray([]);
            self.groups = ko.observableArray([]);
            self.showDetails = ko.observable(false);
            self.cards = ko.observableArray([]);
            self.datadownloadconfig = koMapping.fromJS(options.source.datadownloadconfig) || ko.observable();
            self.tilecache = ko.observable('');
            self.onlinebasemap = ko.observable('');
            self.bounds = ko.observable(self.getDefaultBounds(null));
            self.collectedResources = ko.observable(false);
            self.showCustomDataDownload = ko.observable(false);

            var getUserName = function(id) {
                var user = _.find(self.identities, function(i) {
                    return i.type === 'user' && i.id === id;
                });
                return user ? user.name : '';
            };

            self.setIdentityApproval = function() {
                var groups = ko.unwrap(this.groups);
                var users = ko.unwrap(this.users);
                _.each(this.identities, function(item) {
                    item.approved(false);
                    if ((item.type === 'group' && _.contains(groups, item.id)) ||
                        (item.type === 'user' && _.contains(users, item.id))) {
                        item.approved(true);
                    }
                });
            };

            _.each(this.identities, function(item) {
                if (item.type === 'group') {
                    _.each(item.users, function(user){
                        if (!user.expanded) {
                            user.expanded = ko.observable(false);
                        }
                    });
                }
            });

            self.createdbyName = ko.computed(function() {
                return getUserName(self.createdby());
            });

            self.lasteditedbyName = ko.computed(function() {
                return getUserName(self.lasteditedby());
            });

            self.onlinebasemaps = ko.computed(function(){
                var basemaps = {default: ko.unwrap(self.onlinebasemap)};
                return basemaps;
            });

            self.userFilter = ko.observable('');
            self.selectedUser = ko.observable();

            self.filteredUsers = ko.computed(function() {
                var filter = self.userFilter();
                this.selected = _.filter(self.identities, function(identity) {
                    return ko.unwrap(identity.selected);
                });
                var list = [];

                if (this.selected.length === 1) {
                    list = this.selected[0].users;
                    if (filter.length === 0) {
                        return list;
                    }
                }

                return _.filter(list, function(user) {
                    if (user.username.startsWith(filter)) {
                        return user;
                    }
                });

            });

            self.selectedIdentity = ko.computed(function() {
                var selected = _.filter(self.identities, function(identity) {
                    return ko.unwrap(identity.selected);
                });
                if (selected.length === 1 && selected[0].users) {
                    self.selectedUser(selected[0].users.length > 0 ? selected[0].users[0] : undefined);
                }
                return selected.length > 0 ? selected[0] : undefined;
            });

            self.approvedUserNames = ko.computed(function() {
                var names = [];
                _.each(self.identities, function(identity) {
                    if (identity.type === 'user' && identity.approved()) {
                        names.push(identity.name);
                    }
                }, this);
                return names;
            });

            self.approvedGroupNames = ko.computed(function() {
                var names = [];
                _.each(self.identities, function(identity) {
                    if (identity.type === 'group' && identity.approved()) {
                        names.push(identity.name);
                    }
                }, this);
                return names;
            });

            self.hasIdentity = function() {
                var approved = false;
                var identity = self.selectedIdentity();
                if (identity) {
                    approved = identity.approved();
                }
                return approved;
            };

            self.toggleIdentity = function() {
                var identity = self.selectedIdentity();
                if (identity) {
                    var currentIdentities = identity.type === 'user' ? self.users : self.groups;
                    if (self.hasIdentity()) {
                        currentIdentities.remove(identity.id);
                        if (identity.type === 'user') {
                            identity.approved(false);
                        } else {
                            identity.approved(false);
                            _.chain(self.identities).filter(function(id) {
                                return id.type === 'user' && _.contains(_.pluck(this.selectedIdentity().users, 'id'), id.id);
                            }, this).each(function(user) {
                                if (_.intersection(user.group_ids, self.groups()).length === 0) { // user does not belong to any accepted groups
                                    user.approved(false);
                                    self.users.remove(user.id);
                                }
                            });
                        }
                    } else {
                        if (!_.contains(currentIdentities(), identity.id)) {
                            currentIdentities.push(identity.id);
                        }
                        identity.approved(true);
                        if (identity.type === 'user') {
                            self.users.push(identity.id);
                        } else {
                            _.chain(self.identities).filter(function(id) {
                                var identity = identity;
                                return id.type === 'user';
                            }).each(function(user) {
                                if (_.intersection(user.group_ids, self.groups()).length > 0) {
                                    user.approved(true);
                                    if (!_.contains(self.users(), user.id)) {
                                        self.users.push(user.id);
                                    }
                                }
                            });
                        }
                    }
                }
            };

            self.updateResourceDownloadList = function(val){
                if (_.contains(self.datadownloadconfig.resources(), val.id)) {
                    self.datadownloadconfig.resources.remove(val.id);
                } else {
                    self.datadownloadconfig.resources.push(val.id);
                }
            };

            self.updateCards = function(cards) {
                var approvedCards = _.chain(cards)
                    .filter(function(card){
                        if (card.approved()) {
                            return card.cardid;
                        }
                    })
                    .pluck('cardid').value();
                var diff = _.difference(self.cards(), approvedCards);
                self.cards(_.union(diff, approvedCards));
            };

            self.updateApproved = function(val){
                val.item.approved(true);
                self.updateCards(val.targetParent());
            };

            self.updateUnapproved = function(val){
                val.item.approved(false);
                self.cards.remove(val.item.cardid);
            };

            self.addAllCardsByResource = function(val) {
                var resource = val.resourceList.selected();
                _.each(resource.cards(), function(card){
                    card.approved(true);
                });
                self.updateCards(resource.cards());
            };

            self.removeAllCardsByResource = function(val) {
                var resource = val.resourceList.selected();
                _.each(resource.cards(), function(card){
                    card.approved(false);
                    self.cards.remove(card.cardid);
                });
            };

            self.toggleShowDetails = function() {
                self.setIdentityApproval();
                self.showDetails(!self.showDetails());
            };

            self.parse(options.source);
            self.setIdentityApproval();

            self.json = ko.computed(function() {
                var jsObj = ko.toJS({
                    name: self.name,
                    description: self.description,
                    startdate: self.startdate,
                    enddate: self.enddate,
                    active: self.active,
                    id: self.get('id'),
                    groups: self.groups,
                    users: self.users,
                    cards: self.cards,
                    bounds: self.bounds,
                    tilecache: self.tilecache,
                    onlinebasemaps: ko.unwrap(self.onlinebasemaps),
                    datadownloadconfig: koMapping.toJS(self.datadownloadconfig)
                });
                return JSON.stringify(_.extend(JSON.parse(self._mobilesurvey()), jsObj));
            });

            self.dirty = ko.computed(function() {
                return self.json() !== self._mobilesurvey() || !self.get('id');
            });
        },

        getDefaultBounds: function(geojson) {
            var result = geojson;
            if (!geojson) {
                var fc = {"type": "FeatureCollection", "features": []};
                var geomFactory = function(coords){
                    return { "type": "Feature",
                        "geometry": {
                            "type": "Polygon",
                            "coordinates": coords
                        },
                        "properties": {}
                    };
                };
                //TODO: make the true project boundry available in the arches object rather than just the hexBinBounds
                //and use the true bounds here instead of the hexBinBounds.
                var extent = arches.hexBinBounds;
                var coords = [[
                    [extent[0], extent[1]],
                    [extent[2], extent[1]],
                    [extent[2], extent[3]],
                    [extent[0], extent[3]],
                    [extent[0], extent[1]]
                ]];
                fc.features.push(geomFactory(coords));
                result = fc;
            }
            return result;
        },

        parse: function(source) {
            var self = this;
            self._mobilesurvey(JSON.stringify(source));
            self.name(source.name);
            self.description(source.description);
            self.startdate(source.startdate);
            self.enddate(source.enddate);
            self.active(source.active);
            self.createdby(source.createdby_id);
            self.lasteditedby(source.lasteditedby_id);
            self.groups(source.groups);
            self.users(source.users);
            self.cards(source.cards);
            self.tilecache(source.tilecache);
            self.onlinebasemap(source.onlinebasemaps ? source.onlinebasemaps['default'] : source.onlinebasemaps);
            self.bounds(self.getDefaultBounds(source.bounds));
            self.set('id', source.id);
        },

        reset: function() {
            this.parse(JSON.parse(this._mobilesurvey()), self);
        },

        _getURL: function(method) {
            return this.url(this.id);
        },

        save: function(userCallback, scope) {
            var self = this;
            var method = "POST";
            var callback = function(request, status, model) {
                if (typeof userCallback === 'function') {
                    userCallback.call(this, request, status, model);
                }
                if (status === 'success') {
                    self.set('id', request.responseJSON.mobile_survey.id);
                    self.createdby(request.responseJSON.mobile_survey.createdby_id);
                    self.lasteditedby(request.responseJSON.mobile_survey.lasteditedby_id);
                    self.groups(request.responseJSON.mobile_survey.groups);
                    self.users(request.responseJSON.mobile_survey.users);
                    self.cards(request.responseJSON.mobile_survey.cards);
                    self.tilecache(request.responseJSON.mobile_survey.tilecache);
                    self.bounds(self.getDefaultBounds(request.responseJSON.mobile_survey.bounds));
                    self.datadownloadconfig.download(request.responseJSON.mobile_survey.datadownloadconfig.download);
                    self.datadownloadconfig.count(request.responseJSON.mobile_survey.datadownloadconfig.count);
                    self.datadownloadconfig.resources(request.responseJSON.mobile_survey.datadownloadconfig.resources);
                    self.datadownloadconfig.custom(request.responseJSON.mobile_survey.datadownloadconfig.custom);
                    this._mobilesurvey(this.json());
                }
            };
            this._doRequest({
                type: method,
                url: this._getURL(method),
                data: JSON.stringify(this.toJSON())
            }, callback, scope, 'save');
        },

        toJSON: function() {
            return JSON.parse(this.json());
        },

        update: function() {
            this.setIdentityApproval();
        }
    });
});
<commit_msg>Removes cruft<commit_after>define([
    'underscore',
    'knockout',
    'knockout-mapping',
    'models/abstract',
    'arches'
], function(_, ko, koMapping, AbstractModel, arches) {
    return AbstractModel.extend({
        url: arches.urls.mobile_survey_designer,

        initialize: function(options) {
            var self = this;
            self.identities = options.identities || [];
            self._mobilesurvey = ko.observable('{}');
            self.name = ko.observable('');
            self.description = ko.observable('');
            self.startdate = ko.observable(null);
            self.enddate = ko.observable(null);
            self.active = ko.observable(false);
            self.createdby = ko.observable(null);
            self.lasteditedby = ko.observable(null);
            self.users = ko.observableArray([]);
            self.groups = ko.observableArray([]);
            self.showDetails = ko.observable(false);
            self.cards = ko.observableArray([]);
            self.datadownloadconfig = koMapping.fromJS(options.source.datadownloadconfig) || ko.observable();
            self.tilecache = ko.observable('');
            self.onlinebasemap = ko.observable('');
            self.bounds = ko.observable(self.getDefaultBounds(null));
            self.collectedResources = ko.observable(false);
            self.showCustomDataDownload = ko.observable(false);

            var getUserName = function(id) {
                var user = _.find(self.identities, function(i) {
                    return i.type === 'user' && i.id === id;
                });
                return user ? user.name : '';
            };

            self.setIdentityApproval = function() {
                var groups = ko.unwrap(this.groups);
                var users = ko.unwrap(this.users);
                _.each(this.identities, function(item) {
                    item.approved(false);
                    if ((item.type === 'group' && _.contains(groups, item.id)) ||
                        (item.type === 'user' && _.contains(users, item.id))) {
                        item.approved(true);
                    }
                });
            };

            _.each(this.identities, function(item) {
                if (item.type === 'group') {
                    _.each(item.users, function(user){
                        if (!user.expanded) {
                            user.expanded = ko.observable(false);
                        }
                    });
                }
            });

            self.createdbyName = ko.computed(function() {
                return getUserName(self.createdby());
            });

            self.lasteditedbyName = ko.computed(function() {
                return getUserName(self.lasteditedby());
            });

            self.onlinebasemaps = ko.computed(function(){
                var basemaps = {default: ko.unwrap(self.onlinebasemap)};
                return basemaps;
            });

            self.userFilter = ko.observable('');
            self.selectedUser = ko.observable();

            self.filteredUsers = ko.computed(function() {
                var filter = self.userFilter();
                this.selected = _.filter(self.identities, function(identity) {
                    return ko.unwrap(identity.selected);
                });
                var list = [];

                if (this.selected.length === 1) {
                    list = this.selected[0].users;
                    if (filter.length === 0) {
                        return list;
                    }
                }

                return _.filter(list, function(user) {
                    if (user.username.startsWith(filter)) {
                        return user;
                    }
                });

            });

            self.selectedIdentity = ko.computed(function() {
                var selected = _.filter(self.identities, function(identity) {
                    return ko.unwrap(identity.selected);
                });
                if (selected.length === 1 && selected[0].users) {
                    self.selectedUser(selected[0].users.length > 0 ? selected[0].users[0] : undefined);
                }
                return selected.length > 0 ? selected[0] : undefined;
            });

            self.approvedUserNames = ko.computed(function() {
                var names = [];
                _.each(self.identities, function(identity) {
                    if (identity.type === 'user' && identity.approved()) {
                        names.push(identity.name);
                    }
                }, this);
                return names;
            });

            self.approvedGroupNames = ko.computed(function() {
                var names = [];
                _.each(self.identities, function(identity) {
                    if (identity.type === 'group' && identity.approved()) {
                        names.push(identity.name);
                    }
                }, this);
                return names;
            });

            self.hasIdentity = function() {
                var approved = false;
                var identity = self.selectedIdentity();
                if (identity) {
                    approved = identity.approved();
                }
                return approved;
            };

            self.toggleIdentity = function() {
                var identity = self.selectedIdentity();
                if (identity) {
                    var currentIdentities = identity.type === 'user' ? self.users : self.groups;
                    if (self.hasIdentity()) {
                        currentIdentities.remove(identity.id);
                        if (identity.type === 'user') {
                            identity.approved(false);
                        } else {
                            identity.approved(false);
                            _.chain(self.identities).filter(function(id) {
                                return id.type === 'user' && _.contains(_.pluck(this.selectedIdentity().users, 'id'), id.id);
                            }, this).each(function(user) {
                                if (_.intersection(user.group_ids, self.groups()).length === 0) { // user does not belong to any accepted groups
                                    user.approved(false);
                                    self.users.remove(user.id);
                                }
                            });
                        }
                    } else {
                        if (!_.contains(currentIdentities(), identity.id)) {
                            currentIdentities.push(identity.id);
                        }
                        identity.approved(true);
                        if (identity.type === 'user') {
                            self.users.push(identity.id);
                        } else {
                            _.chain(self.identities).filter(function(id) {
                                var identity = identity;
                                return id.type === 'user';
                            }).each(function(user) {
                                if (_.intersection(user.group_ids, self.groups()).length > 0) {
                                    user.approved(true);
                                    if (!_.contains(self.users(), user.id)) {
                                        self.users.push(user.id);
                                    }
                                }
                            });
                        }
                    }
                }
            };

            self.updateResourceDownloadList = function(val){
                if (_.contains(self.datadownloadconfig.resources(), val.id)) {
                    self.datadownloadconfig.resources.remove(val.id);
                } else {
                    self.datadownloadconfig.resources.push(val.id);
                }
            };

            self.updateCards = function(cards) {
                var approvedCards = _.chain(cards)
                    .filter(function(card){
                        if (card.approved()) {
                            return card.cardid;
                        }
                    })
                    .pluck('cardid').value();
                var diff = _.difference(self.cards(), approvedCards);
                self.cards(_.union(diff, approvedCards));
            };

            self.addAllCardsByResource = function(val) {
                var resource = val.resourceList.selected();
                _.each(resource.cards(), function(card){
                    card.approved(true);
                });
                self.updateCards(resource.cards());
            };

            self.removeAllCardsByResource = function(val) {
                var resource = val.resourceList.selected();
                _.each(resource.cards(), function(card){
                    card.approved(false);
                    self.cards.remove(card.cardid);
                });
            };

            self.toggleShowDetails = function() {
                self.setIdentityApproval();
                self.showDetails(!self.showDetails());
            };

            self.parse(options.source);
            self.setIdentityApproval();

            self.json = ko.computed(function() {
                var jsObj = ko.toJS({
                    name: self.name,
                    description: self.description,
                    startdate: self.startdate,
                    enddate: self.enddate,
                    active: self.active,
                    id: self.get('id'),
                    groups: self.groups,
                    users: self.users,
                    cards: self.cards,
                    bounds: self.bounds,
                    tilecache: self.tilecache,
                    onlinebasemaps: ko.unwrap(self.onlinebasemaps),
                    datadownloadconfig: koMapping.toJS(self.datadownloadconfig)
                });
                return JSON.stringify(_.extend(JSON.parse(self._mobilesurvey()), jsObj));
            });

            self.dirty = ko.computed(function() {
                return self.json() !== self._mobilesurvey() || !self.get('id');
            });
        },

        getDefaultBounds: function(geojson) {
            var result = geojson;
            if (!geojson) {
                var fc = {"type": "FeatureCollection", "features": []};
                var geomFactory = function(coords){
                    return { "type": "Feature",
                        "geometry": {
                            "type": "Polygon",
                            "coordinates": coords
                        },
                        "properties": {}
                    };
                };
                //TODO: make the true project boundry available in the arches object rather than just the hexBinBounds
                //and use the true bounds here instead of the hexBinBounds.
                var extent = arches.hexBinBounds;
                var coords = [[
                    [extent[0], extent[1]],
                    [extent[2], extent[1]],
                    [extent[2], extent[3]],
                    [extent[0], extent[3]],
                    [extent[0], extent[1]]
                ]];
                fc.features.push(geomFactory(coords));
                result = fc;
            }
            return result;
        },

        parse: function(source) {
            var self = this;
            self._mobilesurvey(JSON.stringify(source));
            self.name(source.name);
            self.description(source.description);
            self.startdate(source.startdate);
            self.enddate(source.enddate);
            self.active(source.active);
            self.createdby(source.createdby_id);
            self.lasteditedby(source.lasteditedby_id);
            self.groups(source.groups);
            self.users(source.users);
            self.cards(source.cards);
            self.tilecache(source.tilecache);
            self.onlinebasemap(source.onlinebasemaps ? source.onlinebasemaps['default'] : source.onlinebasemaps);
            self.bounds(self.getDefaultBounds(source.bounds));
            self.set('id', source.id);
        },

        reset: function() {
            this.parse(JSON.parse(this._mobilesurvey()), self);
        },

        _getURL: function(method) {
            return this.url(this.id);
        },

        save: function(userCallback, scope) {
            var self = this;
            var method = "POST";
            var callback = function(request, status, model) {
                if (typeof userCallback === 'function') {
                    userCallback.call(this, request, status, model);
                }
                if (status === 'success') {
                    self.set('id', request.responseJSON.mobile_survey.id);
                    self.createdby(request.responseJSON.mobile_survey.createdby_id);
                    self.lasteditedby(request.responseJSON.mobile_survey.lasteditedby_id);
                    self.groups(request.responseJSON.mobile_survey.groups);
                    self.users(request.responseJSON.mobile_survey.users);
                    self.cards(request.responseJSON.mobile_survey.cards);
                    self.tilecache(request.responseJSON.mobile_survey.tilecache);
                    self.bounds(self.getDefaultBounds(request.responseJSON.mobile_survey.bounds));
                    self.datadownloadconfig.download(request.responseJSON.mobile_survey.datadownloadconfig.download);
                    self.datadownloadconfig.count(request.responseJSON.mobile_survey.datadownloadconfig.count);
                    self.datadownloadconfig.resources(request.responseJSON.mobile_survey.datadownloadconfig.resources);
                    self.datadownloadconfig.custom(request.responseJSON.mobile_survey.datadownloadconfig.custom);
                    this._mobilesurvey(this.json());
                }
            };
            this._doRequest({
                type: method,
                url: this._getURL(method),
                data: JSON.stringify(this.toJSON())
            }, callback, scope, 'save');
        },

        toJSON: function() {
            return JSON.parse(this.json());
        },

        update: function() {
            this.setIdentityApproval();
        }
    });
});
<|endoftext|>


<commit_before>$(function () {
	function WorkbenchViewModel(parameters) {
		var self = this;

		self.files = parameters[0].listHelper;
		self.loginState = parameters[1];
		self.connection = parameters[2];
        self.slicing = parameters[3];

		//resize canvas after Workbench tab is made active.
		self.onAfterTabChange = function (current, previous) {
			if (current == "#workbench") {
				self.updateFileList();
			}
		};

		//append file list with newly updated stl file.
		self.onEventUpload = function (file) {
			if (file.file.substr(file.file.length - 3).toLowerCase() == "stl") {

				BEEwb.main.loadModel(file.file);
			}
		};

		self.updateFileList = function () {
			self.FileList(_.filter(self.files.allItems, self.files.supportedFilters["model"]));
		};

        self.startPrint = function () {
			var location = "local";
            debugger;
            var filename = BEEwb.main.saveScene();

            self.slicing.show(location, filename);
		};

	}

	// This is how our plugin registers itself with the application, by adding some configuration information to
	// the global variable ADDITIONAL_VIEWMODELS
	ADDITIONAL_VIEWMODELS.push([
			// This is the constructor to call for instantiating the plugin
			WorkbenchViewModel,

			// This is a list of dependencies to inject into the plugin, the order which you request here is the order
			// in which the dependencies will be injected into your view model upon instantiation via the parameters
			// argument
			["gcodeFilesViewModel", "loginStateViewModel", "connectionViewModel", "slicingViewModel"],

			// Finally, this is the list of all elements we want this view model to be bound to.
			[("#workbench")]
		]);
});
<commit_msg>BEEWEB-42<commit_after>$(function () {
	function WorkbenchViewModel(parameters) {
		var self = this;

		self.files = parameters[0].listHelper;
		self.loginState = parameters[1];
		self.connection = parameters[2];
        self.slicing = parameters[3];

		//resize canvas after Workbench tab is made active.
		self.onAfterTabChange = function (current, previous) {
			if (current == "#workbench") {
				self.updateFileList();
			}
		};

		//append file list with newly updated stl file.
		self.onEventUpload = function (file) {
			if (file.file.substr(file.file.length - 3).toLowerCase() == "stl") {

				BEEwb.main.loadModel(file.file);
			}
		};

		self.updateFileList = function () {
			self.FileList(_.filter(self.files.allItems, self.files.supportedFilters["model"]));
		};

        self.startPrint = function () {
			var location = "local";
            var filename = BEEwb.main.saveScene();

            self.slicing.show(location, filename);
		};

	}

	// This is how our plugin registers itself with the application, by adding some configuration information to
	// the global variable ADDITIONAL_VIEWMODELS
	ADDITIONAL_VIEWMODELS.push([
			// This is the constructor to call for instantiating the plugin
			WorkbenchViewModel,

			// This is a list of dependencies to inject into the plugin, the order which you request here is the order
			// in which the dependencies will be injected into your view model upon instantiation via the parameters
			// argument
			["gcodeFilesViewModel", "loginStateViewModel", "connectionViewModel", "slicingViewModel"],

			// Finally, this is the list of all elements we want this view model to be bound to.
			[("#workbench")]
		]);
});
<|endoftext|>