<commit_before>"use strict"

var VolTextObject;
var map, annotationLayer;

var annotationChanges = 0
var selvol = "0"
var annotationClassesAndAppliers
var keyCodeActions

var recentLocations = []
var recentLocationsMaxLength = 5

$(document).ready(function() {
    // This handles selection in dataTable
    var table = $('#vol_table').DataTable();

    $('#vol_table tbody').on( 'click', 'tr', function () {
        if ( $(this).hasClass('selected') ) {
            $(this).removeClass('selected');
        }
        else {
            table.$('tr.selected').removeClass('selected');
            $(this).addClass('selected');
        }
    } );

    $('#button').click( function () {
        table.row('.selected').remove().draw( false );
    } );

    $("#col2text").on("cut copy paste", function(e) {
        e.preventDefault()
    })
    // Prevent changes in a content-editable div
    $("#col2text").on("keydown", function(e) {
        e = e || window.event;
        // Allow arrow keys, home, end, pgup, pgdn
        if (e.keyCode < 33 || e.keyCode > 40)
            e.preventDefault()
        keyCodeActions.forEach(function(action) {
            if (e.keyCode == action.code)
                action.action()
        })
    })
} );

var DeleteFeature = OpenLayers.Class(OpenLayers.Control, {
    initialize: function(layer, options) {
        OpenLayers.Control.prototype.initialize.apply(this, [options]);
        this.layer = layer;
        this.handler = new OpenLayers.Handler.Feature(
            this, layer, {click: this.clickFeature}
        );
    },
    clickFeature: function(feature) {
        // if feature doesn't have a fid, destroy it
        if(feature.fid == undefined) {
            this.layer.destroyFeatures([feature]);
        } else {
            feature.state = OpenLayers.State.DELETE;
            this.layer.events.triggerEvent("afterfeaturemodified",
                                           {feature: feature});
            feature.renderIntent = "select";
            this.layer.drawFeature(feature);
        }
    },
    setMap: function(map) {
        this.handler.setMap(map);
        OpenLayers.Control.prototype.setMap.apply(this, arguments);
    },
    CLASS_NAME: "OpenLayers.Control.DeleteFeature"
});

function getMapFeatures() {
    //var mLayers = map.layers;
    // var annLayer = map.getLayersByName("Annotations")
    var annLayer = annotationLayer

    var geoJSON = new OpenLayers.Format.GeoJSON()

    var jsonfeatsarr = annLayer.features.map(function(feature) {
        var layer_geom = feature.geometry.transform("EPSG:900913", "EPSG:4326")
        var geoJSONText = geoJSON.write(layer_geom)
        return geoJSONText
    })
    var jsonfeats = jsonfeatsarr.join("@@")
    // window.alert(jsonfeats)
    return jsonfeats
}

function jsonToMapFeatures(jsonstr) {
    var geoJSON = new OpenLayers.Format.GeoJSON()

    var jsonfeats = jsonstr.split("@@")
    // debugger
    var feats = jsonfeats.map(function(jsonfeat) {
        var geom = geoJSON.read(jsonfeat, "Geometry")
        var transformedGeom = geom.transform("EPSG:4326", "EPSG:900913")
        return new OpenLayers.Feature.Vector(transformedGeom)
    })
    return feats
}

function getSelectionNodes() {
    var selectionRange = getSelectionRange()
    return getRangeNodes(selectionRange, annotationClasses)
}

function getStoredMapFeatures(node) {
    return $.data(node, "features")
}

function setStoredMapFeatures(node, feats) {
    $.data(node, "features", feats)
}

function addMapFeaturesToSelection() {
    var jsonfeats = getMapFeatures()
    var rangenodes = getSelectionNodes()
    rangenodes.forEach(function(node) {
        setStoredMapFeatures(node, jsonfeats)
    })
    if (rangenodes.length > 0)
        addToRecentLocations(rangenodes[0].innerHTML.substring(0, 20), jsonfeats)
}

function zoomFeatures() {
    window.alert("Zoom Action Needed")
}

function populateRecentLocations() {
    var htmlarr = []
    for (var i = recentLocations.length - 1; i >= 0; i--) {
        var recentLoc = recentLocations[i]
        var html = '
' +
                     recentLoc.html + '
'
        console.log(html)
        htmlarr.push(html)
    }
    $('#recentlocs').html(htmlarr.join("\n"))
}

function addToRecentLocations(html, jsonfeats) {
    if (recentLocations.length >= recentLocationsMaxLength)
        recentLocations.slice(1)
    recentLocations.push({html: html, jsonfeats: jsonfeats})
    populateRecentLocations()
}

function locClicked(e) {
    alert($(e.target).attr('data-jsonfeats'))
}

// Save annotations in a serialized format.
function saveVolumeAnnotations() {
    // Fetch annotations
    var annotations = getAnnotations(annotationClasses)
    // Convert to an array of serialized annotations in the form "CLASS$START$END".
    var serialAnnotations = annotations.map(function(ann) {
        var jsonmapfeats = getStoredMapFeatures(ann.node) || ""
        return ann.node.className + "$" + ann.start + "$" + ann.end + "$" + jsonmapfeats
    })
    // Join to a single serialized string
    var serialString = serialAnnotations.join("|")
    var base64 = utf8ToB64(serialString);
    var parse_file = new Parse.File((annotUser + "-" + selvol +".txt"), { base64: base64 });
    // Save to Parse. First look for an existing entry for the user and volume.
    // If found, update it. Else create a new entry.
    var query = new Parse.Query(SpansObject)
    query.equalTo("user", annotUser)
    query.equalTo("vol", selvol)
    query.first().then(function(existing) {
        if (existing) {
            existing.set("spans", parse_file)
            return existing.save()
        } else {
            var spansObject = new SpansObject()
            return spansObject.save({"user":annotUser, "vol":selvol, "spans":parse_file})
        }
    }, savefailure("finding existing entry")
    ).then(savesuccess(function() {
        annotationChanges = 0
        logMessage("Saved " + annotations.length + " annotations")
    }),
        savefailure("saving new or updating existing entry"))
}

// Called from HTML. Save annotations. If saved successfully, reset list of
// article changes.
function saveAnnotations() {
    if (annotUser != "Default") {
        saveVolumeAnnotations()
    } else {
        logMessage("Please select a non-default Annotator Name prior prior to saving")
    }
}

// Load volume annotations
function loadVolumeAnnotations(results) {
    var textNode = getTextNode().childNodes[0]
    httpGet(results[0].get("spans").url(), function(spansText) {
        var spansSerialized = spansText.split("|")
        var spans = spansSerialized.map(function(span) {
            var splitSpan = span.split("$")
            var className = splitSpan[0]
            var start = splitSpan[1]
            var end = splitSpan[2]
            var jsonmapfeats = splitSpan[3]
            return {start: start, end: end, className: className, jsonmapfeats: jsonmapfeats}
        })
        spans.sort(function(a, b) { return b.start - a.start })
        for (var i = 0; i < spans.length; i++) {
            var span = spans[i]
            var range = rangy.createRange()
            range.setStartAndEnd(textNode, span.start, span.end)
            annotationClassesAndAppliers.forEach(function(ca) {
                if (span.className == ca.clazz) {
                    ca.applier.applyToRange(range)
                }
            })
            getRangeNodes(range, annotationClasses).forEach(function(node) {
                if (span.jsonmapfeats)
                    setStoredMapFeatures(node, span.jsonmapfeats)
            })
        }
    })
}

function closeDialog(node) {
    $(node).dialog("close")
}

function checkVol(tableSelector) {
    if (annotUser != "Default") {
        var table = $(tableSelector).DataTable()
        var ret = table.$('tr.selected')
        if (ret.length > 0) {
            var newvol = table.$('tr.selected').find('td:first').text()
            if (annotationChanges > 0) {
                $("
Do you want to save the existing annotations?
").dialog({
                    resizable: false,
                    modal: true,
                    buttons: {
                        "Yes": function() {
                            saveAnnotations()
                            loadVolumeText(newvol, SpansObject)
                            closeDialog(this)
                        },
                        "No": function() {
                            loadVolumeText(newvol, SpansObject)
                            closeDialog(this)
                        },
                        "Cancel": function() {
                            console.log("Canceled")
                            window.alert("FIXME: We should set the visibly selected volume to the old one")
                            closeDialog(this)
                        }
                    }
                })
            }
            loadVolumeText(newvol, SpansObject)
        }
    } else {
        logMessage("Please select a non-default Annotator name prior to loading a volume")
    }
}

function nameChangeAnnotator() {
    var el = document.getElementById("selectUserAnnotator");
    annotUser = el.options[el.selectedIndex].innerHTML;
}

function removeAnnotations() {
    annotationLayer.destroyFeatures()
    annotationClassesAndAppliers.forEach(function(ca) {
        ca.unapplier.undoToRange(makeRange(document.body))
    })
    annotationChanges = 0
}

function removeAnnotation() {
    var selectionRange = getSelectionRange()
    if (overlapsAnnotation(selectionRange, true, annotationClasses))
        logMessage("Selection contains part of an annotation")
    else {
        annotationClassesAndAppliers.forEach(function(ca) {
            ca.unapplier.undoToSelection()
        })
    }
}

function spanClick(element) {
    //window.alert("Clicked inside article")
    var range = rangy.createRange()
    range.selectNodeContents(element)
    var sel = rangy.getSelection()
    sel.setSingleRange(range)
    var jsonfeats = getStoredMapFeatures(element)
    // alert("GeoJSON: " + jsonfeats)
    annotationLayer.destroyFeatures()
    if (jsonfeats)
        annotationLayer.addFeatures(jsonToMapFeatures(jsonfeats))
}

function annotationFeatureChanged(event) {
    addMapFeaturesToSelection()
    // var bounds = event.feature.geometry.getBounds();
    // var answer = "bottom: " + bounds.bottom + "\n";
    // answer += "left: " + bounds.left + "\n";
    // answer += "right: " + bounds.right + "\n";
    // answer += "top: " + bounds.top + "\n";
    // alert("Feature modified: " + answer);
}

