<commit_before>/**
 * Created by Mauriel on 2/9/2016.
 */
// Map js
var coverageMap;
var allOverlays = [];
var allShapes = []; // Keeps track of shapes added by text change events
var drawingManager;

$(document).ready(function () {
    // Draw marker on text change
    $("#id_east").bind('input', drawMarkerOnTextChange);
    $("#id_north").bind('input', drawMarkerOnTextChange);

    // Draw rectangle on text change
    $("#id_northlimit").bind('input', drawRectangleOnTextChange);
    $("#id_eastlimit").bind('input', drawRectangleOnTextChange);
    $("#id_southlimit").bind('input', drawRectangleOnTextChange);
    $("#id_westlimit").bind('input', drawRectangleOnTextChange);

    var $radioPoint = $('input[type="radio"][value="point"]'); // id_type_2
    var $radioBox = $('input[type="radio"][value="box"]'); // id_type_1
    // Set initial coverage fields state
    if ($radioBox.is(':checked')) { //box type coverage
        $("#div_id_north").hide();
        $("#div_id_east").hide();
        $("#div_id_elevation").hide();
    }
    if ($radioPoint.is(':checked')) { // point type coverage
        $("#div_id_northlimit").hide();
        $("#div_id_eastlimit").hide();
        $("#div_id_southlimit").hide();
        $("#div_id_westlimit").hide();
        $("#div_id_uplimit").hide();
        $("#div_id_downlimit").hide();
    }

    if ($("#coverageMap").length) {
        google.maps.event.addDomListener(window, "load", initMap);
    }
});

function drawInitialShape() {
    // This field is populated if the page is in view mode
    var shapeType = $("#coverageMap")[0].getAttribute("data-shape-type");

    var resourceType = $("#resource-type").val();
    var spatialCoverageType = $("#spatial-coverage-type").val();
    // Center the map
    if (shapeType || resourceType === "Time Series") {
        deleteAllShapes();
        if (shapeType == "point" || (resourceType === "Time Series" && spatialCoverageType == "point")) {
            var myLatLng;
            if (shapeType == "point") {
                // resource view mode
                myLatLng = {
                    lat: parseFloat($("#cov_north").text()),
                    lng: parseFloat($("#cov_east").text())
                };
            }
            else {
                // time series resource in edit mode
                myLatLng = {
                    lat: parseFloat($("#id_north").val()),
                    lng: parseFloat($("#id_east").val())
                };
                if ($('#id_north').val()) {
                    $("#id_name").prop('readonly', false);
                }
            }

            if (!myLatLng.lat || !myLatLng.lng) {
                return;
            }
            // Define the rectangle and set its editable property to true.
            var marker = new google.maps.Marker({
                position: myLatLng,
                map: coverageMap
            });
            allShapes.push(marker);
            // Center map at new market
            coverageMap.setCenter(marker.getPosition());
            $("#resetZoomBtn").click(function () {
                coverageMap.setCenter(marker.getPosition());
            });
        }
        else if (shapeType == "box" || (resourceType === "Time Series" && spatialCoverageType == "box")) {
            var bounds;
            if (shapeType == "box") {
                //resource view mode
                bounds = {
                    north: parseFloat($("#cov_northlimit").text()),
                    south: parseFloat($("#cov_southlimit").text()),
                    east: parseFloat($("#cov_eastlimit").text()),
                    west: parseFloat($("#cov_westlimit").text())
                };
            }
            else {
                // time series resource edit mode
                bounds = {
                    north: parseFloat($("#id_northlimit").val()),
                    south: parseFloat($("#id_southlimit").val()),
                    east: parseFloat($("#id_eastlimit").val()),
                    west: parseFloat($("#id_westlimit").val())
                };
                if ($('#id_northlimit').val()) {
                    $("#id_name").prop('readonly', false);
                }
            }

            if (!bounds.north || !bounds.south || !bounds.east || !bounds.west) {
                return;
            }
            // Define the rectangle and set its editable property to true.
            var rectangle = new google.maps.Rectangle({
                bounds: bounds,
                editable: false,
                draggable: false
            });
            rectangle.setMap(coverageMap);
            allShapes.push(rectangle);
            zoomCoverageMap(bounds);
            $("#resetZoomBtn").click(function () {
                zoomCoverageMap(bounds);
            });
        }
    }
    else {
        var $radioBox = $('input[type="radio"][value="box"]'); // id_type_1
        if ($radioBox.is(":checked")) {
            drawRectangleOnTextChange();
        }
        else {
            drawMarkerOnTextChange();
        }
    }
    $("#id-coverage-spatial input:radio").change(function () {
        if ($(this).val() == "point") {
            $("#div_id_north").show();
            $("#div_id_east").show();
            $("#div_id_elevation").show();
            $("#div_id_northlimit").hide();
            $("#div_id_eastlimit").hide();
            $("#div_id_southlimit").hide();
            $("#div_id_westlimit").hide();
            $("#div_id_uplimit").hide();
            $("#div_id_downlimit").hide();
            drawMarkerOnTextChange();
            drawingManager.setDrawingMode(google.maps.drawing.OverlayType.MARKER);
        }
        else {
            $("#div_id_north").hide();
            $("#div_id_east").hide();
            $("#div_id_elevation").hide();
            $("#div_id_northlimit").show();
            $("#div_id_eastlimit").show();
            $("#div_id_southlimit").show();
            $("#div_id_westlimit").show();
            $("#div_id_uplimit").show();
            $("#div_id_downlimit").show();
            drawRectangleOnTextChange();
            drawingManager.setDrawingMode(google.maps.drawing.OverlayType.RECTANGLE);
        }
        // Show save changes button
        $("#coverage-spatial").find(".btn-primary").show();
    });
    if (sessionStorage.signininfo) {
        $("#sign-in-info").text(sessionStorage.signininfo);
        $("#btn-select-irods-file").show();
    }
}

function initMap() {
    var shapeType;
    var resourceType;
    if ($("#coverageMap")[0]) {
        // data-shape-type is set to have a value only in resource view mode
        shapeType = $("#coverageMap")[0].getAttribute("data-shape-type");
        resourceType = $("#resource-type").val();
        if (resourceType === "Time Series"){
            // set to view mode
            shapeType = " ";
        }
    }
    coverageMap = new google.maps.Map(document.getElementById('coverageMap'), {
        color:"#DDD",
        zoom: 3,
        streetViewControl: false,
        scrollwheel: false,
        center: {lat: 41.850033, lng: -87.6500523}, // Default center
        mapTypeControl: true,
        mapTypeControlOptions: {
            style: google.maps.MapTypeControlStyle.DROPDOWN_MENU,
            mapTypeIds: [
                google.maps.MapTypeId.ROADMAP,
                google.maps.MapTypeId.SATELLITE
            ],
            position: google.maps.ControlPosition.TOP_RIGHT
        }
    });

    drawInitialShape();
    if (!shapeType) {
        drawingManager = new google.maps.drawing.DrawingManager({
            drawingControl: true,
            drawingControlOptions: {
                position: google.maps.ControlPosition.TOP_CENTER,
                drawingModes: [
                    google.maps.drawing.OverlayType.MARKER,
                    google.maps.drawing.OverlayType.RECTANGLE
                ]
            },
            rectangleOptions: {
                editable: true,
                draggable: true
            }
        });
        drawingManager.setMap(coverageMap);
        google.maps.event.addListener(drawingManager, 'rectanglecomplete', function (rectangle) {
            var coordinates = (rectangle.getBounds());
            processDrawing(coordinates, "rectangle");
            rectangle.addListener('bounds_changed', function () {
                var coordinates = (rectangle.getBounds());
                processDrawing(coordinates, "rectangle");
            });
        });
        google.maps.event.addListener(drawingManager, 'markercomplete', function (marker) {
            var coordinates = (marker.getPosition());
            // Set onClick event for recenter button
            processDrawing(coordinates, "marker");
        });
        google.maps.event.addListener(drawingManager, 'overlaycomplete', function (e) {
            allOverlays.push(e);
        });
    }
}

function drawMarkerOnTextChange(){
    var myLatLng = {lat: parseFloat($("#id_north").val()), lng: parseFloat($("#id_east").val())};
    // Delete previous drawings
    deleteAllShapes();
    deleteAllOverlays();
    // Bounds validation
    var badInput = false;
    // Lat
    if (myLatLng.lat > 90 || myLatLng.lat < -90) {
        $("#id_north").addClass("invalid-input");
        badInput = true;
    }
    else {
        $("#id_north").removeClass("invalid-input");
    }
    if (myLatLng.lng > 180 || myLatLng.lng < -180) {
        $("#id_east").addClass("invalid-input");
        badInput = true;
    }
    else {
        $("#id_east").removeClass("invalid-input");
    }
    if (badInput || isNaN(myLatLng.lat) || isNaN(myLatLng.lng)) {
        return;
    }
    // Define the rectangle and set its editable property to true.
    var marker = new google.maps.Marker({
        position: myLatLng,
        map: coverageMap
    });
    // Center map at new market
    coverageMap.setCenter(marker.getPosition());
    // Set onClick event for recenter button
    $("#resetZoomBtn").click(function(){
        coverageMap.setCenter(marker.getPosition());
    });
    allShapes.push(marker);
}

