<commit_before>/*
 * Copyright (c) 2010 Kevin Decker (http://www.incaseofstairs.com/)
 * See LICENSE for license information
 */
$(document).ready(function() {
    var pathToImage = $("#pathToImage"),
        editorEl = $("#editorEl"),
        imageEl = $("#imageEl"),
        dividers = $(".divider"),
        sliders = $(".slider"),
        fillEl = $("#fillCenter"),
        cssEl = $("#cssEl"),
        repeat = $(".repeat"),

        validImage = false,
        naturalSize = {},

        state = {
            src: "",

            linkBorder: true,
            borderWidth: [0, 0, 0, 0],
            imageOffset: [0, 0, 0, 0],

            fill: true,
            setRepat: false,
            repeat: ["stretch", "stretch"],

            scaleFactor: 3
        };

    var sliderMap = {
        imageTop: { array: "imageOffset", index: 0 },
        imageRight: { array: "imageOffset", index: 1 },
        imageBottom: { array: "imageOffset", index: 2 },
        imageLeft: { array: "imageOffset", index: 3 },

        borderTop: { array: "borderWidth", index: 0 },
        borderRight: { array: "borderWidth", index: 1 },
        borderBottom: { array: "borderWidth", index: 2 },
        borderLeft: { array: "borderWidth", index: 3 }
    }, dividerMap = {
        dividerTop: {
            setValue: function(el) { state.imageOffset[0] = calcPixels($(el).position().top); },
            updatePos: function(el) { $(el).css("top", state.imageOffset[0]*state.scaleFactor); }
        },
        dividerRight: {
            setValue: function(el) { state.imageOffset[1] = calcPixels(editorEl.innerWidth() - $(el).position().left + 2); },
            updatePos: function(el) { $(el).css("left", (editorEl.innerWidth() - 2 - state.imageOffset[1]*state.scaleFactor)); }
        },
        dividerBottom: {
            setValue: function(el) { state.imageOffset[2] = calcPixels(editorEl.innerHeight() - $(el).position().top + 2); },
            updatePos: function(el) { $(el).css("top", (editorEl.innerHeight() - 2 - state.imageOffset[2]*state.scaleFactor)); }
        },
        dividerLeft: {
            setValue: function(el) { state.imageOffset[3] = calcPixels($(el).position().left); },
            updatePos: function(el) { $(el).css("left", state.imageOffset[3]*state.scaleFactor); }
        }
    }, repeatMap = {
        repeatVertical: { index: 1 },
        repeatHorizontal: { index: 0 }
    };

    function calcPixels(pos) {
        return (pos / state.scaleFactor) | 0;
    }
    function updateFill() {
        fillEl[0].checked = !!state.fill;
    }
    function updateSliders() {
        $(".slider").each(function(index, el) {
            var map = sliderMap[el.id];
            $(el).slider("option", "value", state[map.array][map.index]);
        });
    }
    function updateDividers() {
        dividers.each(function(index, el) {
            dividerMap[el.id].updatePos(el);
        });
    }
    function updateRepeat() {
        repeat.each(function(index, el) {
            var map = repeatMap[el.id];
            $(el).val(state.repeat[map.index]);
        });
    }
    function updateHash() {
        HistoryHandler.store(JSON.stringify(state));
    }
    function joinValues(values, join) {
        var ret = [];
        if (values[3] !== undefined && values[3] !== values[1]) {
            ret.unshift(values[3]);
        }
        if (ret.length || (values[2] !== undefined && values[2] !== values[0])) {
            ret.unshift(values[2]);
        }
        if (ret.length || (values[1] !== undefined && values[1] !== values[0])) {
            ret.unshift(values[1]);
        }
        ret.unshift(values[0]);
        return ret.join(join || " ");
    }
    function updateCSS() {
        var borderImage = "", borderWidthStr = "", style = "",
            fillStr = state.fill ? " fill" : "",
            repeatStr = state.setRepeat ? " " + joinValues(state.repeat) : "";

        if (validImage) {
            var img = "url(" + UserImageCache.getDisplayName() + ")",
                imageOffset = state.imageOffset,
                borderWidth = state.linkBorder ? state.imageOffset : state.borderWidth;

            borderImage = img + " " + joinValues(imageOffset);
            borderWidthStr = joinValues(borderWidth, "px ") + "px";
            style = "border-style: solid;\n"
            	+ "border-width: " + borderWidthStr + ";\n"
                + "-moz-border-image: " + borderImage + repeatStr + ";\n"
                + "-webkit-border-image: " + borderImage + repeatStr + ";\n"
                + "-o-border-image: " + borderImage + repeatStr + ";\n"
                + "border-image: " + borderImage + fillStr + repeatStr + ";\n";

            borderImage = "url(" + UserImageCache.getSrc() + ") " + joinValues(imageOffset);
        }

        $("#cssEl").html(style)
                .css("border-width", borderWidthStr)
                .css("-moz-border-image", borderImage + repeatStr)
                .css("-webkit-border-image", borderImage + repeatStr)
                .css("-o-border-image", borderImage + repeatStr)
                .css("border-image", borderImage + fillStr + repeatStr);
    }

    fillEl.change(function() {
        state.fill = this.checked;
        updateCSS();
        updateHash();
    });

    sliders.slider({
        max: 100,
        slide: function(event, ui) {
            var map = sliderMap[event.target.id];
            state[map.array][map.index] = ui.value;

            updateCSS();
            updateDividers();
        },
        stop: function() {
            updateHash();
        }
    });
    dividers.draggable({
        containment: "parent",
        drag: function(event, ui) {
            dividerMap[event.target.id].setValue(event.target);
            updateCSS();
            updateSliders();
        },
        stop: function() {
            updateHash();
        }
    });
    dividers.filter(":even").draggable("option", "axis", "y");
    dividers.filter(":odd").draggable("option", "axis", "x");

    repeat.change(function() {
        var map = repeatMap[this.id];
        state.repeat[map.index] = $(this).val();
        updateCSS();
        updateHash();
    });

    UserImageCache.setImageEl(imageEl[0]);
    imageEl.load(function() {
        var img = this,
            natWidth = img.naturalWidth || img.width,
            natHeight = img.naturalHeight || img.height,
            width = natWidth*state.scaleFactor,
            height = natHeight*state.scaleFactor;

        // Ensure that the initial scale for the image is always smaller that the size of the screen
        if (width > window.innerWidth || height > window.innerHeight) {
            state.scaleFactor = Math.min(window.innerWidth/width, window.innerHeight/height);
            width = natWidth*state.scaleFactor;
            height = natHeight*state.scaleFactor;
        }

        naturalSize = {
            width: natWidth,
            height: natHeight
        };

        // Correct for any HTTP escaping issues in the input
        state.src = UserImageCache.getEntryId();
        pathToImage.val(UserImageCache.getDisplayName());

        editorEl.width(width).height(height);
        editorEl.show();

        $(".errorMsg").hide();
        validImage = true;

        sliders.filter(":odd").slider("option", "max", natWidth);
        sliders.filter(":even").slider("option", "max", natHeight);
        updateSliders();
        updateDividers();
        updateCSS();
        updateHash();
    });

    function errorHandler(code) {
        var msg;
        if (code === FileError.NOT_FOUND_ERR) {
            msg = "Unable to find image. This may be due to an incorrect path name or a local file that has not been properly loaded.";
        } else if (code) {
            msg = "Failed to load image. Error code: " + code;
        } else {
            msg = "Unknown error occured loading image " + UserImageCache.getDisplayName();
        }

        // Only show the message if the user as attempted to load an image
        if (UserImageCache.getEntryId()) {
            $(".errorMsg").html("*** " + msg).show();
        }

        editorEl.hide();
        validImage = false;

        updateCSS();
    }
    imageEl.error(function() { errorHandler(); });
    pathToImage.change(function(event) {
        // Clear the frame size so Opera can scale the editor down if the new image is smaller than the last
        editorEl.width("auto").height("auto");
        UserImageCache.load(pathToImage.val(), errorHandler);
    });

    function setFlag(name, value) {
        return function() {
            state[name] = value;
            updateCSS();
            updateHash();
        };
    }
    $("#borderOptionsExpander").expander("#borderOptions", setFlag("linkBorder", false), setFlag("linkBorder", true));
    $("#repeatOptionsExpander").expander("#repeatOptions", setFlag("setRepeat", true), setFlag("setRepeat", false));

    editorEl.resizable({
        reverseXAxis: true,
        handles: "s, w, sw",
        aspectRatio: true,
        resize: function() {
            state.scaleFactor = editorEl.innerWidth() / naturalSize.width;

            updateSliders();
            updateDividers();
            updateCSS();
        },
        stop: function() {
            updateHash();
        }
    });

    if (UserImageCache.isLocalSupported()) {
        $("body").bind("dragenter dragover", function(event) {
            // We have to cancel these events or we will not recieve the drop event
            event.preventDefault();
            event.stopPropagation();
        });
        $("body").bind("drop", function(event) {
            event.preventDefault();
            event.stopPropagation();
            var dataTransfer = event.originalEvent.dataTransfer,
                file = dataTransfer.files[0];

            UserImageCache.load(file, errorHandler);
        });
        $("#localImage").bind("change", function(event) {
            var file = this.files[0];

            UserImageCache.load(file, errorHandler);
        });

        $("body").removeClass("no-local");
    }

    HistoryHandler.init(function(hash) {
        var prevScale = state.scaleFactor;

        if (hash) {
            $.extend(state, JSON.parse(hash));
        }
        if ($("#borderOptions").is(":visible") === state.linkBorder) {
            $("#borderOptionsExpander").click();
        }
        if ($("#repeatOptions").is(":visible") !== state.setRepeat) {
            $("#repeatOptionsExpander").click();
        }

        updateFill();

        if (UserImageCache.getEntryId() !== state.src) {
            // The other values will update when the image loads
            UserImageCache.load(state.src, errorHandler);
        } else if (prevScale !== state.scaleFactor) {
            imageEl.load();
        } else {
            updateSliders();
            updateDividers();
            updateCSS();
        }

        updateRepeat();
    });
});
<commit_msg>Fix whitespace<commit_after>/*
 * Copyright (c) 2010 Kevin Decker (http://www.incaseofstairs.com/)
 * See LICENSE for license information
 */