function commonMapInit() {
    var extent = new OpenLayers.Bounds(
        -12003508, 3009847, -9005759, 6557774
    );

    Parse.initialize("Dxi3BvGT3mHiDC7B1YjeEuiUQKtWIeQNofT5FIIx", "QG352rxcZvLrYeV4jOCsIZvM8mIeQyhvHzDNINAb");

    VolTextObject = Parse.Object.extend("VolumeText");

    rangy.init();

    var table = $('#vol_table').DataTable()
    var rows = getVolTableRows(table)

    map = new OpenLayers.Map('map', {
        projection: new OpenLayers.Projection("EPSG:900913"),
        displayProjection: new OpenLayers.Projection("EPSG:4326"),
        controls: [
            new OpenLayers.Control.PanZoom(),
            new OpenLayers.Control.Navigation(),
            new OpenLayers.Control.MousePosition({prefix: 'Long: ', separator: '  Lat: ', numDigits: 3, emptyString:''})
        ]
    });

    var gphy = new OpenLayers.Layer.Google(
        "Google Streets"
    );

    var saveStrategy = new OpenLayers.Strategy.Save();

    annotationLayer = new OpenLayers.Layer.Vector("Annotations", {
        strategies: [new OpenLayers.Strategy.BBOX(), saveStrategy],
        projection: new OpenLayers.Projection("EPSG:4326"),
        protocol : new OpenLayers.Protocol.HTTP({
                url : 'polygons.geojson',
                format : new OpenLayers.Format.GeoJSON()
            })
    })

    map.addLayers([gphy, annotationLayer]);

    annotationLayer.events.on({
        featureadded: annotationFeatureChanged,
        featuremodified: annotationFeatureChanged,
        featureremoved: annotationFeatureChanged
    })

    var panel = new OpenLayers.Control.Panel({
        displayClass: 'customEditingToolbar',
        allowDepress: true
    });

    var draw = new OpenLayers.Control.DrawFeature(
        annotationLayer, OpenLayers.Handler.Polygon,
        {
            title: "Draw Feature",
            displayClass: "olControlDrawFeaturePolygon",
            multi: true
        }
    );

    var edit = new OpenLayers.Control.ModifyFeature(annotationLayer, {
        title: "Modify Feature",
        displayClass: "olControlModifyFeature"
    });

    var del = new DeleteFeature(annotationLayer, {title: "Delete Feature"});

    var save = new OpenLayers.Control.Button({
        title: "Save Changes",
        trigger: function() {
            if(edit.feature) {
                edit.selectControl.unselectAll();
            }
            saveStrategy.save();
            logMessage("Done Saving")
        },
        displayClass: "olControlSaveFeatures"
    });

    panel.addControls([save, del, edit, draw]);
    map.addControl(panel);
    map.zoomToExtent(extent, true);
}

// Set 4-space indentation for vi
// vi:sw=4
<commit_msg>improved handling of very long text nodes<commit_after>"use strict"

var VolTextObject;
var map, annotationLayer;

var annotationChanges = 0
var selvol = "0"
var annotationClassesAndAppliers
var keyCodeActions

var recentLocations = []
var recentLocationsMaxLength = 5

$(document).ready(function() {
    // This handles selection in dataTable
    var table = $('#vol_table').DataTable();

    $('#vol_table tbody').on( 'click', 'tr', function () {
        if ( $(this).hasClass('selected') ) {
            $(this).removeClass('selected');
        }
        else {
            table.$('tr.selected').removeClass('selected');
            $(this).addClass('selected');
        }
    } );

    $('#button').click( function () {
        table.row('.selected').remove().draw( false );
    } );

    $("#col2text").on("cut copy paste", function(e) {
        e.preventDefault()
    })
    // Prevent changes in a content-editable div
    $("#col2text").on("keydown", function(e) {
        e = e || window.event;
        // Allow arrow keys, home, end, pgup, pgdn
        if (e.keyCode < 33 || e.keyCode > 40)
            e.preventDefault()
        keyCodeActions.forEach(function(action) {
            if (e.keyCode == action.code)
                action.action()
        })
    })
} );

var DeleteFeature = OpenLayers.Class(OpenLayers.Control, {
    initialize: function(layer, options) {
        OpenLayers.Control.prototype.initialize.apply(this, [options]);
        this.layer = layer;
        this.handler = new OpenLayers.Handler.Feature(
            this, layer, {click: this.clickFeature}
        );
    },
    clickFeature: function(feature) {
        // if feature doesn't have a fid, destroy it
        if(feature.fid == undefined) {
            this.layer.destroyFeatures([feature]);
        } else {
            feature.state = OpenLayers.State.DELETE;
            this.layer.events.triggerEvent("afterfeaturemodified",
                                           {feature: feature});
            feature.renderIntent = "select";
            this.layer.drawFeature(feature);
        }
    },
    setMap: function(map) {
        this.handler.setMap(map);
        OpenLayers.Control.prototype.setMap.apply(this, arguments);
    },
    CLASS_NAME: "OpenLayers.Control.DeleteFeature"
});

function getMapFeatures() {
    //var mLayers = map.layers;
    // var annLayer = map.getLayersByName("Annotations")
    var annLayer = annotationLayer

    var geoJSON = new OpenLayers.Format.GeoJSON()

    var jsonfeatsarr = annLayer.features.map(function(feature) {
        var layer_geom = feature.geometry.transform("EPSG:900913", "EPSG:4326")
        var geoJSONText = geoJSON.write(layer_geom)
        return geoJSONText
    })
    var jsonfeats = jsonfeatsarr.join("@@")
    // window.alert(jsonfeats)
    return jsonfeats
}

function jsonToMapFeatures(jsonstr) {
    var geoJSON = new OpenLayers.Format.GeoJSON()

    var jsonfeats = jsonstr.split("@@")
    // debugger
    var feats = jsonfeats.map(function(jsonfeat) {
        var geom = geoJSON.read(jsonfeat, "Geometry")
        var transformedGeom = geom.transform("EPSG:4326", "EPSG:900913")
        return new OpenLayers.Feature.Vector(transformedGeom)
    })
    return feats
}

function getSelectionNodes() {
    var selectionRange = getSelectionRange()
    return getRangeNodes(selectionRange, annotationClasses)
}

function getStoredMapFeatures(node) {
    return $.data(node, "features")
}

function setStoredMapFeatures(node, feats) {
    $.data(node, "features", feats)
}

function addMapFeaturesToSelection() {
    var jsonfeats = getMapFeatures()
    var rangenodes = getSelectionNodes()
    rangenodes.forEach(function(node) {
        setStoredMapFeatures(node, jsonfeats)
    })
    if (rangenodes.length > 0)
        addToRecentLocations(rangenodes[0].innerHTML.substring(0, 20), jsonfeats)
}

function zoomFeatures() {
    window.alert("Zoom Action Needed")
}

function populateRecentLocations() {
    var htmlarr = []
    for (var i = recentLocations.length - 1; i >= 0; i--) {
        var recentLoc = recentLocations[i]
        var html = '
' +
                     recentLoc.html + '
'
        console.log(html)
        htmlarr.push(html)
    }
    $('#recentlocs').html(htmlarr.join("\n"))
}

function addToRecentLocations(html, jsonfeats) {
    if (recentLocations.length >= recentLocationsMaxLength)
        recentLocations.slice(1)
    recentLocations.push({html: html, jsonfeats: jsonfeats})
    populateRecentLocations()
}

function locClicked(e) {
    alert($(e.target).attr('data-jsonfeats'))
}

// Save annotations in a serialized format.
function saveVolumeAnnotations() {
    // Fetch annotations
    var annotations = getAnnotations(annotationClasses)
    // Convert to an array of serialized annotations in the form "CLASS$START$END".
    var serialAnnotations = annotations.map(function(ann) {
        var jsonmapfeats = getStoredMapFeatures(ann.node) || ""
        return ann.node.className + "$" + ann.start + "$" + ann.end + "$" + jsonmapfeats
    })
    // Join to a single serialized string
    var serialString = serialAnnotations.join("|")
    var base64 = utf8ToB64(serialString);
    var parse_file = new Parse.File((annotUser + "-" + selvol +".txt"), { base64: base64 });
    // Save to Parse. First look for an existing entry for the user and volume.
    // If found, update it. Else create a new entry.
    var query = new Parse.Query(SpansObject)
    query.equalTo("user", annotUser)
    query.equalTo("vol", selvol)
    query.first().then(function(existing) {
        if (existing) {
            existing.set("spans", parse_file)
            return existing.save()
        } else {
            var spansObject = new SpansObject()
            return spansObject.save({"user":annotUser, "vol":selvol, "spans":parse_file})
        }
    }, savefailure("finding existing entry")
    ).then(savesuccess(function() {
        annotationChanges = 0
        logMessage("Saved " + annotations.length + " annotations")
    }),
        savefailure("saving new or updating existing entry"))
}

// Called from HTML. Save annotations. If saved successfully, reset list of
// article changes.
function saveAnnotations() {
    if (annotUser != "Default") {
        saveVolumeAnnotations()
    } else {
        logMessage("Please select a non-default Annotator Name prior prior to saving")
    }
}

// Load volume annotations
function loadVolumeAnnotations(results) {
    var textDivNode = getTextNode()
    textDivNode.normalize()
    alert(textDivNode.childNodes.length)
    var textNode = textDivNode.childNodes[0]
    httpGet(results[0].get("spans").url(), function(spansText) {
        var spansSerialized = spansText.split("|")
        var spans = spansSerialized.map(function(span) {
            var splitSpan = span.split("$")
            var className = splitSpan[0]
            var start = splitSpan[1]
            var end = splitSpan[2]
            var jsonmapfeats = splitSpan[3]
            return {start: start, end: end, className: className, jsonmapfeats: jsonmapfeats}
        })
        spans.sort(function(a, b) { return b.start - a.start })
        for (var i = 0; i < spans.length; i++) {
            var span = spans[i]
            if (span.start > textNode.length || span.end > textNode.length) {
                console.log("Skipped span [" + span.start + "," +
                    span.end + "] because > " + textNode.length)
            } else {
                var range = rangy.createRange()
                range.setStartAndEnd(textNode, span.start, span.end)
                annotationClassesAndAppliers.forEach(function(ca) {
                    if (span.className == ca.clazz) {
                        ca.applier.applyToRange(range)
                    }
                })
                getRangeNodes(range, annotationClasses).forEach(function(node) {
                    if (span.jsonmapfeats)
                        setStoredMapFeatures(node, span.jsonmapfeats)
                })
            }
        }
    })
}

function closeDialog(node) {
    $(node).dialog("close")
}

function checkVol(tableSelector) {
    if (annotUser != "Default") {
        var table = $(tableSelector).DataTable()
        var ret = table.$('tr.selected')
        if (ret.length > 0) {
            var newvol = table.$('tr.selected').find('td:first').text()
            if (annotationChanges > 0) {
                $("
Do you want to save the existing annotations?
").dialog({
                    resizable: false,
                    modal: true,
                    buttons: {
                        "Yes": function() {
                            saveAnnotations()
                            loadVolumeText(newvol, SpansObject)
                            closeDialog(this)
                        },
                        "No": function() {
                            loadVolumeText(newvol, SpansObject)
                            closeDialog(this)
                        },
                        "Cancel": function() {
                            console.log("Canceled")
                            window.alert("FIXME: We should set the visibly selected volume to the old one")
                            closeDialog(this)
                        }
                    }
                })
            }
            loadVolumeText(newvol, SpansObject)
        }
    } else {
        logMessage("Please select a non-default Annotator name prior to loading a volume")
    }
}