function drawRectangleOnTextChange(){
    var bounds = {
        north: parseFloat($("#id_northlimit").val()),
        south: parseFloat($("#id_southlimit").val()),
        east: parseFloat($("#id_eastlimit").val()),
        west: parseFloat($("#id_westlimit").val())
    };
    // Delete previous drawings
    deleteAllShapes();
    deleteAllOverlays();
    // Bounds validation
    var badInput = false;
    // North
    if (bounds.north > 90 || bounds.north < -90) {
        $("#id_northlimit").addClass("invalid-input");
        badInput = true;
    }
    else {
        $("#id_northlimit").removeClass("invalid-input");
    }
    // East
    if (bounds.east > 180 || bounds.east < -180) {
        badInput = true;
        $("#id_eastlimit").addClass("invalid-input");
    }
    else {
        $("#id_eastlimit").removeClass("invalid-input");
    }
    // South
    if (bounds.south < -90 || bounds.south > 90) {
        badInput = true;
        $("#id_southlimit").addClass("invalid-input");
    }
    else {
        $("#id_southlimit").removeClass("invalid-input");
    }
    // West
    if (bounds.west < -180 || bounds.west > 180) {
        badInput = true;
        $("#id_westlimit").addClass("invalid-input");
    }
    else {
        $("#id_westlimit").removeClass("invalid-input");
    }
    if (badInput || isNaN(bounds.north) || isNaN(bounds.south) || isNaN(bounds.east) || isNaN(bounds.west)) {
        return;
    }
    // Define the rectangle and set its editable property to true.
    var rectangle = new google.maps.Rectangle({
        bounds: bounds,
        editable: true,
        draggable: true
    });
    rectangle.setMap(coverageMap);
    rectangle.addListener('bounds_changed', function () {
        var coordinates = (rectangle.getBounds());
        processDrawing(coordinates, "rectangle");
    });
    zoomCoverageMap(bounds);
    $("#resetZoomBtn").click(function(){
        zoomCoverageMap(bounds);
    });
    allShapes.push(rectangle);
}

function processDrawing (coordinates, shape) {
    // Delete previous drawings
    if (allOverlays.length > 1){
        for (var i = 1; i < allOverlays.length; i++){
            allOverlays[i-1].overlay.setMap(null);
        }
        allOverlays.shift();
    }
    if (allOverlays.length > 0) {
        deleteAllShapes();
    }
    // Show save changes button
    $("#coverage-spatial").find(".btn-primary").not('#btn-update-resource-spatial-coverage').show();
    if (shape == "rectangle"){
        var $radioBox = $('input[type="radio"][value="box"]'); // id_type_1
        $radioBox.checked = true;
        $("#div_id_north").hide();
        $("#div_id_east").hide();
        $("#div_id_elevation").hide();
        $("#div_id_northlimit").show();
        $("#div_id_eastlimit").show();
        $("#div_id_southlimit").show();
        $("#div_id_westlimit").show();
        $("#div_id_uplimit").show();
        $("#div_id_downlimit").show();
        var bounds = {
            north: parseFloat(coordinates.getNorthEast().lat()),
            south: parseFloat(coordinates.getSouthWest().lat()),
            east: parseFloat(coordinates.getNorthEast().lng()),
            west: parseFloat(coordinates.getSouthWest().lng())
        };
        // Update fields
        $("#id_northlimit").val(bounds.north.toFixed(4));
        $("#id_eastlimit").val(bounds.east.toFixed(4));
        $("#id_southlimit").val(bounds.south.toFixed(4));
        $("#id_westlimit").val(bounds.west.toFixed(4));
        // Remove red borders
        $("#id_northlimit").removeClass("invalid-input");
        $("#id_eastlimit").removeClass("invalid-input");
        $("#id_southlimit").removeClass("invalid-input");
        $("#id_westlimit").removeClass("invalid-input");
        $("#resetZoomBtn").click(function(){
            zoomCoverageMap(bounds);
        });
    }
    else {
        var $radioPoint = $('input[type="radio"][value="point"]'); // id_type_2
        $radioPoint.checked = true;
        $("#div_id_north").show();
        $("#div_id_east").show();
        $("#div_id_elevation").show();
        $("#div_id_northlimit").hide();
        $("#div_id_eastlimit").hide();
        $("#div_id_southlimit").hide();
        $("#div_id_westlimit").hide();
        $("#div_id_uplimit").hide();
        $("#div_id_downlimit").hide();
        $("#id_east").val(coordinates.lng().toFixed(4));
        $("#id_north").val(coordinates.lat().toFixed(4));
        // Remove red borders
        $("#id_east").removeClass("invalid-input");
        $("#id_north").removeClass("invalid-input");
        $("#resetZoomBtn").click(function () {
            coverageMap.setCenter(coordinates);
        });
    }
}

function deleteAllOverlays() {
    for (var i = 0; i < allOverlays.length; i++) {
        allOverlays[i].overlay.setMap(null);
    }
    allOverlays = [];
}

function deleteAllShapes(){
    for (var i = 0; i < allShapes.length; i++) {
        allShapes[i].setMap(null);
    }
    allShapes = [];
}