$(document).ready(function() {
    var pathToImage = $("#pathToImage"),
        editorEl = $("#editorEl"),
        imageEl = $("#imageEl"),
        dividers = $(".divider"),
        sliders = $(".slider"),
        fillEl = $("#fillCenter"),
        cssEl = $("#cssEl"),
        repeat = $(".repeat"),

        validImage = false,
        naturalSize = {},

        state = {
            src: "",

            linkBorder: true,
            borderWidth: [0, 0, 0, 0],
            imageOffset: [0, 0, 0, 0],

            fill: true,
            setRepat: false,
            repeat: ["stretch", "stretch"],

            scaleFactor: 3
        };

    var sliderMap = {
        imageTop: { array: "imageOffset", index: 0 },
        imageRight: { array: "imageOffset", index: 1 },
        imageBottom: { array: "imageOffset", index: 2 },
        imageLeft: { array: "imageOffset", index: 3 },

        borderTop: { array: "borderWidth", index: 0 },
        borderRight: { array: "borderWidth", index: 1 },
        borderBottom: { array: "borderWidth", index: 2 },
        borderLeft: { array: "borderWidth", index: 3 }
    }, dividerMap = {
        dividerTop: {
            setValue: function(el) { state.imageOffset[0] = calcPixels($(el).position().top); },
            updatePos: function(el) { $(el).css("top", state.imageOffset[0]*state.scaleFactor); }
        },
        dividerRight: {
            setValue: function(el) { state.imageOffset[1] = calcPixels(editorEl.innerWidth() - $(el).position().left + 2); },
            updatePos: function(el) { $(el).css("left", (editorEl.innerWidth() - 2 - state.imageOffset[1]*state.scaleFactor)); }
        },
        dividerBottom: {
            setValue: function(el) { state.imageOffset[2] = calcPixels(editorEl.innerHeight() - $(el).position().top + 2); },
            updatePos: function(el) { $(el).css("top", (editorEl.innerHeight() - 2 - state.imageOffset[2]*state.scaleFactor)); }
        },
        dividerLeft: {
            setValue: function(el) { state.imageOffset[3] = calcPixels($(el).position().left); },
            updatePos: function(el) { $(el).css("left", state.imageOffset[3]*state.scaleFactor); }
        }
    }, repeatMap = {
        repeatVertical: { index: 1 },
        repeatHorizontal: { index: 0 }
    };

    function calcPixels(pos) {
        return (pos / state.scaleFactor) | 0;
    }
    function updateFill() {
        fillEl[0].checked = !!state.fill;
    }
    function updateSliders() {
        $(".slider").each(function(index, el) {
            var map = sliderMap[el.id];
            $(el).slider("option", "value", state[map.array][map.index]);
        });
    }
    function updateDividers() {
        dividers.each(function(index, el) {
            dividerMap[el.id].updatePos(el);
        });
    }
    function updateRepeat() {
        repeat.each(function(index, el) {
            var map = repeatMap[el.id];
            $(el).val(state.repeat[map.index]);
        });
    }
    function updateHash() {
        HistoryHandler.store(JSON.stringify(state));
    }
    function joinValues(values, join) {
        var ret = [];
        if (values[3] !== undefined && values[3] !== values[1]) {
            ret.unshift(values[3]);
        }
        if (ret.length || (values[2] !== undefined && values[2] !== values[0])) {
            ret.unshift(values[2]);
        }
        if (ret.length || (values[1] !== undefined && values[1] !== values[0])) {
            ret.unshift(values[1]);
        }
        ret.unshift(values[0]);
        return ret.join(join || " ");
    }
    function updateCSS() {
        var borderImage = "", borderWidthStr = "", style = "",
            fillStr = state.fill ? " fill" : "",
            repeatStr = state.setRepeat ? " " + joinValues(state.repeat) : "";

        if (validImage) {
            var img = "url(" + UserImageCache.getDisplayName() + ")",
                imageOffset = state.imageOffset,
                borderWidth = state.linkBorder ? state.imageOffset : state.borderWidth;

            borderImage = img + " " + joinValues(imageOffset);
            borderWidthStr = joinValues(borderWidth, "px ") + "px";
            style = "border-style: solid;\n"
                + "border-width: " + borderWidthStr + ";\n"
                + "-moz-border-image: " + borderImage + repeatStr + ";\n"
                + "-webkit-border-image: " + borderImage + repeatStr + ";\n"
                + "-o-border-image: " + borderImage + repeatStr + ";\n"
                + "border-image: " + borderImage + fillStr + repeatStr + ";\n";

            borderImage = "url(" + UserImageCache.getSrc() + ") " + joinValues(imageOffset);
        }

        $("#cssEl").html(style)
                .css("border-width", borderWidthStr)
                .css("-moz-border-image", borderImage + repeatStr)
                .css("-webkit-border-image", borderImage + repeatStr)
                .css("-o-border-image", borderImage + repeatStr)
                .css("border-image", borderImage + fillStr + repeatStr);
    }

    fillEl.change(function() {
        state.fill = this.checked;
        updateCSS();
        updateHash();
    });

    sliders.slider({
        max: 100,
        slide: function(event, ui) {
            var map = sliderMap[event.target.id];
            state[map.array][map.index] = ui.value;

            updateCSS();
            updateDividers();
        },
        stop: function() {
            updateHash();
        }
    });
    dividers.draggable({
        containment: "parent",
        drag: function(event, ui) {
            dividerMap[event.target.id].setValue(event.target);
            updateCSS();
            updateSliders();
        },
        stop: function() {
            updateHash();
        }
    });
    dividers.filter(":even").draggable("option", "axis", "y");
    dividers.filter(":odd").draggable("option", "axis", "x");

    repeat.change(function() {
        var map = repeatMap[this.id];
        state.repeat[map.index] = $(this).val();
        updateCSS();
        updateHash();
    });

    UserImageCache.setImageEl(imageEl[0]);
    imageEl.load(function() {
        var img = this,
            natWidth = img.naturalWidth || img.width,
            natHeight = img.naturalHeight || img.height,
            width = natWidth*state.scaleFactor,
            height = natHeight*state.scaleFactor;

        // Ensure that the initial scale for the image is always smaller that the size of the screen
        if (width > window.innerWidth || height > window.innerHeight) {
            state.scaleFactor = Math.min(window.innerWidth/width, window.innerHeight/height);
            width = natWidth*state.scaleFactor;
            height = natHeight*state.scaleFactor;
        }

        naturalSize = {
            width: natWidth,
            height: natHeight
        };

        // Correct for any HTTP escaping issues in the input
        state.src = UserImageCache.getEntryId();
        pathToImage.val(UserImageCache.getDisplayName());

        editorEl.width(width).height(height);
        editorEl.show();

        $(".errorMsg").hide();
        validImage = true;

        sliders.filter(":odd").slider("option", "max", natWidth);
        sliders.filter(":even").slider("option", "max", natHeight);
        updateSliders();
        updateDividers();
        updateCSS();
        updateHash();
    });

    function errorHandler(code) {
        var msg;
        if (code === FileError.NOT_FOUND_ERR) {
            msg = "Unable to find image. This may be due to an incorrect path name or a local file that has not been properly loaded.";
        } else if (code) {
            msg = "Failed to load image. Error code: " + code;
        } else {
            msg = "Unknown error occured loading image " + UserImageCache.getDisplayName();
        }

        // Only show the message if the user as attempted to load an image
        if (UserImageCache.getEntryId()) {
            $(".errorMsg").html("*** " + msg).show();
        }

        editorEl.hide();
        validImage = false;

        updateCSS();
    }
    imageEl.error(function() { errorHandler(); });
    pathToImage.change(function(event) {
        // Clear the frame size so Opera can scale the editor down if the new image is smaller than the last
        editorEl.width("auto").height("auto");
        UserImageCache.load(pathToImage.val(), errorHandler);
    });

    function setFlag(name, value) {
        return function() {
            state[name] = value;
            updateCSS();
            updateHash();
        };
    }
    $("#borderOptionsExpander").expander("#borderOptions", setFlag("linkBorder", false), setFlag("linkBorder", true));
    $("#repeatOptionsExpander").expander("#repeatOptions", setFlag("setRepeat", true), setFlag("setRepeat", false));

    editorEl.resizable({
        reverseXAxis: true,
        handles: "s, w, sw",
        aspectRatio: true,
        resize: function() {
            state.scaleFactor = editorEl.innerWidth() / naturalSize.width;

            updateSliders();
            updateDividers();
            updateCSS();
        },
        stop: function() {
            updateHash();
        }
    });

    if (UserImageCache.isLocalSupported()) {
        $("body").bind("dragenter dragover", function(event) {
            // We have to cancel these events or we will not recieve the drop event
            event.preventDefault();
            event.stopPropagation();
        });
        $("body").bind("drop", function(event) {
            event.preventDefault();
            event.stopPropagation();
            var dataTransfer = event.originalEvent.dataTransfer,
                file = dataTransfer.files[0];

            UserImageCache.load(file, errorHandler);
        });
        $("#localImage").bind("change", function(event) {
            var file = this.files[0];

            UserImageCache.load(file, errorHandler);
        });

        $("body").removeClass("no-local");
    }

    HistoryHandler.init(function(hash) {
        var prevScale = state.scaleFactor;

        if (hash) {
            $.extend(state, JSON.parse(hash));
        }
        if ($("#borderOptions").is(":visible") === state.linkBorder) {
            $("#borderOptionsExpander").click();
        }
        if ($("#repeatOptions").is(":visible") !== state.setRepeat) {
            $("#repeatOptionsExpander").click();
        }

        updateFill();

        if (UserImageCache.getEntryId() !== state.src) {
            // The other values will update when the image loads
            UserImageCache.load(state.src, errorHandler);
        } else if (prevScale !== state.scaleFactor) {
            imageEl.load();
        } else {
            updateSliders();
            updateDividers();
            updateCSS();
        }

        updateRepeat();
    });
});
<|endoftext|>