function nameChangeAnnotator() {
    var el = document.getElementById("selectUserAnnotator");
    annotUser = el.options[el.selectedIndex].innerHTML;
}

function removeAnnotations() {
    annotationLayer.destroyFeatures()
    annotationClassesAndAppliers.forEach(function(ca) {
        ca.unapplier.undoToRange(makeRange(document.body))
    })
    annotationChanges = 0
}

function removeAnnotation() {
    var selectionRange = getSelectionRange()
    if (overlapsAnnotation(selectionRange, true, annotationClasses))
        logMessage("Selection contains part of an annotation")
    else {
        annotationClassesAndAppliers.forEach(function(ca) {
            ca.unapplier.undoToSelection()
        })
    }
}

function spanClick(element) {
    //window.alert("Clicked inside article")
    var range = rangy.createRange()
    range.selectNodeContents(element)
    var sel = rangy.getSelection()
    sel.setSingleRange(range)
    var jsonfeats = getStoredMapFeatures(element)
    // alert("GeoJSON: " + jsonfeats)
    annotationLayer.destroyFeatures()
    if (jsonfeats)
        annotationLayer.addFeatures(jsonToMapFeatures(jsonfeats))
}

function annotationFeatureChanged(event) {
    addMapFeaturesToSelection()
    // var bounds = event.feature.geometry.getBounds();
    // var answer = "bottom: " + bounds.bottom + "\n";
    // answer += "left: " + bounds.left + "\n";
    // answer += "right: " + bounds.right + "\n";
    // answer += "top: " + bounds.top + "\n";
    // alert("Feature modified: " + answer);
}

function commonMapInit() {
    var extent = new OpenLayers.Bounds(
        -12003508, 3009847, -9005759, 6557774
    );

    Parse.initialize("Dxi3BvGT3mHiDC7B1YjeEuiUQKtWIeQNofT5FIIx", "QG352rxcZvLrYeV4jOCsIZvM8mIeQyhvHzDNINAb");

    VolTextObject = Parse.Object.extend("VolumeText");

    rangy.init();

    var table = $('#vol_table').DataTable()
    var rows = getVolTableRows(table)

    map = new OpenLayers.Map('map', {
        projection: new OpenLayers.Projection("EPSG:900913"),
        displayProjection: new OpenLayers.Projection("EPSG:4326"),
        controls: [
            new OpenLayers.Control.PanZoom(),
            new OpenLayers.Control.Navigation(),
            new OpenLayers.Control.MousePosition({prefix: 'Long: ', separator: '  Lat: ', numDigits: 3, emptyString:''})
        ]
    });

    var gphy = new OpenLayers.Layer.Google(
        "Google Streets"
    );

    var saveStrategy = new OpenLayers.Strategy.Save();

    annotationLayer = new OpenLayers.Layer.Vector("Annotations", {
        strategies: [new OpenLayers.Strategy.BBOX(), saveStrategy],
        projection: new OpenLayers.Projection("EPSG:4326"),
        protocol : new OpenLayers.Protocol.HTTP({
                url : 'polygons.geojson',
                format : new OpenLayers.Format.GeoJSON()
            })
    })

    map.addLayers([gphy, annotationLayer]);

    annotationLayer.events.on({
        featureadded: annotationFeatureChanged,
        featuremodified: annotationFeatureChanged,
        featureremoved: annotationFeatureChanged
    })

    var panel = new OpenLayers.Control.Panel({
        displayClass: 'customEditingToolbar',
        allowDepress: true
    });

    var draw = new OpenLayers.Control.DrawFeature(
        annotationLayer, OpenLayers.Handler.Polygon,
        {
            title: "Draw Feature",
            displayClass: "olControlDrawFeaturePolygon",
            multi: true
        }
    );

    var edit = new OpenLayers.Control.ModifyFeature(annotationLayer, {
        title: "Modify Feature",
        displayClass: "olControlModifyFeature"
    });

    var del = new DeleteFeature(annotationLayer, {title: "Delete Feature"});

    var save = new OpenLayers.Control.Button({
        title: "Save Changes",
        trigger: function() {
            if(edit.feature) {
                edit.selectControl.unselectAll();
            }
            saveStrategy.save();
            logMessage("Done Saving")
        },
        displayClass: "olControlSaveFeatures"
    });

    panel.addControls([save, del, edit, draw]);
    map.addControl(panel);
    map.zoomToExtent(extent, true);
}

// Set 4-space indentation for vi
// vi:sw=4
<|endoftext|>


<commit_before>import { Box, Grid, GridItem, Row, Stack, Text, Textarea, TextInput } from '@strapi/parts';
import { PropTypes } from 'prop-types';
import React from 'react';
import { useIntl } from 'react-intl';
import styled from 'styled-components';

const UsersRoleNumber = styled.div`
  border: 1px solid ${({ theme }) => theme.colors.primary200};
  background: ${({ theme }) => theme.colors.primary100};
  padding: ${({ theme }) => `${theme.spaces[2]} ${theme.spaces[4]}`};
  color: ${({ theme }) => theme.colors.primary600};
  border-radius: ${({ theme }) => theme.borderRadius};
  font-size: ${12 / 16}rem;
  font-width: bold;
`;

const RoleForm = ({ disabled, role, values, errors, onChange, onBlur }) => {
  const { formatMessage } = useIntl();

  return (
    <>
      <Box background="neutral0" padding={6} shadow="filterShadow" hasRadius>
        <Stack size={4}>
          <Row justifyContent="space-between">
            <Box>
              <Box>
                <Text highlighted>
                  {role
                    ? role.name
                    : formatMessage({
                        id: 'Settings.roles.form.title',
                        defaultMessage: 'Details',
                      })}
                </Text>
              </Box>
              <Box>
                <Text textColor="neutral500" small>
                  {role
                    ? role.description
                    : formatMessage({
                        id: 'Settings.roles.form.description',
                        defaultMessage: 'Name and description of the role',
                      })}
                </Text>
              </Box>
            </Box>
            <UsersRoleNumber>
              {formatMessage(
                {
                  id: 'Settings.roles.form.button.users-with-role',
                  defaultMessage:
                    '{number, plural, =0 {# users} one {# user} other {# users}} with this role',
                },
                { number: role.usersCount }
              )}
            </UsersRoleNumber>
          </Row>
          <Grid gap={4}>
            <GridItem col={6}>
              <TextInput
                disabled={disabled}
                name="name"
                error={errors.name && formatMessage({ id: errors.name })}
                label={formatMessage({
                  id: 'Settings.roles.form.input.name',
                  defaultMessage: 'Name',
                })}
                onChange={onChange}
                onBlur={onBlur}
                value={values.name || ''}
              />
            </GridItem>
            <GridItem col={6}>
              <Textarea
                disabled={disabled}
                label={formatMessage({
                  id: 'Settings.roles.form.input.description',
                  defaultMessage: 'Description',
                })}
                name="description"
                error={errors.name && formatMessage({ id: errors.name })}
                onChange={onChange}
                onBlur={onBlur}
              >
                {values.description || ''}
              </Textarea>
            </GridItem>
          </Grid>
        </Stack>
      </Box>
    </>
  );
};

RoleForm.defaultProps = {
  disabled: false,
  role: null,
  values: { name: '', description: '' },
};
RoleForm.propTypes = {
  disabled: PropTypes.bool,
  errors: PropTypes.object.isRequired,
  onBlur: PropTypes.func.isRequired,
  onChange: PropTypes.func.isRequired,
  role: PropTypes.object,
  values: PropTypes.object,
};

export default RoleForm;
<commit_msg>Fix lint issue<commit_after>import { Box, Grid, GridItem, Row, Stack, Text, Textarea, TextInput } from '@strapi/parts';
import { PropTypes } from 'prop-types';
import React from 'react';
import { useIntl } from 'react-intl';
import styled from 'styled-components';

const UsersRoleNumber = styled.div`
  border: 1px solid ${({ theme }) => theme.colors.primary200};
  background: ${({ theme }) => theme.colors.primary100};
  padding: ${({ theme }) => `${theme.spaces[2]} ${theme.spaces[4]}`};
  color: ${({ theme }) => theme.colors.primary600};
  border-radius: ${({ theme }) => theme.borderRadius};
  font-size: ${12 / 16}rem;
  font-weight: bold;
`;

const RoleForm = ({ disabled, role, values, errors, onChange, onBlur }) => {
  const { formatMessage } = useIntl();

  return (
    <>
      <Box background="neutral0" padding={6} shadow="filterShadow" hasRadius>
        <Stack size={4}>
          <Row justifyContent="space-between">
            <Box>
              <Box>
                <Text highlighted>
                  {role
                    ? role.name
                    : formatMessage({
                        id: 'Settings.roles.form.title',
                        defaultMessage: 'Details',
                      })}
                </Text>
              </Box>
              <Box>
                <Text textColor="neutral500" small>
                  {role
                    ? role.description
                    : formatMessage({
                        id: 'Settings.roles.form.description',
                        defaultMessage: 'Name and description of the role',
                      })}
                </Text>
              </Box>
            </Box>
            <UsersRoleNumber>
              {formatMessage(
                {
                  id: 'Settings.roles.form.button.users-with-role',
                  defaultMessage:
                    '{number, plural, =0 {# users} one {# user} other {# users}} with this role',
                },
                { number: role.usersCount }
              )}
            </UsersRoleNumber>
          </Row>
          <Grid gap={4}>
            <GridItem col={6}>
              <TextInput
                disabled={disabled}
                name="name"
                error={errors.name && formatMessage({ id: errors.name })}
                label={formatMessage({
                  id: 'Settings.roles.form.input.name',
                  defaultMessage: 'Name',
                })}
                onChange={onChange}
                onBlur={onBlur}
                value={values.name || ''}
              />
            </GridItem>
            <GridItem col={6}>
              <Textarea
                disabled={disabled}
                label={formatMessage({
                  id: 'Settings.roles.form.input.description',
                  defaultMessage: 'Description',
                })}
                name="description"
                error={errors.name && formatMessage({ id: errors.name })}
                onChange={onChange}
                onBlur={onBlur}
              >
                {values.description || ''}
              </Textarea>
            </GridItem>
          </Grid>
        </Stack>
      </Box>
    </>
  );
};