function zoomCoverageMap(bounds) {
    // Zoom in on the shape
    var GLOBE_WIDTH = 256; // a constant in Google maps projection
    var c_west = bounds.west * 8;    // Zooms out on the shape a little so that we can see it
    var c_east = bounds.east * 8;
    var angle = c_east - c_west;
    var pixelWidth = parseInt($("#coverageMap").width());
    if (angle < 0) {
        angle += 360;
    }
    var zoom = Math.round(Math.log(pixelWidth * 360 / angle / GLOBE_WIDTH) / Math.LN2);
    if (!isNaN(zoom)){
        coverageMap.setZoom(Math.max(3, zoom)); // Allow minumum zoom level of 3
    }
    else{
        return;
    }
    // Center map at new rectangle
    var latCenter = (bounds.north + bounds.south) / 2;
    var lngCenter = (bounds.west + bounds.east) / 2;
    coverageMap.setCenter(new google.maps.LatLng(latCenter, lngCenter));
}<commit_msg>[#3012] fix and simplify zoom and center logic<commit_after>/**
 * Created by Mauriel on 2/9/2016.
 */
// Map js
var coverageMap;
var allOverlays = [];
var allShapes = []; // Keeps track of shapes added by text change events
var drawingManager;

$(document).ready(function () {
    // Draw marker on text change
    $("#id_east").bind('input', drawMarkerOnTextChange);
    $("#id_north").bind('input', drawMarkerOnTextChange);

    // Draw rectangle on text change
    $("#id_northlimit").bind('input', drawRectangleOnTextChange);
    $("#id_eastlimit").bind('input', drawRectangleOnTextChange);
    $("#id_southlimit").bind('input', drawRectangleOnTextChange);
    $("#id_westlimit").bind('input', drawRectangleOnTextChange);

    var $radioPoint = $('input[type="radio"][value="point"]'); // id_type_2
    var $radioBox = $('input[type="radio"][value="box"]'); // id_type_1
    // Set initial coverage fields state
    if ($radioBox.is(':checked')) { //box type coverage
        $("#div_id_north").hide();
        $("#div_id_east").hide();
        $("#div_id_elevation").hide();
    }
    if ($radioPoint.is(':checked')) { // point type coverage
        $("#div_id_northlimit").hide();
        $("#div_id_eastlimit").hide();
        $("#div_id_southlimit").hide();
        $("#div_id_westlimit").hide();
        $("#div_id_uplimit").hide();
        $("#div_id_downlimit").hide();
    }

    if ($("#coverageMap").length) {
        google.maps.event.addDomListener(window, "load", initMap);
    }
});

function drawInitialShape() {
    // This field is populated if the page is in view mode
    var shapeType = $("#coverageMap")[0].getAttribute("data-shape-type");

    var resourceType = $("#resource-type").val();
    var spatialCoverageType = $("#spatial-coverage-type").val();
    // Center the map
    if (shapeType || resourceType === "Time Series") {
        deleteAllShapes();
        if (shapeType == "point" || (resourceType === "Time Series" && spatialCoverageType == "point")) {
            var myLatLng;
            if (shapeType == "point") {
                // resource view mode
                myLatLng = {
                    lat: parseFloat($("#cov_north").text()),
                    lng: parseFloat($("#cov_east").text())
                };
            }
            else {
                // time series resource in edit mode
                myLatLng = {
                    lat: parseFloat($("#id_north").val()),
                    lng: parseFloat($("#id_east").val())
                };
                if ($('#id_north').val()) {
                    $("#id_name").prop('readonly', false);
                }
            }

            if (!myLatLng.lat || !myLatLng.lng) {
                return;
            }
            // Define the rectangle and set its editable property to true.
            var marker = new google.maps.Marker({
                position: myLatLng,
                map: coverageMap
            });
            allShapes.push(marker);
            // Center map at new market
            coverageMap.setCenter(marker.getPosition());
            $("#resetZoomBtn").click(function () {
                coverageMap.setCenter(marker.getPosition());
            });
        }
        else if (shapeType == "box" || (resourceType === "Time Series" && spatialCoverageType == "box")) {
            var bounds;
            if (shapeType == "box") {
                //resource view mode
                bounds = {
                    north: parseFloat($("#cov_northlimit").text()),
                    south: parseFloat($("#cov_southlimit").text()),
                    east: parseFloat($("#cov_eastlimit").text()),
                    west: parseFloat($("#cov_westlimit").text())
                };
            }
            else {
                // time series resource edit mode
                bounds = {
                    north: parseFloat($("#id_northlimit").val()),
                    south: parseFloat($("#id_southlimit").val()),
                    east: parseFloat($("#id_eastlimit").val()),
                    west: parseFloat($("#id_westlimit").val())
                };
                if ($('#id_northlimit').val()) {
                    $("#id_name").prop('readonly', false);
                }
            }

            if (!bounds.north || !bounds.south || !bounds.east || !bounds.west) {
                return;
            }
            // Define the rectangle and set its editable property to true.
            var rectangle = new google.maps.Rectangle({
                bounds: bounds,
                editable: false,
                draggable: false
            });
            rectangle.setMap(coverageMap);
            allShapes.push(rectangle);
            zoomCoverageMap(bounds);
            $("#resetZoomBtn").click(function () {
                zoomCoverageMap(bounds);
            });
        }
    }
    else {
        var $radioBox = $('input[type="radio"][value="box"]'); // id_type_1
        if ($radioBox.is(":checked")) {
            drawRectangleOnTextChange();
        }
        else {
            drawMarkerOnTextChange();
        }
    }
    $("#id-coverage-spatial input:radio").change(function () {
        if ($(this).val() == "point") {
            $("#div_id_north").show();
            $("#div_id_east").show();
            $("#div_id_elevation").show();
            $("#div_id_northlimit").hide();
            $("#div_id_eastlimit").hide();
            $("#div_id_southlimit").hide();
            $("#div_id_westlimit").hide();
            $("#div_id_uplimit").hide();
            $("#div_id_downlimit").hide();
            drawMarkerOnTextChange();
            drawingManager.setDrawingMode(google.maps.drawing.OverlayType.MARKER);
        }
        else {
            $("#div_id_north").hide();
            $("#div_id_east").hide();
            $("#div_id_elevation").hide();
            $("#div_id_northlimit").show();
            $("#div_id_eastlimit").show();
            $("#div_id_southlimit").show();
            $("#div_id_westlimit").show();
            $("#div_id_uplimit").show();
            $("#div_id_downlimit").show();
            drawRectangleOnTextChange();
            drawingManager.setDrawingMode(google.maps.drawing.OverlayType.RECTANGLE);
        }
        // Show save changes button
        $("#coverage-spatial").find(".btn-primary").show();
    });
    if (sessionStorage.signininfo) {
        $("#sign-in-info").text(sessionStorage.signininfo);
        $("#btn-select-irods-file").show();
    }
}

function initMap() {
    var shapeType;
    var resourceType;
    if ($("#coverageMap")[0]) {
        // data-shape-type is set to have a value only in resource view mode
        shapeType = $("#coverageMap")[0].getAttribute("data-shape-type");
        resourceType = $("#resource-type").val();
        if (resourceType === "Time Series"){
            // set to view mode
            shapeType = " ";
        }
    }
    coverageMap = new google.maps.Map(document.getElementById('coverageMap'), {
        color:"#DDD",
        zoom: 3,
        streetViewControl: false,
        scrollwheel: false,
        center: {lat: 41.850033, lng: -87.6500523}, // Default center
        mapTypeControl: true,
        mapTypeControlOptions: {
            style: google.maps.MapTypeControlStyle.DROPDOWN_MENU,
            mapTypeIds: [
                google.maps.MapTypeId.ROADMAP,
                google.maps.MapTypeId.SATELLITE
            ],
            position: google.maps.ControlPosition.TOP_RIGHT
        }
    });

    drawInitialShape();
    if (!shapeType) {
        drawingManager = new google.maps.drawing.DrawingManager({
            drawingControl: true,
            drawingControlOptions: {
                position: google.maps.ControlPosition.TOP_CENTER,
                drawingModes: [
                    google.maps.drawing.OverlayType.MARKER,
                    google.maps.drawing.OverlayType.RECTANGLE
                ]
            },
            rectangleOptions: {
                editable: true,
                draggable: true
            }
        });
        drawingManager.setMap(coverageMap);
        google.maps.event.addListener(drawingManager, 'rectanglecomplete', function (rectangle) {
            var coordinates = (rectangle.getBounds());
            processDrawing(coordinates, "rectangle");
            rectangle.addListener('bounds_changed', function () {
                var coordinates = (rectangle.getBounds());
                processDrawing(coordinates, "rectangle");
            });
        });
        google.maps.event.addListener(drawingManager, 'markercomplete', function (marker) {
            var coordinates = (marker.getPosition());
            // Set onClick event for recenter button
            processDrawing(coordinates, "marker");
        });
        google.maps.event.addListener(drawingManager, 'overlaycomplete', function (e) {
            allOverlays.push(e);
        });
    }
}

function drawMarkerOnTextChange(){
    var myLatLng = {lat: parseFloat($("#id_north").val()), lng: parseFloat($("#id_east").val())};
    // Delete previous drawings
    deleteAllShapes();
    deleteAllOverlays();
    // Bounds validation
    var badInput = false;
    // Lat
    if (myLatLng.lat > 90 || myLatLng.lat < -90) {
        $("#id_north").addClass("invalid-input");
        badInput = true;
    }
    else {
        $("#id_north").removeClass("invalid-input");
    }
    if (myLatLng.lng > 180 || myLatLng.lng < -180) {
        $("#id_east").addClass("invalid-input");
        badInput = true;
    }
    else {
        $("#id_east").removeClass("invalid-input");
    }
    if (badInput || isNaN(myLatLng.lat) || isNaN(myLatLng.lng)) {
        return;
    }
    // Define the rectangle and set its editable property to true.
    var marker = new google.maps.Marker({
        position: myLatLng,
        map: coverageMap
    });
    // Center map at new market
    coverageMap.setCenter(marker.getPosition());
    // Set onClick event for recenter button
    $("#resetZoomBtn").click(function(){
        coverageMap.setCenter(marker.getPosition());
    });
    allShapes.push(marker);
}

function drawRectangleOnTextChange(){
    var bounds = {
        north: parseFloat($("#id_northlimit").val()),
        south: parseFloat($("#id_southlimit").val()),
        east: parseFloat($("#id_eastlimit").val()),
        west: parseFloat($("#id_westlimit").val())
    };
    // Delete previous drawings
    deleteAllShapes();
    deleteAllOverlays();
    // Bounds validation
    var badInput = false;
    // North
    if (bounds.north > 90 || bounds.north < -90) {
        $("#id_northlimit").addClass("invalid-input");
        badInput = true;
    }
    else {
        $("#id_northlimit").removeClass("invalid-input");
    }
    // East
    if (bounds.east > 180 || bounds.east < -180) {
        badInput = true;
        $("#id_eastlimit").addClass("invalid-input");
    }
    else {
        $("#id_eastlimit").removeClass("invalid-input");
    }
    // South
    if (bounds.south < -90 || bounds.south > 90) {
        badInput = true;
        $("#id_southlimit").addClass("invalid-input");
    }
    else {
        $("#id_southlimit").removeClass("invalid-input");
    }
    // West
    if (bounds.west < -180 || bounds.west > 180) {
        badInput = true;
        $("#id_westlimit").addClass("invalid-input");
    }
    else {
        $("#id_westlimit").removeClass("invalid-input");
    }
    if (badInput || isNaN(bounds.north) || isNaN(bounds.south) || isNaN(bounds.east) || isNaN(bounds.west)) {
        return;
    }
    // Define the rectangle and set its editable property to true.
    var rectangle = new google.maps.Rectangle({
        bounds: bounds,
        editable: true,
        draggable: true
    });
    rectangle.setMap(coverageMap);
    rectangle.addListener('bounds_changed', function () {
        var coordinates = (rectangle.getBounds());
        processDrawing(coordinates, "rectangle");
    });
    zoomCoverageMap(bounds);
    $("#resetZoomBtn").click(function(){
        zoomCoverageMap(bounds);
    });
    allShapes.push(rectangle);
}

function processDrawing (coordinates, shape) {
    // Delete previous drawings
    if (allOverlays.length > 1){
        for (var i = 1; i < allOverlays.length; i++){
            allOverlays[i-1].overlay.setMap(null);
        }
        allOverlays.shift();
    }
    if (allOverlays.length > 0) {
        deleteAllShapes();
    }
    // Show save changes button
    $("#coverage-spatial").find(".btn-primary").not('#btn-update-resource-spatial-coverage').show();
    if (shape == "rectangle"){
        var $radioBox = $('input[type="radio"][value="box"]'); // id_type_1
        $radioBox.checked = true;
        $("#div_id_north").hide();
        $("#div_id_east").hide();
        $("#div_id_elevation").hide();
        $("#div_id_northlimit").show();
        $("#div_id_eastlimit").show();
        $("#div_id_southlimit").show();
        $("#div_id_westlimit").show();
        $("#div_id_uplimit").show();
        $("#div_id_downlimit").show();
        var bounds = {
            north: parseFloat(coordinates.getNorthEast().lat()),
            south: parseFloat(coordinates.getSouthWest().lat()),
            east: parseFloat(coordinates.getNorthEast().lng()),
            west: parseFloat(coordinates.getSouthWest().lng())
        };
        // Update fields
        $("#id_northlimit").val(bounds.north.toFixed(4));
        $("#id_eastlimit").val(bounds.east.toFixed(4));
        $("#id_southlimit").val(bounds.south.toFixed(4));
        $("#id_westlimit").val(bounds.west.toFixed(4));
        // Remove red borders
        $("#id_northlimit").removeClass("invalid-input");
        $("#id_eastlimit").removeClass("invalid-input");
        $("#id_southlimit").removeClass("invalid-input");
        $("#id_westlimit").removeClass("invalid-input");
        $("#resetZoomBtn").click(function(){
            zoomCoverageMap(bounds);
        });
    }
    else {
        var $radioPoint = $('input[type="radio"][value="point"]'); // id_type_2
        $radioPoint.checked = true;
        $("#div_id_north").show();
        $("#div_id_east").show();
        $("#div_id_elevation").show();
        $("#div_id_northlimit").hide();
        $("#div_id_eastlimit").hide();
        $("#div_id_southlimit").hide();
        $("#div_id_westlimit").hide();
        $("#div_id_uplimit").hide();
        $("#div_id_downlimit").hide();
        $("#id_east").val(coordinates.lng().toFixed(4));
        $("#id_north").val(coordinates.lat().toFixed(4));
        // Remove red borders
        $("#id_east").removeClass("invalid-input");
        $("#id_north").removeClass("invalid-input");
        $("#resetZoomBtn").click(function () {
            coverageMap.setCenter(coordinates);
        });
    }
}

function deleteAllOverlays() {
    for (var i = 0; i < allOverlays.length; i++) {
        allOverlays[i].overlay.setMap(null);
    }
    allOverlays = [];
}

function deleteAllShapes(){
    for (var i = 0; i < allShapes.length; i++) {
        allShapes[i].setMap(null);
    }
    allShapes = [];
}

function zoomCoverageMap(bounds) {
    coverageMap.fitBounds(bounds);
}<|endoftext|>


<commit_before>import {v4 as uuid} from 'uuid';

import getLogger from './getLogger';
import socketRegistryFactory from './socketRegistry';

const LOGGER = getLogger('socketManager');

/**
 *
 * @param commandProcessor
 * @param {function} sendEventToRoom
 * @param {function} removeSocketFromRoomByIds
 */
export default function socketManagerFactory(
  commandProcessor,
  sendEventToRoom,
  removeSocketFromRoomByIds
) {
  const registry = socketRegistryFactory(removeSocketFromRoomByIds);

  return {
    handleIncomingCommand,
    onDisconnect
  };

  async function handleIncomingCommand(socket, msg) {
    const matchingUserId = getUserIdForMessage(socket.id, msg);

    try {
      const {producedEvents} = await commandProcessor(msg, matchingUserId);

      if (!producedEvents) {
        return;
      }

      updateSocketRegistryJoining(matchingUserId, producedEvents, socket);

      sendEvents(producedEvents, producedEvents[0].roomId);

      updateSocketRegistryLeaving(matchingUserId, producedEvents, socket);
    } catch (commandProcessingError) {
      handleCommandProcessingError(commandProcessingError, msg, socket);
    }
  }

  function updateSocketRegistryJoining(userId, producedEvents, socket) {
    const joinedRoomEvent = getJoinedRoomEvent(producedEvents);
    if (joinedRoomEvent) {
      registry.registerSocketMapping(socket, userId, joinedRoomEvent.roomId);
    }
  }

  function updateSocketRegistryLeaving(userId, producedEvents, socket) {
    const leftRoomEvent = getLeftRoomEvent(producedEvents);
    if (leftRoomEvent) {
      registry.removeSocketMapping(socket.id, leftRoomEvent.userId, leftRoomEvent.roomId);
    } else {
      const kickedRoomEvent = getKickedRoomEvent(producedEvents);
      if (kickedRoomEvent) {
        // find sockets that match room and userId ( for the kicked user, not the kicking user )
        registry.removeMatchingSocketMappings(
          kickedRoomEvent.payload.userId,
          kickedRoomEvent.roomId
        );
      }
    }
  }

  function getJoinedRoomEvent(producedEvents) {
    if (!producedEvents) {
      return undefined;
    }
    return producedEvents.find((e) => e.name === 'joinedRoom');
  }

  function getLeftRoomEvent(producedEvents) {
    if (!producedEvents) {
      return undefined;
    }
    return producedEvents.find((e) => e.name === 'leftRoom');
  }

  function getKickedRoomEvent(producedEvents) {
    if (!producedEvents) {
      return undefined;
    }
    return producedEvents.find((e) => e.name === 'kicked');
  }

  /**
   * lookup of already set userId for given socket.
   * if no match found, check if it is the special case of a "joinRoom" command.
   * this is the only command where the client can preset a userId.
   * If it is present, use it, otherwise generate a new unique userId.
   *
   * @param {string} socketId
   * @param msg
   * @return {string} the userId
   */
  function getUserIdForMessage(socketId, msg) {
    const mapping = registry.getMapping(socketId);
    if (mapping && mapping.userId) {
      return mapping.userId;
    }

    if (msg.name === 'joinRoom' && msg.payload && msg.payload.userId) {
      return msg.payload.userId;
    }

    const newUserId = uuid();
    LOGGER.warn(`New userId ${newUserId} generated for socket ${socketId}. msg.name=${msg.name}`);
    return newUserId;
  }

  /**
   * send produced events to all sockets in room
   * @param producedEvents
   * @param roomId
   */
  function sendEvents(producedEvents, roomId) {
    producedEvents.forEach((producedEvent) => sendEventToRoom(roomId, producedEvent));
  }

  /**
   * If command processing failed, we send a "commandRejected" event to the client that issued the command.
   * (not sent to all sockets in the room)
   *
   */
  function handleCommandProcessingError(error, command, socket) {
    LOGGER.error(error.message);

    // for debugging, you might want to log error.stack  LOGGER.error(error.message + '\n' + error.stack);

    const commandRejectedEvent = {
      name: 'commandRejected',
      id: uuid(),
      correlationId: command.id,
      roomId: command.roomId,
      payload: {
        command: command,
        reason: error.message
      }
    };

    // command rejected event is only sent to the one socket that sent the command
    socket.emit('event', commandRejectedEvent);
  }

  /**
   * if the socket is disconnected (e.g. user closed browser tab), manually produce and handle
   * a "leaveRoom" command that will mark the user.
   */
  async function onDisconnect(socket) {
    // socket.rooms is at this moment already emptied
    const mapping = registry.getMapping(socket.id);

    if (!mapping) {
      // this happens if user is on landing page, socket is opened, then leaves, never joined a room. perfectly fine.
      LOGGER.debug(`Socket ${socket.id} disconnected. no mapping...`);
      return;
    }

    const {userId, roomId} = mapping;

    LOGGER.debug(
      `Socket ${socket.id} disconnected. Socket is currently mapping to user ${userId} in room ${roomId}`
    );

    if (registry.isLastSocketForUserId(userId)) {
      const leaveRoomCommand = {
        id: uuid(),
        roomId: roomId,
        name: 'leaveRoom',
        payload: {
          connectionLost: true // user did not send "leaveRoom" command manually. But connection was lost (e.g. browser closed)
        }
      };
      await handleIncomingCommand(socket, leaveRoomCommand);
    } else {
      LOGGER.debug(
        `User ${userId} in room ${roomId}, has more open sockets. Removing mapping for socket ${socket.id}`
      );
      registry.removeSocketMapping(socket.id, userId, roomId);
    }
  }
}
<commit_msg>#58 "downgrade" logging messages in socketManager.js command processing errors as warnings.<commit_after>import {v4 as uuid} from 'uuid';

import getLogger from './getLogger';
import socketRegistryFactory from './socketRegistry';

const LOGGER = getLogger('socketManager');

/**
 *
 * @param commandProcessor
 * @param {function} sendEventToRoom
 * @param {function} removeSocketFromRoomByIds
 */
export default function socketManagerFactory(
  commandProcessor,
  sendEventToRoom,
  removeSocketFromRoomByIds
) {
  const registry = socketRegistryFactory(removeSocketFromRoomByIds);

  return {
    handleIncomingCommand,
    onDisconnect
  };

  async function handleIncomingCommand(socket, msg) {
    const matchingUserId = getUserIdForMessage(socket.id, msg);

    try {
      const {producedEvents} = await commandProcessor(msg, matchingUserId);

      if (!producedEvents) {
        return;
      }

      updateSocketRegistryJoining(matchingUserId, producedEvents, socket);

      sendEvents(producedEvents, producedEvents[0].roomId);

      updateSocketRegistryLeaving(matchingUserId, producedEvents, socket);
    } catch (commandProcessingError) {
      handleCommandProcessingError(commandProcessingError, msg, socket);
    }
  }

  function updateSocketRegistryJoining(userId, producedEvents, socket) {
    const joinedRoomEvent = getJoinedRoomEvent(producedEvents);
    if (joinedRoomEvent) {
      registry.registerSocketMapping(socket, userId, joinedRoomEvent.roomId);
    }
  }

  function updateSocketRegistryLeaving(userId, producedEvents, socket) {
    const leftRoomEvent = getLeftRoomEvent(producedEvents);
    if (leftRoomEvent) {
      registry.removeSocketMapping(socket.id, leftRoomEvent.userId, leftRoomEvent.roomId);
    } else {
      const kickedRoomEvent = getKickedRoomEvent(producedEvents);
      if (kickedRoomEvent) {
        // find sockets that match room and userId ( for the kicked user, not the kicking user )
        registry.removeMatchingSocketMappings(
          kickedRoomEvent.payload.userId,
          kickedRoomEvent.roomId
        );
      }
    }
  }

  function getJoinedRoomEvent(producedEvents) {
    if (!producedEvents) {
      return undefined;
    }
    return producedEvents.find((e) => e.name === 'joinedRoom');
  }

  function getLeftRoomEvent(producedEvents) {
    if (!producedEvents) {
      return undefined;
    }
    return producedEvents.find((e) => e.name === 'leftRoom');
  }

  function getKickedRoomEvent(producedEvents) {
    if (!producedEvents) {
      return undefined;
    }
    return producedEvents.find((e) => e.name === 'kicked');
  }

  /**
   * lookup of already set userId for given socket.
   * if no match found, check if it is the special case of a "joinRoom" command.
   * this is the only command where the client can preset a userId.
   * If it is present, use it, otherwise generate a new unique userId.
   *
   * @param {string} socketId
   * @param msg
   * @return {string} the userId
   */
  function getUserIdForMessage(socketId, msg) {
    const mapping = registry.getMapping(socketId);
    if (mapping && mapping.userId) {
      return mapping.userId;
    }

    if (msg.name === 'joinRoom' && msg.payload && msg.payload.userId) {
      return msg.payload.userId;
    }

    const newUserId = uuid();
    LOGGER.warn(`New userId ${newUserId} generated for socket ${socketId}. msg.name=${msg.name}`);
    return newUserId;
  }

  /**
   * send produced events to all sockets in room
   * @param producedEvents
   * @param roomId
   */
  function sendEvents(producedEvents, roomId) {
    producedEvents.forEach((producedEvent) => sendEventToRoom(roomId, producedEvent));
  }

  /**
   * If command processing failed, we send a "commandRejected" event to the client that issued the command.
   * (not sent to all sockets in the room)
   *
   */
  function handleCommandProcessingError(error, command, socket) {
    // for debugging, you might want to log error.stack  LOGGER.error(error.message + '\n' + error.stack);
    LOGGER.warn(error.message);

    const commandRejectedEvent = {
      name: 'commandRejected',
      id: uuid(),
      correlationId: command.id,
      roomId: command.roomId,
      payload: {
        command: command,
        reason: error.message
      }
    };

    // command rejected event is only sent to the one socket that sent the command
    socket.emit('event', commandRejectedEvent);
  }

  /**
   * if the socket is disconnected (e.g. user closed browser tab), manually produce and handle
   * a "leaveRoom" command that will mark the user.
   */
  async function onDisconnect(socket) {
    // socket.rooms is at this moment already emptied
    const mapping = registry.getMapping(socket.id);

    if (!mapping) {
      // this happens if user is on landing page, socket is opened, then leaves, never joined a room. perfectly fine.
      LOGGER.debug(`Socket ${socket.id} disconnected. no mapping...`);
      return;
    }

    const {userId, roomId} = mapping;

    LOGGER.debug(
      `Socket ${socket.id} disconnected. Socket is currently mapping to user ${userId} in room ${roomId}`
    );

    if (registry.isLastSocketForUserId(userId)) {
      const leaveRoomCommand = {
        id: uuid(),
        roomId: roomId,
        name: 'leaveRoom',
        payload: {
          connectionLost: true // user did not send "leaveRoom" command manually. But connection was lost (e.g. browser closed)
        }
      };
      await handleIncomingCommand(socket, leaveRoomCommand);
    } else {
      LOGGER.debug(
        `User ${userId} in room ${roomId}, has more open sockets. Removing mapping for socket ${socket.id}`
      );
      registry.removeSocketMapping(socket.id, userId, roomId);
    }
  }
}
<|endoftext|>


<commit_before>//DaisyGame
function daisyGame(number){if(number % 2 === 0){ return 'Love me not'} else return 'Love me';};

//Maior Texto
function maiorText(palavras){
  var maior = "";
  for(var palavra in palavras){
      if(maior.length < palavras[palavra].length){
          maior = palavras[palavra];
      }
  }
  return maior;
  }

//Instrutor Querido
function imprime(e, fn){
  if(typeof fn === 'function'){
   for(var instrutor in e){
      fn(e[instrutor]);
   }
  }
  else{
    console.log('TypeError: second value is not a function');
  }
};

//Soma Diferentona
<commit_msg>feat(lista-js-basico): adicionar resolução dos exercicios de js dia01.<commit_after>//DaisyGame
function daisyGame(number) { if (number % 2 === 0) { return 'Love me not' } else return 'Love me'; };

//Maior Texto
function maiorText(palavras) {
  var maior = "";
  for (var palavra in palavras) {
    if (maior.length < palavras[palavra].length) {
      maior = palavras[palavra];
    }
  }
  return maior;
}

//Instrutor Querido
function imprime(e, fn) {
  if (typeof fn === 'function') {
    for (var instrutor in e) {
      fn(e[instrutor]);
    }
  }
  else {
    console.log('TypeError: second value is not a function');
  }
};

//Soma Diferentona
function soma(numeroUm) {
  return function (numeroDois) {
    return numeroUm + numeroDois;
  };
}

//fibona
function fiboSum(number) {
  if (number == 0) {
    return 0;
  }
  if (number <= 2) {
    return 1;
  }
  return fiboSum(number - 1) + fiboSum(number - 2);
}

//queroCafe
function queroCafe(mascada, precos) {
  var precosAteMascada = " ";
  precos.sort();
  for (var i in precos) {
    if (precos[i] <= mascada) {
      precosAteMascada += precos[i].toString() + ",";
    }
  }
  return precosAteMascada;
}

//variosTipos ---------------- Deve ter uma forma mais facil!!!!
/*function contarPorTipo(obj, tipo){
    var soma = 0;
    var tipoValidacao = 0;
    if(tipo === 'null'){
       tipoValidacao = 3;
    }
    if(tipo === 'array'){
       tipoValidacao = 2;
    }
    if(tipo === 'object'){
       tipoValidacao = 1;
    }
    for(var atributo in obj){
       if(tipoValidacao === 1){
          if(obj[atributo].constructor === Object){
              soma++;
          }
       }
       else if(tipoValidacao === 2){
          if(obj[atributo].constructor === Array){
              soma++;
          }
       }
       else if(tipoValidacao ===3){
          if(obj[atributo] === null && typeof obj[atributo] === "object"){
              soma++;
          }
       }
       else
          if(typeof obj[atributo] === tipo){
              soma++;
          }
    }
    return soma;
}*/

function contarPorTipo(objeto, tipo) {

  var count = 0;

  for (var campo in objeto) {

    if (

      (tipo === 'array' && objeto[campo] && objeto[campo].constructor === Array) ||

      (tipo === 'null' && objeto[campo] === null) ||

      (typeof objeto[campo] === tipo) && (tipo == 'object' && objeto[campo].constructor === Object)

    )

      count++;

  }

  return count;

};

//Exercício 8
/* O motivo de retornar Son undefined é que, na atribuição - var gohan = 'Son ' + gohan; - se declara uma variavel do tipo local gohan, essa sem valor. A mesma é utilizada na concatenação.
   Se o valor de gohan fosse passado por parametro e utilizado então na função, tal erro nao aconteceria.*/<|endoftext|>


<commit_before>/* jshint -W097 */
/* jshint strict:false */
/* jslint node: true */
/* jshint expr: true */
var expect = require('chai').expect;
var fs        = require('fs');

describe('Test package.json and io-package.json', function() {
    it('Test package files', function (done) {
        console.log();

        var fileContentIOPackage = fs.readFileSync(__dirname + '/../io-package.json', 'utf8');
        var ioPackage = JSON.parse(fileContentIOPackage);

        var fileContentNPMPackage = fs.readFileSync(__dirname + '/../package.json', 'utf8');
        var npmPackage = JSON.parse(fileContentNPMPackage);

        expect(ioPackage).to.be.an('object');
        expect(npmPackage).to.be.an('object');

        expect(ioPackage.common.version, 'ERROR: Version number in io-package.json needs to exist').to.exist;
        expect(npmPackage.version, 'ERROR: Version number in package.json needs to exist').to.exist;

        expect(ioPackage.common.version, 'ERROR: Version numbers in package.json and io-package.json needs to match').to.be.equal(npmPackage.version);

        if (!ioPackage.common.news || !ioPackage.common.news[ioPackage.common.version]) {
            console.log('WARNING: No news entry for current version exists in io-package.json, no rollback in Admin possible!');
            console.log();
        }

        expect(npmPackage.author, 'ERROR: Author in package.json needs to exist').to.exist;
        expect(ioPackage.common.authors, 'ERROR: Authors in io-package.json needs to exist').to.exist;

        if (ioPackage.common.name.indexOf('template') !== 0) {
            if (Array.isArray(ioPackage.common.authors)) {
                expect(ioPackage.common.authors.length, 'ERROR: Author in io-package.json needs to be set').to.not.be.equal(0);
                if (ioPackage.common.authors.length === 1) {
                    expect(ioPackage.common.authors[0], 'ERROR: Author in io-package.json needs to be a real name').to.not.be.equal('my Name <my@email.com>');
                }
            }
            else {
                expect(ioPackage.common.authors, 'ERROR: Author in io-package.json needs to be a real name').to.not.be.equal('my Name <my@email.com>');
            }
        }
        else {
            console.log('WARNING: Testing for set authors field in io-package skipped because template adapter');
            console.log();
        }
        expect(fs.existsSync(__dirname + '/../README.md'), 'ERROR: README.md needs to exist! Please create one with description, detail information and changelog. English is mandatory.').to.be.true;
        expect(fs.existsSync(__dirname + '/../LICENSE'), 'ERROR: LICENSE needs to exist! Please create one.').to.be.true;
        if (!ioPackage.common.titleLang || typeof ioPackage.common.titleLang !== 'object') {
            console.log('WARNING: titleLang is not existing in io-package.json. Please add');
            console.log();
        }
        if (
            ioPackage.common.title.indexOf('iobroker') !== -1 ||
            ioPackage.common.title.indexOf('ioBroker') !== -1 ||
            ioPackage.common.title.indexOf('adapter') !== -1 ||
            ioPackage.common.title.indexOf('Adapter') !== -1
        ) {
            console.log('WARNING: title contains Adapter or ioBroker. It is clear anyway, that it is adapter for ioBroker.');
            console.log();
        }

        if (ioPackage.common.name.indexOf('vis-') !== 0) {
            if (!ioPackage.common.materialize || !fs.existsSync(__dirname + '/../admin/index_m.html') || !fs.existsSync(__dirname + '/../gulpfile.js')) {
                console.log('WARNING: Admin3 support is missing! Please add it');
                console.log();
            }
            if (ioPackage.common.materialize) {
                expect(fs.existsSync(__dirname + '/../admin/index_m.html'), 'Admin3 support is enabled in io-package.json, but index_m.html is missing!').to.be.true;
            }
        }

        expect(fs.existsSync(__dirname + '/../LICENSE'), 'A LICENSE must exist');
        var fileContentReadme = fs.readFileSync(__dirname + '/../README.md', 'utf8');
        if (fileContentReadme.indexOf('## License') === -1) {
            console.log('Warning: The README.md should have a section ## License');
            console.log();
        }
        if (fileContentReadme.indexOf('## Changelog') === -1) {
            console.log('Warning: The README.md should have a section ## Changelog');
            console.log();
        }
        done();
    });
});
<commit_msg>update basic package-file testing<commit_after>/* jshint -W097 */
/* jshint strict:false */
/* jslint node: true */
/* jshint expr: true */
var expect = require('chai').expect;
var fs        = require('fs');

describe('Test package.json and io-package.json', function() {
    it('Test package files', function (done) {
        console.log();

        var fileContentIOPackage = fs.readFileSync(__dirname + '/../io-package.json', 'utf8');
        var ioPackage = JSON.parse(fileContentIOPackage);

        var fileContentNPMPackage = fs.readFileSync(__dirname + '/../package.json', 'utf8');
        var npmPackage = JSON.parse(fileContentNPMPackage);

        expect(ioPackage).to.be.an('object');
        expect(npmPackage).to.be.an('object');

        expect(ioPackage.common.version, 'ERROR: Version number in io-package.json needs to exist').to.exist;
        expect(npmPackage.version, 'ERROR: Version number in package.json needs to exist').to.exist;

        expect(ioPackage.common.version, 'ERROR: Version numbers in package.json and io-package.json needs to match').to.be.equal(npmPackage.version);

        if (!ioPackage.common.news || !ioPackage.common.news[ioPackage.common.version]) {
            console.log('WARNING: No news entry for current version exists in io-package.json, no rollback in Admin possible!');
            console.log();
        }

        expect(npmPackage.author, 'ERROR: Author in package.json needs to exist').to.exist;
        expect(ioPackage.common.authors, 'ERROR: Authors in io-package.json needs to exist').to.exist;

        if (ioPackage.common.name.indexOf('template') !== 0) {
            if (Array.isArray(ioPackage.common.authors)) {
                expect(ioPackage.common.authors.length, 'ERROR: Author in io-package.json needs to be set').to.not.be.equal(0);
                if (ioPackage.common.authors.length === 1) {
                    expect(ioPackage.common.authors[0], 'ERROR: Author in io-package.json needs to be a real name').to.not.be.equal('my Name <my@email.com>');
                }
            }
            else {
                expect(ioPackage.common.authors, 'ERROR: Author in io-package.json needs to be a real name').to.not.be.equal('my Name <my@email.com>');
            }
        }
        else {
            console.log('WARNING: Testing for set authors field in io-package skipped because template adapter');
            console.log();
        }
        expect(fs.existsSync(__dirname + '/../README.md'), 'ERROR: README.md needs to exist! Please create one with description, detail information and changelog. English is mandatory.').to.be.true;
        expect(fs.existsSync(__dirname + '/../LICENSE'), 'ERROR: LICENSE needs to exist! Please create one.').to.be.true;
        if (!ioPackage.common.titleLang || typeof ioPackage.common.titleLang !== 'object') {
            console.log('WARNING: titleLang is not existing in io-package.json. Please add');
            console.log();
        }
        if (
            ioPackage.common.title.indexOf('iobroker') !== -1 ||
            ioPackage.common.title.indexOf('ioBroker') !== -1 ||
            ioPackage.common.title.indexOf('adapter') !== -1 ||
            ioPackage.common.title.indexOf('Adapter') !== -1
        ) {
            console.log('WARNING: title contains Adapter or ioBroker. It is clear anyway, that it is adapter for ioBroker.');
            console.log();
        }

        if (ioPackage.common.name.indexOf('vis-') !== 0) {
            if (!ioPackage.common.materialize || !fs.existsSync(__dirname + '/../admin/index_m.html') || !fs.existsSync(__dirname + '/../gulpfile.js')) {
                console.log('WARNING: Admin3 support is missing! Please add it');
                console.log();
            }
            if (ioPackage.common.materialize) {
                expect(fs.existsSync(__dirname + '/../admin/index_m.html'), 'Admin3 support is enabled in io-package.json, but index_m.html is missing!').to.be.true;
            }
        }

        var licenseFileExists = fs.existsSync(__dirname + '/../LICENSE');
        var fileContentReadme = fs.readFileSync(__dirname + '/../README.md', 'utf8');
        if (fileContentReadme.indexOf('## Changelog') === -1) {
            console.log('Warning: The README.md should have a section ## Changelog');
            console.log();
        }
        expect((licenseFileExists || fileContentReadme.indexOf('## License') !== -1), 'A LICENSE must exist as LICENSE file or as part of the README.md').to.be.true;
        if (!licenseFileExists) {
            console.log('Warning: The License should also exist as LICENSE file');
            console.log();
        }
        if (fileContentReadme.indexOf('## License') === -1) {
            console.log('Warning: The README.md should also have a section ## License to be shown in Admin3');
            console.log();
        }
        done();
    });
});
<|endoftext|>


<commit_before>/////////////////////////////////////////////////////////////////////
// Copyright (c) Autodesk, Inc. All rights reserved
// Written by Forge Partner Development
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE.  AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
/////////////////////////////////////////////////////////////////////

'use strict'; // http://www.w3schools.com/js/js_strict.asp

// token handling in session
var Credentials = require('./../../credentials');
// forge config information, such as client ID and secret
var config = require('./../../config');

// web framework
var express = require('express');
var router = express.Router();
// box sdk: https://github.com/box/box-node-sdk/
var BoxSDK = require('box-node-sdk');

router.get('/api/storage/tree', function (req, res) {
  var token = new Credentials(req.session);
  var credentials = token.getStorageCredentials();
  if (credentials === undefined) {
    res.status(401).end();
    return;
  }

  var sdk = new BoxSDK({
    clientID: config.storage.credentials.client_id, // required
    clientSecret: config.storage.credentials.client_secret // required
  });

  var box = sdk.getBasicClient(credentials.accessToken);
  var id = (req.query.id === '#' ? '0' : req.query.id);

  box.folders.getItems(id, {fields: 'name,shared_link,permissions,collections,sync_state'}, function (err, data) {
    if (data == null || data.entries == null) return '';
    var items = [];
    data.entries.forEach(function (item, index) {
      var item = {
        id: item.id,
        text: item.name,
        type: item.type,
        children: (item.type === 'folder')
      };
      if (item.type === 'folder') item.type = 'folders';// required for the common ground
      items.push(item);
    });
    res.json(items);
  });
});

module.exports = router;<commit_msg>box folder list limit<commit_after>/////////////////////////////////////////////////////////////////////
// Copyright (c) Autodesk, Inc. All rights reserved
// Written by Forge Partner Development
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE.  AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
/////////////////////////////////////////////////////////////////////

'use strict'; // http://www.w3schools.com/js/js_strict.asp

// token handling in session
var Credentials = require('./../../credentials');
// forge config information, such as client ID and secret
var config = require('./../../config');

// web framework
var express = require('express');
var router = express.Router();
// box sdk: https://github.com/box/box-node-sdk/
var BoxSDK = require('box-node-sdk');

router.get('/api/storage/tree', function (req, res) {
  var token = new Credentials(req.session);
  var credentials = token.getStorageCredentials();
  if (credentials === undefined) {
    res.status(401).end();
    return;
  }

  var sdk = new BoxSDK({
    clientID: config.storage.credentials.client_id, // required
    clientSecret: config.storage.credentials.client_secret // required
  });

  var box = sdk.getBasicClient(credentials.accessToken);
  var id = (req.query.id === '#' ? '0' : req.query.id);

  box.folders.getItems(id, {fields: 'name,shared_link,permissions,collections,sync_state', limit: 1000}, function (err, data) {
    if (data == null || data.entries == null) return '';
    var items = [];
    data.entries.forEach(function (item, index) {
      var item = {
        id: item.id,
        text: item.name,
        type: item.type,
        children: (item.type === 'folder')
      };
      if (item.type === 'folder') item.type = 'folders';// required for the common ground
      items.push(item);
    });
    res.json(items);
  });
});

module.exports = router;<|endoftext|>


<commit_before>angular
	.module('exporter', ['ui','indx'])
	.controller('main', function($scope, client, utils) {
		var box, u = utils;
		$scope.objs = [];
		$scope.format = 'json';
		$scope.$watch('selectedBox + selectedUser', function() {
			if ($scope.selectedUser && $scope.selectedBox) {
				console.log('getting box', $scope.selectedBox);
				client.store.getBox($scope.selectedBox).then(function(b) {
					box = b;
					$scope.objs = b.getObjIDs();
				}).fail(function(e) { u.error('error ', e); });
			}
		});

		var setWait = function(b) {
			console.log
			u.safeApply($scope, function() { $scope.wait = b;	});
		};

		$scope.doSave = function() {
			setWait(true);
			return $scope.save().pipe(function() { setWait(false); });
		};

		$scope.save = function() {
			var dd = u.deferred();
			console.log("box has : ", $scope.objs.length);
			console.log("the format : ", $scope.format);

			// box.getObj($scope.objs).then(function(objects) {
			// 	u.safeApply($scope, function() {
			// 		$scope.boxData = $scope.serializers[$scope.format](objects);
			// 		$scope.fileext = file_formats[$scope.format];
			// 	});
			// 	dd.resolve();
			// }).fail(dd.reject);
			box.query({}, "*").then(function(response) {
				objects = response["data"];
				u.safeApply($scope, function() {
					$scope.boxData = $scope.serializers[$scope.format](objects);
					$scope.fileext = file_formats[$scope.format];
				});
				dd.resolve();
			}).fail(dd.reject);

			return dd.promise();
		};

		$scope.toFile = function() {
			saveAs(new Blob([$scope.boxData], {type: "text/plain"}), $scope.filename || $scope.selectedBox+"."+$scope.fileext );
		};

		$scope.isIdOfOther = function(s) {
			if ($scope.objs.indexOf(s) !== -1) {
				return true;
			}
			return false;
		};

		$scope.createContextObj = function() {

		};

		var parseValue = function(val) {
			console.log("parsing value ", val);
			if (Array.isArray(val)) {
				return val.map(function(o) {
					if (o.hasOwnProperty("@id")) {
						return o["@id"];
					}
					if (o.hasOwnProperty("@value")) {
						console.log(o["@type"]);
						return literalDeserialisers[o["@type"]](o["@value"]);
					}
				});
			} else {
				return val;
			}
		};
		var literalDeserialisers = {
			'': function(v) { return v; },
			"http://www.w3.org/2001/XMLSchema#integer": function(v) { return parseInt(v, 10); },
			"http://www.w3.org/2001/XMLSchema#float": function(v) { return parseFloat(v, 10); },
			"http://www.w3.org/2001/XMLSchema#double": function(v) { return parseFloat(v, 10); },
			"http://www.w3.org/2001/XMLSchema#boolean": function(v) { return v.toLowerCase() === 'true'; },
			"http://www.w3.org/2001/XMLSchema#dateTime": function(v) { return new Date(Date.parse(v)); }
		};

		$scope.serializers = {
			'json' : function(obs) {
				console.log("serializing list to json");
				ids = Object.keys(obs);
				newobs = ids.map(function(oid) {
					console.log("processing object ",obs[oid]);
					obj = obs[oid];
					newobj = {};
					keys = Object.keys(obj);
					for (i in keys) {
						newobj[keys[i]] = parseValue(obj[keys[i]]);
					}
					return newobj;
				});
				return JSON.stringify(newobs);
			},
			'jsonld' : function(obs) {
				console.log("serializing list to json-ld");
				// create a context for the list, containing as base/vocab? the url of the server/box
				context = $scope.createContextObj();
				// save the box as a graph? with @graph? or not needed ...

				return ['[',obs.join(',\n'),']'].join('\n');
			},
			'turtle' : function(obs) {
				console.log("serializing list to turtle");
				// return toTurtle(obs);
			},
			'csv' : function(obs) {
				console.log("serializing list to csv");
				// return toCSV(obs);
			}
		};
		var file_formats = {
			'json' : 'json',
			'jsonld' : 'jsonld',
			'turtle' : 'ttl'
		};

	});
<commit_msg>csv and json-ld and turtle export<commit_after>angular
	.module('exporter', ['ui','indx'])
	.controller('main', function($scope, client, utils) {
		var box, u = utils;
		$scope.objs = [];
		$scope.format = 'json';
		$scope.$watch('selectedBox + selectedUser', function() {
			if ($scope.selectedUser && $scope.selectedBox) {
				console.log('getting box', $scope.selectedBox);
				client.store.getBox($scope.selectedBox).then(function(b) {
					box = b;
					$scope.objs = b.getObjIDs();
				}).fail(function(e) { u.error('error ', e); });
			}
		});

		var setWait = function(b) {
			console.log
			u.safeApply($scope, function() { $scope.wait = b;	});
		};

		$scope.doSave = function() {
			setWait(true);
			return $scope.save().pipe(function() { setWait(false); });
		};

		$scope.save = function() {
			var dd = u.deferred();
			console.log("box has : ", $scope.objs.length);
			console.log("the format : ", $scope.format);

			// box.getObj($scope.objs).then(function(objects) {
			// 	u.safeApply($scope, function() {
			// 		$scope.boxData = $scope.serializers[$scope.format](objects);
			// 		$scope.fileext = file_formats[$scope.format];
			// 	});
			// 	dd.resolve();
			// }).fail(dd.reject);
			box.query({}, "*").then(function(response) {
				objects = response["data"];
				u.safeApply($scope, function() {
					$scope.boxData = $scope.serializers[$scope.format](objects);
					$scope.fileext = file_formats[$scope.format];
				});
				dd.resolve();
			}).fail(dd.reject);

			return dd.promise();
		};

		$scope.toFile = function() {
			saveAs(new Blob([$scope.boxData], {type: "text/plain"}), $scope.filename || $scope.selectedBox+"."+$scope.fileext );
		};

		$scope.isIdOfOther = function(s) {
			if ($scope.objs.indexOf(s) !== -1) {
				return true;
			}
			return false;
		};

		$scope.createContextObj = function() {
			context = {};
			// what is the box url in indx?
			context["vocab"]=client.store.get('server_host')+"/box/"+$scope.selectedBox+"/";
			// what else should go in context?
			return context
		};

		var parseValue = function(val) {
			console.log("parsing value ", val);
			if (Array.isArray(val)) {
				return val.map(function(o) {
					if (o.hasOwnProperty("@id")) {
						return o["@id"];
					}
					if (o.hasOwnProperty("@value")) {
						console.log(o["@type"]);
						return literalDeserialisers[o["@type"]](o["@value"]);
					}
				});
			} else {
				return val;
			}
		};
		var literalDeserialisers = {
			'': function(v) { return v; },
			"http://www.w3.org/2001/XMLSchema#integer": function(v) { return parseInt(v, 10); },
			"http://www.w3.org/2001/XMLSchema#float": function(v) { return parseFloat(v, 10); },
			"http://www.w3.org/2001/XMLSchema#double": function(v) { return parseFloat(v, 10); },
			"http://www.w3.org/2001/XMLSchema#boolean": function(v) { return v.toLowerCase() === 'true'; },
			"http://www.w3.org/2001/XMLSchema#dateTime": function(v) { return new Date(Date.parse(v)); }
		};

		$scope.serializers = {
			'json' : function(obs) {
				console.log("serializing list to json");
				ids = Object.keys(obs);
				newobs = ids.map(function(oid) {
					console.log("processing object ",obs[oid]);
					obj = obs[oid];
					newobj = {};
					keys = Object.keys(obj);
					for (i in keys) {
						newobj[keys[i]] = parseValue(obj[keys[i]]);
					}
					return newobj;
				});
				return JSON.stringify(newobs);
			},
			'jsonld' : function(obs) {
				console.log("serializing list to json-ld");
				// create a context for the list, containing as base/vocab? the url of the server/box
				out = {}
				out["@context"] = $scope.createContextObj();
				// save the box as a graph? with @graph? or not needed ...
				ids = Object.keys(obs);
				out["@graph"] = ids.map(function(oid) {
					console.log("processing object ",obs[oid]);
					obj = obs[oid];
					newobj = {};
					keys = Object.keys(obj);
					for (i in keys) {
						key = keys[i];
						val = obj[keys[i]];
						if (Array.isArray(val)) {
							newVal = val.map(function(o) {
								if (o.hasOwnProperty("@id")) {
									return {"@id":o["@id"]};
								} else {
									return o;
								}
							});
							newobj[key] = newVal;
						} else {
							newobj[key] = val;
						}
					}
					return newobj;
				});
				return JSON.stringify(out);
			},
			'turtle' : function(obs) {
				console.log("serializing list to turtle");
				defaultPrefix = "@prefix : <"+client.store.get('server_host')+"/box/"+$scope.selectedBox+"/"+"> .\n";
				indxPrefix = "@prefix indx: <http://sociam.org/ontology/indx/> .\n";
				return defaultPrefix + indxPrefix + "\n"+ toTurtle(obs);
			},
			'csv' : function(obs) {
				console.log("serializing list to csv");
				return toCSV(obs);
			}
		};

		var toCSV = function(obs) {
			ids = Object.keys(obs);
			cols=["@id"]
			ids.map(function(oid) {
				keys = Object.keys(obs[oid]);
				for (i in keys) {
					key = keys[i];
					if (cols.indexOf(key) == -1) {
						cols.push(key);
					}
				}
			});
			console.log(cols);
			rows = ids.map(function(oid) {
				obj = obs[oid];
				row = [];
				for (i in cols) {
					if (obj.hasOwnProperty(cols[i])) {
						val = parseValue(obj[cols[i]]);
						if (Array.isArray(val) && (val.length > 1)) {
							row.push('"['+val.toString()+']"');
						} else {
							row.push('"'+val.toString()+'"');
						}
					} else {
						row.push("");
					}
				}
				return row;
			});
			return cols + "\n" +rows.join("\n");
		};

		var toTurtle = function(obs) {
			ids = Object.keys(obs);
			triples = ids.map(function(oid) {
				obj = obs[oid];
				objTriples = [":"+oid+" a indx:Object"];
				keys = Object.keys(obj);
				for (i in keys) {
					key = keys[i];
					if (key != "@id") {
						console.log(obj[key]);
						val = parseValue(obj[key]);
						console.log(val);
						// if (Array.isArray(val) && (val.length > 1)) {
						// 	objTriples.push("\t :"+key + " :"+val.toString());
						// } else {
						// 	row.push('"'+val.toString()+'"');
						// }
					}
				}
				return objTriples.join(";") + " .";
			});
			return triples.join("\n");
		}

		var file_formats = {
			'json' : 'json',
			'jsonld' : 'jsonld',
			'turtle' : 'ttl',
			'csv' : 'csv'
		};

	});
<|endoftext|>


<commit_before>'use strict'

var util = require('util')

/**
 * Make custom error types that pass `instanceof` checks, have stack traces,
 * support custom messages and properties, and support wrapping errors (causes).
 *
 * @module
 */

//
// For ES6+ Classes
//

/**
 * A base class for custom errors that handles:
 *
 * 1. Wrapping an optional 'cause'.
 * 2. Storing an 'info' object with additional data.
 * 3. Setting the name to the subclass name.
 *
 * @extends Error
 */
class ErrorTypeError extends Error {
  /**
   * @param {string} message as for built-in Error
   * @param {?object} info extra data to attach to the error
   */
  constructor ({ message, info }) {
    super(message)
    this.name = this.constructor.name
    if (info) {
      this.info = info
    }
  }

  /**
   * Wrap the given error, which caused this error.
   *
   * @param {Error} cause
   * @return {this}
   */
  withCause (cause) {
    this.cause = cause
    if (this.message && cause.message) {
      this.message += ': ' + cause.message
    }
    return this
  }
}

/**
 * Base class for errors with a corresponding HTTP status code.
 *
 * @extends ErrorTypeError
 */
class ErrorWithStatusCode extends ErrorTypeError {
  /**
   * @param {?number} statusCode an HTTP status code
   * @param {object} options as for ErrorTypeError
   */
  constructor ({ statusCode, ...options }) {
    super(options)
    this.statusCode = statusCode || 500
  }
}
exports.ErrorWithStatusCode = ErrorWithStatusCode

/**
 * Return the `info` property from `error` and recursively merge the `info`
 * properties from the error's causes, if any.
 *
 * If a property is repeated, the first one in the cause chain wins.
 *
 * @param {?Error} error assumed not to have circular causes
 * @return {Object}
 */
function getFullInfo (error) {
  if (!error) return {}
  const info = getFullInfo(error.cause)
  if (typeof error.info === 'object') Object.assign(info, error.info)
  return info
}

/**
 * Return the `stack` property from `error` and recursively append the `stack`
 * properties from the error's causes, if any.
 *
 * @param {?Error} error assumed not to have circular causes
 * @return {string}
 */
function getFullStack (error) {
  if (!error) return ''
  const causeStack = getFullStack(error.cause)
  if (causeStack) return (error.stack + '\ncaused by: ' + causeStack)
  return error.stack
}

/**
 * Is `error` or one of its causes an instance of `klass`?
 *
 * @param  {?Error} error assumed not to have circular causes
 * @param  {function} klass
 * @return {Boolean}
 */
function hasCauseInstanceOf (error, klass) {
  if (!error) return false
  return error instanceof klass || hasCauseInstanceOf(error.cause, klass)
}

exports.Error = ErrorTypeError
exports.getFullInfo = getFullInfo
exports.getFullStack = getFullStack
exports.hasCauseInstanceOf = hasCauseInstanceOf

//
// For ES5
//

function extendErrorType (base, name, builder) {
  var errorConstructor = function () {
    Error.captureStackTrace && Error.captureStackTrace(this, this.constructor)
    if (builder) builder.apply(this, arguments)
    this.name = name
  }

  util.inherits(errorConstructor, base)

  errorConstructor.prototype.withCause = function (cause) {
    this.cause = cause
    if (this.message && cause.message) {
      this.message += ': ' + cause.message
    }
    return this
  }

  return errorConstructor
}

function defineErrorType (name, builder) {
  return extendErrorType(Error, name, builder)
}

function extendErrorTypeIn (container, base, name, builder) {
  container[name] = extendErrorType(base, name, builder)
}

function defineErrorTypeIn (container, name, builder) {
  extendErrorTypeIn(container, Error, name, builder)
}

exports.extend = extendErrorType
exports.define = defineErrorType
exports.extendIn = extendErrorTypeIn
exports.defineIn = defineErrorTypeIn
<commit_msg>remove ErrorWithStatusCode<commit_after>'use strict'

var util = require('util')

/**
 * Make custom error types that pass `instanceof` checks, have stack traces,
 * support custom messages and properties, and support wrapping errors (causes).
 *
 * @module
 */

//
// For ES6+ Classes
//

/**
 * A base class for custom errors that handles:
 *
 * 1. Wrapping an optional 'cause'.
 * 2. Storing an 'info' object with additional data.
 * 3. Setting the name to the subclass name.
 *
 * @extends Error
 */
class ErrorTypeError extends Error {
  /**
   * @param {string} message as for built-in Error
   * @param {?object} info extra data to attach to the error
   */
  constructor ({ message, info }) {
    super(message)
    this.name = this.constructor.name
    if (info) {
      this.info = info
    }
  }

  /**
   * Wrap the given error, which caused this error.
   *
   * @param {Error} cause
   * @return {this}
   */
  withCause (cause) {
    this.cause = cause
    if (this.message && cause.message) {
      this.message += ': ' + cause.message
    }
    return this
  }
}

/**
 * Return the `info` property from `error` and recursively merge the `info`
 * properties from the error's causes, if any.
 *
 * If a property is repeated, the first one in the cause chain wins.
 *
 * @param {?Error} error assumed not to have circular causes
 * @return {Object}
 */
function getFullInfo (error) {
  if (!error) return {}
  const info = getFullInfo(error.cause)
  if (typeof error.info === 'object') Object.assign(info, error.info)
  return info
}

/**
 * Return the `stack` property from `error` and recursively append the `stack`
 * properties from the error's causes, if any.
 *
 * @param {?Error} error assumed not to have circular causes
 * @return {string}
 */
function getFullStack (error) {
  if (!error) return ''
  const causeStack = getFullStack(error.cause)
  if (causeStack) return (error.stack + '\ncaused by: ' + causeStack)
  return error.stack
}

/**
 * Is `error` or one of its causes an instance of `klass`?
 *
 * @param  {?Error} error assumed not to have circular causes
 * @param  {function} klass
 * @return {Boolean}
 */
function hasCauseInstanceOf (error, klass) {
  if (!error) return false
  return error instanceof klass || hasCauseInstanceOf(error.cause, klass)
}

exports.Error = ErrorTypeError
exports.getFullInfo = getFullInfo
exports.getFullStack = getFullStack
exports.hasCauseInstanceOf = hasCauseInstanceOf

//
// For ES5
//

function extendErrorType (base, name, builder) {
  var errorConstructor = function () {
    Error.captureStackTrace && Error.captureStackTrace(this, this.constructor)
    if (builder) builder.apply(this, arguments)
    this.name = name
  }

  util.inherits(errorConstructor, base)

  errorConstructor.prototype.withCause = function (cause) {
    this.cause = cause
    if (this.message && cause.message) {
      this.message += ': ' + cause.message
    }
    return this
  }

  return errorConstructor
}

function defineErrorType (name, builder) {
  return extendErrorType(Error, name, builder)
}

function extendErrorTypeIn (container, base, name, builder) {
  container[name] = extendErrorType(base, name, builder)
}

function defineErrorTypeIn (container, name, builder) {
  extendErrorTypeIn(container, Error, name, builder)
}

exports.extend = extendErrorType
exports.define = defineErrorType
exports.extendIn = extendErrorTypeIn
exports.defineIn = defineErrorTypeIn
<|endoftext|>