<commit_before>// Encapsulate code in self-executing anonymous function to prevent cluttering global namespace
// and avoid naming collisions, as code inside parentheses is run immediately but invisible to outside code
(function(){

  'use strict';

  var MyhealthDirectives = angular.module('Myhealth.directives', []);

  MyhealthDirectives.directive('map', function() {
    return {
      restrict: 'E',
      scope: {
        onCreate: '&'
      },
      link: function ($scope, $element, $attr) {

        function initialize() {

          console.log('Myhealth.directives - initialize method called');

          var mapElement = $element[0];
          // Third arg is noWrap boolean that forces Lat -90 to +90 and Lng -180 to +180
          var latLng = new google.maps.LatLng(-36.4300, 148.3230, true);

          // Note: Controls added first appear closest to edge of map
          var mapOptions = {
            center: latLng,
            zoom: 13,
            noClear: true, // default is false. clears map container content before placing map
            backgroundColor: '#ff5511',
            mapTypeId: google.maps.MapTypeId.ROADMAP,
            keyboardShortcuts: true, // default is true. arrow keys pan. +/- zooms
            disableDoubleClickZoom: false, // default is false.
            draggable: true, // default is true. pan the map by dragging
            scrollwheel: true, // default is true. scroll wheel of mouse zooms
            streetViewControl: true, // default is true. toggles display of pegman
            disableDefaultUI: false, // default is false. property for UI (zoom, map control bar)
            mapTypeControl: true, // default is true. property for UI (map control bar)
            mapTypeControlOptions: { // DEFAULT (auto), HORIZONTAL_BAR, or DROPDOWN_MENU
              style: google.maps.MapTypeControlStyle.DROPDOWN_MENU,
              position: google.maps.ControlPosition.TOP_LEFT,
              mapTypeIds: [ // array of map options available
                google.maps.MapTypeId.ROADMAP, // default
                google.maps.MapTypeId.SATELLITE, // default
                google.maps.MapTypeId.TERRAIN // default
              ]
            },
            navigationControl: true, // default is true
            navigationControlOptions: {
              position: google.maps.ControlPosition.TOP_LEFT,
              style: google.maps.NavigationControlStyle.SMALL // default SMALL (DEFAULT, ZOOM_PAN, ANDROID)
            },
            scaleControl: true, // default is false
            scaleControlOptions: {
              position: google.maps.ControlPosition.TOP,
              style: google.maps.ScaleControlStyle.SMALL // unsure of alternatives
            }
          };

          var map = new google.maps.Map(mapElement, mapOptions);

          $scope.onCreate({map: map});

          // Check when map initialized only once and remove event listener after its run
          var mapReady = google.maps.event.addListenerOnce(map, 'bounds_changed', function() {
            var bounds = map.getBounds();
            console.log('Myhealth.directives - map bounds initialized');
          });

          // Create a marker and instantly add it to a map
          var marker = new google.maps.Marker({
            position: new google.maps.LatLng(-36.4300, 148.3230),
            icon: '../images/star_health_high.png',
            shadow: '../images/star_health_high_shadow.png',
            title: 'Star'
          });

          // Create new InfoWindow objects
          var infoWindowLadyBird = new google.maps.InfoWindow({
            content: 'Warning: Alpine ladybird beetle territory'
          });

          // Content for InfoWindow
          var infoWindowLadyBirdContent = '
' +
            '' +
            '
Ladybird
' +
            '
Harmonia Conformis
' +
            '
';

          var infoWindowCrossCountry = new google.maps.InfoWindow({
            content: 'Cross country skiing area'
          });

          // Listen for close window click event
          // Reference: https://github.com/amenadiel/google-maps-documentation/blob/master/docs/google.maps.StreetViewPanorama.md
          var closeInfoWindowLadyBird = google.maps.event.addDomListener(infoWindowLadyBird, 'closeclick', function (e) {
            console.log('Myhealth.directives - close infoWindowLadyBird clicked');
            // Close InfoWindow
            infoWindowLadyBird.close(map, infoWindowLadyBird);
            // Assign the returned MouseEvent object property of e
            var positionClicked = marker.getPosition();
            console.log('InfoWindowLadyBird Closed is at PositionClicked: ' + positionClicked);

            return false;
          });

          var closeInfoWindowCrossCountry = google.maps.event.addDomListener(infoWindowCrossCountry, 'mouseout', function (e) {
            console.log('Myhealth.directives - close infoWindowCrossCountry mouseout');
            // Close InfoWindow
            infoWindowCrossCountry.close(map, infoWindowCrossCountry);
            // Assign the returned MouseEvent object property of e
            var positionClicked = polygon.getPosition();
            console.log('InfoWindowCrossCountry Closed is at PositionMouseOut: ' + positionClicked);

            return false;
          });

          // Create array of points
          var points = [
            new google.maps.LatLng(-36.4317, 148.3286),
            new google.maps.LatLng(-36.4300, 148.3220),
            new google.maps.LatLng(-36.4100, 148.2913)
          ];

          // Create new polygon from polylines
          var polygon = new google.maps.Polygon({
            path: points,
            strokeColor: '#ff44dd',
            strokeWeight: 10,
            strokeOpacity: 0.5,
            fillColor: '#ff9999',
            fillOpacity: 0.3,
            map: map
          });
          // Note: Event listeners assigned to a variable to prevent global variables
          var placeMarker = google.maps.event.addDomListener($element[0], 'mousedown', function (e) {
            console.log('Myhealth.directives - mousedown method called');
            // Stop the side bar from dragging when mousedown/tapdown on the map
            e.preventDefault();
            // Add marker to map
            marker.setMap(map);
            return false;
          });

          // Listen for marker click event
          var handleMarker = google.maps.event.addDomListener(marker, 'click', function () {

            console.log('Myhealth.directives - click marker method called');
            // Invoke sending message to parent controller (MapCtrl)
            $scope.$emit('togglePanoEvent', true);

            $scope.$on('loadedPano', function(event, message) {
              console.log('loadedPanoEvent msg sent to child directive is: ' + message);

              // Set the content of the InfoWindow
              infoWindowLadyBird.setContent(infoWindowLadyBirdContent);
              // Add InfoWindow to map
              infoWindowLadyBird.open(map, marker);
              // Assign the returned MouseEvent object property of e
              var positionClicked = marker.getPosition();
              console.log('Marker PositionClicked is: ' + positionClicked);

              // Reference: http://blog.mridey.com/2010/05/how-to-create-and-display-custom.html
              var panorama = new google.maps.StreetViewPanorama(
                document.getElementById('streetview')
              );

              panorama.registerPanoProvider(function(pano) {
                return {
                  location: {
                    pano: pano,
                    description: "Mount Carruthers"
                  },
                  links: [], // Array of StreetViewLink
                  copyright: 'Imagery \xA9 2014 Luke Schoen',
                  tiles: {
                    tileSize: new google.maps.Size(512, 512),
                    worldSize: new google.maps.Size(1500, 750),
                    originHeading: 0, // Align panorama with the headings in links
                    getTileUrl: function(room, zoom, x, y) {
                      return '../images/happy_campers' + '_' + room + '_' + zoom + '_' + x + '_' + y + '.jpg';
                    }
                  }
                };
              });

              panorama.setPano('panorama');

              // Change properties of MapOptions after map has been initialised
              map.setOptions({
                zoom: 10
              });

            });

            return false;
          });

          // Listen for polyline click event
          var handlePolyline = google.maps.event.addDomListener(polygon, 'mouseover', function (e) {
            console.log('Myhealth.directives - click polygon method called');

            // Add InfoWindow for polygon to map
            infoWindowCrossCountry.open(map, polygon);

            // Assign the returned MouseEvent object property of e
            var positionClicked = e.latLng;
            console.log('Polygon PositionClicked is: ' + positionClicked);
            return false;
          });

        }
        // Wait for window object map element to load in browser before run initialize method
        google.maps.event.addDomListener(window, 'load', initialize);
      }
    };
  });

})();<commit_msg>Removed blank line<commit_after>// Encapsulate code in self-executing anonymous function to prevent cluttering global namespace
// and avoid naming collisions, as code inside parentheses is run immediately but invisible to outside code
(function(){

  'use strict';

  var MyhealthDirectives = angular.module('Myhealth.directives', []);

  MyhealthDirectives.directive('map', function() {
    return {
      restrict: 'E',
      scope: {
        onCreate: '&'
      },
      link: function ($scope, $element, $attr) {

        function initialize() {

          console.log('Myhealth.directives - initialize method called');

          var mapElement = $element[0];
          // Third arg is noWrap boolean that forces Lat -90 to +90 and Lng -180 to +180
          var latLng = new google.maps.LatLng(-36.4300, 148.3230, true);

          // Note: Controls added first appear closest to edge of map
          var mapOptions = {
            center: latLng,
            zoom: 13,
            noClear: true, // default is false. clears map container content before placing map
            backgroundColor: '#ff5511',
            mapTypeId: google.maps.MapTypeId.ROADMAP,
            keyboardShortcuts: true, // default is true. arrow keys pan. +/- zooms
            disableDoubleClickZoom: false, // default is false.
            draggable: true, // default is true. pan the map by dragging
            scrollwheel: true, // default is true. scroll wheel of mouse zooms
            streetViewControl: true, // default is true. toggles display of pegman
            disableDefaultUI: false, // default is false. property for UI (zoom, map control bar)
            mapTypeControl: true, // default is true. property for UI (map control bar)
            mapTypeControlOptions: { // DEFAULT (auto), HORIZONTAL_BAR, or DROPDOWN_MENU
              style: google.maps.MapTypeControlStyle.DROPDOWN_MENU,
              position: google.maps.ControlPosition.TOP_LEFT,
              mapTypeIds: [ // array of map options available
                google.maps.MapTypeId.ROADMAP, // default
                google.maps.MapTypeId.SATELLITE, // default
                google.maps.MapTypeId.TERRAIN // default
              ]
            },
            navigationControl: true, // default is true
            navigationControlOptions: {
              position: google.maps.ControlPosition.TOP_LEFT,
              style: google.maps.NavigationControlStyle.SMALL // default SMALL (DEFAULT, ZOOM_PAN, ANDROID)
            },
            scaleControl: true, // default is false
            scaleControlOptions: {
              position: google.maps.ControlPosition.TOP,
              style: google.maps.ScaleControlStyle.SMALL // unsure of alternatives
            }
          };

          var map = new google.maps.Map(mapElement, mapOptions);

          $scope.onCreate({map: map});

          // Check when map initialized only once and remove event listener after its run
          var mapReady = google.maps.event.addListenerOnce(map, 'bounds_changed', function() {
            var bounds = map.getBounds();
            console.log('Myhealth.directives - map bounds initialized');
          });

          // Create a marker and instantly add it to a map
          var marker = new google.maps.Marker({
            position: new google.maps.LatLng(-36.4300, 148.3230),
            icon: '../images/star_health_high.png',
            shadow: '../images/star_health_high_shadow.png',
            title: 'Star'
          });

          // Create new InfoWindow objects
          var infoWindowLadyBird = new google.maps.InfoWindow({
            content: 'Warning: Alpine ladybird beetle territory'
          });

          // Content for InfoWindow
          var infoWindowLadyBirdContent = '
' +
            '' +
            '
Ladybird
' +
            '
Harmonia Conformis
' +
            '
';

          var infoWindowCrossCountry = new google.maps.InfoWindow({
            content: 'Cross country skiing area'
          });

          // Listen for close window click event
          // Reference: https://github.com/amenadiel/google-maps-documentation/blob/master/docs/google.maps.StreetViewPanorama.md
          var closeInfoWindowLadyBird = google.maps.event.addDomListener(infoWindowLadyBird, 'closeclick', function (e) {
            console.log('Myhealth.directives - close infoWindowLadyBird clicked');
            // Close InfoWindow
            infoWindowLadyBird.close(map, infoWindowLadyBird);
            // Assign the returned MouseEvent object property of e
            var positionClicked = marker.getPosition();
            console.log('InfoWindowLadyBird Closed is at PositionClicked: ' + positionClicked);

            return false;
          });

          var closeInfoWindowCrossCountry = google.maps.event.addDomListener(infoWindowCrossCountry, 'mouseout', function (e) {
            console.log('Myhealth.directives - close infoWindowCrossCountry mouseout');
            // Close InfoWindow
            infoWindowCrossCountry.close(map, infoWindowCrossCountry);
            // Assign the returned MouseEvent object property of e
            var positionClicked = polygon.getPosition();
            console.log('InfoWindowCrossCountry Closed is at PositionMouseOut: ' + positionClicked);

            return false;
          });

          // Create array of points
          var points = [
            new google.maps.LatLng(-36.4317, 148.3286),
            new google.maps.LatLng(-36.4300, 148.3220),
            new google.maps.LatLng(-36.4100, 148.2913)
          ];

          // Create new polygon from polylines
          var polygon = new google.maps.Polygon({
            path: points,
            strokeColor: '#ff44dd',
            strokeWeight: 10,
            strokeOpacity: 0.5,
            fillColor: '#ff9999',
            fillOpacity: 0.3,
            map: map
          });
          // Note: Event listeners assigned to a variable to prevent global variables
          var placeMarker = google.maps.event.addDomListener($element[0], 'mousedown', function (e) {
            console.log('Myhealth.directives - mousedown method called');
            // Stop the side bar from dragging when mousedown/tapdown on the map
            e.preventDefault();
            // Add marker to map
            marker.setMap(map);
            return false;
          });

          // Listen for marker click event
          var handleMarker = google.maps.event.addDomListener(marker, 'click', function () {

            console.log('Myhealth.directives - click marker method called');
            // Invoke sending message to parent controller (MapCtrl)
            $scope.$emit('togglePanoEvent', true);

            $scope.$on('loadedPano', function(event, message) {
              console.log('loadedPanoEvent msg sent to child directive is: ' + message);

              // Set the content of the InfoWindow
              infoWindowLadyBird.setContent(infoWindowLadyBirdContent);
              // Add InfoWindow to map
              infoWindowLadyBird.open(map, marker);
              // Assign the returned MouseEvent object property of e
              var positionClicked = marker.getPosition();
              console.log('Marker PositionClicked is: ' + positionClicked);

              // Reference: http://blog.mridey.com/2010/05/how-to-create-and-display-custom.html
              var panorama = new google.maps.StreetViewPanorama(
                document.getElementById('streetview')
              );

              panorama.registerPanoProvider(function(pano) {
                return {
                  location: {
                    pano: pano,
                    description: "Mount Carruthers"
                  },
                  links: [], // Array of StreetViewLink
                  copyright: 'Imagery \xA9 2014 Luke Schoen',
                  tiles: {
                    tileSize: new google.maps.Size(512, 512),
                    worldSize: new google.maps.Size(1500, 750),
                    originHeading: 0, // Align panorama with the headings in links
                    getTileUrl: function(room, zoom, x, y) {
                      return '../images/happy_campers' + '_' + room + '_' + zoom + '_' + x + '_' + y + '.jpg';
                    }
                  }
                };
              });

              panorama.setPano('panorama');

              // Change properties of MapOptions after map has been initialised
              map.setOptions({
                zoom: 10
              });

            });

            return false;
          });

          // Listen for polyline click event
          var handlePolyline = google.maps.event.addDomListener(polygon, 'mouseover', function (e) {
            console.log('Myhealth.directives - click polygon method called');

            // Add InfoWindow for polygon to map
            infoWindowCrossCountry.open(map, polygon);

            // Assign the returned MouseEvent object property of e
            var positionClicked = e.latLng;
            console.log('Polygon PositionClicked is: ' + positionClicked);
            return false;
          });

        }
        // Wait for window object map element to load in browser before run initialize method
        google.maps.event.addDomListener(window, 'load', initialize);
      }
    };
  });

})();<|endoftext|>