RoleForm.defaultProps = {
  disabled: false,
  role: null,
  values: { name: '', description: '' },
};
RoleForm.propTypes = {
  disabled: PropTypes.bool,
  errors: PropTypes.object.isRequired,
  onBlur: PropTypes.func.isRequired,
  onChange: PropTypes.func.isRequired,
  role: PropTypes.object,
  values: PropTypes.object,
};

export default RoleForm;
<|endoftext|>


<commit_before>'use strict';

var fs = require('fs'),
    path = require('path'),
    expat = require('node-expat')

var RenameHandler = function(dir, encoding) {
    this.dir = dir
    this.encoding = encoding
}

RenameHandler.prototype.parsePackageName = function(filename) {
    var self = this
    var filepath = path.join(this.dir, filename)

    // sax parse xml file
    var parser = new expat.Parser(this.encoding)
    parser.on('startElement', function (name, attrs) {
        if (name.match(/manifest/i)) {
            console.log('found oldPackageName => ' + attrs.package)
            self.oldPackageName = attrs.package
        }
    })

    parser.on('error', function (error) {
        console.error(error)
    })
    parser.write(fs.readFileSync(filepath))
}

RenameHandler.prototype.parseResource = function(filename) {
    // cache file to memory
    var filepath = path.join(this.dir, filename)
    var content = fs.readFileSync(filepath)

    // sax parse xml file
    var parser = new expat.Parser(this.encoding)
    parser.on('startElement', function (name, attrs) {
        for(var attrName in attrs) {
            if (attrName.match(/^xmlns:/i)) {
                console.log('found xml define: ' + attrName + " => " + attrs[attrName])
            }
        }
    })

    parser.on('error', function (error) {
        console.error(error)
    })
    parser.write(content)
}

RenameHandler.prototype.parseJava = function(filename) {

}

module.exports = RenameHandler
<commit_msg>move errorhandler<commit_after>'use strict';

var fs = require('fs'),
    path = require('path'),
    expat = require('node-expat')

var RenameHandler = function (dir, encoding) {
    this.dir = dir
    this.encoding = encoding
    this.errorHandler = function (error) {
        console.error(error)
    }
}

RenameHandler.prototype.parsePackageName = function (filename) {
    var self = this
    var filepath = path.join(this.dir, filename)

    // sax parse xml file
    var parser = new expat.Parser(this.encoding)
    parser.on('startElement', function (name, attrs) {
        if (name.match(/manifest/i)) {
            console.log('found oldPackageName => ' + attrs.package)
            self.oldPackageName = attrs.package
        }
    })

    parser.on('error', this.errorHandler)
    parser.write(fs.readFileSync(filepath))
}

RenameHandler.prototype.parseResource = function (filename) {
    // cache file to memory
    var filepath = path.join(this.dir, filename)
    var content = fs.readFileSync(filepath)

    // sax parse xml file
    var parser = new expat.Parser(this.encoding)
    parser.on('startElement', function (name, attrs) {
        for(var attrName in attrs) {
            if (attrName.match(/^xmlns:/i)) {
                console.log('found xml define: ' + attrName + " => " + attrs[attrName])
            }
        }
    })

    parser.on('error', this.errorHandler)
    parser.write(content)
}

RenameHandler.prototype.parseAndroidManifest = function (filename) {
    // cache file to memory
    var filepath = path.join(this.dir, filename)
    var content = fs.readFileSync(filepath)

    // sax parse xml file
    var parser = new expat.Parser(this.encoding)
    parser.on('startElement', function (name, attrs) {
        for(var attrName in attrs) {
            if (attrName.match(/^xmlns:/i)) {
                console.log('found xml define: ' + attrName + " => " + attrs[attrName])
            }
        }
    })

    parser.on('error', this.errorHandler)
    parser.write(content)
}

RenameHandler.prototype.parseJava = function(filename) {

}

module.exports = RenameHandler
<|endoftext|>


<commit_before>var session = 0;

