<commit_before>'use strict';

$(document).ready(function () {
    /**
     *  Global variables.
     */
    let path,
        originMarker,
        destinationMarker,
        markers = [];

    /**
     * Adds a listener for each marker.
     * On a click event, retrieve information about the station (marker clicked).
     * Creates an info window containing information.
     * Opens the info window.
     *
     * @param marker Google map marker object
     */
    function addMarkerListener(marker) {
        marker.addListener('click', function () {
            let info = new google.maps.InfoWindow();

            $.ajax({
                type: "GET",
                url: `/stations/station/${marker.number}`,
                dataType: 'json',
                success: function (data) {
                    info.setPosition(marker.position);
                    info.setContent([
                            'address: ' + data.address,
                            'banking: ' + data.banking,
                            'status: ' + data.status,
                            'bike_stands: ' + data.bike_stands,
                            'available_bike_stands: ' + data.available_bike_stands,
                            'available_bikes: ' + data.available_bikes,
                            'last_update: ' + data.last_update
                        ].join('
')
                    );

                    info.open(marker.getMap(), marker);
                },
                error: function (response) {
                    console.log(response);
                }
            });
        });
    }

    /**
     * Adds a path on the map.
     *
     * @param path
     * @param map
     */
    function addLineToMap(path, map) {
        path.setMap(map);
    }

    /**
     * Adds two markers on the map. One for the origin and the another for the destination.
     *
     * @param origin
     * @param destination
     * @param map
     */
    function addDirectionMarkersToMap(origin, destination, map) {
        origin.setMap(map);
        destination.setMap(map);
    }

    /**
     * Updates information about the direction. i.e. distance, duration, etc..
     *
     * @param data
     */
    function updateInformation(data) {
        let distance = data.distance.value / 1000,
            duration = data.duration.value / 60,
            calories = getEnergyConsumption(localStorage.intensity, duration, localStorage.weight),
            emission = getCO2Emission(distance);

        $('#distance').text(data.distance.text);
        $('#duration').text(data.duration.text);
        $('#calories').text(calories + ' Kcal');
        $('#emission').text(emission + ' Kg');

        $('#directionTable').find('tbody tr').remove();

        data.steps.forEach(function (step) {
            $('#directionTable').find('tbody').append(`<tr><td>${step.distance.text}</td><td>${step.html_instructions}</td></tr>`);
        });
    }

    /**
     * Retrieves the route between two points.
     * Adds the route and the markers on the map .
     *
     * @param origin
     * @param destination
     * @param map
     */
    function traceDirection(origin, destination, map) {
        $.ajax({
            type: "GET",
            url: `directions/origin/lat/${origin.lat}/lng/${origin.lng}/destination/lat/${destination.lat}/lng/${destination.lng}/`,
            dataType: 'json',
            success: function (data) {
                console.log(data);
                if (data.hasOwnProperty('routes') && data.routes.length > 0) {
                    let points = google.maps.geometry.encoding.decodePath(data.routes[0].overview_polyline.points);

                    path.setPath(points);
                    originMarker.setPosition(origin);
                    destinationMarker.setPosition(destination);

                    addLineToMap(path, map);
                    addDirectionMarkersToMap(originMarker, destinationMarker, map);
                    updateInformation(data.routes[0].legs[0]);
                }

            },
            error: function (response) {
                console.log(response);
            }
        });
    }

    /**
     * Opens the side menu.
     */
    function openNav() {
        $('#menu').css('width', '250px');
        $('#map').css('marginLeft', '250px');
    }

    /**
     * Closes the side menu.
     */
    function closeNav() {
        $('#menu').css('width', '0');
        $('#map').css('marginLeft', '0');
    }

    /**
     * The marker is animated. i.e. bounces.
     *
     * @param marker
     */
    function toggleBounce(marker) {
        marker.setAnimation(google.maps.Animation.BOUNCE);
    }

    /**
     * Retrieves stations within the same county/district as the client.
     * Creates a marker referring each station.
     * Finally, adds the markers to the google map.
     *
     * Latitude and Longitude are swapped because of the GeoJSON's structure.
     *
     * @param map Google map object
     */
    function addStationsToMap(map) {
        $.ajax({
            type: "GET",
            url: `/stations/distance/0.5/lat/${map.getCenter().lat()}/lng/${map.getCenter().lng()}/`,
            dataType: 'json',
            success: function (data) {
                const ICON_SIZE = 38;

                let icon = {
                    url: "/images/velib-marker.png",
                    scaledSize: new google.maps.Size(ICON_SIZE, ICON_SIZE),
                    origin: new google.maps.Point(0, 0),
                    anchor: new google.maps.Point(0, 0)
                };

                markers.forEach(function (marker) {
                    marker.setMap(null);
                    marker = null;
                });

                markers = [];

                data.forEach(function (place) { //for each station...
                    let marker = new google.maps.Marker({
                        map: map,
                        title: place.name,
                        icon: icon,
                        position: new google.maps.LatLng(
                            parseFloat(place.location.coordinates[1]),  //Lat
                            parseFloat(place.location.coordinates[0])   //Lng
                        )
                    });

                    //useful to retrieve information about the station. (station's number).
                    marker.number = place.number;

                    addMarkerListener(marker);

                    markers.push(marker);
                });
            },
            error: function (response) {
                console.log(response);
            }
        });
    }

    /**
     * Estimate the CO2 emission of a car.
     * The constant is a generic factor calculated
     * using the latest version (6.1) of Bilan Carbone®.
     *
     * @param distance in kms.
     * @returns {number} in kgs.
     */
    function getCO2Emission(distance) {
        return Number((0.06981 * distance).toFixed(1));
    }

    /**
     * Estimate the consumption of energy driving a bicycle.
     *
     * @param met intensity level. soft: MET = 4, average: MET = 7, intense: MET = 10, very intense: MET = 14
     * @param time in minutes
     * @param weight in kilograms
     * @returns {number} in Kcal
     */
    function getEnergyConsumption(met, time, weight) {
        return Number((met * 3.5 * weight * time / 200).toFixed(1));
    }

    function disconnection() {
        document.getElementById('disconnectionForm').submit();
    }

    function saveSettings() {
        localStorage.weight = $('#weight').val();
        localStorage.intensity = $('select[name=intensity]').val();
    }

    function createMarkers() {
        path = new google.maps.Polyline({
            strokeColor: "#FF0000",
            strokeOpacity: 1.0,
            strokeWeight: 2
        });
        originMarker = new google.maps.Marker({
            icon: 'https://mts.googleapis.com/maps/vt/icon/name=icons/spotlight/spotlight-waypoint-a.png&text=A&psize=16&font=fonts/Roboto-Regular.ttf&color=ff333333&ax=44&ay=48&scale=1'
        });
        destinationMarker = new google.maps.Marker({
            icon: 'https://mts.googleapis.com/maps/vt/icon/name=icons/spotlight/spotlight-waypoint-b.png&text=B&psize=16&font=fonts/Roboto-Regular.ttf&color=ff333333&ax=44&ay=48&scale=1'
        });
    }

    function addControlsToMap(map) {
        map.controls[google.maps.ControlPosition.BOTTOM_CENTER].push(document.getElementById('footer'));
        map.controls[google.maps.ControlPosition.TOP_LEFT].push(document.getElementById('menuBtn'));
        map.controls[google.maps.ControlPosition.TOP_RIGHT].push(document.getElementById('directions'));
    }

    /**
     * Gets the current position via geolocation.
     * Adds stations to the map.
     */
    function initMap() {
        if (navigator.geolocation) {
            navigator.geolocation.getCurrentPosition(function (position) {
                //For testing
                position = {
                    lat: 48.893268664697416,
                    lng: 2.412715733388685
                };

                let update_timeout = null;

                let map = new google.maps.Map(document.getElementById('map'), {
                    center: position, //{lat: position.coords.latitude, lng: position.coords.longitude},
                    zoom: 14
                });

                let positionMarker = new google.maps.Marker({
                    map: map,
                    title: "You are here!",
                    position: position
                });

                toggleBounce(positionMarker);

                createMarkers();

                addControlsToMap(map);

                map.addListener('click', function (event) {
                    update_timeout = setTimeout(function () {
                        let lat = event.latLng.lat(),
                            lng = event.latLng.lng();

                        traceDirection(position, {lat: lat, lng: lng}, map);
                    }, 200);
                });

                google.maps.event.addListener(map, 'dblclick', function () {
                    clearTimeout(update_timeout);
                });

                addStationsToMap(map);
            });
        }
    }

    $(window).load(function () {
        $('#settingsModal').modal('show');

        $('#menu').find('a').on('click', closeNav);
        $('#menuBtn').on('click', openNav);
        $('#disconnection').on('click', disconnection);
        $('#save').on('click', saveSettings);

        initMap();
    });
});

<commit_msg>loads settings<commit_after>'use strict';

$(document).ready(function () {
    /**
     *  Global variables.
     */
    let path,
        originMarker,
        destinationMarker,
        markers = [];

    /**
     * Adds a listener for each marker.
     * On a click event, retrieve information about the station (marker clicked).
     * Creates an info window containing information.
     * Opens the info window.
     *
     * @param marker Google map marker object
     */
    function addMarkerListener(marker) {
        marker.addListener('click', function () {
            let info = new google.maps.InfoWindow();

            $.ajax({
                type: "GET",
                url: `/stations/station/${marker.number}`,
                dataType: 'json',
                success: function (data) {
                    info.setPosition(marker.position);
                    info.setContent([
                            'address: ' + data.address,
                            'banking: ' + data.banking,
                            'status: ' + data.status,
                            'bike_stands: ' + data.bike_stands,
                            'available_bike_stands: ' + data.available_bike_stands,
                            'available_bikes: ' + data.available_bikes,
                            'last_update: ' + data.last_update
                        ].join('
')
                    );

                    info.open(marker.getMap(), marker);
                },
                error: function (response) {
                    console.log(response);
                }
            });
        });
    }

    /**
     * Adds a path on the map.
     *
     * @param path
     * @param map
     */
    function addLineToMap(path, map) {
        path.setMap(map);
    }

    /**
     * Adds two markers on the map. One for the origin and the another for the destination.
     *
     * @param origin
     * @param destination
     * @param map
     */
    function addDirectionMarkersToMap(origin, destination, map) {
        origin.setMap(map);
        destination.setMap(map);
    }

    /**
     * Updates information about the direction. i.e. distance, duration, etc..
     *
     * @param data
     */
    function updateInformation(data) {
        let distance = data.distance.value / 1000,
            duration = data.duration.value / 60,
            calories = getEnergyConsumption(
                localStorage.getItem('intensity'),
                duration,
                localStorage.getItem('weight')
            ),
            emission = getCO2Emission(distance);

        $('#distance').text(data.distance.text);
        $('#duration').text(data.duration.text);
        $('#calories').text(calories + ' Kcal');
        $('#emission').text(emission + ' Kg');

        $('#directionTable').find('tbody tr').remove();

        data.steps.forEach(function (step) {
            $('#directionTable').find('tbody').append(`<tr><td>${step.distance.text}</td><td>${step.html_instructions}</td></tr>`);
        });
    }

    /**
     * Retrieves the route between two points.
     * Adds the route and the markers on the map .
     *
     * @param origin
     * @param destination
     * @param map
     */
    function traceDirection(origin, destination, map) {
        $.ajax({
            type: "GET",
            url: `directions/origin/lat/${origin.lat}/lng/${origin.lng}/destination/lat/${destination.lat}/lng/${destination.lng}/`,
            dataType: 'json',
            success: function (data) {
                console.log(data);
                if (data.hasOwnProperty('routes') && data.routes.length > 0) {
                    let points = google.maps.geometry.encoding.decodePath(data.routes[0].overview_polyline.points);

                    path.setPath(points);
                    originMarker.setPosition(origin);
                    destinationMarker.setPosition(destination);

                    addLineToMap(path, map);
                    addDirectionMarkersToMap(originMarker, destinationMarker, map);
                    updateInformation(data.routes[0].legs[0]);
                }

            },
            error: function (response) {
                console.log(response);
            }
        });
    }

    /**
     * Opens the side menu.
     */
    function openNav() {
        $('#menu').css('width', '250px');
        $('#map').css('marginLeft', '250px');
    }

    /**
     * Closes the side menu.
     */
    function closeNav() {
        $('#menu').css('width', '0');
        $('#map').css('marginLeft', '0');
    }

    /**
     * The marker is animated. i.e. bounces.
     *
     * @param marker
     */
    function toggleBounce(marker) {
        marker.setAnimation(google.maps.Animation.BOUNCE);
    }

    /**
     * Retrieves stations within the same county/district as the client.
     * Creates a marker referring each station.
     * Finally, adds the markers to the google map.
     *
     * Latitude and Longitude are swapped because of the GeoJSON's structure.
     *
     * @param map Google map object
     */
    function addStationsToMap(map) {
        $.ajax({
            type: "GET",
            url: `/stations/distance/0.5/lat/${map.getCenter().lat()}/lng/${map.getCenter().lng()}/`,
            dataType: 'json',
            success: function (data) {
                const ICON_SIZE = 38;

                let icon = {
                    url: "/images/velib-marker.png",
                    scaledSize: new google.maps.Size(ICON_SIZE, ICON_SIZE),
                    origin: new google.maps.Point(0, 0),
                    anchor: new google.maps.Point(0, 0)
                };

                markers.forEach(function (marker) {
                    marker.setMap(null);
                    marker = null;
                });

                markers = [];

                data.forEach(function (place) { //for each station...
                    let marker = new google.maps.Marker({
                        map: map,
                        title: place.name,
                        icon: icon,
                        position: new google.maps.LatLng(
                            parseFloat(place.location.coordinates[1]),  //Lat
                            parseFloat(place.location.coordinates[0])   //Lng
                        )
                    });

                    //useful to retrieve information about the station. (station's number).
                    marker.number = place.number;

                    addMarkerListener(marker);

                    markers.push(marker);
                });
            },
            error: function (response) {
                console.log(response);
            }
        });
    }

    /**
     * Estimate the CO2 emission of a car.
     * The constant is a generic factor calculated
     * using the latest version (6.1) of Bilan Carbone®.
     *
     * @param distance in kms.
     * @returns {number} in kgs.
     */
    function getCO2Emission(distance) {
        return Number((0.06981 * distance).toFixed(1));
    }

    /**
     * Estimate the consumption of energy driving a bicycle.
     *
     * @param met intensity level. soft: MET = 4, average: MET = 7, intense: MET = 10, very intense: MET = 14
     * @param time in minutes
     * @param weight in kilograms
     * @returns {number} in Kcal
     */
    function getEnergyConsumption(met, time, weight) {
        return Number((met * 3.5 * weight * time / 200).toFixed(1));
    }

    function disconnection() {
        document.getElementById('disconnectionForm').submit();
    }

    function createMarkers() {
        path = new google.maps.Polyline({
            strokeColor: "#FF0000",
            strokeOpacity: 1.0,
            strokeWeight: 2
        });
        originMarker = new google.maps.Marker({
            icon: 'https://mts.googleapis.com/maps/vt/icon/name=icons/spotlight/spotlight-waypoint-a.png&text=A&psize=16&font=fonts/Roboto-Regular.ttf&color=ff333333&ax=44&ay=48&scale=1'
        });
        destinationMarker = new google.maps.Marker({
            icon: 'https://mts.googleapis.com/maps/vt/icon/name=icons/spotlight/spotlight-waypoint-b.png&text=B&psize=16&font=fonts/Roboto-Regular.ttf&color=ff333333&ax=44&ay=48&scale=1'
        });
    }

    function addControlsToMap(map) {
        map.controls[google.maps.ControlPosition.BOTTOM_CENTER].push(document.getElementById('footer'));
        map.controls[google.maps.ControlPosition.TOP_LEFT].push(document.getElementById('menuBtn'));
        map.controls[google.maps.ControlPosition.TOP_RIGHT].push(document.getElementById('directions'));
    }

    function saveSettings() {
        let weight = $('#weight').val(), intensity = $('select[name=intensity]').val();

        localStorage.setItem('weight', weight);
        localStorage.setItem('intensity', intensity);
    }

    /**
     * @returns {boolean}
     */
    function loadSettings() {
        let intensity, weight;

        if ((intensity = localStorage.getItem('intensity')) && intensity != undefined)
            $('#intensity').val(intensity);

        if ((weight = localStorage.getItem('weight')) && weight != undefined)
            $('#weight').val(weight);

        return intensity > 0 && weight > 0;
    }

    /**
     * Gets the current position via geolocation.
     * Adds stations to the map.
     */
    function initMap() {
        if (navigator.geolocation) {
            navigator.geolocation.getCurrentPosition(function (position) {
                //For testing
                position = {
                    lat: 48.893268664697416,
                    lng: 2.412715733388685
                };

                let update_timeout = null;

                let map = new google.maps.Map(document.getElementById('map'), {
                    center: position, //{lat: position.coords.latitude, lng: position.coords.longitude},
                    zoom: 14
                });

                let positionMarker = new google.maps.Marker({
                    map: map,
                    title: "You are here!",
                    position: position
                });

                toggleBounce(positionMarker);

                createMarkers();

                addControlsToMap(map);

                map.addListener('click', function (event) {
                    update_timeout = setTimeout(function () {
                        let lat = event.latLng.lat(),
                            lng = event.latLng.lng();

                        traceDirection(position, {lat: lat, lng: lng}, map);
                    }, 200);
                });

                google.maps.event.addListener(map, 'dblclick', function () {
                    clearTimeout(update_timeout);
                });

                addStationsToMap(map);
            });
        }
    }

    $(window).load(function () {
        if (loadSettings() == false)
            $('#settingsModal').modal('show');

        $('#menu').find('a').on('click', closeNav);
        $('#menuBtn').on('click', openNav);
        $('#disconnection').on('click', disconnection);
        $('#save').on('click', saveSettings);

        initMap();
    });
});

<|endoftext|>


<commit_before>$(".vote-option").bind("click", function() {
	if($(this).hasClass("voted")){
		$(this).closest(".vote").find(".already-voted").show();
		return false;
	}
	vote($(this));
});

function vote(link) {
	var vote = link.data("value");
	var type = link.data("type");
	var id = link.data("id");
	var params = "/"+ type +"/"+ id +"/"+ vote;
	$.ajax(""+ params, {
		success: function() { voteSuccess(link) },
		error: voteError,
		method: "POST"
	});
}

function highlight(link) {
	link.addClass("voted").siblings().removeClass("voted");
}

function voteSuccess(link) {
	highlight(link);
}

function voteError() {
	console.log("falhou");
}
<commit_msg>escondendo mensagem de ja votou<commit_after>$(".vote-option").bind("click", function() {
	if($(this).hasClass("voted")){
		$(this).closest(".vote").find(".already-voted").show();
	}else{
		$(this).closest(".vote").find(".already-voted").hide();
		vote($(this));
	}
});

function vote(link) {
	var vote = link.data("value");
	var type = link.data("type");
	var id = link.data("id");
	var params = "/"+ type +"/"+ id +"/"+ vote;
	$.ajax(""+ params, {
		success: function() { voteSuccess(link) },
		error: voteError,
		method: "POST"
	});
}

function highlight(link) {
	link.addClass("voted").siblings().removeClass("voted");
}

function voteSuccess(link) {
	highlight(link);
}

function voteError() {
	console.log("falhou");
}
<|endoftext|>


<commit_before>function Coffee() {
  Transformer.call(this);

  this.name = 'CoffeeScript';
  this.handle = 'coffee';
  this.opts = {
    bare: true
  };
}

// Inherit from Transformer
Coffee.prototype = Object.create(Transformer.prototype);
Coffee.prototype.constructor = Coffee;

Coffee.prototype.transform = function(input) {
  return CoffeeScript.compile(input, this.opts);
}

var coffeeTransformer = new Coffee();
<commit_msg>Use coffee-script as a handle to match node_modules<commit_after>function Coffee() {
  Transformer.call(this);

  this.name = 'CoffeeScript';
  this.handle = 'coffee-script';
  this.opts = {
    bare: true
  };
}

// Inherit from Transformer
Coffee.prototype = Object.create(Transformer.prototype);
Coffee.prototype.constructor = Coffee;

Coffee.prototype.transform = function(input) {
  return CoffeeScript.compile(input, this.opts);
}

var coffeeTransformer = new Coffee();
<|endoftext|>


<commit_before>//===================================================================================================
// REVEALING MODLUE PATTERN: BigPipe
//===================================================================================================
var BigPipe = (function() {
	//===================================================================================================
	// PROTOTYPE: PageletResource-Konstruktor
	//===================================================================================================
	function PageletResource(file, type, pageletID) {
		this.pageletID = pageletID;
		this.callbacks = [];
		this.done = false;
		this.file = file;
		this.type = type;
	}

	//===================================================================================================
	// PROTOTYPE: Startet den Ladevorgang der Ressource
	//===================================================================================================
	PageletResource.prototype.start = function() {
		if(this.type === 0) {
			var element = document.createElement('link');
			element.setAttribute('rel', 'stylesheet');
			element.setAttribute('href', this.file);
		}

		else {
			var element = document.createElement('script');
			element.setAttribute('src', this.file);
			element.async = true;
		}

		document.head.appendChild(element);

		element.onload = function() {
			BigPipe.executePhaseDoneCallbacks('RESOURCE_DONE', this);
			this.executeCallbacks();
		}.bind(this);

		element.onerror = function() {
			BigPipe.executePhaseDoneCallbacks('RESOURCE_DONE', this);
			this.executeCallbacks();
		}.bind(this);
	};

	//===================================================================================================
	// PROTOTYPE: Registriert eine Callback-Funktion
	//===================================================================================================
	PageletResource.prototype.registerCallback = function(callback) {
		return this.callbacks.push(callback);
	};

	//===================================================================================================
	// PROTOTYPE: Führt alle registrierten Callback-Funktionen aus
	//===================================================================================================
	PageletResource.prototype.executeCallbacks = function() {
		if(!this.done) {
			this.done = true;

			this.callbacks.forEach(function(callback) {
				callback();
			});
		}
	};

	//===================================================================================================
	// PROTOTYPE: Pagelet-Konstruktor
	//===================================================================================================
	function Pagelet(data) {
		this.pageletID = data.ID;
		this.HTML      = data.HTML || "";
		this.CSSFiles  = data.RESOURCES.CSS;
		this.JSFiles   = data.RESOURCES.JS;
		this.JSCode    = data.RESOURCES.JS_CODE;

		this.phase = 0; // 1 => Laden von CSS-Ressourcen, 2 => CSS-Ressourcen geladen, 3 => HTML wurde injiziert, 4 => JS-Ressourcen geladen und JS-Code ausgeführt
		this.CSSResources = [];
		this.JSResources  = [];
	}

	//===================================================================================================
	// PROTOTYPE: Startet die Initialisierung des Pagelets und startet die Pagelet-Ressourcen
	//===================================================================================================
	Pagelet.prototype.start = function() {
		BigPipe.executePhaseDoneCallbacks('PAGELET_STARTED', this);
		this.CSSFiles.forEach(function(file) {
			this.attachCSSResource(new PageletResource(file, 0, this.pageletID));
		}.bind(this));

		this.JSFiles.forEach(function(file) {
			this.attachJSResource(new PageletResource(file, 1, this.pageletID));
		}.bind(this));

		this.CSSResources.forEach(function(resource) {
			this.phase = 1;
			resource.start();
		}.bind(this));

		if(this.phase === 0) {
			this.injectHTML();
		}
	};

	//===================================================================================================
	// PROTOTYPE: Fügt eine CSS-Ressource hinzu
	//===================================================================================================
	Pagelet.prototype.attachCSSResource = function(resource) {
		resource.registerCallback(this.onloadCSS.bind(this));
		return this.CSSResources.push(resource);
	};

	//===================================================================================================
	// PROTOTYPE: Fügt eine JS-Ressource hinzu
	//===================================================================================================
	Pagelet.prototype.attachJSResource = function(resource) {
		resource.registerCallback(this.onloadJS.bind(this));
		return this.JSResources.push(resource);
	};

	//===================================================================================================
	// PROTOTYPE: Führt den statischen JS-Code des Pagelets aus
	//===================================================================================================
	Pagelet.prototype.executeJSCode = function() {
		try {
			globalExecution(this.JSCode);
			BigPipe.executePhaseDoneCallbacks('PAGELET_JS_EXECUTED', this);
		} catch(e) {
			console.error(this.pageletID + ":\t" + e);
		}
	};

	//===================================================================================================
	// PROTOTYPE: Pagelet-Methode
	//===================================================================================================
	Pagelet.prototype.onloadJS = function() {
		if(this.phase === 3 && this.JSResources.every(function(resource){
			return resource.done;
		})) {
			this.executeJSCode();
			this.phase = 4;
		}
	};

	//===================================================================================================
	// PROTOTYPE: Pagelet-Methode
	//===================================================================================================
	Pagelet.prototype.onloadCSS = function() {
		if(this.CSSResources.every(function(resource){
			return resource.done;
		})) {
			this.injectHTML();
		}
	};

	//===================================================================================================
	// PROTOTYPE: Injiziert den HTML-Code des Pagelets in den DOM
	//===================================================================================================
	Pagelet.prototype.injectHTML = function() {
		this.phase = 2;
		if(placeholder = document.getElementById(this.pageletID)) {
			if(this.HTML) {
				placeholder.innerHTML = this.HTML;
			}

			else {
				var content = document.getElementById('_' + this.pageletID);
				placeholder.innerHTML = content.innerHTML.substring(5, content.innerHTML.length - 4);
				document.body.removeChild(content);
			}
		}

		this.phase = 3;

		BigPipe.executePhaseDoneCallbacks('PAGELET_HTML_RENDERED', this);
		BigPipe.executeNextPagelet();

		if(BigPipe.phase === 2 && BigPipe.pagelets[BigPipe.pagelets.length - 1].pageletID === this.pageletID) {
			BigPipe.executePhaseDoneCallbacks('BIGPIPE_PAGELETS_RENDERED');
			BigPipe.loadJSResources();
		}
	};

	//===================================================================================================
	// BigPipe-Hauptobjekt
	//===================================================================================================
	var BigPipe = {
		pagelets:  [],
		phase: 0, // 1 => Erstes Pagelet gestartet, 2 => Alle Pagelets angekommen, 3 => JS-Ressourcen geladen + JS-Code ausgeführt
		offset: 0,
		phaseDoneCallbacks: {},

		executeNextPagelet: function() {
			if(this.pagelets[this.offset]) {
				this.pagelets[this.offset++].start();
			}

			else if(this.phase < 2) {
				setTimeout(this.executeNextPagelet.bind(this), 30);
			}
		},

		registerPhaseDoneCallback: function(phase, callback) {
			if(!this.phaseDoneCallbacks[phase]) {
				this.phaseDoneCallbacks[phase] = [];
			}
			return this.phaseDoneCallbacks[phase].push(callback);
		},

		executePhaseDoneCallbacks: function(phase, param) {
			if(this.phaseDoneCallbacks[phase]) {
				this.phaseDoneCallbacks[phase].forEach(function(callback) {
					callback(param);
				});
			}
		},

		onPageletArrive: function(data) {
			if(this.pagelets.push(new Pagelet(data)) && this.phase === 0 && !data.IS_LAST) {
				this.phase = 1;
				this.executeNextPagelet();
			}

			else if(data.IS_LAST) {
				this.phase = 2;
				if(this.pagelets.length === 1) {
					this.executeNextPagelet();
				}
			}
		},

		loadJSResources: function() {
			this.phase = 3;
			var isLoading = false;

			this.pagelets.forEach(function(Pagelet) {
				if(Pagelet.JSResources.length === 0) {
					Pagelet.onloadJS();
				}
			});

			this.pagelets.forEach(function(Pagelet) {
				Pagelet.JSResources.forEach(function(Resource) {
					Resource.start();
					isLoading = true;
				});
			});

			if(!isLoading) {
				this.pagelets.forEach(function(Pagelet) {
					Pagelet.onloadJS();
				});
			}
		}
	};

	//===================================================================================================
	// REVEALING MODULE PATTERN: Öffentliche API
	//===================================================================================================
	return {
		onPageletArrive: function(data) {
			BigPipe.onPageletArrive(data);
		},

		registerPhaseDoneCallback: function(phase, callback) {
			BigPipe.registerPhaseDoneCallback(phase, callback);
		},

		reset: function() {
			BigPipe.phaseDoneCallbacks = {};
			BigPipe.pagelets = [];
			BigPipe.offset = 0;
			BigPipe.phase = 0;
		}
	};
})();<commit_msg>Some changes<commit_after>//===================================================================================================
// REVEALING MODLUE PATTERN: BigPipe
//===================================================================================================
var BigPipe = (function() {
	//===================================================================================================
	// PROTOTYPE: PageletResource-Konstruktor
	//===================================================================================================
	function PageletResource(file, type, pageletID) {
		this.pageletID = pageletID;
		this.callbacks = [];
		this.done = false;
		this.file = file;
		this.type = type;
	}

	//===================================================================================================
	// PROTOTYPE: Startet den Ladevorgang der Ressource
	//===================================================================================================
	PageletResource.prototype.start = function() {
		if(this.type === 0) {
			var element = document.createElement('link');
			element.setAttribute('rel', 'stylesheet');
			element.setAttribute('href', this.file);
		}

		else {
			var element = document.createElement('script');
			element.setAttribute('src', this.file);
			element.async = true;
		}

		document.head.appendChild(element);

		element.onload = function() {
			BigPipe.executePhaseDoneCallbacks('RESOURCE_DONE', this);
			this.executeCallbacks();
		}.bind(this);

		element.onerror = function() {
			BigPipe.executePhaseDoneCallbacks('RESOURCE_DONE', this);
			this.executeCallbacks();
		}.bind(this);
	};

	//===================================================================================================
	// PROTOTYPE: Registriert eine Callback-Funktion
	//===================================================================================================
	PageletResource.prototype.registerCallback = function(callback) {
		return this.callbacks.push(callback);
	};

	//===================================================================================================
	// PROTOTYPE: Führt alle registrierten Callback-Funktionen aus
	//===================================================================================================
	PageletResource.prototype.executeCallbacks = function() {
		if(!this.done) {
			this.done = true;

			this.callbacks.forEach(function(callback) {
				callback();
			});
		}
	};

	//===================================================================================================
	// PROTOTYPE: Pagelet-Konstruktor
	//===================================================================================================
	function Pagelet(data) {
		this.pageletID = data.ID;
		this.HTML      = data.HTML || "";
		this.CSSFiles  = data.RESOURCES.CSS;
		this.JSFiles   = data.RESOURCES.JS;
		this.JSCode    = data.RESOURCES.JS_CODE;

		this.phase = 0; // 1 => Laden von CSS-Ressourcen, 2 => CSS-Ressourcen geladen, 3 => HTML wurde injiziert, 4 => JS-Ressourcen geladen und JS-Code ausgeführt
		this.CSSResources = [];
		this.JSResources  = [];
	}

	//===================================================================================================
	// PROTOTYPE: Startet die Initialisierung des Pagelets und startet die Pagelet-Ressourcen
	//===================================================================================================
	Pagelet.prototype.start = function() {
		BigPipe.executePhaseDoneCallbacks('PAGELET_STARTED', this);
		this.CSSFiles.forEach(function(file) {
			this.attachCSSResource(new PageletResource(file, 0, this.pageletID));
		}.bind(this));

		this.JSFiles.forEach(function(file) {
			this.attachJSResource(new PageletResource(file, 1, this.pageletID));
		}.bind(this));

		this.CSSResources.forEach(function(resource) {
			this.phase = 1;
			resource.start();
		}.bind(this));

		if(this.phase === 0) {
			this.injectHTML();
		}
	};

	//===================================================================================================
	// PROTOTYPE: Fügt eine CSS-Ressource hinzu
	//===================================================================================================
	Pagelet.prototype.attachCSSResource = function(resource) {
		resource.registerCallback(this.onloadCSS.bind(this));
		return this.CSSResources.push(resource);
	};

	//===================================================================================================
	// PROTOTYPE: Fügt eine JS-Ressource hinzu
	//===================================================================================================
	Pagelet.prototype.attachJSResource = function(resource) {
		resource.registerCallback(this.onloadJS.bind(this));
		return this.JSResources.push(resource);
	};

	//===================================================================================================
	// PROTOTYPE: Führt den statischen JS-Code des Pagelets aus
	//===================================================================================================
	Pagelet.prototype.executeJSCode = function() {
		try {
			globalExecution(this.JSCode);
			BigPipe.executePhaseDoneCallbacks('PAGELET_JS_EXECUTED', this);
		} catch(e) {
			console.error(this.pageletID + ":\t" + e);
		}
	};

	//===================================================================================================
	// PROTOTYPE: Pagelet-Methode
	//===================================================================================================
	Pagelet.prototype.onloadJS = function() {
		if(this.phase === 3 && this.JSResources.every(function(resource){
			return resource.done;
		})) {
			this.executeJSCode();
			this.phase = 4;
		}
	};

	//===================================================================================================
	// PROTOTYPE: Pagelet-Methode
	//===================================================================================================
	Pagelet.prototype.onloadCSS = function() {
		if(this.CSSResources.every(function(resource){
			return resource.done;
		})) {
			this.injectHTML();
		}
	};

	//===================================================================================================
	// PROTOTYPE: Injiziert den HTML-Code des Pagelets in den DOM
	//===================================================================================================
	Pagelet.prototype.injectHTML = function() {
		this.phase = 2;
		if(placeholder = document.getElementById(this.pageletID)) {
			if(this.HTML) {
				placeholder.innerHTML = this.HTML;
			}

			else {
				var content = document.getElementById('_' + this.pageletID);
				placeholder.innerHTML = content.innerHTML.substring(5, content.innerHTML.length - 4);
				document.body.removeChild(content);
			}
		}

		this.phase = 3;

		BigPipe.executePhaseDoneCallbacks('PAGELET_HTML_RENDERED', this);
		BigPipe.executeNextPagelet();

		if(BigPipe.phase === 2 && BigPipe.pagelets[BigPipe.pagelets.length - 1].pageletID === this.pageletID) {
			BigPipe.executePhaseDoneCallbacks('BIGPIPE_PAGELETS_RENDERED');
			BigPipe.loadJSResources();
		}
	};

	//===================================================================================================
	// BigPipe-Hauptobjekt
	//===================================================================================================
	var BigPipe = {
		pagelets:  [],
		phase: 0, // 1 => Erstes Pagelet gestartet, 2 => Alle Pagelets angekommen, 3 => JS-Ressourcen geladen + JS-Code ausgeführt
		offset: 0,
		phaseDoneCallbacks: {},

		executeNextPagelet: function() {
			if(this.pagelets[this.offset]) {
				this.pagelets[this.offset++].start();
			}

			else if(this.phase < 2) {
				setTimeout(this.executeNextPagelet.bind(this), 30);
			}
		},

		registerPhaseDoneCallback: function(phase, callback) {
			if(!this.phaseDoneCallbacks[phase]) {
				this.phaseDoneCallbacks[phase] = [];
			}
			return this.phaseDoneCallbacks[phase].push(callback);
		},

		executePhaseDoneCallbacks: function(phase, param) {
			if(this.phaseDoneCallbacks[phase]) {
				this.phaseDoneCallbacks[phase].forEach(function(callback) {
					callback(param);
				});
			}
		},

		onPageletArrive: function(data) {
			if(this.pagelets.push(new Pagelet(data)) && this.phase === 0 && !data.IS_LAST) {
				this.phase = 1;
				this.executeNextPagelet();
			}

			else if(data.IS_LAST) {
				this.phase = 2;
				if(this.pagelets.length === 1) {
					this.executeNextPagelet();
				}
			}
		},

		loadJSResources: function() {
			this.phase = 3;
			var isLoading = false;

			this.pagelets.forEach(function(Pagelet) {
				if(Pagelet.JSResources.length === 0) {
					Pagelet.onloadJS();
				}
			});

			this.pagelets.forEach(function(Pagelet) {
				Pagelet.JSResources.forEach(function(Resource) {
					Resource.start();
					isLoading = true;
				});
			});

			if(!isLoading) {
				this.pagelets.forEach(function(Pagelet) {
					Pagelet.onloadJS();
				});
			}
		}
	};

	//===================================================================================================
	// Public-Access
	//===================================================================================================
	return {
		onPageletArrive: function(data) {
			BigPipe.onPageletArrive(data);
		},

		registerPhaseDoneCallback: function(phase, callback) {
			BigPipe.registerPhaseDoneCallback(phase, callback);
		},

		reset: function() {
			BigPipe.phaseDoneCallbacks = {};
			BigPipe.pagelets = [];
			BigPipe.offset = 0;
			BigPipe.phase = 0;
		}
	};
})();<|endoftext|>


<commit_before>/* Function(s) for comparing user's courses with degree requirements
 *
 */
<commit_msg>Created empty function to compare courses, audit<commit_after>/* Function(s) for comparing user's courses with degree requirements
 *
 */

/* Compares a user's taken courses with a degree's requirements and returns an
 * object containing lists of classes towards the degree and classes still
 * needed.
 *
 * @param courses An object containing all of courses a user has taken.
 * @param audit An object containing all the requirements of a degree.
 * @return An object containing a list of courses that meet degree requirements
 * and a list of requirements not known to have been met.
 */
function compareCoursesToAudit(courses, audit)
{

}
<|endoftext|>


<commit_before>var Sequelize = require('sequelize'),
  dbConfig = require('./database.json'),
  pg = require('pg').native;

function createDb (env) {
  if (!env) {
    env = 'dev';
  }

  // console.log('connecting to db: ' + dbConfig[env].database + ' as user: ' + dbConfig[env].user);

  if (process.env.HEROKU_POSTGRESQL_ROSE_URL) {
    console.log("Rose uRL!!");
    var match = process.env.HEROKU_POSTGRESQL_ROSE_URL.match(/postgres:\/\/([^:]+):([^@]+)@([^:]+):(\d+)\/(.+)/);

    var db = new Sequelize(match[5], match[1], match[2], {
      dialect:  'postgres',
      protocol: 'postgres',
      port:     match[4],
      host:     match[3],
      logging:  true,
      native: true
    })

  } else {

    var db = new Sequelize(dbConfig[env].database, dbConfig[env].user, dbConfig[env].password, {
      dialect: "postgres",
      host: dbConfig[env].host,
      port: 5432,
      omitNull: true,
      native: true,
      protocol: 'postgres',
      define: {
        underscored: true
      }
    });

  }

  console.log(db);

  db.authenticate()
    .error(function(err){
      throw(err);
    })
    .success(function(){
      console.log('Connected to postgres db');
    });

  return db;
}

module.exports = createDb;

var Sequelize = require('sequelize'),
  dbConfig = require('./database.json'),
  pg = require('pg').native;

function createDb (env) {
  if (!env) {
    env = 'dev';
  }

  if (process.env.POSTGRES_URL) {
    var match = process.env.POSTGRES_URL.match(/postgres:\/\/([^:]+):([^@]+)@([^:]+):(\d+)\/(.+)/);

    var db = new Sequelize(match[5], match[1], match[2], {
      dialect:  'postgres',
      protocol: 'postgres',
      port:     match[4],
      host:     match[3],
      logging:  true,
      native: true
    })

  } else {

    var db = new Sequelize(dbConfig[env].database, dbConfig[env].user, dbConfig[env].password, {
      dialect: "postgres",
      host: dbConfig[env].host,
      port: 5432,
      omitNull: true,
      native: true,
      protocol: 'postgres',
      define: {
        underscored: true
      }
    });

  }

  db.authenticate()
    .error(function(err){
      throw(new Error('Cannot connect to postgres db: ' + err));
    })
    .success(function(){
      console.log('Connected to postgres db');
    });

  return db;
}

module.exports = createDb;
<commit_msg>[CHORE] Remove redundant code from db config.<commit_after>var Sequelize = require('sequelize'),
  dbConfig = require('./database.json'),
  pg = require('pg').native;

function createDb (env) {
  if (!env) {
    env = 'dev';
  }

  if (process.env.POSTGRES_URL) {
    var match = process.env.POSTGRES_URL.match(/postgres:\/\/([^:]+):([^@]+)@([^:]+):(\d+)\/(.+)/);

    var db = new Sequelize(match[5], match[1], match[2], {
      dialect:  'postgres',
      protocol: 'postgres',
      port:     match[4],
      host:     match[3],
      logging:  true,
      native: true
    })

  } else {

    var db = new Sequelize(dbConfig[env].database, dbConfig[env].user, dbConfig[env].password, {
      dialect: "postgres",
      host: dbConfig[env].host,
      port: 5432,
      omitNull: true,
      native: true,
      protocol: 'postgres',
      define: {
        underscored: true
      }
    });

  }

  db.authenticate()
    .error(function(err){
      throw(new Error('Cannot connect to postgres db: ' + err));
    })
    .success(function(){
      console.log('Connected to postgres db');
    });

  return db;
}

module.exports = createDb;
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'

import { msg } from '_/intl'
import { isNumber } from '_/utils'
import { createDiskFormatList, createStorageDomainList, isDiskNameValid } from '_/components/utils'

import {
  Button,
  Col,
  ControlLabel,
  FieldLevelHelp,
  Form,
  FormControl,
  FormGroup,
  Modal,
  HelpBlock,
} from 'patternfly-react'
import SelectBox from '_/components/SelectBox'
import style from './style.css'
import OverlayTooltip from '_/components/OverlayTooltip'

const DISK_DEFAULTS = {
  active: true,
  bootable: false,
  iface: 'virtio_scsi', // virtio | virtio_scsi

  id: undefined,
  name: '',
  type: 'image',
  format: 'cow', // cow | raw
  sparse: true,

  provisionedSize: 1 * 1024 ** 3,
}

const DISK_FORMATS = createDiskFormatList()

const LabelCol = ({ children, ...props }) => {
  return <Col componentClass={ControlLabel} {...props}>
    { children }
  </Col>
}
LabelCol.propTypes = {
  children: PropTypes.node.isRequired,
}

/**
 * Collect required information required to create a new or edit an existing Disk Image
 * for a VM.
 *
 * Note: Only deal with Disk Images.  Does not support iSCSI/LUN or Cinder disks.
 *
 * Note 2: Ultimately will use the DiskAttachments Services to create and DiskAttachment
 *         service to edit and remove disk images.
 *
 *    http://ovirt.github.io/ovirt-engine-api-model/master/#services/disk_attachments/methods/add
 *    http://ovirt.github.io/ovirt-engine-api-model/master/#services/disk_attachment/methods/update
 *    http://ovirt.github.io/ovirt-engine-api-model/master/#services/disk_attachment/methods/remove
 *
 * Needed for Create:
 *   - Alias (aka Name) (defaulting to a suggested name)
 *   - Size in GiB
 *   - Storage Domain (defaulted to a suggested storage domain)
 *   - Disk Image Format (Allocation Policy ... Thin Provision vs Preallocated)
 *   - (auto-selected and never on the UI): Interface
 *
 * May be changed via Edit for a Disk Image (type == 'image'):
 *   - Alias
 *   - Size, but only allow extension: "Extend size by (GiB)"
 *
 * May be changed via Edit for a Direct LUN (type == 'lun'):
 *   - Alias
 */
class DiskImageEditor extends Component {
  constructor (props) {
    super(props)
    this.state = {
      showModal: false,
      storageDomainSelectList: createStorageDomainList(props.storageDomainList, undefined, true),

      id: undefined,
      values: {
        alias: props.suggestedName || '',
        size: DISK_DEFAULTS.provisionedSize / 1024 ** 3,
        storageDomain: props.suggestedStorageDomain || '',
        format: DISK_DEFAULTS.format, // cow vs raw .. Allocation Policy (thin sparse vs preallocated !sparse)?
      },
      errors: {},
    }
    this.changesMade = false

    this.open = this.open.bind(this)
    this.close = this.close.bind(this)
    this.composeDisk = this.composeDisk.bind(this)
    this.isFormValid = this.isFormValid.bind(this)
    this.validateField = this.validateField.bind(this)
    this.handleSave = this.handleSave.bind(this)

    this.changeAlias = this.changeAlias.bind(this)
    this.changeSize = this.changeSize.bind(this)
    this.changeStorageDomain = this.changeStorageDomain.bind(this)
    this.changeFormat = this.changeFormat.bind(this)
  }

  open (e) {
    e.preventDefault()
    const { disk, suggestedName, suggestedStorageDomain } = this.props
    const { storageDomainSelectList } = this.state

    const diskInfo = disk
      ? { // edit
        id: disk.get('id'),
        values: {
          alias: disk.get('name'),
          size: 0,
          storageDomain: disk.get('storageDomainId'),
          format: disk.get('format'),
        },
      }
      : { // new
        id: undefined,
        values: {
          alias: suggestedName,
          size: DISK_DEFAULTS.provisionedSize / 1024 ** 3,
          storageDomain:
            (/\w+/.test(suggestedStorageDomain) && suggestedStorageDomain) ||
            (storageDomainSelectList.length > 0 && storageDomainSelectList[0].id) ||
            '',
          format: DISK_DEFAULTS.format,
        },
        errors: {},
      }

    this.setState({
      showModal: true,
      storageDomainSelectList: createStorageDomainList(this.props.storageDomainList, true),
      ...diskInfo,
    })
    this.changesMade = false
  }

  close () {
    this.setState({ showModal: false })
  }

  composeDisk () {
    const { vm, disk } = this.props

    const vmDiskInSameStorageDomain =
      vm.get('disks') &&
      vm.get('disks').find(disk => disk.get('storageDomainId') === this.state.values.storageDomain)

    const iface =
      (disk && disk.get('iface')) ||
      (vmDiskInSameStorageDomain && vmDiskInSameStorageDomain.get('iface')) ||
      'virtio_scsi'

    const provisionedSize = disk
      ? disk.get('provisionedSize') + this.state.values.size * 1024 ** 3
      : this.state.values.size * 1024 ** 3

    const newDisk = {
      ...DISK_DEFAULTS,
      attachmentId: disk && disk.get('attachmentId'),

      iface,

      id: this.state.id,
      name: this.state.values.alias,
      provisionedSize,
      storageDomainId: this.state.values.storageDomain,
      format: this.state.values.format,
      sparse: this.state.values.format === 'cow',
    }

    if (disk && disk.get('type') !== 'image') {
      newDisk.type = disk.get('type')
      newDisk.provisionedSize = undefined
    }

    return newDisk
  }

  validateField (field = '') {
    return () => {
      const errors = {}
      let isErrors = false
      switch (field) {
        case 'alias':
          if (!isDiskNameValid(this.state.values.alias)) {
            errors['alias'] = msg.pleaseEnterValidDiskName()
            isErrors = true
          }
          break
      }
      this.setState((state) => ({ errors: { ...state.errors, ...errors } }))
      return isErrors
    }
  }

  handleSave () {
    if (this.validateField('alias')()) {
      return
    }
    if (!this.props.disk || this.changesMade) {
      const newDisk = this.composeDisk()
      this.props.onSave(this.props.vm.get('id'), newDisk)
    }
    this.close()
  }

  changeAlias ({ target: { value } }) {
    this.setState((state) => ({ values: { ...state.values, alias: value }, errors: { ...state.errors, 'alias': '' } }))
    this.changesMade = true
  }

  changeSize ({ target: { value } }) {
    if (isNumber(value) && value >= 0) {
      this.setState((state) => ({ values: { ...state.values, size: value } }))
      this.changesMade = true
    }
  }

  changeStorageDomain (value) {
    this.setState((state) => ({ values: { ...state.values, storageDomain: value } }))
    this.changesMade = true
  }

  changeFormat (value) {
    this.setState((state) => ({ values: { ...state.values, format: value } }))
    this.changesMade = true
  }

  isFormValid () {
    const isNotAllFieldFilled = Object.values(this.state.values).reduce((acc, value) => !value ? true : acc, false)
    const isErrors = Object.values(this.state.errors).reduce((acc, value) => value ? true : acc, false)
    return isNotAllFieldFilled || isErrors
  }

  render () {
    const { idPrefix, disk, trigger } = this.props

    const createMode = !disk
    const isImage = disk && disk.get('type') === 'image'
    const isDirectLUN = disk && disk.get('type') === 'lun'

    const diskSize = disk && (disk.get('lunSize') ? disk.get('lunSize') : disk.get('provisionedSize'))

    return <React.Fragment>
      {React.cloneElement(trigger, { onClick: this.open })}

      <Modal
        dialogClassName={style['editor-modal']}
        id={`${idPrefix}-modal`}
        show={this.state.showModal}
        onHide={this.close}
      >
        <Modal.Header>
          <Modal.CloseButton id={`${idPrefix}-modal-close`} onClick={this.close} />
          <Modal.Title>{createMode ? msg.createNewDisk() : msg.editDisk()}</Modal.Title>
        </Modal.Header>
        <Modal.Body>

          <Form
            horizontal
            onSubmit={e => { e.preventDefault() }}
            id={`${idPrefix}-modal-form`}
          >
            {/* Alias */}
            <FormGroup controlId={`${idPrefix}-alias`} validationState={this.state.errors['alias'] && 'error'}>
              <LabelCol sm={3}>
                { msg.diskEditorAliasLabel() }
              </LabelCol>
              <Col sm={9}>
                <FormControl
                  type='text'
                  defaultValue={this.state.values.alias}
                  onChange={this.changeAlias}
                  onBlur={this.validateField('alias')}
                />
                {this.state.errors['alias'] && <HelpBlock>{this.state.errors['alias']}</HelpBlock>}
              </Col>
            </FormGroup>

            {/* Size Display (for edit mode) */}
            { !createMode &&
            <FormGroup controlId={`${idPrefix}-size`}>
              <LabelCol sm={3}>
                { msg.diskEditorSizeEditLabel() }
                { !isImage &&
                  <FieldLevelHelp
                    inline
                    content={msg.diskEditorSizeCantChangeHelp()}
                    buttonClass={style['editor-field-help']}
                  />
                }
              </LabelCol>
              <Col sm={9}>
                <div id={`${idPrefix}-size`} className={style['editor-field-read-only']}>
                  { diskSize / 1024 ** 3 }

              </Col>
            </FormGroup>
            }

            {/* Size Editor (initial size for create, expand by size for edit) */}
            { (createMode || isImage) &&
            <FormGroup controlId={`${idPrefix}-size-edit`}>
              <LabelCol sm={3}>
                { createMode &&
                  <React.Fragment>
                    {msg.diskEditorSizeLabel()}
                    <FieldLevelHelp
                      inline
                      content={msg.diskEditorSizeCreateHelp()}
                      buttonClass={style['editor-field-help']}
                    />
                  </React.Fragment>
                }
                { !createMode && msg.diskEditorResizeLabel() }
              </LabelCol>
              <Col sm={2}>
                <OverlayTooltip id={`${idPrefix}-form-tooltip`} tooltip={msg.diskEditorResizeNote()} placement='right'>
                  <FormControl
                    type='number'
                    value={this.state.values.size}
                    onChange={this.changeSize}
                  />
                </OverlayTooltip>
              </Col>
            </FormGroup>
            }

            {/* Storage Domain */}
            <FormGroup controlId={`${idPrefix}-storage-domain`}>
              <LabelCol sm={3}>
                { msg.diskEditorStorageDomainLabel() }
                <FieldLevelHelp
                  inline
                  content={
                    createMode
                      ? msg.diskEditorStorageDomainCreateHelp()
                      : msg.diskEditorStorageDomainCantChangeHelp()
                  }
                  buttonClass={style['editor-field-help']}
                />
              </LabelCol>
              <Col sm={9}>
                { createMode &&
                  <SelectBox
                    id={`${idPrefix}-storage-domain`}
                    items={this.state.storageDomainSelectList}
                    selected={this.state.values.storageDomain}
                    onChange={this.changeStorageDomain}
                  />
                }
                { !createMode && !isDirectLUN &&
                  <div id={`${idPrefix}-storage-domain`} className={style['editor-field-read-only']}>
                    {
                      this.props.storageDomains.getIn([this.state.values.storageDomain, 'name']) ||
                      msg.diskEditorStorageDomainNotAvailable()
                    }

                }
                { isDirectLUN &&
                  <div id={`${idPrefix}-storage-domain`} className={style['editor-field-read-only']}>
                    { msg.diskEditorStorageDomainNotAvailable() }

                }
              </Col>
            </FormGroup>

            {/* Disk Format */}
            <FormGroup controlId={`${idPrefix}-format`}>
              <LabelCol sm={3}>
                { msg.diskEditorFormatLabel() }
                <FieldLevelHelp
                  inline
                  content={
                    createMode
                      ? msg.diskEditorFormatCreateHelp()
                      : msg.diskEditorFormatCantChangeHelp()
                  }
                  buttonClass={style['editor-field-help']}
                />
              </LabelCol>
              <Col sm={9}>
                { createMode &&
                  <SelectBox
                    id={`${idPrefix}-format`}
                    items={DISK_FORMATS}
                    selected={this.state.format}
                    onChange={this.changeFormat}
                  />
                }
                { !createMode && !isDirectLUN &&
                  <div id={`${idPrefix}-format`} className={style['editor-field-read-only']}>
                    { this.state.values.format === 'raw' && msg.diskEditorFormatOptionRaw() }
                    { this.state.values.format === 'cow' && msg.diskEditorFormatOptionCow() }

                }
                { isDirectLUN &&
                  <div id={`${idPrefix}-format`} className={style['editor-field-read-only']}>
                    { msg.diskEditorFormatNotAvailable() }

                }
              </Col>
            </FormGroup>
          </Form>

        </Modal.Body>
        <Modal.Footer>
          <Button
            id={`${idPrefix}-modal-cancel`}
            bsStyle='default'
            className='btn-cancel'
            onClick={this.close}
          >
            { msg.cancel() }
          </Button>
          <Button
            id={`${idPrefix}-modal-ok`}
            bsStyle='primary'
            onClick={this.handleSave}
            disabled={this.isFormValid()}
          >
            { msg.ok() }
          </Button>
        </Modal.Footer>
      </Modal>
    </React.Fragment>
  }
}
DiskImageEditor.propTypes = {
  idPrefix: PropTypes.string.isRequired,
  vm: PropTypes.object.isRequired,

  disk: PropTypes.object, // if !!disk then edit mode
  suggestedName: PropTypes.string, // if suggestedName && !disk then create mode
  suggestedStorageDomain: PropTypes.string,

  storageDomainList: PropTypes.object.isRequired,
  trigger: PropTypes.element.isRequired,
  onSave: PropTypes.func.isRequired,

  storageDomains: PropTypes.object.isRequired,
}

export default connect(
  (state) => ({
    storageDomains: state.storageDomains,
  })
)(DiskImageEditor)
<commit_msg>Fix DiskImageEditor storage domain list<commit_after>import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'

import { msg } from '_/intl'
import { isNumber } from '_/utils'
import { createDiskFormatList, createStorageDomainList, isDiskNameValid } from '_/components/utils'

import {
  Button,
  Col,
  ControlLabel,
  FieldLevelHelp,
  Form,
  FormControl,
  FormGroup,
  Modal,
  HelpBlock,
} from 'patternfly-react'
import SelectBox from '_/components/SelectBox'
import style from './style.css'
import OverlayTooltip from '_/components/OverlayTooltip'

const DISK_DEFAULTS = {
  active: true,
  bootable: false,
  iface: 'virtio_scsi', // virtio | virtio_scsi

  id: undefined,
  name: '',
  type: 'image',
  format: 'cow', // cow | raw
  sparse: true,

  provisionedSize: 1 * 1024 ** 3,
}

const DISK_FORMATS = createDiskFormatList()

const LabelCol = ({ children, ...props }) => {
  return <Col componentClass={ControlLabel} {...props}>
    { children }
  </Col>
}
LabelCol.propTypes = {
  children: PropTypes.node.isRequired,
}

/**
 * Collect required information required to create a new or edit an existing Disk Image
 * for a VM.
 *
 * Note: Only deal with Disk Images.  Does not support iSCSI/LUN or Cinder disks.
 *
 * Note 2: Ultimately will use the DiskAttachments Services to create and DiskAttachment
 *         service to edit and remove disk images.
 *
 *    http://ovirt.github.io/ovirt-engine-api-model/master/#services/disk_attachments/methods/add
 *    http://ovirt.github.io/ovirt-engine-api-model/master/#services/disk_attachment/methods/update
 *    http://ovirt.github.io/ovirt-engine-api-model/master/#services/disk_attachment/methods/remove
 *
 * Needed for Create:
 *   - Alias (aka Name) (defaulting to a suggested name)
 *   - Size in GiB
 *   - Storage Domain (defaulted to a suggested storage domain)
 *   - Disk Image Format (Allocation Policy ... Thin Provision vs Preallocated)
 *   - (auto-selected and never on the UI): Interface
 *
 * May be changed via Edit for a Disk Image (type == 'image'):
 *   - Alias
 *   - Size, but only allow extension: "Extend size by (GiB)"
 *
 * May be changed via Edit for a Direct LUN (type == 'lun'):
 *   - Alias
 */
class DiskImageEditor extends Component {
  constructor (props) {
    super(props)
    this.state = {
      showModal: false,
      storageDomainSelectList: createStorageDomainList(props.storageDomainList, props.dataCenterId, true),

      id: undefined,
      values: {
        alias: props.suggestedName || '',
        size: DISK_DEFAULTS.provisionedSize / 1024 ** 3,
        storageDomain: props.suggestedStorageDomain || '',
        format: DISK_DEFAULTS.format, // cow vs raw .. Allocation Policy (thin sparse vs preallocated !sparse)?
      },
      errors: {},
    }
    this.changesMade = false

    this.open = this.open.bind(this)
    this.close = this.close.bind(this)
    this.composeDisk = this.composeDisk.bind(this)
    this.isFormValid = this.isFormValid.bind(this)
    this.validateField = this.validateField.bind(this)
    this.handleSave = this.handleSave.bind(this)

    this.changeAlias = this.changeAlias.bind(this)
    this.changeSize = this.changeSize.bind(this)
    this.changeStorageDomain = this.changeStorageDomain.bind(this)
    this.changeFormat = this.changeFormat.bind(this)
  }

  open (e) {
    e.preventDefault()
    const { disk, suggestedName, suggestedStorageDomain } = this.props
    const { storageDomainSelectList } = this.state

    const diskInfo = disk
      ? { // edit
        id: disk.get('id'),
        values: {
          alias: disk.get('name'),
          size: 0,
          storageDomain: disk.get('storageDomainId'),
          format: disk.get('format'),
        },
      }
      : { // new
        id: undefined,
        values: {
          alias: suggestedName,
          size: DISK_DEFAULTS.provisionedSize / 1024 ** 3,
          storageDomain:
            (/\w+/.test(suggestedStorageDomain) && suggestedStorageDomain) ||
            (storageDomainSelectList.length > 0 && storageDomainSelectList[0].id) ||
            '',
          format: DISK_DEFAULTS.format,
        },
        errors: {},
      }

    this.setState({
      showModal: true,
      storageDomainSelectList: createStorageDomainList(this.props.storageDomainList, this.props.dataCenterId, true),
      ...diskInfo,
    })
    this.changesMade = false
  }

  close () {
    this.setState({ showModal: false })
  }

  composeDisk () {
    const { vm, disk } = this.props

    const vmDiskInSameStorageDomain =
      vm.get('disks') &&
      vm.get('disks').find(disk => disk.get('storageDomainId') === this.state.values.storageDomain)

    const iface =
      (disk && disk.get('iface')) ||
      (vmDiskInSameStorageDomain && vmDiskInSameStorageDomain.get('iface')) ||
      'virtio_scsi'

    const provisionedSize = disk
      ? disk.get('provisionedSize') + this.state.values.size * 1024 ** 3
      : this.state.values.size * 1024 ** 3

    const newDisk = {
      ...DISK_DEFAULTS,
      attachmentId: disk && disk.get('attachmentId'),

      iface,

      id: this.state.id,
      name: this.state.values.alias,
      provisionedSize,
      storageDomainId: this.state.values.storageDomain,
      format: this.state.values.format,
      sparse: this.state.values.format === 'cow',
    }

    if (disk && disk.get('type') !== 'image') {
      newDisk.type = disk.get('type')
      newDisk.provisionedSize = undefined
    }

    return newDisk
  }

  validateField (field = '') {
    return () => {
      const errors = {}
      let isErrors = false
      switch (field) {
        case 'alias':
          if (!isDiskNameValid(this.state.values.alias)) {
            errors['alias'] = msg.pleaseEnterValidDiskName()
            isErrors = true
          }
          break
      }
      this.setState((state) => ({ errors: { ...state.errors, ...errors } }))
      return isErrors
    }
  }

  handleSave () {
    if (this.validateField('alias')()) {
      return
    }
    if (!this.props.disk || this.changesMade) {
      const newDisk = this.composeDisk()
      this.props.onSave(this.props.vm.get('id'), newDisk)
    }
    this.close()
  }

  changeAlias ({ target: { value } }) {
    this.setState((state) => ({ values: { ...state.values, alias: value }, errors: { ...state.errors, 'alias': '' } }))
    this.changesMade = true
  }

  changeSize ({ target: { value } }) {
    if (isNumber(value) && value >= 0) {
      this.setState((state) => ({ values: { ...state.values, size: value } }))
      this.changesMade = true
    }
  }

  changeStorageDomain (value) {
    this.setState((state) => ({ values: { ...state.values, storageDomain: value } }))
    this.changesMade = true
  }

  changeFormat (value) {
    this.setState((state) => ({ values: { ...state.values, format: value } }))
    this.changesMade = true
  }

  isFormValid () {
    const isNotAllFieldFilled = Object.values(this.state.values).reduce((acc, value) => !value ? true : acc, false)
    const isErrors = Object.values(this.state.errors).reduce((acc, value) => value ? true : acc, false)
    return isNotAllFieldFilled || isErrors
  }

  render () {
    const { idPrefix, disk, trigger } = this.props

    const createMode = !disk
    const isImage = disk && disk.get('type') === 'image'
    const isDirectLUN = disk && disk.get('type') === 'lun'

    const diskSize = disk && (disk.get('lunSize') ? disk.get('lunSize') : disk.get('provisionedSize'))

    return <React.Fragment>
      {React.cloneElement(trigger, { onClick: this.open })}

      <Modal
        dialogClassName={style['editor-modal']}
        id={`${idPrefix}-modal`}
        show={this.state.showModal}
        onHide={this.close}
      >
        <Modal.Header>
          <Modal.CloseButton id={`${idPrefix}-modal-close`} onClick={this.close} />
          <Modal.Title>{createMode ? msg.createNewDisk() : msg.editDisk()}</Modal.Title>
        </Modal.Header>
        <Modal.Body>

          <Form
            horizontal
            onSubmit={e => { e.preventDefault() }}
            id={`${idPrefix}-modal-form`}
          >
            {/* Alias */}
            <FormGroup controlId={`${idPrefix}-alias`} validationState={this.state.errors['alias'] && 'error'}>
              <LabelCol sm={3}>
                { msg.diskEditorAliasLabel() }
              </LabelCol>
              <Col sm={9}>
                <FormControl
                  type='text'
                  defaultValue={this.state.values.alias}
                  onChange={this.changeAlias}
                  onBlur={this.validateField('alias')}
                />
                {this.state.errors['alias'] && <HelpBlock>{this.state.errors['alias']}</HelpBlock>}
              </Col>
            </FormGroup>

            {/* Size Display (for edit mode) */}
            { !createMode &&
            <FormGroup controlId={`${idPrefix}-size`}>
              <LabelCol sm={3}>
                { msg.diskEditorSizeEditLabel() }
                { !isImage &&
                  <FieldLevelHelp
                    inline
                    content={msg.diskEditorSizeCantChangeHelp()}
                    buttonClass={style['editor-field-help']}
                  />
                }
              </LabelCol>
              <Col sm={9}>
                <div id={`${idPrefix}-size`} className={style['editor-field-read-only']}>
                  { diskSize / 1024 ** 3 }

              </Col>
            </FormGroup>
            }

            {/* Size Editor (initial size for create, expand by size for edit) */}
            { (createMode || isImage) &&
            <FormGroup controlId={`${idPrefix}-size-edit`}>
              <LabelCol sm={3}>
                { createMode &&
                  <React.Fragment>
                    {msg.diskEditorSizeLabel()}
                    <FieldLevelHelp
                      inline
                      content={msg.diskEditorSizeCreateHelp()}
                      buttonClass={style['editor-field-help']}
                    />
                  </React.Fragment>
                }
                { !createMode && msg.diskEditorResizeLabel() }
              </LabelCol>
              <Col sm={2}>
                <OverlayTooltip id={`${idPrefix}-form-tooltip`} tooltip={msg.diskEditorResizeNote()} placement='right'>
                  <FormControl
                    type='number'
                    value={this.state.values.size}
                    onChange={this.changeSize}
                  />
                </OverlayTooltip>
              </Col>
            </FormGroup>
            }

            {/* Storage Domain */}
            <FormGroup controlId={`${idPrefix}-storage-domain`}>
              <LabelCol sm={3}>
                { msg.diskEditorStorageDomainLabel() }
                <FieldLevelHelp
                  inline
                  content={
                    createMode
                      ? msg.diskEditorStorageDomainCreateHelp()
                      : msg.diskEditorStorageDomainCantChangeHelp()
                  }
                  buttonClass={style['editor-field-help']}
                />
              </LabelCol>
              <Col sm={9}>
                { createMode &&
                  <SelectBox
                    id={`${idPrefix}-storage-domain`}
                    items={this.state.storageDomainSelectList}
                    selected={this.state.values.storageDomain}
                    onChange={this.changeStorageDomain}
                  />
                }
                { !createMode && !isDirectLUN &&
                  <div id={`${idPrefix}-storage-domain`} className={style['editor-field-read-only']}>
                    {
                      this.props.storageDomains.getIn([this.state.values.storageDomain, 'name']) ||
                      msg.diskEditorStorageDomainNotAvailable()
                    }

                }
                { isDirectLUN &&
                  <div id={`${idPrefix}-storage-domain`} className={style['editor-field-read-only']}>
                    { msg.diskEditorStorageDomainNotAvailable() }

                }
              </Col>
            </FormGroup>

            {/* Disk Format */}
            <FormGroup controlId={`${idPrefix}-format`}>
              <LabelCol sm={3}>
                { msg.diskEditorFormatLabel() }
                <FieldLevelHelp
                  inline
                  content={
                    createMode
                      ? msg.diskEditorFormatCreateHelp()
                      : msg.diskEditorFormatCantChangeHelp()
                  }
                  buttonClass={style['editor-field-help']}
                />
              </LabelCol>
              <Col sm={9}>
                { createMode &&
                  <SelectBox
                    id={`${idPrefix}-format`}
                    items={DISK_FORMATS}
                    selected={this.state.format}
                    onChange={this.changeFormat}
                  />
                }
                { !createMode && !isDirectLUN &&
                  <div id={`${idPrefix}-format`} className={style['editor-field-read-only']}>
                    { this.state.values.format === 'raw' && msg.diskEditorFormatOptionRaw() }
                    { this.state.values.format === 'cow' && msg.diskEditorFormatOptionCow() }

                }
                { isDirectLUN &&
                  <div id={`${idPrefix}-format`} className={style['editor-field-read-only']}>
                    { msg.diskEditorFormatNotAvailable() }

                }
              </Col>
            </FormGroup>
          </Form>

        </Modal.Body>
        <Modal.Footer>
          <Button
            id={`${idPrefix}-modal-cancel`}
            bsStyle='default'
            className='btn-cancel'
            onClick={this.close}
          >
            { msg.cancel() }
          </Button>
          <Button
            id={`${idPrefix}-modal-ok`}
            bsStyle='primary'
            onClick={this.handleSave}
            disabled={this.isFormValid()}
          >
            { msg.ok() }
          </Button>
        </Modal.Footer>
      </Modal>
    </React.Fragment>
  }
}
DiskImageEditor.propTypes = {
  idPrefix: PropTypes.string.isRequired,
  vm: PropTypes.object.isRequired,

  disk: PropTypes.object, // if !!disk then edit mode
  suggestedName: PropTypes.string, // if suggestedName && !disk then create mode
  suggestedStorageDomain: PropTypes.string,

  storageDomainList: PropTypes.object.isRequired,
  trigger: PropTypes.element.isRequired,
  onSave: PropTypes.func.isRequired,

  storageDomains: PropTypes.object.isRequired,
  dataCenterId: PropTypes.string.isRequired,
}

export default connect(
  (state, { vm }) => ({
    storageDomains: state.storageDomains,
    dataCenterId: state.clusters.getIn([ vm.getIn([ 'cluster', 'id' ]), 'dataCenterId' ]),
  })
)(DiskImageEditor)
<|endoftext|>


<commit_before>/*\
title: $:/plugins/gsd5/ticklers/modules/startup/tickler.js
type: application/javascript
module-type: startup

Tickler alert manager.

\*/
(function(){

/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";

// Export name and synchronous status
exports.name = "tickler";
//exports.platforms = ["browser"];
exports.after = ["story"];
exports.synchronous = true;

exports.startup = function() {
	$tw.wiki.forEachTiddler(checkForAlert);
	var interval = setInterval(function() {
		$tw.wiki.forEachTiddler(checkForAlert);
	}, 3600000);
};

function checkForAlert(title, tiddler) {
	var now = new Date();
	if(!tiddler) {
		return;
	}
	if(tiddler.fields.gsd_type === "action") {
		if(tiddler.fields.gsd_tickdate) {
			var alert_date = $tw.utils.parseDate(tiddler.fields.gsd_tickdate);
			if(alert_date <= now) {
				var alertTiddler = new $tw.Tiddler({
					"title": "$:/temp/alert/" + title,
					"modified": tiddler.fields.gsd_tickdate,
					"component": title,
					"text": "[[Go to Action|" + title + "]]",
					"tags": "$:/tags/Alert"
				});
				$tw.wiki.addTiddler(alertTiddler);
			}
		}
	}
}

})();
<commit_msg>Decreased check for ticklers to 15 minutes.<commit_after>/*\
title: $:/plugins/gsd5/ticklers/modules/startup/tickler.js
type: application/javascript
module-type: startup

Tickler alert manager.

\*/
(function(){

/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";

// Export name and synchronous status
exports.name = "tickler";
//exports.platforms = ["browser"];
exports.after = ["story"];
exports.synchronous = true;

exports.startup = function() {
	$tw.wiki.forEachTiddler(checkForAlert);
	var interval = setInterval(function() {
		$tw.wiki.forEachTiddler(checkForAlert);
	}, 90000);
};

function checkForAlert(title, tiddler) {
	var now = new Date();
	if(!tiddler) {
		return;
	}
	if(tiddler.fields.gsd_type === "action") {
		if(tiddler.fields.gsd_tickdate) {
			var alert_date = $tw.utils.parseDate(tiddler.fields.gsd_tickdate);
			if(alert_date <= now) {
				var alertTiddler = new $tw.Tiddler({
					"title": "$:/temp/alert/" + title,
					"modified": tiddler.fields.gsd_tickdate,
					"component": title,
					"text": "[[Go to Action|" + title + "]]",
					"tags": "$:/tags/Alert"
				});
				$tw.wiki.addTiddler(alertTiddler);
			}
		}
	}
}

})();
<|endoftext|>


<commit_before>/*\
title: $:/plugins/gsd5/ticklers/modules/startup/tickler.js
type: application/javascript
module-type: startup

Tickler alert manager.

\*/
(function(){

/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";

// Export name and synchronous status
exports.name = "tickler";
//exports.platforms = ["browser"];
exports.after = ["story"];
exports.synchronous = true;

exports.startup = function() {
	$tw.wiki.forEachTiddler(checkForAlert);
	var interval = setInterval(function() {
		$tw.wiki.forEachTiddler(checkForAlert);
	}, 3600000);
};

function checkForAlert(title, tiddler) {
	var now = new Date();
	if(!tiddler) {
		return;
	}
	if(tiddler.fields.gsd_type === "action") {
		if(tiddler.fields.gsd_tickdate) {
			var alert_date = $tw.utils.parseDate(tiddler.fields.gsd_tickdate);
			if(alert_date <= now) {
				var alertTiddler = new $tw.Tiddler({
					"title": title,
					"modified": tiddler.fields.gsd_tickdate,
					"component": title,
					"tags": "$:/tags/Alert"
				});
				$tw.wiki.addTiddler(alertTiddler);
			}
		}
	}
}

})();
<commit_msg>Fixed some tiddler creation issues.<commit_after>/*\
title: $:/plugins/gsd5/ticklers/modules/startup/tickler.js
type: application/javascript
module-type: startup

Tickler alert manager.

\*/
(function(){

/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";

// Export name and synchronous status
exports.name = "tickler";
//exports.platforms = ["browser"];
exports.after = ["story"];
exports.synchronous = true;

exports.startup = function() {
	$tw.wiki.forEachTiddler(checkForAlert);
	var interval = setInterval(function() {
		$tw.wiki.forEachTiddler(checkForAlert);
	}, 3600000);
};

function checkForAlert(title, tiddler) {
	var now = new Date();
	if(!tiddler) {
		return;
	}
	if(tiddler.fields.gsd_type === "action") {
		if(tiddler.fields.gsd_tickdate) {
			var alert_date = $tw.utils.parseDate(tiddler.fields.gsd_tickdate);
			if(alert_date <= now) {
				var alertTiddler = new $tw.Tiddler({
					"title": "$:/temp/alert/" + title,
					"modified": tiddler.fields.gsd_tickdate,
					"component": title,
					"text": "[[Go to Action|" + title + "]]",
					"tags": "$:/tags/Alert"
				});
				$tw.wiki.addTiddler(alertTiddler);
			}
		}
	}
}

})();
<|endoftext|>


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

/**
 * SessionManager Middleware
 *
 * Manages the clients session and calls callbacks to manage
 * the stored subscriptions for clean and unclean clients.
 *
 * Enabled Callbacks:
 * - storeSubscription
 * - lookupSubscriptions
 * - clearSubscriptions
 *
 * Required Callbacks:
 *  - subscribeTopic
 */
var SessionManager = function(){};

/**
 * Stores subscriptions if the client is unclean.
 *
 * @param ctx
 * @param store
 * @param callback
 */
SessionManager.prototype.subscribeTopic = function(ctx, store, callback) {
  if(ctx.client._managed_session) {
    this.stack.execute('storeSubscription', ctx, callback);
  }
};

/**
 * Checks the clean flag on connect and calls appropriate functions and
 * sets clientId as client._client_id if unclean.
 *
 * @param client
 * @param packet
 * @param next
 * @param done
 */
SessionManager.prototype.handle = function(client, packet, next, done) {
  if(packet.cmd == 'connect') {
    client._client_id = packet.clientId;
    if(packet.clean) {
      client._managed_session = false;
      this._handleCleanClient(client, packet, next, done);
    } else {
      client._managed_session = true;
      this._handleUncleanClient(client, packet, next, done);
    }
  } else {
    return next();
  }
};

/**
 * For clean clients executes 'clearSubscriptions' and sends 'connack' with
 * sessionPresent' set to false as there are no subscriptions..
 *
 * @param client
 * @param packet
 * @param next
 * @param done
 * @private
 */
SessionManager.prototype._handleCleanClient = function(client, packet, next, done) {
  this.stack.execute('clearSubscriptions', {
    client: client,
    packet: packet,
    clientId: packet.clientId
  }, function(err){
    if(err) return next(err);

    client.write({
      cmd: 'connack',
      returnCode: 0,
      sessionPresent: false
    });

    return done();
  });
};

/**
 * For unclean clients executes 'lookupSubscriptions' and executes
 * 'subscribeTopic' for each and finally sends a 'connack' with
 * 'sessionPresent' set to true if there are any subscriptions.
 * @param client
 * @param packet
 * @param next
 * @param done
 * @private
 */
SessionManager.prototype._handleUncleanClient = function(client, packet, next, done) {
  var self = this;

  var store = [];
  this.stack.execute('lookupSubscriptions', {
    client: client,
    packet: packet,
    clientId: packet.clientId
  }, store, function(err){
    if(err) return next(err);

    async.mapSeries(store, function(s, cb){
      self.stack.execute('subscribeTopic', {
        client: client,
        packet: packet,
        topic: s.topic,
        qos: s.qos
      }, {}, cb);
    }, function(err){
      if(err) return next(err);

      client.write({
        cmd: 'connack',
        returnCode: 0,
        sessionPresent: (store.length > 0)
      });

      return done();
    });
  });
};

module.exports = SessionManager;
<commit_msg>added missing callback call<commit_after>var _ = require('underscore');
var async = require('async');

/**
 * SessionManager Middleware
 *
 * Manages the clients session and calls callbacks to manage
 * the stored subscriptions for clean and unclean clients.
 *
 * Enabled Callbacks:
 * - storeSubscription
 * - lookupSubscriptions
 * - clearSubscriptions
 *
 * Required Callbacks:
 *  - subscribeTopic
 */
var SessionManager = function(){};

/**
 * Stores subscriptions if the client is unclean.
 *
 * @param ctx
 * @param store
 * @param callback
 */
SessionManager.prototype.subscribeTopic = function(ctx, store, callback) {
  if(ctx.client._managed_session) {
    this.stack.execute('storeSubscription', ctx, callback);
  } else {
    callback();
  }
};

/**
 * Checks the clean flag on connect and calls appropriate functions and
 * sets clientId as client._client_id if unclean.
 *
 * @param client
 * @param packet
 * @param next
 * @param done
 */
SessionManager.prototype.handle = function(client, packet, next, done) {
  if(packet.cmd == 'connect') {
    client._client_id = packet.clientId;
    if(packet.clean) {
      client._managed_session = false;
      this._handleCleanClient(client, packet, next, done);
    } else {
      client._managed_session = true;
      this._handleUncleanClient(client, packet, next, done);
    }
  } else {
    return next();
  }
};

/**
 * For clean clients executes 'clearSubscriptions' and sends 'connack' with
 * sessionPresent' set to false as there are no subscriptions..
 *
 * @param client
 * @param packet
 * @param next
 * @param done
 * @private
 */
SessionManager.prototype._handleCleanClient = function(client, packet, next, done) {
  this.stack.execute('clearSubscriptions', {
    client: client,
    packet: packet,
    clientId: packet.clientId
  }, function(err){
    if(err) return next(err);

    client.write({
      cmd: 'connack',
      returnCode: 0,
      sessionPresent: false
    });

    return done();
  });
};

/**
 * For unclean clients executes 'lookupSubscriptions' and executes
 * 'subscribeTopic' for each and finally sends a 'connack' with
 * 'sessionPresent' set to true if there are any subscriptions.
 * @param client
 * @param packet
 * @param next
 * @param done
 * @private
 */
SessionManager.prototype._handleUncleanClient = function(client, packet, next, done) {
  var self = this;

  var store = [];
  this.stack.execute('lookupSubscriptions', {
    client: client,
    packet: packet,
    clientId: packet.clientId
  }, store, function(err){
    if(err) return next(err);

    async.mapSeries(store, function(s, cb){
      self.stack.execute('subscribeTopic', {
        client: client,
        packet: packet,
        topic: s.topic,
        qos: s.qos
      }, {}, cb);
    }, function(err){
      if(err) return next(err);

      client.write({
        cmd: 'connack',
        returnCode: 0,
        sessionPresent: (store.length > 0)
      });

      return done();
    });
  });
};

module.exports = SessionManager;
<|endoftext|>


<commit_before>const SekshiModule = require('../Module')
const command = require('../command')
const mongoose = require('mongoose')

const Achievement = mongoose.modelNames().indexOf('Achievement') === -1
  ? mongoose.model('Achievement', {
      _id: String,
      image: String,
      description: String
    })
  : mongoose.model('Achievement')

const AchievementUnlock = mongoose.modelNames().indexOf('AchievementUnlock') === -1
  ? mongoose.model('AchievementUnlock', {
      achievement: { type: String, ref: 'Achievement',  },
      user: { type: Number, ref: 'User' },
      giver: { type: Number, ref: 'User' },
      time: { type: Date, default: Date.now }
    })
  : mongoose.model('AchievementUnlock')

export default class Achievements extends SekshiModule {

  constructor(sekshi, options) {
    super(sekshi, options)

    this.version = '0.1.0'
    this.description = 'Achievements.'

    this.Achievement = Achievement
    this.AchievementUnlock = AchievementUnlock
  }

  defaultOptions() {
    return {
      showDescription: false
    }
  }

  getUnlockedAchievements(uid) {
    return AchievementUnlock.find({ user: uid }, [ 'achievement' ]).lean().exec()
      .then(unlocked => unlocked.map(ach => ach.achievement))
      .catch(e => [])
  }

  hasAchievement(id, name) {
    return AchievementUnlock.count({
      user: id,
      achievement: name
    }).exec().then(
      num => num > 0,
      e => false
    )
  }

  defineAchievement({ name, image, description }) {
    return Achievement.create({ _id: name, image, description })
  }

  unlockAchievement(user, achievement) {
    // normalise achievement name
    achievement = achievement.toLowerCase()
    return this.hasAchievement(user, achievement).then(has => {
      if (has) {
        return null
      }
      return AchievementUnlock.create({
        user,
        achievement,
      })
    })
  }

  notifyUnlocked(unlock) {
    let target = this.sekshi.getUserByID(unlock.user)
    return Achievement.findById(unlock.achievement).then(ach => {
      if (ach.description && this.options.showDescription) {
        this.sekshi.sendChat(ach.description)
      }
      this.sekshi.sendChat(`@${target.username} unlocked achievement ${ach.image}`)
    })
  }

  @command('addachievement', { role: command.ROLE.COHOST, ninjaVanish: true })
  addachievement({ username }, name, image, ...description) {
    description = description.join(' ')
    let e
    if (!name) e = `You have to enter a name.`
    if (!image) e = `You have to add an image link.`

    if (e) return this.sekshi.sendChat(`@${username} ${e}`)

    // normalise achievement names
    name = name.toLowerCase()

    this.defineAchievement({ name, image, description }).then(
      ach => { this.sekshi.sendChat(`@${username} Created achievement "${ach.id}"!`) },
      e => { console.error(e.stack || e.message) }
    )
  }

  @command('giveachievement', 'ga', { role: command.ROLE.BOUNCER })
  giveachievement(user, targetName, achievement) {
    const target = this.sekshi.getUserByName(targetName)
    if (target) {
      this.unlockAchievement(target.id, achievement).then(unlock => {
        if (unlock == null) {
          this.sekshi.sendChat(`@${user.username} ${target.username} ` +
                               `already has that achievement!`)
          return
        }
        unlock.set('giver', user.id).save()
        return this.notifyUnlocked(unlock)
      }).then(null, e => {
        console.error(e.stack || e.message)
      })
    }
  }

}
<commit_msg>achievements: check achievement existence before giving<commit_after>const SekshiModule = require('../Module')
const command = require('../command')
const mongoose = require('mongoose')
const Promise = require('bluebird')

const Achievement = mongoose.modelNames().indexOf('Achievement') === -1
  ? mongoose.model('Achievement', {
      _id: String,
      image: String,
      description: String
    })
  : mongoose.model('Achievement')

const AchievementUnlock = mongoose.modelNames().indexOf('AchievementUnlock') === -1
  ? mongoose.model('AchievementUnlock', {
      achievement: { type: String, ref: 'Achievement',  },
      user: { type: Number, ref: 'User' },
      giver: { type: Number, ref: 'User' },
      time: { type: Date, default: Date.now }
    })
  : mongoose.model('AchievementUnlock')

export default class Achievements extends SekshiModule {

  constructor(sekshi, options) {
    super(sekshi, options)

    this.version = '0.1.0'
    this.description = 'Achievements.'

    this.Achievement = Achievement
    this.AchievementUnlock = AchievementUnlock
  }

  defaultOptions() {
    return {
      showDescription: false
    }
  }

  getUnlockedAchievements(uid) {
    return AchievementUnlock.find({ user: uid }, [ 'achievement' ]).lean().exec()
      .then(unlocked => unlocked.map(ach => ach.achievement))
      .catch(e => [])
  }

  hasAchievement(id, name) {
    return AchievementUnlock.count({
      user: id,
      achievement: name
    }).exec().then(
      num => num > 0,
      e => false
    )
  }

  defineAchievement({ name, image, description }) {
    return Achievement.create({ _id: name, image, description })
  }

  unlockAchievement(user, achievement) {
    // normalise achievement name
    achievement = achievement.toLowerCase()
    return Achievement.findById(achievement)
      .then(exists => {
        if (!exists) {
          return Promise.reject(new Error(`Achievement ${achievement} does not exist`))
        }
        return this.hasAchievement(user, achievement)
      })
      .then(has => {
        if (has) {
          return null
        }
        return AchievementUnlock.create({
          user,
          achievement
        })
      })
  }

  notifyUnlocked(unlock) {
    let target = this.sekshi.getUserByID(unlock.user)
    return Achievement.findById(unlock.achievement).then(ach => {
      if (ach.description && this.options.showDescription) {
        this.sekshi.sendChat(ach.description)
      }
      this.sekshi.sendChat(`@${target.username} unlocked achievement ${ach.image}`)
    })
  }

  @command('addachievement', { role: command.ROLE.COHOST, ninjaVanish: true })
  addachievement({ username }, name, image, ...description) {
    description = description.join(' ')
    let e
    if (!name) e = `You have to enter a name.`
    if (!image) e = `You have to add an image link.`

    if (e) return this.sekshi.sendChat(`@${username} ${e}`)

    // normalise achievement names
    name = name.toLowerCase()

    this.defineAchievement({ name, image, description }).then(
      ach => { this.sekshi.sendChat(`@${username} Created achievement "${ach.id}"!`) },
      e => { console.error(e.stack || e.message) }
    )
  }

  @command('giveachievement', 'ga', { role: command.ROLE.BOUNCER })
  giveachievement(user, targetName, achievement) {
    const target = this.sekshi.getUserByName(targetName)
    if (target) {
      this.unlockAchievement(target.id, achievement).then(unlock => {
        if (unlock == null) {
          this.sekshi.sendChat(`@${user.username} ${target.username} ` +
                               `already has that achievement!`)
          return
        }
        unlock.set('giver', user.id).save()
        return this.notifyUnlocked(unlock)
      }).then(null, e => {
        console.error(e.stack || e.message)
      })
    }
  }

}
<|endoftext|>


<commit_before>const { Command } = require('discord-akairo');

function exec(message){
    const color = this.client.color(message);
    const embed = this.client.util.embed().setColor(color);

    const fields = [
        [
            'Memory Usage',
            `${(process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2)} MB`,
            true
        ],
        [
            'Client Uptime',
            this.formatMs(this.client.uptime),
            true
        ],
        [
            'Github Repo',
            '[Selfbot by 1Computer](https://github.com/1Computer1/megumin-selfbot)',
            true
        ]
    ];

    for (const field of fields) embed.addField(...field);
    return message.edit('', { embed });
}

module.exports = new Command('stats', exec, {
    aliases: ['stats', 'info', 'about'],
    category: 'info'
});

module.exports.formatMs = ms => {
    let x = Math.floor(ms / 1000);
    let seconds = x % 60;

    x = Math.floor(x / 60);
    let minutes = x % 60;

    x = Math.floor(x / 60);
    let hours = x % 24;

    let days = Math.floor(x / 24);

    seconds = `${'0'.repeat(2 - seconds.toString().length)}${seconds}`;
    minutes = `${'0'.repeat(2 - minutes.toString().length)}${minutes}`;
    hours = `${'0'.repeat(Math.max(0, 2 - hours.toString().length))}${hours}`;
    days = `${'0'.repeat(Math.max(0, 2 - days.toString().length))}${days}`;
    return `${days !== '00' ? `${days}:` : ''}${hours}:${minutes}:${seconds}`;
};
<commit_msg>remove math.max from hours<commit_after>const { Command } = require('discord-akairo');

function exec(message){
    const color = this.client.color(message);
    const embed = this.client.util.embed().setColor(color);

    const fields = [
        [
            'Memory Usage',
            `${(process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2)} MB`,
            true
        ],
        [
            'Client Uptime',
            this.formatMs(this.client.uptime),
            true
        ],
        [
            'Github Repo',
            '[Selfbot by 1Computer](https://github.com/1Computer1/megumin-selfbot)',
            true
        ]
    ];

    for (const field of fields) embed.addField(...field);
    return message.edit('', { embed });
}

module.exports = new Command('stats', exec, {
    aliases: ['stats', 'info', 'about'],
    category: 'info'
});

module.exports.formatMs = ms => {
    let x = Math.floor(ms / 1000);
    let seconds = x % 60;

    x = Math.floor(x / 60);
    let minutes = x % 60;

    x = Math.floor(x / 60);
    let hours = x % 24;

    let days = Math.floor(x / 24);

    seconds = `${'0'.repeat(2 - seconds.toString().length)}${seconds}`;
    minutes = `${'0'.repeat(2 - minutes.toString().length)}${minutes}`;
    hours = `${'0'.repeat(2 - hours.toString().length)}${hours}`;
    days = `${'0'.repeat(Math.max(0, 2 - days.toString().length))}${days}`;
    return `${days !== '00' ? `${days}:` : ''}${hours}:${minutes}:${seconds}`;
};
<|endoftext|>