<commit_before>// VVVV.js -- Visual Web Client Programming
// (c) 2011 Matthias Zauner
// VVVV.js is freely distributable under the MIT license.
// Additional authors of sub components are mentioned at the specific code locations.

if (!WebSocket && MozWebSocket)
  var WebSocket = MozWebSocket;

VVVV.Core.VVVVConnector = function(patch) {

  this.patch = patch;
  this.host = false;
  var socket = false;

  var that = this;

  this.enable = function(opts) {
    opts = opts || {}
    if (!this.host)
      return;
    socket = new WebSocket(this.host+":4444", "vvvvjs");

    var opened = false;
    socket.onopen = function() {
      opened = true;
      console.log("connected to VVVV ...");
      that.pushCompletePatch();
      window.setTimeout(function() {
        that.pullCompletePatch();
      }, 1000);
      if (opts.success)
        opts.success();
    }
    socket.onclose = function() {
      if (!opened && opts.error)
        opts.error();
      opened = false;
    }
    socket.onmessage = function(m) {
      patch.doLoad(m.data);
      patch.afterUpdate();
    }
  }

  this.disable = function() {
    if (socket)
      socket.close();
    socket.onmessage = null;
    socket.onopen = null;
    socket = false;
  }

  this.pullCompletePatch = function() {
    console.log('pulling patch...');
    socket.send('PULL');
  }

  this.pushCompletePatch = function() {
    console.log('pushing patch ...');
    socket.send('PUSH'+this.patch.XMLCode);
  }

  this.sendUndo = function() {
    if (socket) {
      console.log('forcing Undo ...');
      socket.send('UNDO');
    }
  }

  this.isConnected = function() {
    return socket!==false;
  }

}
<commit_msg>adds empty VVVVJsConnector (VVVVjs) node to prevent VVVV.js from trying to load it as a subpatch<commit_after>// VVVV.js -- Visual Web Client Programming
// (c) 2011 Matthias Zauner
// VVVV.js is freely distributable under the MIT license.
// Additional authors of sub components are mentioned at the specific code locations.

if (!WebSocket && MozWebSocket)
  var WebSocket = MozWebSocket;

VVVV.Core.VVVVConnector = function(patch) {

  this.patch = patch;
  this.host = false;
  var socket = false;

  var that = this;

  this.enable = function(opts) {
    opts = opts || {}
    if (!this.host)
      return;
    socket = new WebSocket(this.host+":4444", "vvvvjs");

    var opened = false;
    socket.onopen = function() {
      opened = true;
      console.log("connected to VVVV ...");
      that.pushCompletePatch();
      window.setTimeout(function() {
        that.pullCompletePatch();
      }, 1000);
      if (opts.success)
        opts.success();
    }
    socket.onclose = function() {
      if (!opened && opts.error)
        opts.error();
      opened = false;
    }
    socket.onmessage = function(m) {
      patch.doLoad(m.data);
      patch.afterUpdate();
    }
  }

  this.disable = function() {
    if (socket)
      socket.close();
    socket.onmessage = null;
    socket.onopen = null;
    socket = false;
  }

  this.pullCompletePatch = function() {
    console.log('pulling patch...');
    socket.send('PULL');
  }

  this.pushCompletePatch = function() {
    console.log('pushing patch ...');
    socket.send('PUSH'+this.patch.XMLCode);
  }

  this.sendUndo = function() {
    if (socket) {
      console.log('forcing Undo ...');
      socket.send('UNDO');
    }
  }

  this.isConnected = function() {
    return socket!==false;
  }

}

VVVV.Nodes.VVVVJsConnector = function(id, graph) {
  this.constructor(id, "VVVVJsConnector (VVVVjs)", graph);
}
VVVV.Nodes.VVVVJsConnector.prototype = new VVVV.Core.Node();
<|endoftext|>


<commit_before>;(function(){
	'use strict';
    window.views = window.views || {};
    window.views.Item = window.views.Item || {};

    var View = Backbone.View.extend({
        el : $('#item'),
        template: $('#itemTpl').html(),
        status: 'waiting',
        events: {
            'click .add' : 'add'
        },
        render : function(status){
            this.status = status;

            var markup = Mustache.render(this.template, { status:  this.status });
            var el = $(this.el);
            el.html(markup)
        },
        add : function(evt){
            var el = $(evt.target);
            var id = el.attr('task_id');
            var removed = this.model.where({ id: id });
            this.model.remove(removed);
            el.parent().parent().remove();
        }
    });
    var v = new View();
    window.views.Item.initialize = function(opts){
        v.model = opts.model;
        return v;
    };
})();
<commit_msg>Delete item.js<commit_after><|endoftext|>


<commit_before>import firebase from 'app/services/Firebase';
import {
    AppState
} from 'react-native';
import * as ScannedDevicesSelectors from 'app/redux/selectors/ScannedDevicesSelectors';
import * as SetsSelectors from 'app/redux/selectors/SetsSelectors';
import * as ConnectedDeviceStatusSelectors from 'app/redux/selectors/ConnectedDeviceStatusSelectors';
import * as AppStateSelectors from 'app/redux/selectors/AppStateSelectors';
import * as SurveySelectors from 'app/redux/selectors/SurveySelectors';
import DeviceInfo from 'react-native-device-info';

//initial analytics and initial screen

export const setInitialAnalytics = () => {
    const mobileID = DeviceInfo.getUniqueID();
    // set initial user props analytics
    setUserProp('connected_device_id', null);
    setUserProp('mobile_identifier', mobileID);
    setUserProp('device_version', null);
    setCurrentScreen('settings');
};

// User ID

// user ID defaults to the mobile identifier for anonymous users
export const setUserID = (userID=DeviceInfo.getUniqueID()) => {
    firebase.app().analytics().setUserId(userID);
    firebase.fabric.crashlytics().setUserIdentifier(userID);

    console.tron.display({
        name: 'UserID',
        value: userID,
        preview: userID,
        important: true,
        image: 'https://firebase.google.com/_static/images/firebase/touchicon-180.png'
    });
};

// Screens

export const setCurrentScreen = (screen) => {
    firebase.app().analytics().setCurrentScreen(screen);

    console.tron.display({
        name: 'SetScreen',
        value: screen,
        preview: screen,
        important: true,
        image: 'https://firebase.google.com/_static/images/firebase/touchicon-180.png'
    });
};

// User Properties

export const setUserProp = (name, value) => {
    firebase.app().analytics().setUserProperty(name, value);

    console.tron.display({
        name: 'SetUserProp',
        value: value,
        preview: name + " = " + value,
        important: true,
        image: 'https://firebase.google.com/_static/images/firebase/touchicon-180.png'
    });
};

// Log Events
// params must be an object
export const logEvent = (event, params) => {
    firebase.app().analytics().logEvent(event, params);

    console.tron.display({
        name: 'LogEvent',
        value: params,
        preview: event,
        important: true,
        image: 'https://firebase.google.com/_static/images/firebase/touchicon-180.png'
    });
};

export const logEventWithAppState = (event, params, state) => {
    const screenStatus = AppStateSelectors.getScreenStatus(state);
    const currentAppState = AppState.currentState;

    // if (screenStatus === 'active') {
    //     params.is_screen_locked = false;
    // } else {
    //     params.is_screen_locked = true;
    // }

    // if (currentAppState === 'active') {
    //     params.is_app_active = true;
    //     params.is_app_in_background = false;
    //     params.is_app_inactive = false;
    // } else if (currentAppState === 'background') {
    //     params.is_app_active = false;
    //     params.is_app_in_background = true;
    //     params.is_app_inactive = false;
    // } else if (currentAppState === 'inactive') {
    //     params.is_app_active = false;
    //     params.is_app_in_background = true;
    //     params.is_app_inactive = true;
    // }

    let devices = ScannedDevicesSelectors.getScannedDevices(state);
    if (devices.length > 25) {
        devices = devices.slice(0, 25);
    };
    const connectedDeviceStatus = ConnectedDeviceStatusSelectors.getConnectedDeviceStatus(state);
    const isWorkoutEmpty = SetsSelectors.getIsWorkoutEmpty(state);
    const isSurveyVisible = SurveySelectors.getSurveyAvailable(state);

    const scanned_devices = devices.join().replace(/\s|OB|,/g, '');
    params.scanned_devices = scanned_devices;

    params.num_scanned_devices = devices.length;

    // params.is_bluetooth_on = connectedDeviceStatus !== 'BLUETOOTH_OFF';

    params.is_workout_in_progress = !isWorkoutEmpty;

    params.is_survey_visible = isSurveyVisible;

    logEvent(event, params);
};