exports.commands = {
	panagramhelp: 'panagramrules',
	panagramrules: function(target, room, user) {
		if (!this.canBroadcast()) return;
		return this.sendReplyBox(
		    'Pangram rules and commands' +
		    '(By SilverTactic and panpawn)
' +
		    '/panagram [session number] - Starts a game of Panagram in the room for [session number] games (Panagrams are just anagrams with Pokemon). Illegal and CAP Pokemon won\'t be selected. Must be ranked + or higher to use.
' +
		    '/guessp [Pokemon] - Guesses a Pokémon.
' +
		    '/panagramend OR /endpanagram - Ends the current game of Panagram.
' +
		    '/panagramhint - Shows a hint of the panagram answer.'
        );
	},
	panagrams: 'panagram',
	panagram: function(target, room, user) {
		if (!this.can('roommod', null, room)) return this.sendReply('You must be ranked + or higher to be able to start a game of Panagram in this room.');
		if (room.panagram) return this.sendReply('There is already a game of Panagram going on.');
		if (!this.canTalk()) return;
		if (!target) return this.sendReply("Usage: /panagram [number of games]");
		if (isNaN(target)) return this.sendReply("Target must be a number.");
		room.panagram = {};
		session = Number(target);
		var pokedex = [];
		for (var i in Tools.data.Pokedex) {
			if (Tools.data.Pokedex[i].num > 0 && !Tools.data.Pokedex[i].forme) {
				pokedex.push(i);
			}
		}
		var mixer = function(word) {
			var array = [];
			for (var k = 0; k < word.length; k++) {
				array.push(word[k]);
			}
			var a;
			var b;
			var i = array.length;
			while (i) {
				a = Math.floor(Math.random() * i);
				i--;
				b = array[i];
				array[i] = array[a];
				array[a] = b;
			}
			return array.join('').toString();
		};
		var poke = pokedex[Math.floor(Math.random() * pokedex.length)];
		var panagram = mixer(poke.toString());
		while (panagram == poke) {
			panagram = mixer(poke);
		}
		this.add('|html|
A game of Panagram has been started! (' + session + ' remaining)
' + 'The scrambled Pokémon is ' + panagram + '
' + 'Type in /gp [Pokémon] to guess the Pokémon!');
		room.panagram.guessed = [];
		room.panagram.chances = 2;
		room.panagram.answer = toId(poke);
	},
	gp: 'guessp',
	guesspoke: 'guessp',
	guessp: function(target, room, user, cmd) {
		if (!room.panagram) return this.sendReply('There is no game of Panagram going on in this room.');
		if (!this.canTalk()) return;
		//if (room.panagram[user.userid]) return this.sendReply("You've already guessed once!");
		if (!target) return this.sendReply("The proper syntax is /guessp [pokemon]");
		//if (!Tools.data.Pokedex[toId(target)]) return this.sendReply("'" + target + "' is not a valid Pokémon.");
		//if (Tools.data.Pokedex[toId(target)].num < 1) return this.sendReply(Tools.data.Pokedex[toId(target)].species + ' is either an illegal or a CAP Pokémon. They are not used in Panagrams.');
		//if (Tools.data.Pokedex[toId(target)].baseSpecies) target = toId(Tools.data.Pokedex[toId(target)].baseSpecies);
		if (room.panagram.guessed.indexOf(toId(target)) > -1) return this.sendReply("That has already been guessed!");
		if (room.panagram.answer == toId(target)) {
			this.add('|html|' + Tools.escapeHTML(user.name) + ' guessed ' + Tools.data.Pokedex[toId(target)].species + ', which was the correct answer! Congratulations!  They have also won 1 buck!');
			economy.writeMoney('money', toId(user.name), +1);
			delete room.panagram;
			if (session > 1) {
			    session--;
				var pokedex = [];
				for (var i in Tools.data.Pokedex) {
					if (Tools.data.Pokedex[i].num > 0 && !Tools.data.Pokedex[i].forme) {
						pokedex.push(i);
					}
				}
				var mixer = function(word) {
					var array = [];
					for (var k = 0; k < word.length; k++) {
						array.push(word[k]);
					}
					var a;
					var b;
					var i = array.length;
					while (i) {
						a = Math.floor(Math.random() * i);
						i--;
						b = array[i];
						array[i] = array[a];
						array[a] = b;
					}
					return array.join('').toString();
				}
				var poke = pokedex[Math.floor(Math.random() * pokedex.length)];
				var panagram = mixer(poke.toString());
				while (panagram == poke) {
					panagram = mixer(poke);
				}
				this.add('|html|
A game of Panagram has been started! (' + session + ' remaining)
' + 'The scrambled Pokémon is ' + panagram + '
' + 'Type in /gp [Pokémon] to guess the Pokémon!');
				room.panagram = {};
				room.panagram.guessed = [];
				room.panagram.chances = 2;
				room.panagram.answer = toId(poke);
			}
		} else {
			this.add('|html|' + Tools.escapeHTML(user.name) + ' guessed ' + Tools.escapeHTML(target) + ', but was not the correct answer...');
			room.panagram[user.userid] = toId(target);
			room.panagram.guessed.push(toId(target));
		}
	},
	panagramend: 'endpanagram',
	endpanagram: function(target, room, user) {
		if (!this.can('broadcast', null, room)) return this.sendReply('You must be ranked + or higher to be able to end a game of Panagram in this room.');
		if (!room.panagram) return this.sendReply('There is no Panagram game going on in this room.');
		if (!this.canTalk()) return;
		this.add("|html|The game of Panagram has been ended by " + Tools.escapeHTML(user.name) + ".");
		delete room.panagram;
	},
	ph: 'panagramhint',
	panagramhint: function(target, room, user) {
		if (!this.canBroadcast()) return;
		if (!room.panagram) return this.sendReply('There is no Panagram game going on in this room.');
		var hint = "The Pokemon is " + room.panagram.answer.length + " characters long.  The first letter is " + room.panagram.answer.substring(0, 1).toUpperCase() + ".";
		this.sendReplyBox(hint);
	}
};<commit_msg>Can only be used in specific room<commit_after>var session = 0;

exports.commands = {
	panagramhelp: 'panagramrules',
	panagramrules: function(target, room, user) {
		if (!this.canBroadcast()) return;
		if (room.id !== 'gamechamber') return this.sendReply("This command can only be used in the 'Game Chamber' room.");
		return this.sendReplyBox(
		    'Pangram rules and commands' +
		    '(By SilverTactic and panpawn)
' +
		    '/panagram [session number] - Starts a game of Panagram in the room for [session number] games (Panagrams are just anagrams with Pokemon). Illegal and CAP Pokemon won\'t be selected. Must be ranked + or higher to use.
' +
		    '/guessp [Pokemon] - Guesses a Pokémon.
' +
		    '/panagramend OR /endpanagram - Ends the current game of Panagram.
' +
		    '/panagramhint - Shows a hint of the panagram answer.'
        );
	},
	panagrams: 'panagram',
	panagram: function(target, room, user) {
		if (!this.can('roommod', null, room)) return this.sendReply('You must be ranked + or higher to be able to start a game of Panagram in this room.');
		if (room.panagram) return this.sendReply('There is already a game of Panagram going on.');
		if (room.id !== 'gamechamber') return this.sendReply("This command can only be used in the 'Game Chamber' room.");
		if (!this.canTalk()) return;
		if (!target) return this.sendReply("Usage: /panagram [number of games]");
		if (isNaN(target)) return this.sendReply("Target must be a number.");
		room.panagram = {};
		session = Number(target);
		var pokedex = [];
		for (var i in Tools.data.Pokedex) {
			if (Tools.data.Pokedex[i].num > 0 && !Tools.data.Pokedex[i].forme) {
				pokedex.push(i);
			}
		}
		var mixer = function(word) {
			var array = [];
			for (var k = 0; k < word.length; k++) {
				array.push(word[k]);
			}
			var a;
			var b;
			var i = array.length;
			while (i) {
				a = Math.floor(Math.random() * i);
				i--;
				b = array[i];
				array[i] = array[a];
				array[a] = b;
			}
			return array.join('').toString();
		};
		var poke = pokedex[Math.floor(Math.random() * pokedex.length)];
		var panagram = mixer(poke.toString());
		while (panagram == poke) {
			panagram = mixer(poke);
		}
		this.add('|html|
A game of Panagram has been started! (' + session + ' remaining)
' + 'The scrambled Pokémon is ' + panagram + '
' + 'Type in /gp [Pokémon] to guess the Pokémon!');
		room.panagram.guessed = [];
		room.panagram.chances = 2;
		room.panagram.answer = toId(poke);
	},
	gp: 'guessp',
	guesspoke: 'guessp',
	guessp: function(target, room, user, cmd) {
		if (room.id !== 'gamechamber') return this.sendReply("This command can only be used in the 'Game Chamber' room.");
		if (!room.panagram) return this.sendReply('There is no game of Panagram going on in this room.');
		if (!this.canTalk()) return;
		//if (room.panagram[user.userid]) return this.sendReply("You've already guessed once!");
		if (!target) return this.sendReply("The proper syntax is /guessp [pokemon]");
		//if (!Tools.data.Pokedex[toId(target)]) return this.sendReply("'" + target + "' is not a valid Pokémon.");
		//if (Tools.data.Pokedex[toId(target)].num < 1) return this.sendReply(Tools.data.Pokedex[toId(target)].species + ' is either an illegal or a CAP Pokémon. They are not used in Panagrams.');
		//if (Tools.data.Pokedex[toId(target)].baseSpecies) target = toId(Tools.data.Pokedex[toId(target)].baseSpecies);
		if (room.panagram.guessed.indexOf(toId(target)) > -1) return this.sendReply("That has already been guessed!");
		if (room.panagram.answer == toId(target)) {
			this.add('|html|' + Tools.escapeHTML(user.name) + ' guessed ' + Tools.data.Pokedex[toId(target)].species + ', which was the correct answer! Congratulations!  They have also won 1 buck!');
			economy.writeMoney('money', toId(user.name), +1);
			delete room.panagram;
			if (session > 1) {
			    session--;
				var pokedex = [];
				for (var i in Tools.data.Pokedex) {
					if (Tools.data.Pokedex[i].num > 0 && !Tools.data.Pokedex[i].forme) {
						pokedex.push(i);
					}
				}
				var mixer = function(word) {
					var array = [];
					for (var k = 0; k < word.length; k++) {
						array.push(word[k]);
					}
					var a;
					var b;
					var i = array.length;
					while (i) {
						a = Math.floor(Math.random() * i);
						i--;
						b = array[i];
						array[i] = array[a];
						array[a] = b;
					}
					return array.join('').toString();
				}
				var poke = pokedex[Math.floor(Math.random() * pokedex.length)];
				var panagram = mixer(poke.toString());
				while (panagram == poke) {
					panagram = mixer(poke);
				}
				this.add('|html|
A game of Panagram has been started! (' + session + ' remaining)
' + 'The scrambled Pokémon is ' + panagram + '
' + 'Type in /gp [Pokémon] to guess the Pokémon!');
				room.panagram = {};
				room.panagram.guessed = [];
				room.panagram.chances = 2;
				room.panagram.answer = toId(poke);
			}
		} else {
			this.add('|html|' + Tools.escapeHTML(user.name) + ' guessed ' + Tools.escapeHTML(target) + ', but was not the correct answer...');
			room.panagram[user.userid] = toId(target);
			room.panagram.guessed.push(toId(target));
		}
	},
	panagramend: 'endpanagram',
	endpanagram: function(target, room, user) {
		if (room.id !== 'gamechamber') return this.sendReply("This command can only be used in the 'Game Chamber' room.");
		if (!this.can('broadcast', null, room)) return this.sendReply('You must be ranked + or higher to be able to end a game of Panagram in this room.');
		if (!room.panagram) return this.sendReply('There is no Panagram game going on in this room.');
		if (!this.canTalk()) return;
		this.add("|html|The game of Panagram has been ended by " + Tools.escapeHTML(user.name) + ".");
		delete room.panagram;
	},
	ph: 'panagramhint',
	panagramhint: function(target, room, user) {
		if (room.id !== 'gamechamber') return this.sendReply("This command can only be used in the 'Game Chamber' room.");
		if (!this.canBroadcast()) return;
		if (!room.panagram) return this.sendReply('There is no Panagram game going on in this room.');
		var hint = "The Pokemon is " + room.panagram.answer.length + " characters long.  The first letter is " + room.panagram.answer.substring(0, 1).toUpperCase() + ".";
		this.sendReplyBox(hint);
	}
};<|endoftext|>


<commit_before>/* global FastBoot */
import { getOwner } from '@ember/application';
import { computed, get } from '@ember/object';
import { readOnly } from '@ember/object/computed';
import { assert } from '@ember/debug';
import EObject from '@ember/object';
import Service from '@ember/service';

const RequestObject = EObject.extend({
  init() {
    this._super(...arguments);

    let request = this.request;
    delete this.request;

    this.method = request.method;
    this.body = request.body;
    this.cookies = request.cookies;
    this.headers = request.headers;
    this.queryParams = request.queryParams;
    this.path = request.path;
    this.protocol = request.protocol;
    this._host = function() {
      return request.host();
    };
  },

  host: computed(function() {
    return this._host();
  })
});

const Shoebox = EObject.extend({
  put(key, value) {
    assert('shoebox.put is only invoked from the FastBoot rendered application', this.get('fastboot.isFastBoot'));
    assert('the provided key is a string', typeof key === 'string');

    let fastbootInfo = this.get('fastboot._fastbootInfo');
    if (!fastbootInfo.shoebox) { fastbootInfo.shoebox = {}; }

    fastbootInfo.shoebox[key] = value;
  },

  retrieve(key) {
    if (this.get('fastboot.isFastBoot')) {
      let shoebox = this.get('fastboot._fastbootInfo.shoebox');
      if (!shoebox) { return; }

      return shoebox[key];
    }

    let shoeboxItem = this.get(key);
    if (shoeboxItem) { return shoeboxItem; }

    let el = document.querySelector(`#shoebox-${key}`);
    if (!el) { return; }
    let valueString = el.textContent;
    if (!valueString) { return; }

    shoeboxItem = JSON.parse(valueString);
    this.set(key, shoeboxItem);

    return shoeboxItem;
  }
});

const FastBootService = Service.extend({
  isFastBoot: typeof FastBoot !== 'undefined',

  isFastboot: computed(function() {
    assert(
      'The fastboot service does not have an `isFastboot` property. This is likely a typo. Please use `isFastBoot` instead.',
      false
    );
  }),

  init() {
    this._super(...arguments);

    let shoebox = Shoebox.create({ fastboot: this });
    this.set('shoebox', shoebox);
  },

  response: readOnly('_fastbootInfo.response'),
  metadata: readOnly('_fastbootInfo.metadata'),

  request: computed(function() {
    if (!this.isFastBoot) return null;
    return RequestObject.create({ request: get(this, '_fastbootInfo.request') });
  }),

  _fastbootInfo: computed(function() {
    // this getter is to avoid deprecation from [RFC - 680](https://github.com/emberjs/rfcs/pull/680)
    return getOwner(this).lookup('info:-fastboot');
  }),

  deferRendering(promise) {
    assert('deferRendering requires a promise or thennable object', typeof promise.then === 'function');
    this._fastbootInfo.deferRendering(promise);
  }
});

export default FastBootService;
<commit_msg>Avoid implicit injection _fastbootInfo deprecation pt 2<commit_after>/* global FastBoot */
import { getOwner } from '@ember/application';
import { computed, get } from '@ember/object';
import { readOnly } from '@ember/object/computed';
import { assert } from '@ember/debug';
import EObject from '@ember/object';
import Service from '@ember/service';

const RequestObject = EObject.extend({
  init() {
    this._super(...arguments);

    let request = this.request;
    delete this.request;

    this.method = request.method;
    this.body = request.body;
    this.cookies = request.cookies;
    this.headers = request.headers;
    this.queryParams = request.queryParams;
    this.path = request.path;
    this.protocol = request.protocol;
    this._host = function() {
      return request.host();
    };
  },

  host: computed(function() {
    return this._host();
  })
});

const Shoebox = EObject.extend({
  put(key, value) {
    assert('shoebox.put is only invoked from the FastBoot rendered application', this.get('fastboot.isFastBoot'));
    assert('the provided key is a string', typeof key === 'string');

    let fastbootInfo = this.get('fastboot._fastbootInfo');
    if (!fastbootInfo.shoebox) { fastbootInfo.shoebox = {}; }

    fastbootInfo.shoebox[key] = value;
  },

  retrieve(key) {
    if (this.get('fastboot.isFastBoot')) {
      let shoebox = this.get('fastboot._fastbootInfo.shoebox');
      if (!shoebox) { return; }

      return shoebox[key];
    }

    let shoeboxItem = this.get(key);
    if (shoeboxItem) { return shoeboxItem; }

    let el = document.querySelector(`#shoebox-${key}`);
    if (!el) { return; }
    let valueString = el.textContent;
    if (!valueString) { return; }

    shoeboxItem = JSON.parse(valueString);
    this.set(key, shoeboxItem);

    return shoeboxItem;
  }
});

const FastBootService = Service.extend({
  isFastBoot: typeof FastBoot !== 'undefined',

  isFastboot: computed(function() {
    assert(
      'The fastboot service does not have an `isFastboot` property. This is likely a typo. Please use `isFastBoot` instead.',
      false
    );
  }),

  init() {
    this._super(...arguments);

    let shoebox = Shoebox.create({ fastboot: this });
    this.set('shoebox', shoebox);
  },

  response: readOnly('_fastbootInfo.response'),
  metadata: readOnly('_fastbootInfo.metadata'),

  request: computed(function() {
    if (!this.isFastBoot) return null;
    return RequestObject.create({ request: get(this, '_fastbootInfo.request') });
  }),

  _fastbootInfo: computed({
    get() {
      if (this.__fastbootInfo) {
        return this.__fastbootInfo;
      }

      // this getter is to avoid deprecation from [RFC - 680](https://github.com/emberjs/rfcs/pull/680)
      return getOwner(this).lookup('info:-fastboot');
    },
    set(_key, value) {
      this.__fastbootInfo = value;
      return value;
    }
  }),

  deferRendering(promise) {
    assert('deferRendering requires a promise or thennable object', typeof promise.then === 'function');
    this._fastbootInfo.deferRendering(promise);
  }
});

export default FastBootService;
<|endoftext|>


<commit_before>import chai from 'chai';
import request from 'supertest';
import app from '../../src/app';
import { ADMINISTRATOR } from '../../src/auth/constants';
import { loadFixtures, test404, createAuthorization } from '../helpers';

chai.should();

const headers = {
    Authorization: createAuthorization(ADMINISTRATOR)
};

describe('APIToken API', () => {
    describe('List all tokens', () => {
        beforeEach(() => loadFixtures());

        it('should list all tokens', done => {
            request(app)
            .get('/api-tokens/')
            .set(headers)
            .expect('Content-Type', /json/)
            .expect(200)
            .end((err, res) => {
                if (err) return done(err);
                const tokens = res.body;
                const [token] = tokens;
                tokens.length.should.equal(2);
                token.id.should.equal(1);
                token.name.should.equal('test token');
                done();
            });
        });
    });

    describe('Create token', () => {
        it('should generate a new token', done => {
            const body = {
                name: 'test',
                systemId: 1
            };

            request(app)
            .post('/api-tokens')
            .send(body)
            .set(headers)
            .expect('Content-Type', /json/)
            .expect(201)
            .end((err, res) => {
                if (err) return done(err);
                const auth = res.body;
                auth.token.length.should.equal(32);
                auth.name.should.equal(body.name);
                done();
            });
        });

        it('should return a validation error for missing info', done => {
            const auth = {
                systemId: 1
            };

            request(app)
            .post('/api-tokens/')
            .send(auth)
            .set(headers)
            .expect('Content-Type', /json/)
            .expect(400)
            .end((err, res) => {
                if (err) return done(err);
                res.body.message.should.equal('notNull Violation: name cannot be null');
                res.body.errors.length.should.equal(1);
                done();
            });
        });
    });

    describe('Delete token', () => {
        beforeEach(() => loadFixtures());

        it('should delete a token', done => {
            request(app)
            .delete('/api-tokens/1')
            .set(headers)
            .expect(204)
            .end((err, res) => {
                if (err) return done(err);
                done();
            });
        });

        it('should return 404 for missing tokens', done => {
            test404('/api-tokens/1337', done, headers, 'delete');
        });
    });
});
<commit_msg>Fix api token tests by adding system id to urls<commit_after>import chai from 'chai';
import request from 'supertest';
import app from '../../src/app';
import { ADMINISTRATOR } from '../../src/auth/constants';
import { loadFixtures, test404, createAuthorization } from '../helpers';

chai.should();

const headers = {
    Authorization: createAuthorization(ADMINISTRATOR)
};

describe('APIToken API', () => {
    describe('List all tokens', () => {
        beforeEach(() => loadFixtures());

        it('should list all tokens', done => {
            request(app)
            .get('/1/api-tokens/')
            .set(headers)
            .expect('Content-Type', /json/)
            .expect(200)
            .end((err, res) => {
                if (err) return done(err);
                const tokens = res.body;
                const [token] = tokens;
                tokens.length.should.equal(2);
                token.id.should.equal(1);
                token.name.should.equal('test token');
                done();
            });
        });
    });

    describe('Create token', () => {
        it('should generate a new token', done => {
            const body = {
                name: 'test',
                systemId: 1
            };

            request(app)
            .post('/1/api-tokens/')
            .send(body)
            .set(headers)
            .expect('Content-Type', /json/)
            .expect(201)
            .end((err, res) => {
                if (err) return done(err);
                const auth = res.body;
                auth.token.length.should.equal(32);
                auth.name.should.equal(body.name);
                done();
            });
        });

        it('should return a validation error for missing info', done => {
            const auth = {
                systemId: 1
            };

            request(app)
            .post('/1/api-tokens/')
            .send(auth)
            .set(headers)
            .expect('Content-Type', /json/)
            .expect(400)
            .end((err, res) => {
                if (err) return done(err);
                res.body.message.should.equal('notNull Violation: name cannot be null');
                res.body.errors.length.should.equal(1);
                done();
            });
        });
    });

    describe('Delete token', () => {
        beforeEach(() => loadFixtures());

        it('should delete a token', done => {
            request(app)
            .delete('/1/api-tokens/1/')
            .set(headers)
            .expect(204)
            .end((err, res) => {
                if (err) return done(err);
                done();
            });
        });

        it('should return 404 for missing tokens', done => {
            test404('/1/api-tokens/1337', done, headers, 'delete');
        });
    });
});
<|endoftext|>


<commit_before>'use strict';

var Test = require('../testparams');
var StoreBucketTypeProps = require('../../../lib/commands/kv/storebuckettypeprops');
var FetchBucketTypeProps = require('../../../lib/commands/kv/fetchbuckettypeprops');
var RiakNode = require('../../../lib/core/riaknode');
var RiakCluster = require('../../../lib/core/riakcluster');
var assert = require('assert');

var bucketName = Test.bucketName + '_sp';

describe('Store and Fetch Bucket props - Integration', function() {

    this.timeout(10000);

    var cluster;
    before(function(done) {
        var nodes = RiakNode.buildNodes(Test.nodeAddresses);
        cluster = new RiakCluster({ nodes: nodes});
        cluster.start(function (err, rslt) {
            assert(!err, err);
            done();
        });
    });

    after(function(done) {
        var sc = function (state) {
            if (state === RiakCluster.State.SHUTDOWN) {
                done();
            }
        };
        cluster.on('stateChange', sc);
        cluster.stop();
    });

    describe('StoreBucketTypeProps', function() {
        it('Should NOT store props for the default bucket type', function(done) {
            var callback = function(err, resp) {
                assert(err, err);
                done();
            };
            var store = new StoreBucketTypeProps.Builder()
                    .withAllowMult(true)
                    .withCallback(callback)
                    .build();
            cluster.execute(store);
        });

        it('Should store bucket props for a non-default bucket type', function(done) {
            var cb2 = function(err, resp) {
                assert(!err, err);
                done();
            };
            var cb1 = function(err, resp) {
                assert(!err, err);
                var store = new StoreBucketTypeProps.Builder()
                        .withBucketType(Test.bucketType)
                        .withAllowMult(true)
                        .withCallback(cb2)
                        .build();
                cluster.execute(store);
            };
            var store = new StoreBucketTypeProps.Builder()
                    .withBucketType(Test.bucketType)
                    .withAllowMult(false)
                    .withCallback(cb1)
                    .build();
            cluster.execute(store);
        });
    });

    describe('FetchBucketTypeProps', function() {
        it('Should fetch props for the default bucket type', function(done) {
            var callback = function(err, resp) {
                assert(!err, err);
                assert(resp.nVal);
                done();
            };
            var fetch = new FetchBucketTypeProps.Builder()
                .withCallback(callback)
                .build();
            cluster.execute(fetch);
        });

        it('Should fetch props for a non-default bucket type', function(done) {
            var callback = function(err, resp) {
                assert(!err, err);
                assert(resp.nVal);
                done();
            };
            var fetch = new FetchBucketTypeProps.Builder()
                .withBucketType(Test.bucketType)
                .withCallback(callback)
                .build();
            cluster.execute(fetch);
        });
    });
});
<commit_msg>add to test case<commit_after>'use strict';

var Test = require('../testparams');
var StoreBucketTypeProps = require('../../../lib/commands/kv/storebuckettypeprops');
var FetchBucketTypeProps = require('../../../lib/commands/kv/fetchbuckettypeprops');
var RiakNode = require('../../../lib/core/riaknode');
var RiakCluster = require('../../../lib/core/riakcluster');
var assert = require('assert');

var bucketName = Test.bucketName + '_sp';

describe('Store and Fetch Bucket props - Integration', function() {

    this.timeout(10000);

    var cluster;
    before(function(done) {
        var nodes = RiakNode.buildNodes(Test.nodeAddresses);
        cluster = new RiakCluster({ nodes: nodes});
        cluster.start(function (err, rslt) {
            assert(!err, err);
            done();
        });
    });

    after(function(done) {
        var sc = function (state) {
            if (state === RiakCluster.State.SHUTDOWN) {
                done();
            }
        };
        cluster.on('stateChange', sc);
        cluster.stop();
    });

    describe('StoreBucketTypeProps', function() {
        it('Should NOT store props for the default bucket type', function(done) {
            var callback = function(err, resp) {
                assert(err, err);
                done();
            };
            var store = new StoreBucketTypeProps.Builder()
                    .withAllowMult(true)
                    .withCallback(callback)
                    .build();
            cluster.execute(store);
        });

        it('Should store bucket props for a non-default bucket type', function(done) {
            var cb3 = function(err, resp) {
                assert(!err, err);
                done();
            };
            var cb2 = function(err, resp) {
                assert(!err, err);
                assert.strictEqual(resp.allowMult, false);
                assert.strictEqual(resp.nVal, 4);
                var store = new StoreBucketTypeProps.Builder()
                        .withBucketType(Test.bucketType)
                        .withAllowMult(true)
                        .withNVal(3)
                        .withCallback(cb3)
                        .build();
                cluster.execute(store);
            };
            var cb1 = function(err, resp) {
                assert(!err, err);
                var fetch = new FetchBucketTypeProps.Builder()
                    .withBucketType(Test.bucketType)
                    .withCallback(cb2)
                    .build();
                cluster.execute(fetch);
            };
            var store = new StoreBucketTypeProps.Builder()
                    .withBucketType(Test.bucketType)
                    .withAllowMult(false)
                    .withNVal(4)
                    .withCallback(cb1)
                    .build();
            cluster.execute(store);
        });
    });

    describe('FetchBucketTypeProps', function() {
        it('Should fetch props for the default bucket type', function(done) {
            var callback = function(err, resp) {
                assert(!err, err);
                assert(resp.nVal);
                done();
            };
            var fetch = new FetchBucketTypeProps.Builder()
                .withCallback(callback)
                .build();
            cluster.execute(fetch);
        });

        it('Should fetch props for a non-default bucket type', function(done) {
            var callback = function(err, resp) {
                assert(!err, err);
                assert(resp.nVal);
                done();
            };
            var fetch = new FetchBucketTypeProps.Builder()
                .withBucketType(Test.bucketType)
                .withCallback(callback)
                .build();
            cluster.execute(fetch);
        });
    });
});
<|endoftext|>


<commit_before>import './styles.scss'

import React, { Component } from 'react'
import { kea } from 'kea'
import PropTypes from 'prop-types'

import range from 'lib/utils/range'

import explorerLogic from '~/scenes/explorer/logic'

export const colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf']

const compareWithForTimeGroup = {
  year: [0, 1, 2, 3, 4],
  quarter: [0, 1, 2, 4],
  month: [0, 1, 3, 6, 12, 24],
  week: [0, 1, 4, 12, 52],
  day: [0, 1, 7, 28, 364, 365]
}

@kea({
  connect: {
    actions: [
      explorerLogic, [
        'setGraphControls'
      ]
    ],
    props: [
      explorerLogic, [
        'graphControls',
        'graphTimeGroup'
      ]
    ]
  },

  actions: () => ({
    showMore: true,
    showLess: true
  }),

  reducers: ({ actions }) => ({
    moreShown: [false, PropTypes.bool, {
      [actions.showMore]: () => true,
      [actions.showLess]: () => false,
      [actions.setGraphControls]: () => false
    }]
  })
})
export default class ControlsLeft extends Component {
  render () {
    const { graphControls, moreShown, graphTimeGroup } = this.props
    const { setGraphControls, showMore, showLess } = this.actions

    const { compareWith } = graphControls

    const options = compareWithForTimeGroup[graphTimeGroup]

    return (

           moreShown ? showLess() : showMore()}>
            Compare with

          {(moreShown ? options : compareWith ? [compareWith] : []).map(option => (
             moreShown ? setGraphControls({ compareWith: compareWith === option ? 0 : option }) : showMore()}>
              {option}

          ))}

    )
  }
}
<commit_msg>set bar type if setting to compare<commit_after>import './styles.scss'

import React, { Component } from 'react'
import { kea } from 'kea'
import PropTypes from 'prop-types'

import range from 'lib/utils/range'

import explorerLogic from '~/scenes/explorer/logic'

export const colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf']

const compareWithForTimeGroup = {
  year: [0, 1, 2, 3, 4],
  quarter: [0, 1, 2, 4],
  month: [0, 1, 3, 6, 12, 24],
  week: [0, 1, 4, 12, 52],
  day: [0, 1, 7, 28, 364, 365]
}

@kea({
  connect: {
    actions: [
      explorerLogic, [
        'setGraphControls'
      ]
    ],
    props: [
      explorerLogic, [
        'graphControls',
        'graphTimeGroup'
      ]
    ]
  },

  actions: () => ({
    showMore: true,
    showLess: true
  }),

  reducers: ({ actions }) => ({
    moreShown: [false, PropTypes.bool, {
      [actions.showMore]: () => true,
      [actions.showLess]: () => false,
      [actions.setGraphControls]: () => false
    }]
  })
})
export default class ControlsLeft extends Component {
  render () {
    const { graphControls, moreShown, graphTimeGroup } = this.props
    const { setGraphControls, showMore, showLess } = this.actions

    const { compareWith } = graphControls

    const options = compareWithForTimeGroup[graphTimeGroup]

    return (

           moreShown ? showLess() : showMore()}>
            Compare with

          {(moreShown ? options : compareWith ? [compareWith] : []).map(option => (
             moreShown ? setGraphControls({ compareWith: compareWith === option ? 0 : option, type: 'bar' }) : showMore()}>
              {option}

          ))}

    )
  }
}
<|endoftext|>