// ERRORS
// auto adds error to the params
// auto chooses the code from the error if it exists, else defaults to 9001 as it's unknown

const addErrorToParams = (error, params) => {
    // parse error string
    if (error) {
        var errorString = JSON.stringify(error);
    } else {
        var errorString = "";
    }

    // create params
    if (params) {
        params.error = errorString;
    } else {
        params = {error: errorString};
    }

    return params;
};

const getErrorCode = (error) => {
    if (error && error.code) {
        return error.code;
    } else {
        return 9001;
    }
}

const logCrashlyticsError = (code, event, params) => {
    let message = JSON.stringify(params);
    firebase.fabric.crashlytics().setStringValue("error_params", message);
    firebase.fabric.crashlytics().recordError(code, event);
};

export const logError = (error, event, params) => {
    let errorParams = addErrorToParams(error, params);
    let errorCode = getErrorCode(error);
    logCrashlyticsError(errorCode, event, errorParams);
    logEvent(event, errorParams);
};

export const logErrorWithAppState = (error, event, params, state) => {
    let errorParams = addErrorToParams(error, params);
    let errorCode = getErrorCode(error);
    logCrashlyticsError(errorCode, event, errorParams);
    logEventWithAppState(event, errorParams, state);
};
<commit_msg>Added semicoloin<commit_after>import firebase from 'app/services/Firebase';
import {
    AppState
} from 'react-native';
import * as ScannedDevicesSelectors from 'app/redux/selectors/ScannedDevicesSelectors';
import * as SetsSelectors from 'app/redux/selectors/SetsSelectors';
import * as ConnectedDeviceStatusSelectors from 'app/redux/selectors/ConnectedDeviceStatusSelectors';
import * as AppStateSelectors from 'app/redux/selectors/AppStateSelectors';
import * as SurveySelectors from 'app/redux/selectors/SurveySelectors';
import DeviceInfo from 'react-native-device-info';

//initial analytics and initial screen

export const setInitialAnalytics = () => {
    const mobileID = DeviceInfo.getUniqueID();
    // set initial user props analytics
    setUserProp('connected_device_id', null);
    setUserProp('mobile_identifier', mobileID);
    setUserProp('device_version', null);
    setCurrentScreen('settings');
};

// User ID

// user ID defaults to the mobile identifier for anonymous users
export const setUserID = (userID=DeviceInfo.getUniqueID()) => {
    firebase.app().analytics().setUserId(userID);
    firebase.fabric.crashlytics().setUserIdentifier(userID);

    console.tron.display({
        name: 'UserID',
        value: userID,
        preview: userID,
        important: true,
        image: 'https://firebase.google.com/_static/images/firebase/touchicon-180.png'
    });
};

// Screens

export const setCurrentScreen = (screen) => {
    firebase.app().analytics().setCurrentScreen(screen);

    console.tron.display({
        name: 'SetScreen',
        value: screen,
        preview: screen,
        important: true,
        image: 'https://firebase.google.com/_static/images/firebase/touchicon-180.png'
    });
};

// User Properties

export const setUserProp = (name, value) => {
    firebase.app().analytics().setUserProperty(name, value);

    console.tron.display({
        name: 'SetUserProp',
        value: value,
        preview: name + " = " + value,
        important: true,
        image: 'https://firebase.google.com/_static/images/firebase/touchicon-180.png'
    });
};

// Log Events
// params must be an object
export const logEvent = (event, params) => {
    firebase.app().analytics().logEvent(event, params);

    console.tron.display({
        name: 'LogEvent',
        value: params,
        preview: event,
        important: true,
        image: 'https://firebase.google.com/_static/images/firebase/touchicon-180.png'
    });
};

export const logEventWithAppState = (event, params, state) => {
    const screenStatus = AppStateSelectors.getScreenStatus(state);
    const currentAppState = AppState.currentState;

    // if (screenStatus === 'active') {
    //     params.is_screen_locked = false;
    // } else {
    //     params.is_screen_locked = true;
    // }

    // if (currentAppState === 'active') {
    //     params.is_app_active = true;
    //     params.is_app_in_background = false;
    //     params.is_app_inactive = false;
    // } else if (currentAppState === 'background') {
    //     params.is_app_active = false;
    //     params.is_app_in_background = true;
    //     params.is_app_inactive = false;
    // } else if (currentAppState === 'inactive') {
    //     params.is_app_active = false;
    //     params.is_app_in_background = true;
    //     params.is_app_inactive = true;
    // }

    let devices = ScannedDevicesSelectors.getScannedDevices(state);
    if (devices.length > 25) {
        devices = devices.slice(0, 25);
    };
    const connectedDeviceStatus = ConnectedDeviceStatusSelectors.getConnectedDeviceStatus(state);
    const isWorkoutEmpty = SetsSelectors.getIsWorkoutEmpty(state);
    const isSurveyVisible = SurveySelectors.getSurveyAvailable(state);

    const scanned_devices = devices.join().replace(/\s|OB|,/g, '');
    params.scanned_devices = scanned_devices;

    params.num_scanned_devices = devices.length;

    // params.is_bluetooth_on = connectedDeviceStatus !== 'BLUETOOTH_OFF';

    params.is_workout_in_progress = !isWorkoutEmpty;

    params.is_survey_visible = isSurveyVisible;

    logEvent(event, params);
};

// ERRORS
// auto adds error to the params
// auto chooses the code from the error if it exists, else defaults to 9001 as it's unknown

const addErrorToParams = (error, params) => {
    // parse error string
    if (error) {
        var errorString = JSON.stringify(error);
    } else {
        var errorString = "";
    }

    // create params
    if (params) {
        params.error = errorString;
    } else {
        params = {error: errorString};
    }

    return params;
};

const getErrorCode = (error) => {
    if (error && error.code) {
        return error.code;
    } else {
        return 9001;
    }
};

const logCrashlyticsError = (code, event, params) => {
    let message = JSON.stringify(params);
    firebase.fabric.crashlytics().setStringValue("error_params", message);
    firebase.fabric.crashlytics().recordError(code, event);
};

export const logError = (error, event, params) => {
    let errorParams = addErrorToParams(error, params);
    let errorCode = getErrorCode(error);
    logCrashlyticsError(errorCode, event, errorParams);
    logEvent(event, errorParams);
};

export const logErrorWithAppState = (error, event, params, state) => {
    let errorParams = addErrorToParams(error, params);
    let errorCode = getErrorCode(error);
    logCrashlyticsError(errorCode, event, errorParams);
    logEventWithAppState(event, errorParams, state);
};
<|endoftext|>


<commit_before>var request = require("request");
var graphql = require("graphql.js");

module.exports = function() {
  var configuration = {};
  var graph;

  return {
    configure: function(options) {
      configuration = Object.assign(configuration, options);
      configuration.orgSlug =
        process.env.BUILDKITE_ORGANISATION_SLUG || configuration.orgSlug;
      configuration.teamSlug =
        process.env.BUILDKITE_TEAM_SLUG || configuration.teamSlug;

      if (!configuration.orgSlug)
        throw new Error(
          "Must configure the orgSlug property for the buildkite plugin"
        );
      if (!configuration.teamSlug)
        throw new Error(
          "Must configure the teamSlug property for the buildkite plugin"
        );
      if (!process.env.BUILDKITE_TOKEN)
        throw new Error(
          "Must configure the BUILDKITE_TOKEN environment variable with your bk token."
        );

      graph = graphql("https://graphql.buildkite.com/v1", {
        asJSON: true,
        headers: {
          Authorization: `Bearer ${process.env.BUILDKITE_TOKEN}`
        }
      });
    },
    check: function(callback) {
      graph
        .query(
          `
      SimpleQuery {
        organization(slug: "${configuration.orgSlug}") {
          name
          pipelines(first: 100, team: "${configuration.teamSlug}") {
            edges {
              node {
                name
                slug
                builds(first: 1) {
                  edges {
                    node {
                      branch
                      message
                      number
                      state
                      startedAt
                      finishedAt
                      url
                      createdBy {
                        ... on User {
                          name
                        }
                        ... on UnregisteredUser {
                          name
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
      `,
          {}
        )
        .then(function(response) {
          const result = response.organization.pipelines.edges.map(x => {
            const pipeline = x.node;
            const build =
              x.node.builds.edges.length > 0
                ? x.node.builds.edges[0].node
                : {
                    branch: "master",
                    isRunning: false,
                    createdBy: {
                      name: ""
                    },
                    state: "NOT_RUN",
                    message: "Pipeline Created",
                    number: "N/A"
                  };

            const buildStates = {
              SKIPPED: { desc: "The build was skipped", color: "#ffff00" },
              SCHEDULED: {
                desc: "The build has yet to start running jobs",
                color: "#0000ff"
              },
              RUNNING: {
                desc: " The build is currently running jobs",
                color: "#ffa500"
              },
              PASSED: { desc: "The build passed", color: "#008000" },
              FAILED: { desc: "The build failed", color: "#ff0000" },
              CANCELING: {
                desc: "The build is currently being canceled",
                color: "#ffb3b3"
              },
              CANCELED: { desc: "The build was canceled", color: "#ff4d4d" },
              BLOCKED: { desc: "The build is blocked", color: "#003300" },
              NOT_RUN: { desc: "The build wasn't run", color: "#808080" }
            };

            return {
              id: pipeline.slug + "/" + build.number,
              project: pipeline.name,
              branch: build.branch,
              number: build.number,
              isRunning: build.state === "RUNNING",
              startedAt: new Date(build.startedAt),
              finishedAt: new Date(build.finishedAt),
              requestedFor: build.createdBy && build.createdBy.name,
              status: buildStates[build.state].color,
              statusText: build.state,
              reason: build.message,
              hasErrors: false,
              hasWarnings: false,
              url: build.url
            };
          });
          callback(null, result);
        })
        .catch(function(error) {
          console.log(error);
          callback(error);
        });
    }
  };
};
<commit_msg>:sparkles: fix lint<commit_after>var request = require("request");
var graphql = require("graphql.js");

module.exports = function() {
  var configuration = {};
  var graph;

  return {
    configure: function(options) {
      configuration = Object.assign(configuration, options);
      configuration.orgSlug =
        process.env.BUILDKITE_ORGANISATION_SLUG || configuration.orgSlug;
      configuration.teamSlug =
        process.env.BUILDKITE_TEAM_SLUG || configuration.teamSlug;

      if (!configuration.orgSlug)
        throw new Error(
          "Must configure the orgSlug property for the buildkite plugin"
        );
      if (!configuration.teamSlug)
        throw new Error(
          "Must configure the teamSlug property for the buildkite plugin"
        );
      if (!process.env.BUILDKITE_TOKEN)
        throw new Error(
          "Must configure the BUILDKITE_TOKEN environment variable with your bk token."
        );

      graph = graphql("https://graphql.buildkite.com/v1", {
        asJSON: true,
        headers: {
          Authorization: `Bearer ${process.env.BUILDKITE_TOKEN}`
        }
      });
    },
    check: function(callback) {
      graph
        .query(
          `
      SimpleQuery {
        organization(slug: "${configuration.orgSlug}") {
          name
          pipelines(first: 100, team: "${configuration.teamSlug}") {
            edges {
              node {
                name
                slug
                builds(first: 1) {
                  edges {
                    node {
                      branch
                      message
                      number
                      state
                      startedAt
                      finishedAt
                      url
                      createdBy {
                        ... on User {
                          name
                        }
                        ... on UnregisteredUser {
                          name
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
      `,
          {}
        )
        .then(function(response) {
          const result = response.organization.pipelines.edges.map(x => {
            const pipeline = x.node;
            const build =
              x.node.builds.edges.length > 0 ?
                x.node.builds.edges[0].node : {
                    branch: "master",
                    isRunning: false,
                    createdBy: {
                      name: ""
                    },
                    state: "NOT_RUN",
                    message: "Pipeline Created",
                    number: "N/A"
                  };

            const buildStates = {
              SKIPPED: { desc: "The build was skipped", color: "#ffff00" },
              SCHEDULED: {
                desc: "The build has yet to start running jobs",
                color: "#0000ff"
              },
              RUNNING: {
                desc: " The build is currently running jobs",
                color: "#ffa500"
              },
              PASSED: { desc: "The build passed", color: "#008000" },
              FAILED: { desc: "The build failed", color: "#ff0000" },
              CANCELING: {
                desc: "The build is currently being canceled",
                color: "#ffb3b3"
              },
              CANCELED: { desc: "The build was canceled", color: "#ff4d4d" },
              BLOCKED: { desc: "The build is blocked", color: "#003300" },
              NOT_RUN: { desc: "The build wasn't run", color: "#808080" }
            };

            return {
              id: pipeline.slug + "/" + build.number,
              project: pipeline.name,
              branch: build.branch,
              number: build.number,
              isRunning: build.state === "RUNNING",
              startedAt: new Date(build.startedAt),
              finishedAt: new Date(build.finishedAt),
              requestedFor: build.createdBy && build.createdBy.name,
              status: buildStates[build.state].color,
              statusText: build.state,
              reason: build.message,
              hasErrors: false,
              hasWarnings: false,
              url: build.url
            };
          });
          callback(null, result);
        })
        .catch(function(error) {
          console.log(error);
          callback(error);
        });
    }
  };
};
<|endoftext|>


<commit_before>var extend = require('node.extend');
var EntityManagement = require('./entity-management');
var PersistentCollection = require('./persistent-collection');
var dataTranslator = require('./mysql-translator');
var country = require('../model/country');
var ownership = require('../model/ownership');
var stamp = require('../model/stamp');
var q = require('q');

var countries = extend(true, {}, new EntityManagement(), new PersistentCollection(), function() {
    "use strict";

    function updateImagePaths(connection,merged,storedObj) {
        var defer = q.defer();

        var selection = "UPDATE " + ownership.getTableName() + " " + ownership.getAlias() + " INNER JOIN " +
          stamp.getTableName() + " "  + stamp.getAlias() + " on " + ownership.getAlias() + ".STAMP_ID = " + stamp.getAlias() +
            ".ID AND " + stamp.getAlias() + ".COUNTRY_ID = " + storedObj.ID + " SET IMAGE = REPLACE(IMAGE, '" +
            storedObj.NAME + "', '" + merged.NAME + "') WHERE IMAGE LIKE '" + storedObj.NAME + "%';";
        connection.query(selection, null, function (err, results) {
            if (err) {
                defer.reject(dataTranslator.getErrorMessage(err));
            } else {
                defer.resolve();
            }
        });
        return defer.promise;
    }

    return {
        collectionName: 'countries',
        fieldDefinition: country,

        getCountStampWhereStatement: function() {
            return stamp.getAlias() + '.COUNTRY_ID=' + this.fieldDefinition.getAlias() + '.ID';
        },

        preCommitUpdate: function(connection,merged,storedObj,params) {
            var defer = q.defer();
            if(params.modifyImagePath && params.modifyImagePath === 'true' ) {
                updateImagePaths(connection,merged,storedObj).then(function(result) {
                    defer.resolve({
                        modified: true
                    });
                }).catch(function(err) {
                    defer.reject(dataTranslator.getErrorMessage(err));
                });
            } else {
                defer.resolve({modified: false});
            }
            return defer.promise;
        }
    };
}());

module.exports = countries;
<commit_msg>Ensure an exact country name match in the image update<commit_after>var extend = require('node.extend');
var EntityManagement = require('./entity-management');
var PersistentCollection = require('./persistent-collection');
var dataTranslator = require('./mysql-translator');
var country = require('../model/country');
var ownership = require('../model/ownership');
var stamp = require('../model/stamp');
var q = require('q');

var countries = extend(true, {}, new EntityManagement(), new PersistentCollection(), function() {
    "use strict";

    function updateImagePaths(connection,merged,storedObj) {
        var defer = q.defer();

        var selection = "UPDATE " + ownership.getTableName() + " " + ownership.getAlias() + " INNER JOIN " +
          stamp.getTableName() + " "  + stamp.getAlias() + " on " + ownership.getAlias() + ".STAMP_ID = " + stamp.getAlias() +
            ".ID AND " + stamp.getAlias() + ".COUNTRY_ID = " + storedObj.ID + " SET IMAGE = REPLACE(IMAGE, '" +
            storedObj.NAME + "', '" + merged.NAME + "') WHERE IMAGE LIKE '" + storedObj.NAME + "/%';";
        connection.query(selection, null, function (err, results) {
            if (err) {
                defer.reject(dataTranslator.getErrorMessage(err));
            } else {
                defer.resolve();
            }
        });
        return defer.promise;
    }

    return {
        collectionName: 'countries',
        fieldDefinition: country,

        getCountStampWhereStatement: function() {
            return stamp.getAlias() + '.COUNTRY_ID=' + this.fieldDefinition.getAlias() + '.ID';
        },

        preCommitUpdate: function(connection,merged,storedObj,params) {
            var defer = q.defer();
            if(params.modifyImagePath && params.modifyImagePath === 'true' ) {
                updateImagePaths(connection,merged,storedObj).then(function(result) {
                    defer.resolve({
                        modified: true
                    });
                }).catch(function(err) {
                    defer.reject(dataTranslator.getErrorMessage(err));
                });
            } else {
                defer.resolve({modified: false});
            }
            return defer.promise;
        }
    };
}());

module.exports = countries;
<|endoftext|>


<commit_before>import Ember from 'ember';
import DS from 'ember-data';
import { pluralize } from 'ember-inflector';

const { inject, Service, RSVP, computed } = Ember;
const { PromiseArray } = DS;
const { service } = inject;

export default Service.extend({
  store: service(),
  currentUser: service(),
  reportsList: computed('currentUser.model.reports.[]', function(){
    let defer = RSVP.defer();
    this.get('currentUser').get('model').then( user => {
      user.get('reports').then( reports => {
        defer.resolve(reports);
      });
    });
    return PromiseArray.create({
      promise: defer.promise
    });
  }),
  getResults(report){
    const subject = report.get('subject');
    const object = report.get('prepositionalObject');
    const objectId = report.get('prepositionalObjectTableRowId');
    let defer = RSVP.defer();
    this.get('store').query(
      this.getModel(subject),
      this.getQuery(subject, object, objectId)
    ).then(results => {
      let mapper = subject + 'Results';
      this[mapper](results).then(mappedResults => {
        defer.resolve(mappedResults.sortBy('value'));
      });
    });

    return DS.PromiseArray.create({
      promise: defer.promise
    });
  },
  getModel(subject){
    let model = subject.dasherize();
    if(model === 'instructor'){
      model = 'user';
    }
    if(model === 'mesh-term'){
      model = 'mesh-descriptor';
    }

    return model;
  },
  getQuery(subject, object, objectId){
    let query = {
      limit: 1000
    };

    if(object && objectId){
      let what = pluralize(object.camelize());
      if(object === 'mesh term'){
        what = 'meshDescriptors';
      }
      if(subject = 'session' && object === 'session type'){
        what = 'sessionType';
      }
      query.filters = {};
      query.filters[what] = objectId;
    }

    return query;
  },
  courseResults(results){
    const canViewCourses = this.get('currentUser.canViewCourses');
    let map = results.map(course => {
      let rhett = {};
      rhett.value = course.get('academicYear') + ' ' + course.get('title');
      if(canViewCourses){
        rhett.route = 'course';
        rhett.model = course;
      }

      return rhett;
    });

    return RSVP.resolve(map);
  },
  sessionResults(results){
    const canView = this.get('currentUser.canViewCourses');
    let map = results.map(item => {
      return new RSVP.Promise(resolve => {
        let rhett = {};
        item.get('course').then(course => {
          rhett.value = course.get('academicYear') + ' ' + course.get('title') + ' ' + item.get('title');
          if(canView){
              rhett.route = 'session';
              rhett.model = course;
              rhett.model2 = item;
          }
          resolve(rhett);
        });
      });
    });

    return RSVP.all(map);
  },
  programResults(results){
    const canView = this.get('currentUser.canViewPrograms');
    let map = results.map(item => {
      return new RSVP.Promise(resolve => {
        let rhett = {};
        item.get('school').then(school => {
          rhett.value = school.get('title') + ': ' + item.get('title');
          if(canView){
              rhett.route = 'program';
              rhett.model = item;
          }
          resolve(rhett);
        });
      });
    });

    return RSVP.all(map);
  }
});

/*
{value: 'course', label: this.get('i18n').t('general.courses')},
{value: 'session', label: this.get('i18n').t('general.sessions')},
{value: 'program', label: this.get('i18n').t('general.programs')},
{value: 'program year', label: this.get('i18n').t('general.programYears')},
{value: 'instructor', label: this.get('i18n').t('general.instructors')},
{value: 'instructor group', label: this.get('i18n').t('general.instructorGroups')},
{value: 'learning material', label: this.get('i18n').t('general.learningMaterials')},
{value: 'competency', label: this.get('i18n').t('general.competencies')},
{value: 'topic', label: this.get('i18n').t('general.topics')},
{value: 'mesh term', label: this.get('i18n').t('general.meshTerms')},
{value: 'session type', label: this.get('i18n').t('general.sessionTypes')},
 */
<commit_msg>Improved report display for program years<commit_after>import Ember from 'ember';
import DS from 'ember-data';
import { pluralize } from 'ember-inflector';

const { inject, Service, RSVP, computed } = Ember;
const { PromiseArray } = DS;
const { service } = inject;