<commit_before>// Grunt task runner.

module.exports = function(grunt) {
    // Project configuration.
    grunt.initConfig({
        handlebars: {
            options: {
                amd: true,          // wrap in amd/requirejs module
                namespace: false,   // no template -- just return the function as the amd module
            },
            compile: {
                files: [
                    {
                        expand: true,
                        cwd: 'client/views/',
                        src: ['**/*.hbs'],
                        dest: 'public/views/',
                        ext: '.js'
                    }
                ]
            }
        },
        copy: {
            // Copy client files that don't need processing to the public dir unmodified.
            client: {
                expand: true,
                cwd: 'client/',
                src: ['**/*.js', '**/*.html', '**/*.css'],
                dest: 'public/'
            },
        },
        bower: {
            install: {
                options: {
                    targetDir: "public/lib",
                    layout: "byComponent",
                    cleanTargetDir: false
                }
            }
        },
        requirejs: {
            compile: {
                options: {
                    baseUrl: "public",
                    mainConfigFile: "public/main.js",
                    dir: "public-opt",
                    optimize: "uglify2",
                    modules: [
                        {
                            name: "main",
                            include: ["handlebars",
                                      "views/renderwidgets",
                                      "text",
                                      "devices/devices"]
                        },
                        {
                            name: "views/default",
                            exclude: ["main"]
                        },
                        {
                            name: "views/customise",
                            exclude: ["main"]
                        },
                        {
                            name: "views/login",
                            exclude: ["main"]
                        },
                        {
                            name: "views/createaccount",
                            exclude: ["main"]
                        }
                    ]
                }
            }
        },
        watch: {
            client: {
                files: ['client/**/*.js', 'client/**/*.html', 'client/**/*.css'],
                tasks: ['copy:client']
            },
            handlebars: {
                files: ['client/views/**/*.hbs'],
                tasks: ['handlebars']
            }
        }
    });

    // Load plugins
    grunt.loadNpmTasks('grunt-contrib-handlebars');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks("grunt-bower-task");
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-requirejs');

    // Run watch by default.
    grunt.registerTask('default', ['watch']);

    // Prep for production environment.
    grunt.registerTask('prod', ['bower', 'handlebars', 'copy', 'requirejs']);
};
<commit_msg>Dev grunt alias to set up dev public folder<commit_after>// Grunt task runner.

module.exports = function(grunt) {
    // Project configuration.
    grunt.initConfig({
        handlebars: {
            options: {
                amd: true,          // wrap in amd/requirejs module
                namespace: false,   // no template -- just return the function as the amd module
            },
            compile: {
                files: [
                    {
                        expand: true,
                        cwd: 'client/views/',
                        src: ['**/*.hbs'],
                        dest: 'public/views/',
                        ext: '.js'
                    }
                ]
            }
        },
        copy: {
            // Copy client files that don't need processing to the public dir unmodified.
            client: {
                expand: true,
                cwd: 'client/',
                src: ['**/*.js', '**/*.html', '**/*.css'],
                dest: 'public/'
            },
        },
        bower: {
            install: {
                options: {
                    targetDir: "public/lib",
                    layout: "byComponent",
                    cleanTargetDir: false
                }
            }
        },
        requirejs: {
            compile: {
                options: {
                    baseUrl: "public",
                    mainConfigFile: "public/main.js",
                    dir: "public-opt",
                    optimize: "uglify2",
                    modules: [
                        {
                            name: "main",
                            include: ["handlebars",
                                      "views/renderwidgets",
                                      "text",
                                      "devices/devices"]
                        },
                        {
                            name: "views/default",
                            exclude: ["main"]
                        },
                        {
                            name: "views/customise",
                            exclude: ["main"]
                        },
                        {
                            name: "views/login",
                            exclude: ["main"]
                        },
                        {
                            name: "views/createaccount",
                            exclude: ["main"]
                        }
                    ]
                }
            }
        },
        watch: {
            client: {
                files: ['client/**/*.js', 'client/**/*.html', 'client/**/*.css'],
                tasks: ['copy:client']
            },
            handlebars: {
                files: ['client/views/**/*.hbs'],
                tasks: ['handlebars']
            }
        }
    });

    // Load plugins
    grunt.loadNpmTasks('grunt-contrib-handlebars');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks("grunt-bower-task");
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-requirejs');

    // Run watch by default.
    grunt.registerTask('default', ['watch']);

    // Prep for development or production environment.
    grunt.registerTask('dev', ['bower', 'handlebars', 'copy']);
    grunt.registerTask('prod', ['bower', 'handlebars', 'copy', 'requirejs']);
};
<|endoftext|>


<commit_before>'use strict';
const eslint = require('eslint');

// envs: ['eslint-samples/p5'],

var itemtypes = ['method', 'property'];
var classes = ['p5', 'p5.dom'];

var dataDoc = require('../docs/reference/data.min.json');
var globals = {};
dataDoc.classitems
  .filter(
    ci => classes.indexOf(ci.class) >= 0 && itemtypes.indexOf(ci.itemtype) >= 0
  )
  .forEach(ci => {
    globals[ci.name] = true;
  });

Object.keys(dataDoc.consts).forEach(c => {
  globals[c] = true;
});

dataDoc.classitems
  .find(ci => ci.name === 'keyCode' && ci.class === 'p5')
  .description.match(/[A-Z\r\n, _]{10,}/m)[0]
  .match(/[A-Z_]+/gm)
  .forEach(c => {
    globals[c] = true;
  });

function splitLines(text) {
  var lines = [];

  lines.lineFromIndex = function(index) {
    var lines = this;
    var lineCount = lines.length;
    for (var i = 0; i < lineCount; i++) {
      if (index < lines[i].index) return i - 1;
    }
    return lineCount - 1;
  };

  var m;
  var reSplit = /(( *\* ?)?.*)(?:\r\n|\r|\n)/g;
  while ((m = reSplit.exec(text)) != null) {
    if (m.index === reSplit.lastIndex) {
      reSplit.lastIndex++;
    }

    lines.push({
      index: m.index,
      text: m[1],
      prefixLength: m[2] ? m[2].length : 0
    });
  }

  return lines;
}

var EOL = require('os').EOL;