export default Service.extend({
  store: service(),
  currentUser: service(),
  reportsList: computed('currentUser.model.reports.[]', function(){
    let defer = RSVP.defer();
    this.get('currentUser').get('model').then( user => {
      user.get('reports').then( reports => {
        defer.resolve(reports);
      });
    });
    return PromiseArray.create({
      promise: defer.promise
    });
  }),
  getResults(report){
    const subject = report.get('subject');
    const object = report.get('prepositionalObject');
    const objectId = report.get('prepositionalObjectTableRowId');
    let defer = RSVP.defer();
    this.get('store').query(
      this.getModel(subject),
      this.getQuery(subject, object, objectId)
    ).then(results => {
      let mapper = pluralize(subject.camelize()) + 'Results';
      this[mapper](results).then(mappedResults => {
        defer.resolve(mappedResults.sortBy('value'));
      });
    });

    return DS.PromiseArray.create({
      promise: defer.promise
    });
  },
  getModel(subject){
    let model = subject.dasherize();
    if(model === 'instructor'){
      model = 'user';
    }
    if(model === 'mesh-term'){
      model = 'mesh-descriptor';
    }

    return model;
  },
  getQuery(subject, object, objectId){
    let query = {
      limit: 1000
    };

    if(object && objectId){
      let what = pluralize(object.camelize());
      if(object === 'mesh term'){
        what = 'meshDescriptors';
      }
      if(subject = 'session' && object === 'session type'){
        what = 'sessionType';
      }
      query.filters = {};
      query.filters[what] = objectId;
    }

    return query;
  },
  courseResults(results){
    const canViewCourses = this.get('currentUser.canViewCourses');
    let map = results.map(course => {
      let rhett = {};
      rhett.value = course.get('academicYear') + ' ' + course.get('title');
      if(canViewCourses){
        rhett.route = 'course';
        rhett.model = course;
      }

      return rhett;
    });

    return RSVP.resolve(map);
  },
  sessionResults(results){
    const canView = this.get('currentUser.canViewCourses');
    let map = results.map(item => {
      return new RSVP.Promise(resolve => {
        let rhett = {};
        item.get('course').then(course => {
          rhett.value = course.get('academicYear') + ' ' + course.get('title') + ' ' + item.get('title');
          if(canView){
              rhett.route = 'session';
              rhett.model = course;
              rhett.model2 = item;
          }
          resolve(rhett);
        });
      });
    });

    return RSVP.all(map);
  },
  programResults(results){
    const canView = this.get('currentUser.canViewPrograms');
    let map = results.map(item => {
      return new RSVP.Promise(resolve => {
        let rhett = {};
        item.get('school').then(school => {
          rhett.value = school.get('title') + ': ' + item.get('title');
          if(canView){
              rhett.route = 'program';
              rhett.model = item;
          }
          resolve(rhett);
        });
      });
    });

    return RSVP.all(map);
  },
  programYearsResults(results){
    const canView = this.get('currentUser.canViewPrograms');
    let map = results.map(item => {
      return new RSVP.Promise(resolve => {
        let rhett = {};
        item.get('program').then(program => {
          program.get('school').then(school => {
            rhett.value = school.get('title') + ' ' + program.get('title') + ' ' + item.get('title');
            if(canView){
                rhett.route = 'programYear';
                rhett.model = program;
                rhett.model2 = item;
            }
            resolve(rhett);
          });
        });

      });
    });

    return RSVP.all(map);
  }
});

/*
{value: 'course', label: this.get('i18n').t('general.courses')},
{value: 'session', label: this.get('i18n').t('general.sessions')},
{value: 'program', label: this.get('i18n').t('general.programs')},
{value: 'program year', label: this.get('i18n').t('general.programYears')},
{value: 'instructor', label: this.get('i18n').t('general.instructors')},
{value: 'instructor group', label: this.get('i18n').t('general.instructorGroups')},
{value: 'learning material', label: this.get('i18n').t('general.learningMaterials')},
{value: 'competency', label: this.get('i18n').t('general.competencies')},
{value: 'topic', label: this.get('i18n').t('general.topics')},
{value: 'mesh term', label: this.get('i18n').t('general.meshTerms')},
{value: 'session type', label: this.get('i18n').t('general.sessionTypes')},
 */
<|endoftext|>


<commit_before>/**
 * @ngdoc service
 * @name  core.service:wsservice
 * @requires ng.$interval
 * @requires ng.$q
 * @requires core.service:AlertService
 *
 * @description
 *  An angular service wrapper for stop communication over websockets.
 *
 */
core.service("wsservice", function($interval, $q, AlertService) {

	var wsservice = this;

	/**
	 * @ngdoc property
	 * @name  core.service:wsservice#wsservice.pendingReqCounter
	 * @propertyOf core.service:wsservice
	 *
	 * @description
	 *  A count of all unresolved requests.
	 *
	 */
	wsservice.pendingReqCounter = 0;

	/**
	 * @ngdoc property
	 * @name  core.service:wsservice#wsservice.pendingReq
	 * @propertyOf core.service:wsservice
	 *
	 * @description
	 *  An object store for pending requests.
	 *
	 */
	wsservice.pendingReq = {};

	/**
	 * @ngdoc property
	 * @name  core.service:wsservice#wsservice.subscriptions
	 * @propertyOf core.service:wsservice
	 *
	 * @description
	 *  An object store for subscriptions.
	 *
	 */
	wsservice.subscriptions = {};

	/**
	 * @ngdoc method
	 * @name  core.service:wsservice#wsservice.subscribe
	 * @methodOf core.service:wsservice
	 * @param {string} channel
	 *  The channel which will be subscribed to.
	 * @param {boolean=} persist
	 *  Indicates that the subscribe channel should not be removed on view change.
	 *
	 * @description
	 *  Registers a subscription to a stomp channel.
	 *
	 */
	wsservice.subscribe = function(channel, persist) {
		var id = "sub-" + window.stompClient.counter;
		var defer;

		if(!persist) persist = false;

		var subObj;

		if((subObj = wsservice.subExist(channel))) {
			defer = subObj.defer;
		} else {

			defer = $q.defer();
			subObj = {
				channel: channel,
				defer: defer
			};

			window.stompClient.subscribe(channel, function(data) {

				var meta = JSON.parse(data.body).meta

				var requestId = meta.id ? meta.id : null;
				var response = meta.type;

				if(wsservice.pendingReq[requestId]) {

					//logger.info("");
					//logger.debug(channel);
					//logger.info("Resolving Request " + requestId + ": " + wsservice.pendingReq[requestId].request);
					//logger.log(JSON.parse(data.body));

					if(response == "REFRESH") {
						wsservice.pendingReq[requestId].defer.notify(data);
					} else {
						// We should always resolve to handle alternative notifications.
						wsservice.pendingReq[requestId].defer.resolve(data);
						AlertService.add(meta, channel);
						delete wsservice.pendingReq[requestId];
					}

				}

				defer.notify(data);

			});

			wsservice.subscriptions[id] = subObj;
		}

		return defer.promise;
	};

	/**
	 * @ngdoc method
	 * @name  core.service:wsservice#wsservice.send
	 * @methodOf core.service:wsservice
	 * @param {string} request
	 *  The destination of this request.
	 * @param {object} headers
	 *  An object containing desired stomp headers
	 * @param {object} payload
	 *  An objecct containing any data that should be communicated
	 *  with the request
	 * @param {string} channel
	 *  The chennel which the reseponse will be communicated over.
	 *
	 * @description
	 *  Sends a websocket message.
	 *
	 */
	wsservice.send = function(request, headers, payload, channel) {

		if(!wsservice.subExist(channel)) {
			var endpoint = channel;
			var controller = channel.substr(0, channel.lastIndexOf("/"));
			AlertService.create(endpoint);
			AlertService.create(controller);
			wsservice.subscribe(channel);
		}

		headers.id = wsservice.pendingReqCounter++;

		window.stompClient.send(request, headers, payload);

		wsservice.pendingReq[headers.id] = {
			defer: $q.defer(),
			timestamp: new Date().getTime(),
			resend: function() {
				headers.jwt = sessionStorage.token;
				window.stompClient.send(request, headers, payload);
			}
		};

		return wsservice.pendingReq[headers.id].defer.promise;

	};

	/**
	 * @ngdoc method
	 * @name  core.service:wsservice#wsservice.subExist
	 * @methodOf core.service:wsservice
	 * @param {string} channel
	 *  The channel which is being confirmed.
	 * @returns {boolean|object}
	 *  Returns either false, or the subscription object
	 *  associated with the indicated channel.
	 * @description
	 *  Both requests and confirms the existense of a specific
	 *  subscription.
	 *
	 */
	wsservice.subExist = function(channel) {
		for(var key in wsservice.subscriptions) {
			var subObj = wsservice.subscriptions[key];
			if(subObj.channel == channel) return subObj;
		}
		return false;
	};

	/**
	 * @ngdoc method
	 * @name  core.service:wsservice#wsservice.unsubscribe
	 * @methodOf core.service:wsservice
	 * @param {object} sub
	 *  The subscription which will be unsubscribed to.
	 * @returns {void} returns void
	 *
	 *  @description
	 *   Unsubscribes from the indicated subscription.
	 *
	 */
	wsservice.unsubscribe = function(sub) {
		window.stompClient.unsubscribe(sub);
		delete wsservice.subscriptions[sub];
	};

	/**
	 * @ngdoc method
	 * @name  core.service:wsservice#wsservice.unsubscribeAll
	 * @methodOf core.service:wsservice
	 * @returns {void} returns void
	 *
	 *  @description
	 *   Unsubscribes from all subscriptions.
	 *
	 */
	wsservice.unsubscribeAll = function() {
		for(var key in wsservice.subscriptions){
			var sub = wsservice.subscriptions[key];
			if(!sub.persist) wsservice.unsubscribe(key);
		}
	};

	$interval(function() {

		var now = new Date().getTime();

		for(var req in wsservice.pendingReq) {
			if(now - wsservice.pendingReq[req].timestamp > 60000) {
				AlertService.add({type: "WARNING", message: "Web service is taking too long to respond. Please refresh. If this continues to appear you can email helpdesk@library.tamu.edu."}, "/app/warnings");
			}
		}

	}, 10000);

});<commit_msg>Log pending requests for debugging.<commit_after>/**
 * @ngdoc service
 * @name  core.service:wsservice
 * @requires ng.$interval
 * @requires ng.$q
 * @requires core.service:AlertService
 *
 * @description
 *  An angular service wrapper for stop communication over websockets.
 *
 */