var userFunctions = [
  'draw',
  'setup',
  'preload',
  'mousePressed',
  'mouseDragged',
  'mouseMoved',
  'mouseReleased',
  'mouseClicked',
  'mouseWheel',
  'doubleClicked',
  'windowResized',
  'touchStarted',
  'touchMoved',
  'touchEnded',
  'deviceMoved',
  'deviceTurned',
  'deviceShaken',
  'keyPressed',
  'keyReleased',
  'keyTyped'
];
var userFunctionTrailer =
  EOL + userFunctions.map(s => 'typeof ' + s + ';').join(EOL) + EOL;

module.exports = {
  environments: {
    p5: {
      globals: globals
    }
  },
  processors: {
    '.js': {
      supportsAutofix: true,
      preprocess: function(text) {
        this.lines = splitLines(text);

        var m;
        var comments = [];

        var reComment = /\/\*\*(?:.|\r|\n)*?\*\//g;
        while ((m = reComment.exec(text)) != null) {
          var value = m[0];
          comments.push({
            value: value,
            range: [m.index, m.index + value.length]
          });
        }

        var samples = (this.samples = []);

        for (var i = 0; i < comments.length; i++) {
          var comment = comments[i];
          var commentText = comment.value;

          var re = /(<code[^>]*>\s*(?:\r\n|\r|\n))((?:.|\r|\n)*?)<\/code>/gm;
          while ((m = re.exec(commentText)) != null) {
            var code = m[2];
            if (!code) continue;
            code = code.replace(/^ *\* ?/gm, '');

            samples.push({
              comment: comment,
              index: m.index + m[1].length,
              code: code
            });
          }
        }

        return samples.map(s => s.code + userFunctionTrailer);
      },

      postprocess: function(sampleMessages, filename) {
        var problems = [];

        for (var i = 0; i < sampleMessages.length; i++) {
          var messages = sampleMessages[i];
          var sample = this.samples[i];
          if (!messages.length) continue;

          var sampleLines;

          var sampleIndex = sample.comment.range[0] + sample.index;
          var sampleLine = this.lines.lineFromIndex(sampleIndex);

          for (var j = 0; j < messages.length; j++) {
            var msg = messages[j];

            var fix = msg.fix;
            if (fix) {
              if (!sampleLines) {
                sampleLines = splitLines(sample.code);
              }

              var fixLine1 = sampleLines.lineFromIndex(fix.range[0]);
              var fixLine2 = sampleLines.lineFromIndex(fix.range[1] - 1);
              if (fixLine1 !== fixLine2) {
                // TODO: handle multi-line fixes
                fix.range = [0, 0];
                fix.text = '';
              } else {
                var line = this.lines[sampleLine + fixLine1];

                var fixColumn1 = fix.range[0] - sampleLines[fixLine1].index;
                var fixColumn2 = fix.range[1] - sampleLines[fixLine1].index;

                fix.range[0] = line.index + line.prefixLength + fixColumn1;
                fix.range[1] = line.index + line.prefixLength + fixColumn2;
              }
            }

            var startLine = msg.line + sampleLine;
            msg.column += this.lines[startLine].prefixLength;
            msg.line = startLine;

            if (msg.endLine) {
              var endLine = msg.endLine + sampleLine;
              msg.endColumn += this.lines[endLine].prefixLength;
              msg.endLine = endLine;
            }

            msg.message = msg.message
              .replace(/\r/g, '\\r')
              .replace(/\n|\u23CE/g, '\\n');

            problems.push(msg);
          }
        }
        return problems;
      }
    }
  }
};

function eslintFiles(opts, filesSrc) {
  opts = opts || {
    outputFile: false,
    quiet: false,
    maxWarnings: -1,
    envs: ['eslint-samples/p5', 'amd'],
    format: 'unix'
  };

  if (filesSrc.length === 0) {
    console.warn('Could not find any files to validate');
    return true;
  }

  const formatter = eslint.CLIEngine.getFormatter(opts.format);
  if (!formatter) {
    console.warn(`Could not find formatter ${opts.format}`);
    return false;
  }

  const engine = new eslint.CLIEngine(opts);
  engine.addPlugin('eslint-samples', module.exports);

  let report = engine.executeOnFiles(filesSrc);

  if (opts.fix) {
    eslint.CLIEngine.outputFixes(report);
  }

  let results = report.results;
  if (opts.quiet) {
    results = eslint.CLIEngine.getErrorResults(results);
  }

  return { report, output: formatter(results) };
}

module.exports.eslintFiles = eslintFiles;

if (!module.parent) {
  var result = eslintFiles(null, process.argv.slice(2));
  console.log(result.output);
  process.exit(result.report.errorCount === 0 ? 0 : 1);
}
<commit_msg>Update sample-linter.js<commit_after>'use strict';
import eslint from 'eslint';

// envs: ['eslint-samples/p5'],

const itemtypes = ['method', 'property'];
const classes = ['p5', 'p5.dom'];

import dataDoc from '../docs/reference/data.min.json';
const globals = {};
dataDoc.classitems
  .filter(
    ci => classes.indexOf(ci.class) >= 0 && itemtypes.indexOf(ci.itemtype) >= 0
  )
  .forEach(ci => {
    globals[ci.name] = true;
  });

Object.keys(dataDoc.consts).forEach(c => {
  globals[c] = true;
});

dataDoc.classitems
  .find(ci => ci.name === 'keyCode' && ci.class === 'p5')
  .description.match(/[A-Z\r\n, _]{10,}/m)[0]
  .match(/[A-Z_]+/gm)
  .forEach(c => {
    globals[c] = true;
  });

function splitLines(text) {
  const lines = [];

  lines.lineFromIndex = function(index) {
    const lines = this;
    const lineCount = lines.length;
    for (let i = 0; i < lineCount; i++) {
      if (index < lines[i].index) return i - 1;
    }
    return lineCount - 1;
  };

  let m;
  const reSplit = /(( *\* ?)?.*)(?:\r\n|\r|\n)/g;
  while ((m = reSplit.exec(text)) != null) {
    if (m.index === reSplit.lastIndex) {
      reSplit.lastIndex++;
    }

    lines.push({
      index: m.index,
      text: m[1],
      prefixLength: m[2] ? m[2].length : 0
    });
  }

  return lines;
}

const EOL = require('os').EOL;

const userFunctions = [
  'draw',
  'setup',
  'preload',
  'mousePressed',
  'mouseDragged',
  'mouseMoved',
  'mouseReleased',
  'mouseClicked',
  'mouseWheel',
  'doubleClicked',
  'windowResized',
  'touchStarted',
  'touchMoved',
  'touchEnded',
  'deviceMoved',
  'deviceTurned',
  'deviceShaken',
  'keyPressed',
  'keyReleased',
  'keyTyped'
];
const userFunctionTrailer =
  EOL + userFunctions.map(s => 'typeof ' + s + ';').join(EOL) + EOL;

module.exports = {
  environments: {
    p5: {
      globals: globals
    }
  },
  processors: {
    '.js': {
      supportsAutofix: true,
      preprocess: function(text) {
        this.lines = splitLines(text);

        let m;
        const comments = [];

        const reComment = /\/\*\*(?:.|\r|\n)*?\*\//g;
        while ((m = reComment.exec(text)) != null) {
          const value = m[0];
          comments.push({
            value: value,
            range: [m.index, m.index + value.length]
          });
        }

        const samples = (this.samples = []);

        for (let i = 0; i < comments.length; i++) {
          const comment = comments[i];
          const commentText = comment.value;

          const re = /(<code[^>]*>\s*(?:\r\n|\r|\n))((?:.|\r|\n)*?)<\/code>/gm;
          while ((m = re.exec(commentText)) != null) {
            const code = m[2];
            if (!code) continue;
            code = code.replace(/^ *\* ?/gm, '');

            samples.push({
              comment: comment,
              index: m.index + m[1].length,
              code: code
            });
          }
        }

        return samples.map(s => s.code + userFunctionTrailer);
      },

      postprocess: function(sampleMessages, filename) {
        const problems = [];

        for (let i = 0; i < sampleMessages.length; i++) {
          const messages = sampleMessages[i];
          const sample = this.samples[i];
          if (!messages.length) continue;

          var sampleLines;

          const sampleIndex = sample.comment.range[0] + sample.index;
          const sampleLine = this.lines.lineFromIndex(sampleIndex);

          for (let j = 0; j < messages.length; j++) {
            const msg = messages[j];

            const fix = msg.fix;
            if (fix) {
              if (!sampleLines) {
                sampleLines = splitLines(sample.code);
              }

              const fixLine1 = sampleLines.lineFromIndex(fix.range[0]);
              const fixLine2 = sampleLines.lineFromIndex(fix.range[1] - 1);
              if (fixLine1 !== fixLine2) {
                // TODO: handle multi-line fixes
                fix.range = [0, 0];
                fix.text = '';
              } else {
                const line = this.lines[sampleLine + fixLine1];

                const fixColumn1 = fix.range[0] - sampleLines[fixLine1].index;
                const fixColumn2 = fix.range[1] - sampleLines[fixLine1].index;

                fix.range[0] = line.index + line.prefixLength + fixColumn1;
                fix.range[1] = line.index + line.prefixLength + fixColumn2;
              }
            }

            const startLine = msg.line + sampleLine;
            msg.column += this.lines[startLine].prefixLength;
            msg.line = startLine;

            if (msg.endLine) {
              const endLine = msg.endLine + sampleLine;
              msg.endColumn += this.lines[endLine].prefixLength;
              msg.endLine = endLine;
            }

            msg.message = msg.message
              .replace(/\r/g, '\\r')
              .replace(/\n|\u23CE/g, '\\n');

            problems.push(msg);
          }
        }
        return problems;
      }
    }
  }
};

function eslintFiles(opts, filesSrc) {
  opts = opts || {
    outputFile: false,
    quiet: false,
    maxWarnings: -1,
    envs: ['eslint-samples/p5', 'amd'],
    format: 'unix'
  };

  if (filesSrc.length === 0) {
    console.warn('Could not find any files to validate');
    return true;
  }

  const formatter = eslint.CLIEngine.getFormatter(opts.format);
  if (!formatter) {
    console.warn(`Could not find formatter ${opts.format}`);
    return false;
  }

  const engine = new eslint.CLIEngine(opts);
  engine.addPlugin('eslint-samples', module.exports);

  const report = engine.executeOnFiles(filesSrc);

  if (opts.fix) {
    eslint.CLIEngine.outputFixes(report);
  }

  const results = report.results;
  if (opts.quiet) {
    results = eslint.CLIEngine.getErrorResults(results);
  }

  return { report, output: formatter(results) };
}

module.exports.eslintFiles = eslintFiles;

if (!module.parent) {
  const result = eslintFiles(null, process.argv.slice(2));
  console.log(result.output);
  process.exit(result.report.errorCount === 0 ? 0 : 1);
}
<|endoftext|>