core.service("wsservice", function($interval, $q, AlertService) {

	var wsservice = this;

	/**
	 * @ngdoc property
	 * @name  core.service:wsservice#wsservice.pendingReqCounter
	 * @propertyOf core.service:wsservice
	 *
	 * @description
	 *  A count of all unresolved requests.
	 *
	 */
	wsservice.pendingReqCounter = 0;

	/**
	 * @ngdoc property
	 * @name  core.service:wsservice#wsservice.pendingReq
	 * @propertyOf core.service:wsservice
	 *
	 * @description
	 *  An object store for pending requests.
	 *
	 */
	wsservice.pendingReq = {};

	/**
	 * @ngdoc property
	 * @name  core.service:wsservice#wsservice.subscriptions
	 * @propertyOf core.service:wsservice
	 *
	 * @description
	 *  An object store for subscriptions.
	 *
	 */
	wsservice.subscriptions = {};

	/**
	 * @ngdoc method
	 * @name  core.service:wsservice#wsservice.subscribe
	 * @methodOf core.service:wsservice
	 * @param {string} channel
	 *  The channel which will be subscribed to.
	 * @param {boolean=} persist
	 *  Indicates that the subscribe channel should not be removed on view change.
	 *
	 * @description
	 *  Registers a subscription to a stomp channel.
	 *
	 */
	wsservice.subscribe = function(channel, persist) {
		var id = "sub-" + window.stompClient.counter;
		var defer;

		if(!persist) persist = false;

		var subObj;

		if((subObj = wsservice.subExist(channel))) {
			defer = subObj.defer;
		} else {

			defer = $q.defer();
			subObj = {
				channel: channel,
				defer: defer
			};

			window.stompClient.subscribe(channel, function(data) {

				var meta = JSON.parse(data.body).meta

				var requestId = meta.id ? meta.id : null;
				var response = meta.type;

				if(wsservice.pendingReq[requestId]) {

					//logger.info("");
					//logger.debug(channel);
					//logger.info("Resolving Request " + requestId + ": " + wsservice.pendingReq[requestId].request);
					//logger.log(JSON.parse(data.body));

					if(response == "REFRESH") {
						wsservice.pendingReq[requestId].defer.notify(data);
					} else {
						// We should always resolve to handle alternative notifications.
						wsservice.pendingReq[requestId].defer.resolve(data);
						AlertService.add(meta, channel);
						delete wsservice.pendingReq[requestId];
					}

				}

				defer.notify(data);

			});

			wsservice.subscriptions[id] = subObj;
		}

		return defer.promise;
	};

	/**
	 * @ngdoc method
	 * @name  core.service:wsservice#wsservice.send
	 * @methodOf core.service:wsservice
	 * @param {string} request
	 *  The destination of this request.
	 * @param {object} headers
	 *  An object containing desired stomp headers
	 * @param {object} payload
	 *  An objecct containing any data that should be communicated
	 *  with the request
	 * @param {string} channel
	 *  The chennel which the reseponse will be communicated over.
	 *
	 * @description
	 *  Sends a websocket message.
	 *
	 */
	wsservice.send = function(request, headers, payload, channel) {

		if(!wsservice.subExist(channel)) {
			var endpoint = channel;
			var controller = channel.substr(0, channel.lastIndexOf("/"));
			AlertService.create(endpoint);
			AlertService.create(controller);
			wsservice.subscribe(channel);
		}

		headers.id = wsservice.pendingReqCounter++;

		window.stompClient.send(request, headers, payload);

		wsservice.pendingReq[headers.id] = {
			defer: $q.defer(),
			timestamp: new Date().getTime(),
			request: request,
			resend: function() {
				headers.jwt = sessionStorage.token;
				window.stompClient.send(request, headers, payload);
			}
		};

		return wsservice.pendingReq[headers.id].defer.promise;

	};

	/**
	 * @ngdoc method
	 * @name  core.service:wsservice#wsservice.subExist
	 * @methodOf core.service:wsservice
	 * @param {string} channel
	 *  The channel which is being confirmed.
	 * @returns {boolean|object}
	 *  Returns either false, or the subscription object
	 *  associated with the indicated channel.
	 * @description
	 *  Both requests and confirms the existense of a specific
	 *  subscription.
	 *
	 */
	wsservice.subExist = function(channel) {
		for(var key in wsservice.subscriptions) {
			var subObj = wsservice.subscriptions[key];
			if(subObj.channel == channel) return subObj;
		}
		return false;
	};

	/**
	 * @ngdoc method
	 * @name  core.service:wsservice#wsservice.unsubscribe
	 * @methodOf core.service:wsservice
	 * @param {object} sub
	 *  The subscription which will be unsubscribed to.
	 * @returns {void} returns void
	 *
	 *  @description
	 *   Unsubscribes from the indicated subscription.
	 *
	 */
	wsservice.unsubscribe = function(sub) {
		window.stompClient.unsubscribe(sub);
		delete wsservice.subscriptions[sub];
	};

	/**
	 * @ngdoc method
	 * @name  core.service:wsservice#wsservice.unsubscribeAll
	 * @methodOf core.service:wsservice
	 * @returns {void} returns void
	 *
	 *  @description
	 *   Unsubscribes from all subscriptions.
	 *
	 */
	wsservice.unsubscribeAll = function() {
		for(var key in wsservice.subscriptions){
			var sub = wsservice.subscriptions[key];
			if(!sub.persist) wsservice.unsubscribe(key);
		}
	};

	$interval(function() {

		var now = new Date().getTime();

		for(var req in wsservice.pendingReq) {
			if(now - wsservice.pendingReq[req].timestamp > 60000) {
				console.log(wsservice.pendingReq);
				AlertService.add({type: "WARNING", message: "Web service is taking too long to respond. Please refresh. If this continues to appear you can email helpdesk@library.tamu.edu."}, "/app/warnings");
			}
		}

	}, 10000);

});<|endoftext|>


<commit_before>var app_config = function ($scope) {
    $scope.CONFIG = {
        /**
         * 伺服器的位置
         */
        //"server_url": "http://localhost/voc4fun/voc4fun-server/",
        "server_url": "http://exp-voc4fun-2015.dlll.nccu.edu.tw/voc4fun-server/",
        //"server_url": "http://pc.pulipuli.info:8080/voc4fun/voc4fun-server/",
        // http://pc.pulipuli.info:8080/voc4fun/voc4fun-client  http://goo.gl/BCV6gy
        /**
         * 選擇題考試的選項數量
         */
        "test_select_option_learn": 3,
        /**
         * 目標設定切換的時間
         *
         * 單位是小時
         * 8 = 每天早上8點，8點之前算是前一天的份
         */
        "target_offset_hours": 8,
        /**
         * 控制組模式
         *
         * 會關閉部分功能
         */
        "control_group_version": false,
        /**
         * 單元測試模式
         *
         * 如果設為true，則強制轉移到單元測試顯示畫面
         */
        "qunit": false,
        /**
         * 清空資料庫的模式
         */
        //"empty_database": false,
        //"empty_database": true,

        /**
         * 設定時間偏移，單位是天數
         */
        day_offset: 0,

        /**
         * 預設的使用者名稱
         */
        default_name: "Voc4FunE",

        /**
         * 自動間隔同步時間，單位是分鐘
         * -1表示不設定
         */
        sync_interval: 5,

        /**
         * 小螢幕尺寸
         */
        small_width: 500,

        /**
         * 是否啟用發音功能
         */
        enable_speak: false,

        /**
         * 是否顯示重置按鈕
         */
        enable_reset: true,

        /**
         * 重置動作中包含遠端資料庫的重置
         */
        enable_database_reset: false,

        /**
         * 表格名稱
         * @params String[]
         */
        "tables": ["log", "flashcard", "status", "target_history"],
        "target_setting": [
            {
                "key": "learn_flashcard",
                //"default_target": 30,
                "default_target": 10,
                "min": 0,
                "default_max": 100,
                "title": "學習單字",
                "help_img": "img/go_learning.png",
                "help": "設定每天目標學習的單字數量。",
                "complete_message": "恭喜您完成了今日目標！"
            },
            {
                "key": "take_note",
                //"default_target": 20,
                "default_target": 10,
                "min": 0,
                "default_max": 100,
                "title": "撰寫筆記",
                "help_img": "img/write_note.png",
                "help": "設定每天要撰寫的筆記數量。\n針對不同單字，寫下你對不同單字的筆記與想法。\n字數及內容不拘，可隨意發揮。",
                "complete_message": "恭喜您完成了今日目標！"
            },
            {
                "key": "test_select",
                //"default_target": 30,
                "default_target": 10,
                "min": 0,
                "default_max": 100,
                "title": "答對測驗",
                "help_img": "img/ans_test.png",
                "help": "設定每天目標答對的題目數量。\n題目都是三選一的選擇題。",
                "complete_message": "恭喜您完成了今日目標！"
            }
        ],
        "test_survey":[
                {
                        "key": "wordcard",
                        "title": "單字卡學習法"
                },
                {
                        "key": "image",
                        "title": "圖像學習法"
                },
                {
                        "key": "synonym",
                        "title": "同義詞學習法"
                },
                {
                        "key": "rootprefix",
                        "title": "字根字首學習法"
                }
        ]
    };
};
<commit_msg>0315  default_max<commit_after>var app_config = function ($scope) {
    $scope.CONFIG = {
        /**
         * 伺服器的位置
         */
        //"server_url": "http://localhost/voc4fun/voc4fun-server/",
        "server_url": "http://exp-voc4fun-2015.dlll.nccu.edu.tw/voc4fun-server/",
        //"server_url": "http://pc.pulipuli.info:8080/voc4fun/voc4fun-server/",
        // http://pc.pulipuli.info:8080/voc4fun/voc4fun-client  http://goo.gl/BCV6gy
        /**
         * 選擇題考試的選項數量
         */
        "test_select_option_learn": 3,
        /**
         * 目標設定切換的時間
         *
         * 單位是小時
         * 8 = 每天早上8點，8點之前算是前一天的份
         */
        "target_offset_hours": 8,
        /**
         * 控制組模式
         *
         * 會關閉部分功能
         */
        "control_group_version": false,
        /**
         * 單元測試模式
         *
         * 如果設為true，則強制轉移到單元測試顯示畫面
         */
        "qunit": false,
        /**
         * 清空資料庫的模式
         */
        //"empty_database": false,
        //"empty_database": true,

        /**
         * 設定時間偏移，單位是天數
         */
        day_offset: 0,

        /**
         * 預設的使用者名稱
         */
        default_name: "Voc4FunE",

        /**
         * 自動間隔同步時間，單位是分鐘
         * -1表示不設定
         */
        sync_interval: 5,

        /**
         * 小螢幕尺寸
         */
        small_width: 500,

        /**
         * 是否啟用發音功能
         */
        enable_speak: false,

        /**
         * 是否顯示重置按鈕
         */
        enable_reset: true,

        /**
         * 重置動作中包含遠端資料庫的重置
         */
        enable_database_reset: false,

        /**
         * 表格名稱
         * @params String[]
         */
        "tables": ["log", "flashcard", "status", "target_history"],
        "target_setting": [
            {
                "key": "learn_flashcard",
                //"default_target": 30,
                "default_target": 10,
                "min": 0,
                "default_max": 188,
                "title": "學習單字",
                "help_img": "img/go_learning.png",
                "help": "設定每天目標學習的單字數量。",
                "complete_message": "恭喜您完成了今日目標！"
            },
            {
                "key": "take_note",
                //"default_target": 20,
                "default_target": 10,
                "min": 0,
                "default_max": 188,
                "title": "撰寫筆記",
                "help_img": "img/write_note.png",
                "help": "設定每天要撰寫的筆記數量。\n針對不同單字，寫下你對不同單字的筆記與想法。\n字數及內容不拘，可隨意發揮。",
                "complete_message": "恭喜您完成了今日目標！"
            },
            {
                "key": "test_select",
                //"default_target": 30,
                "default_target": 10,
                "min": 0,
                "default_max": 188,
                "title": "答對測驗",
                "help_img": "img/ans_test.png",
                "help": "設定每天目標答對的題目數量。\n題目都是三選一的選擇題。",
                "complete_message": "恭喜您完成了今日目標！"
            }
        ],
        "test_survey":[
                {
                        "key": "wordcard",
                        "title": "單字卡學習法"
                },
                {
                        "key": "image",
                        "title": "圖像學習法"
                },
                {
                        "key": "synonym",
                        "title": "同義詞學習法"
                },
                {
                        "key": "rootprefix",
                        "title": "字根字首學習法"
                }
        ]
    };
};
<|endoftext|>