<commit_before>// Subscribe to Provider data
Meteor.subscribe('providers');
Meteor.subscribe('counties');

var Counties  = new Mongo.Collection('counties'),

// Providers cursor
providers,

// Map handler
map = {},

// Initialize Google Maps API
initialize = function () {
    // Map Initialization function
    var initialize = function () {
        var mapElement = document.querySelector('#mapCanvas'),

        // Map options
        options = {
            scrollwheel : false,
            zoom        : 12,
            center      : new google.maps.LatLng(43.1, -89.4),
            zoomControl : true,
            minZoom     : 6,
            maxZoom     : 13,
            streetViewControl: false,
            zoomControlOptions: {
                style: 3
            },
        };

        // Map instance
        map = new google.maps.Map(mapElement, options);
        map.set('styles', [
            {
                "featureType": "poi",
                "elementType": "labels",
                "stylers": [{ "visibility": "off" }]
            },
            {
                "stylers": [
                    { "gamma": 0.78 },
                    { "lightness": 5 },
                    { "saturation": 22 }
                ]
            },
            {
                "featureType": "water",
                "stylers": [
                    { "hue": "#00ddff" },
                    { "color": "#04648d" },
                    { "saturation": -23 },
                    { "lightness": 17 },
                    { "gamma": 1.94 }
                ]
            }
        ]);

        // Wait for collection to become available before acting on it
        Deps.autorun(function (c) {
            // Get all providers' IDs, names, and coordinates
            providers = Providers.find({}, { name: 1, coordinates: 1});

            // If collection not ready, try again
            if ( !providers.count() ) return;

            // Create map markers for each provider
            providers.forEach(function (provider) {
                var marker = new google.maps.Marker({
                    position : new google.maps.LatLng(provider.coordinates[0],
                            provider.coordinates[1]),
                    icon     : createPin('#00b7c5','#004146'),
                    animation: google.maps.Animation.DROP,
                    title    : provider.name,
                    id       : provider._id
                });

                // Add hover effect
                google.maps.event.addListener(marker, 'mouseover', mouseover);
                google.maps.event.addListener(marker, 'mouseout',  mouseout);

                // Display Label
                google.maps.event.addListener(marker, 'mouseover', displayLabel);

                // Add to map
                marker.setMap(map);

                //Click Marker
                marker.addListener('click', function() {
                    fullMap(false);
                    google.maps.event.trigger(map,'resize');
                    map.setZoom(12);
                    map.setCenter(marker.getPosition());

                    //Populate Details
                    // Show results if the result has an ID
                    if (this.id)
                        Session.set('currentProvider', Providers.findOne({ _id: this.id }));
                });
            });

            // Stop
            c.stop();
            var infoWindow = new google.maps.InfoWindow({map: map});
            // Geolocation
            if (navigator.geolocation) {
                navigator.geolocation.getCurrentPosition(function (position) {
                    var closest,

                    // Get the distance from current location for each provider
                    providers = Providers.find({}, { coordinates: 1 }).map(function (provider) {
                        // Calculate distance
                        var distance = google.maps.geometry.spherical.computeDistanceBetween(
                            new google.maps.LatLng(position.coords.latitude,
                                position.coords.longitude),
                            new google.maps.LatLng(provider.coordinates[0],
                                provider.coordinates[1])
                        );

                        return { id: provider._id, distance: distance };
                    });

                    // Sort array
                    providers.sort(function (a, b) { return a.distance - b.distance; });

                    // Get closest provider
                    closest = Providers.findOne({ _id: providers[0].id });

                    // Center on it
                    map.panTo(new google.maps.LatLng(
                        closest.coordinates[0],
                        closest.coordinates[1]
                    ));

                    // Show results
                    Session.set('currentProvider', closest);
                }, function() {
                    handleLocationError(true, infoWindow, map.getCenter());
                });
            } else{
                handleLocationError(false, infoWindow, map.getCenter());
            }
        });

      function handleLocationError(browserHasGeolocation, infoWindow, pos) {
          document.getElementById("service-providers").classList.add("full-view");
          if (map.getZoom() > 0) map.setZoom(7);
          map.setCenter(new google.maps.LatLng(44.863579, -89.574563));
      }

        // Create a WCASA map marker
        (function () {
            var marker = new google.maps.Marker({
                position : new google.maps.LatLng(43.0346679, -89.4252416),
                icon     : createPin('#062131','##062131'),
                animation: google.maps.Animation.DROP,
                title    : 'WCASA'
            });

            // Display Label
            google.maps.event.addListener(marker, 'mouseover', displayLabel);
            google.maps.event.addListener(marker, 'mouseout',  hideLabel);

            // Add to map
            marker.setMap(map);
        })();

    },

    // Create SVG Marker Pin
    createPin = function (fillColor,strokeColor) {
        return {
            // SVG Path
            path: 'M 24,4.1C21.2,1.4,17.9,0,14,0c-3.9,0-7.2,1.4-9.9,4.1C1.4,6.9,0,10.2,0,14c0,2,0.3,3.6,0.9,4.9l10,21.2c0.3,0.6,0.7,1.1,1.3,1.4c0.6,0.3,1.2,0.5,1.9,0.5c0.7,0,1.3-0.2,1.9-0.5c0.6-0.3,1-0.8,1.3-1.4l10-21.2c0.6-1.3,0.9-2.9,0.9-4.9C28.1,10.2,26.7,6.9,24,4.1L24,4.1z M19,19c-1.4,1.4-3,2.1-5,2.1c-1.9,0-3.6-0.7-5-2.1C7.7,17.6,7,16,7,14c0-1.9,0.7-3.6,2.1-5c1.4-1.4,3-2.1,5-2.1c1.9,0,3.6,0.7,5,2.1c1.4,1.4,2.1,3,2.1,5C21.1,16,20.4,17.6,19,19L19,19z M19,19',

            // Attributes
            fillColor   : fillColor,
            fillOpacity : 1,
            scale       : 0.9,
            //shape     : shape,
            strokeWeight: 2,
            strokeColor : strokeColor,

            // Pin Position/Offset Controls
            size        : new google.maps.Size(29, 43),
            origin      : new google.maps.Point(0,0),
            anchor      : new google.maps.Point(14, 43)
        }
    },

    // Hover effects
    mouseover = function () {
        this.setIcon(createPin('#00cad9','#004146'), this);
    },
    mouseout = function () {
        this.setIcon(createPin('#00b7c5','#004146'), this);
    },

    // Display info label on hover
    displayLabel = function () {
        // Close any existing infowindow
        if (map.infowindow)
            map.infowindow.close();

        // Create new infowindow
        map.infowindow = new google.maps.InfoWindow({
            content: '
' + this.title + '
'
        });

        // Open new infowindow
        map.infowindow.open(this.get('map'), this);

    },

    // Create maps API script
    script = document.createElement('script');
    script.src = 'https://maps.googleapis.com/maps/api/js?v=3.exp' +
        '&libraries=geometry&callback=initializeMap';
    document.body.appendChild(script);

    // Maps API will look for initialize script in global scope
    window.initializeMap = initialize;
},

// Helper for moving map based on provider locations
moveMap = function (county) {
    var providers = [], x = [], y = [];

    // Mutual Suspician
    county = '' + county;
    if (!county) throw new Error('Invalid county');

    // Get coordinates for all providers for that county
    providers = Providers.find({ counties: { $elemMatch: { $in: [county] }}},
        { coordinates: 1, name:1 }).map(function (provider) {
            // We only care about the coordinates
            return {
                coordinates: provider.coordinates,
                id: provider._id,
                name: provider.name
            };
    });

    // Calculate bounding box
    // Determine lowest and highest Lat values
    providers.sort(function (a, b) {
        return b.coordinates[0] - a.coordinates[0];
    });
    x = [ providers[0].coordinates[0], providers[providers.length - 1].coordinates[0] ];

    // Determine lowest and highest Lon values
    providers.sort(function (a, b) {
        return b.coordinates[1] - a.coordinates[1];
    });
    y = [ providers[0].coordinates[1], providers[providers.length - 1].coordinates[1] ];

    // Bounds
    map.fitBounds(new google.maps.LatLngBounds(
        new google.maps.LatLng( x[1], y[1] ), // Southwest
        new google.maps.LatLng( x[0], y[0] )  // to Northeast
    ));

    // If there was only one result, click on it for the user
    if (providers.length === 1)
        Session.set('currentProvider', Providers.findOne({ _id: providers[0].id }));
},

// Setting the map view to full
fullMap = function (condition) {
    if (condition == true){
        document.getElementById("service-providers").classList.add("full-view");
        if (map.getZoom() > 0) map.setZoom(7);
        map.setCenter(new google.maps.LatLng(44.863579, -89.574563));
    } else{
        document.getElementById("service-providers").classList.remove("full-view");
    }
},

// Hide info label on mouseout
hideLabel = function () {
    if (map.infowindow)
        map.infowindow.close();
},

// Get X and Y Coordinates based on web mercator projection
getXY = function (lat, lon) {
    console.info('Meters per pixel', 156543.03392 * Math.cos(lat * Math.PI / 180)
        / Math.pow(2, 12));
    return [
        128 / Math.PI * Math.pow(2, 12) * (lon + Math.PI),
        128 / Math.PI * Math.pow(2, 12) * (Math.PI -
            Math.log( Math.tan( Math.PI / 4 + lat / 2 ) ))
    ];
},

// Get county from ZIP code number
getCounty = function (zip) {
    var county = '';

    // Mutual Suspicion
    if (!zip) throw new Error('No ZIP element?');

    // Get county
    county = Counties.findOne({ zips:
        // Minimongo doesn't support $eq for some reason
        { $elemMatch: { $in: [zip] } }});

    // Now get providers that support that county
    moveMap(county.name);
};

// On proper initialization (meteor sucks at handling race conditions)
//Template.body.onRendered(function () {
    Template.providers.onRendered(initialize);
//});

Template.providers.events({
    // County drop-down list
    'change #county': function (event) {
        var name = event.target.value;

        // Mutual Suspician
        if (!name) throw new Error('Invalid county');

        moveMap(name);

        // Close search field
        closeMapSearch();
        openDetails();
        document.body.classList.remove('providersListOpen');
    },
    'click .mapView': function (event) {
        event.stopPropagation();event.preventDefault();
        document.body.classList.remove('providersListOpen');
        document.getElementById("service-providers").classList.add("full-view");
        google.maps.event.trigger(map,'resize');
        hideLabel();
        fullMap(true);
    },
    'click .fullMap': function (event){
        event.stopPropagation();event.preventDefault();
        document.body.classList.remove('providersListOpen');
        document.getElementById("service-providers").classList.add("full-view");
        google.maps.event.trigger(map,'resize');
        hideLabel();
        fullMap(true);
    },
    // Clicking ZIP Code GO button
    'click #zip + .submit': function (event) {
        // Stop form submission
        event.preventDefault();

        getCounty(event.currentTarget.parentElement.querySelector('#zip').value);

        // Close search field
        closeMapSearch();
        openDetails();
    },
    // Reaching 5 digits
    'keyup #zip': function (event) {
        if (event.currentTarget.value.length === 5) {
            getCounty(event.currentTarget.value);
            document.body.classList.remove('providersListOpen');
            // Close search field
            closeMapSearch();
            openDetails();
            google.maps.event.trigger(map,'resize');
        }
    }
});

/**
 * Follow Provider link to pin on map
 * @method
 *   @param {$.Event} event - jQuery event passed to handler
 */
Template.providerListViewItem.events({
    'click div.pad': function (event) {
        if ( !(event instanceof $.Event) ) return;
        event.stopPropagation();
        event.preventDefault();

        // Update info section
        Session.set('currentProvider', Providers.findOne({ _id: this._id }));

        // Update map
        map.panTo(new google.maps.LatLng(
            this.coordinates[0],
            this.coordinates[1]
        ));

        // Close providers section
        document.body.classList.remove('providersListOpen');
    }
});
<commit_msg>Added condition, if multiple providers, show full map.<commit_after>// Subscribe to Provider data
Meteor.subscribe('providers');
Meteor.subscribe('counties');

var Counties  = new Mongo.Collection('counties'),

// Providers cursor
providers,

// Map handler
map = {},

// Initialize Google Maps API
initialize = function () {
    // Map Initialization function
    var initialize = function () {
        var mapElement = document.querySelector('#mapCanvas'),

        // Map options
        options = {
            scrollwheel : false,
            zoom        : 12,
            center      : new google.maps.LatLng(43.1, -89.4),
            zoomControl : true,
            minZoom     : 6,
            maxZoom     : 13,
            streetViewControl: false,
            zoomControlOptions: {
                style: 3
            },
        };

        // Map instance
        map = new google.maps.Map(mapElement, options);
        map.set('styles', [
            {
                "featureType": "poi",
                "elementType": "labels",
                "stylers": [{ "visibility": "off" }]
            },
            {
                "stylers": [
                    { "gamma": 0.78 },
                    { "lightness": 5 },
                    { "saturation": 22 }
                ]
            },
            {
                "featureType": "water",
                "stylers": [
                    { "hue": "#00ddff" },
                    { "color": "#04648d" },
                    { "saturation": -23 },
                    { "lightness": 17 },
                    { "gamma": 1.94 }
                ]
            }
        ]);

        // Wait for collection to become available before acting on it
        Deps.autorun(function (c) {
            // Get all providers' IDs, names, and coordinates
            providers = Providers.find({}, { name: 1, coordinates: 1});

            // If collection not ready, try again
            if ( !providers.count() ) return;

            // Create map markers for each provider
            providers.forEach(function (provider) {
                var marker = new google.maps.Marker({
                    position : new google.maps.LatLng(provider.coordinates[0],
                            provider.coordinates[1]),
                    icon     : createPin('#00b7c5','#004146'),
                    animation: google.maps.Animation.DROP,
                    title    : provider.name,
                    id       : provider._id
                });

                // Add hover effect
                google.maps.event.addListener(marker, 'mouseover', mouseover);
                google.maps.event.addListener(marker, 'mouseout',  mouseout);

                // Display Label
                google.maps.event.addListener(marker, 'mouseover', displayLabel);

                // Add to map
                marker.setMap(map);

                //Click Marker
                marker.addListener('click', function() {
                    fullMap(false);
                    google.maps.event.trigger(map,'resize');
                    map.setZoom(12);
                    map.setCenter(marker.getPosition());

                    // Show results if the result has an ID
                    if (this.id)
                        Session.set('currentProvider', Providers.findOne({ _id: this.id }));
                });
            });

            // Stop
            c.stop();
            var infoWindow = new google.maps.InfoWindow({map: map});
            // Geolocation
            if (navigator.geolocation) {
                navigator.geolocation.getCurrentPosition(function (position) {
                    var closest,

                    // Get the distance from current location for each provider
                    providers = Providers.find({}, { coordinates: 1 }).map(function (provider) {
                        // Calculate distance
                        var distance = google.maps.geometry.spherical.computeDistanceBetween(
                            new google.maps.LatLng(position.coords.latitude,
                                position.coords.longitude),
                            new google.maps.LatLng(provider.coordinates[0],
                                provider.coordinates[1])
                        );

                        return { id: provider._id, distance: distance };
                    });

                    // Sort array
                    providers.sort(function (a, b) { return a.distance - b.distance; });

                    // Get closest provider
                    closest = Providers.findOne({ _id: providers[0].id });

                    // Center on it
                    map.panTo(new google.maps.LatLng(
                        closest.coordinates[0],
                        closest.coordinates[1]
                    ));

                    // Show results
                    Session.set('currentProvider', closest);
                }, function() {
                    handleLocationError(true, infoWindow, map.getCenter());
                });
            } else{
                handleLocationError(false, infoWindow, map.getCenter());
            }
        });

      function handleLocationError(browserHasGeolocation, infoWindow, pos) {
          document.getElementById("service-providers").classList.add("full-view");
          if (map.getZoom() > 0) map.setZoom(7);
          map.setCenter(new google.maps.LatLng(44.863579, -89.574563));
      }

        // Create a WCASA map marker
        (function () {
            var marker = new google.maps.Marker({
                position : new google.maps.LatLng(43.0346679, -89.4252416),
                icon     : createPin('#062131','##062131'),
                animation: google.maps.Animation.DROP,
                title    : 'WCASA'
            });

            // Display Label
            google.maps.event.addListener(marker, 'mouseover', displayLabel);
            google.maps.event.addListener(marker, 'mouseout',  hideLabel);

            // Add to map
            marker.setMap(map);
        })();

    },

    // Create SVG Marker Pin
    createPin = function (fillColor,strokeColor) {
        return {
            // SVG Path
            path: 'M 24,4.1C21.2,1.4,17.9,0,14,0c-3.9,0-7.2,1.4-9.9,4.1C1.4,6.9,0,10.2,0,14c0,2,0.3,3.6,0.9,4.9l10,21.2c0.3,0.6,0.7,1.1,1.3,1.4c0.6,0.3,1.2,0.5,1.9,0.5c0.7,0,1.3-0.2,1.9-0.5c0.6-0.3,1-0.8,1.3-1.4l10-21.2c0.6-1.3,0.9-2.9,0.9-4.9C28.1,10.2,26.7,6.9,24,4.1L24,4.1z M19,19c-1.4,1.4-3,2.1-5,2.1c-1.9,0-3.6-0.7-5-2.1C7.7,17.6,7,16,7,14c0-1.9,0.7-3.6,2.1-5c1.4-1.4,3-2.1,5-2.1c1.9,0,3.6,0.7,5,2.1c1.4,1.4,2.1,3,2.1,5C21.1,16,20.4,17.6,19,19L19,19z M19,19',

            // Attributes
            fillColor   : fillColor,
            fillOpacity : 1,
            scale       : 0.9,
            //shape     : shape,
            strokeWeight: 2,
            strokeColor : strokeColor,

            // Pin Position/Offset Controls
            size        : new google.maps.Size(29, 43),
            origin      : new google.maps.Point(0,0),
            anchor      : new google.maps.Point(14, 43)
        }
    },

    // Hover effects
    mouseover = function () {
        this.setIcon(createPin('#00cad9','#004146'), this);
    },
    mouseout = function () {
        this.setIcon(createPin('#00b7c5','#004146'), this);
    },

    // Display info label on hover
    displayLabel = function () {
        // Close any existing infowindow
        if (map.infowindow)
            map.infowindow.close();

        // Create new infowindow
        map.infowindow = new google.maps.InfoWindow({
            content: '
' + this.title + '
'
        });

        // Open new infowindow
        map.infowindow.open(this.get('map'), this);

    },

    // Create maps API script
    script = document.createElement('script');
    script.src = 'https://maps.googleapis.com/maps/api/js?v=3.exp' +
        '&libraries=geometry&callback=initializeMap';
    document.body.appendChild(script);

    // Maps API will look for initialize script in global scope
    window.initializeMap = initialize;
},

// Helper for moving map based on provider locations
moveMap = function (county) {
    var providers = [], x = [], y = [];

    // Mutual Suspician
    county = '' + county;
    if (!county) throw new Error('Invalid county');

    // Get coordinates for all providers for that county
    providers = Providers.find({ counties: { $elemMatch: { $in: [county] }}},
        { coordinates: 1, name:1 }).map(function (provider) {
            // We only care about the coordinates
            return {
                coordinates: provider.coordinates,
                id: provider._id,
                name: provider.name
            };
    });

    // Calculate bounding box
    // Determine lowest and highest Lat values
    providers.sort(function (a, b) {
        return b.coordinates[0] - a.coordinates[0];
    });
    x = [ providers[0].coordinates[0], providers[providers.length - 1].coordinates[0] ];

    // Determine lowest and highest Lon values
    providers.sort(function (a, b) {
        return b.coordinates[1] - a.coordinates[1];
    });
    y = [ providers[0].coordinates[1], providers[providers.length - 1].coordinates[1] ];

    // Bounds
    map.fitBounds(new google.maps.LatLngBounds(
        new google.maps.LatLng( x[1], y[1] ), // Southwest
        new google.maps.LatLng( x[0], y[0] )  // to Northeast
    ));

    // If there was only one result, click on it for the user
    if (providers.length === 1){
        Session.set('currentProvider', Providers.findOne({ _id: providers[0].id }));
    } else{
        document.getElementById("service-providers").classList.add("full-view");
    }
},

// Setting the map view to full
fullMap = function (condition) {
    if (condition == true){
        document.getElementById("service-providers").classList.add("full-view");
        if (map.getZoom() > 0) map.setZoom(7);
        map.setCenter(new google.maps.LatLng(44.863579, -89.574563));
    } else{
        document.getElementById("service-providers").classList.remove("full-view");
    }
},

// Hide info label on mouseout
hideLabel = function () {
    if (map.infowindow)
        map.infowindow.close();
},

// Get X and Y Coordinates based on web mercator projection
getXY = function (lat, lon) {
    console.info('Meters per pixel', 156543.03392 * Math.cos(lat * Math.PI / 180)
        / Math.pow(2, 12));
    return [
        128 / Math.PI * Math.pow(2, 12) * (lon + Math.PI),
        128 / Math.PI * Math.pow(2, 12) * (Math.PI -
            Math.log( Math.tan( Math.PI / 4 + lat / 2 ) ))
    ];
},

// Get county from ZIP code number
getCounty = function (zip) {
    var county = '';

    // Mutual Suspicion
    if (!zip) throw new Error('No ZIP element?');

    // Get county
    county = Counties.findOne({ zips:
        // Minimongo doesn't support $eq for some reason
        { $elemMatch: { $in: [zip] } }});

    // Now get providers that support that county
    moveMap(county.name);
};

// On proper initialization (meteor sucks at handling race conditions)
//Template.body.onRendered(function () {
    Template.providers.onRendered(initialize);
//});

Template.providers.events({
    // County drop-down list
    'change #county': function (event) {
        var name = event.target.value;

        // Mutual Suspician
        if (!name) throw new Error('Invalid county');

        moveMap(name);

        // Close search field
        closeMapSearch();
        openDetails();
        document.body.classList.remove('providersListOpen');
    },
    'click .mapView': function (event) {
        event.stopPropagation();event.preventDefault();
        document.body.classList.remove('providersListOpen');
        document.getElementById("service-providers").classList.add("full-view");
        google.maps.event.trigger(map,'resize');
        hideLabel();
        fullMap(true);
    },
    'click .fullMap': function (event){
        event.stopPropagation();event.preventDefault();
        document.body.classList.remove('providersListOpen');
        document.getElementById("service-providers").classList.add("full-view");
        google.maps.event.trigger(map,'resize');
        hideLabel();
        fullMap(true);
    },
    // Clicking ZIP Code GO button
    'click #zip + .submit': function (event) {
        // Stop form submission
        event.preventDefault();

        getCounty(event.currentTarget.parentElement.querySelector('#zip').value);

        // Close search field
        closeMapSearch();
        openDetails();
    },
    // Reaching 5 digits
    'keyup #zip': function (event) {
        if (event.currentTarget.value.length === 5) {
            openDetails();
            getCounty(event.currentTarget.value);
            document.body.classList.remove('providersListOpen');
            // Close search field
            closeMapSearch();
            google.maps.event.trigger(map,'resize');
        }
    }
});

/**
 * Follow Provider link to pin on map
 * @method
 *   @param {$.Event} event - jQuery event passed to handler
 */
Template.providerListViewItem.events({
    'click div.pad': function (event) {
        if ( !(event instanceof $.Event) ) return;
        event.stopPropagation();
        event.preventDefault();

        // Update info section
        Session.set('currentProvider', Providers.findOne({ _id: this._id }));

        // Update map
        map.panTo(new google.maps.LatLng(
            this.coordinates[0],
            this.coordinates[1]
        ));

        // Close providers section
        document.body.classList.remove('providersListOpen');
    }
});
<|endoftext|>


<commit_before>
var url = require("url"),
http = require("http");

exports.name = "links.compound";
exports.check = function (sr, done) {
    var links = [];
    if ( typeof String.prototype.startsWith != 'function' ) {
        String.prototype.startsWith = function( str ) {
            return this.substring( 0, str.length ) === str;
        }
    };

    sr.$('a[href]').each(function () {
        var parsedLink = url.parse(url.resolve(sr.url, sr.$(this).attr("href"))),
        l = parsedLink.protocol + '//' + parsedLink.host + parsedLink.pathname;
        if (l.startsWith(sr.url) && l != sr.url) {
            links.push(l);
        }
    });
    links = links.sort().filter(function (item, pos) {return (!pos || item != links[pos - 1]);});
    var c = 0;
    links.forEach(function (l, i) {
        var parsedLink = url.parse(l),
            options = {method: 'HEAD', host: parsedLink.hostname, port: parsedLink.port, path: parsedLink.pathname},
            req = http.request(options, function(res) {
                if (res.headers["content-type"].indexOf("text/html") > -1 || res.headers["content-type"].indexOf("application/xhtml+xml") > -1) {
                    sr.warning(exports.name, "links", { file : l.split('/').pop(), link : l } )
                }
                c++;
                if (c === links.length - 1) {
                    done();
                }
            });
        req.end();
    });
};
<commit_msg>2nd version without checking the content-type because it's too slow<commit_after>
var url = require("url");

exports.name = "links.compound";
exports.check = function (sr, done) {
    var links = [];
    if ( typeof String.prototype.startsWith != 'function' ) {
        String.prototype.startsWith = function( str ) {
            return this.substring( 0, str.length ) === str;
        }
    };

    sr.$('a[href]').each(function () {
        var parsedLink = url.parse(url.resolve(sr.url, sr.$(this).attr("href"))),
        l = parsedLink.protocol + '//' + parsedLink.host + parsedLink.pathname;
        if (l.startsWith(sr.url) && l != sr.url) {
            links.push(l);
        }
    });
    // sort and remove duplicates
    links = links.sort().filter(function (item, pos) {return (!pos || item != links[pos - 1]);});
    links.forEach(function (l) {
        sr.info(exports.name, "links", { file : l.split('/').pop(), link : l } )
    });
};
<|endoftext|>


<commit_before>var isFinite = require('../');
var test = require('tape');

test('returns `true` for finite values', function(t) {
  t.plan(5);

  t.ok(isFinite(0));
  t.ok(isFinite(1));
  t.ok(isFinite(3.14));
  t.ok(isFinite(-1));
  t.ok(isFinite(new Number(0)));
});

test('returns `false` for non-finite values', function(t) {
  t.plan(3);

  t.ok(!isFinite(NaN));
  t.ok(!isFinite(Infinity));
  t.ok(!isFinite(-Infinity));
});

test('returns `false` for non-numeric values', function(t) {
  t.plan(8);

  t.ok(!isFinite(null));
  t.ok(!isFinite(undefined));
  t.ok(!isFinite([]));
  t.ok(!isFinite(true));
  t.ok(!isFinite(new Date));
  t.ok(!isFinite(''));
  t.ok(!isFinite(' '));
  t.ok(!isFinite('2px'));
});

test('returns `true` for numeric string values', function(t) {
  t.plan(3);

  t.ok(isFinite('2'));
  t.ok(isFinite('0'));
  t.ok(isFinite('08'));
});<commit_msg>notOk<commit_after>var isFinite = require('../');
var test = require('tape');

test('returns `true` for finite values', function(t) {
  t.plan(5);

  t.ok(isFinite(0));
  t.ok(isFinite(1));
  t.ok(isFinite(3.14));
  t.ok(isFinite(-1));
  t.ok(isFinite(new Number(0)));
});

test('returns `false` for non-finite values', function(t) {
  t.plan(3);

  t.notOk(isFinite(NaN));
  t.notOk(isFinite(Infinity));
  t.notOk(isFinite(-Infinity));
});

test('returns `false` for non-numeric values', function(t) {
  t.plan(8);

  t.notOk(isFinite(null));
  t.notOk(isFinite(undefined));
  t.notOk(isFinite([]));
  t.notOk(isFinite(true));
  t.notOk(isFinite(new Date));
  t.notOk(isFinite(''));
  t.notOk(isFinite(' '));
  t.notOk(isFinite('2px'));
});

test('returns `true` for numeric string values', function(t) {
  t.plan(3);

  t.ok(isFinite('2'));
  t.ok(isFinite('0'));
  t.ok(isFinite('08'));
});<|endoftext|>


<commit_before>import http from 'http';
import assert from 'assert';

import { PORT } from '../src/constants';
import '../src/index.js';

const URL = `http://127.0.0.1:${PORT}`;

describe('Node Server', () => {
  it('should return 200', done => {
    http.get(URL, res => {
      assert.equal(200, res.statusCode);
      done();
    });
  });
});
<commit_msg>added test/index.js file<commit_after>import http from 'http';
import assert from 'assert';

import { PORT } from '../src/constants';
import '../src/index.js';

const URL = `http://127.0.0.1:${PORT}`;

describe('Node Server', () => {
  it('should return 200', done => {
    http.get(URL, res => {
      assert.equal(200, res.statusCode);
      done();
    });
  });
});
<|endoftext|>


<commit_before>if (typeof(PhpDebugBar) == 'undefined') {
    // namespace
    var PhpDebugBar = {};
    PhpDebugBar.$ = jQuery;
}

(function($) {

    var csscls = function(cls) {
        return PhpDebugBar.utils.csscls(cls, 'phpdebugbar-openhandler-');
    };

    PhpDebugBar.OpenHandler = PhpDebugBar.Widget.extend({

        className: 'phpdebugbar-openhandler',

        defaults: {
            items_per_page: 20
        },

        render: function() {
            var self = this;

            this.$el.appendTo('body').hide();
            this.$closebtn = $('');
            this.$table = $('
');
            $('
PHP DebugBar | Open
').addClass(csscls('header')).append(this.$closebtn).appendTo(this.$el);
            $('

Load	Method	URL	Date	IP

').append(this.$table).appendTo(this.$el);
            this.$actions = $('
').addClass(csscls('actions')).appendTo(this.$el);

            this.$closebtn.on('click', function() {
                self.hide();
            });

            this.$loadmorebtn = $('Load more')
                .appendTo(this.$actions)
                .on('click', function() {
                    self.find(self.last_find_request, self.last_find_request.offset + self.get('items_per_page'), self.handleFind.bind(self));
                });

            this.$showonlycurrentbtn = $('Show only current URL')
                .appendTo(this.$actions)
                .on('click', function() {
                    self.$table.empty();
                    self.find({uri: window.location.pathname}, 0, self.handleFind.bind(self));
                });

            this.$showallbtn = $('Show all')
                .appendTo(this.$actions)
                .on('click', function() {
                    self.refresh();
                });

            this.$clearbtn = $('Delete all')
                .appendTo(this.$actions)
                .on('click', function() {
                    self.clear(function() {
                        self.hide();
                    });
                });

            this.addSearch();

            this.$overlay = $('
').addClass(csscls('overlay')).hide().appendTo('body');
            this.$overlay.on('click', function() {
                self.hide();
            });
        },

        refresh: function() {
            this.$table.empty();
            this.$loadmorebtn.show();
            this.find({}, 0, this.handleFind.bind(this));
        },

        addSearch: function(){
            var self = this;
            var searchBtn = $('<button />')
                .text('Search')
                .on('click', function(e) {
                    self.$table.empty();
                    var search = {};
                    var a = $(this).parent().serializeArray();
                    $.each(a, function() {
                        if(this.value){
                            search[this.name] = this.value;
                        }
                    });

                    self.find(search, 0, self.handleFind.bind(self));
                    e.preventDefault();
                });

            $('<form />')
                .append('
Filter results
')
                .append('Method: <select name="method"><option></option><option>GET</option><option>POST</option><option>PUT</option><option>DELETE</option></select>
')
                .append('Uri: <input type="text" name="uri">
')
                .append('IP: <input type="text" name="ip">
')
                .append(searchBtn)
                .appendTo(this.$actions);
        },

        handleFind: function(data) {
            var self = this;
            $.each(data, function(i, meta) {
               var a = $('')
                    .text('Load dataset')
                    .on('click', function(e) {
                        self.hide();
                        self.load(meta['id'], function(data) {
                            self.callback(meta['id'], data);
                        });
                        e.preventDefault();
                    });

                var method = $('')
                    .text(meta['method'])
                    .on('click', function(e) {
                        self.$table.empty();
                        self.find({method: meta['method']}, 0, self.handleFind.bind(self));
                        e.preventDefault();
                    });

                var uri = $('')
                    .text(meta['uri'])
                    .on('click', function(e) {
                        self.$table.empty();
                        self.find({uri: meta['uri']}, 0, self.handleFind.bind(self));
                        e.preventDefault();
                    });

                var ip = $('')
                    .text(meta['ip'])
                    .on('click', function(e) {
                        self.$table.empty();
                        self.find({ip: meta['ip']}, 0, self.handleFind.bind(self));
                        e.preventDefault();
                    });

                $('
')
                    .append($('').append(a))
                    .append($('').append(method))
                    .append($('').append(uri))
                    .append('' + meta['datetime'] + '	')
                    .append($('').append(ip))
                    .appendTo(self.$table);
            });
            if (data.length < this.get('items_per_page')) {
                this.$loadmorebtn.hide();
            }
        },

        show: function(callback) {
            this.callback = callback;
            this.$el.show();
            this.$overlay.show();
            this.refresh();
        },

        hide: function() {
            this.$el.hide();
            this.$overlay.hide();
        },

        find: function(filters, offset, callback) {
            var data = $.extend({}, filters, {max: this.get('items_per_page'), offset: offset || 0});
            this.last_find_request = data;
            this.ajax(data, callback);
        },

        load: function(id, callback) {
            this.ajax({op: "get", id: id}, callback);
        },

        clear: function(callback) {
            this.ajax({op: "clear"}, callback);
        },

        ajax: function(data, callback) {
            $.ajax({
                dataType: 'json',
                url: this.get('url'),
                data: data,
                success: callback,
                ignoreDebugBarAjaxHandler: true
            });
        }

    });

})(PhpDebugBar.$);
<commit_msg>Tweak openhandler<commit_after>if (typeof(PhpDebugBar) == 'undefined') {
    // namespace
    var PhpDebugBar = {};
    PhpDebugBar.$ = jQuery;
}

(function($) {

    var csscls = function(cls) {
        return PhpDebugBar.utils.csscls(cls, 'phpdebugbar-openhandler-');
    };

    PhpDebugBar.OpenHandler = PhpDebugBar.Widget.extend({

        className: 'phpdebugbar-openhandler',

        defaults: {
            items_per_page: 20
        },

        render: function() {
            var self = this;

            this.$el.appendTo('body').hide();
            this.$closebtn = $('');
            this.$table = $('
');
            $('
PHP DebugBar | Open
').addClass(csscls('header')).append(this.$closebtn).appendTo(this.$el);
            $('

Date	Method	URL	IP	Filter data

').append(this.$table).appendTo(this.$el);
            this.$actions = $('
').addClass(csscls('actions')).appendTo(this.$el);

            this.$closebtn.on('click', function() {
                self.hide();
            });

            this.$loadmorebtn = $('Load more')
                .appendTo(this.$actions)
                .on('click', function() {
                    self.find(self.last_find_request, self.last_find_request.offset + self.get('items_per_page'), self.handleFind.bind(self));
                });

            this.$showonlycurrentbtn = $('Show only current URL')
                .appendTo(this.$actions)
                .on('click', function() {
                    self.$table.empty();
                    self.find({uri: window.location.pathname}, 0, self.handleFind.bind(self));
                });

            this.$showallbtn = $('Show all')
                .appendTo(this.$actions)
                .on('click', function() {
                    self.refresh();
                });

            this.$clearbtn = $('Delete all')
                .appendTo(this.$actions)
                .on('click', function() {
                    self.clear(function() {
                        self.hide();
                    });
                });

            this.addSearch();

            this.$overlay = $('
').addClass(csscls('overlay')).hide().appendTo('body');
            this.$overlay.on('click', function() {
                self.hide();
            });
        },

        refresh: function() {
            this.$table.empty();
            this.$loadmorebtn.show();
            this.find({}, 0, this.handleFind.bind(this));
        },

        addSearch: function(){
            var self = this;
            var searchBtn = $('<button />')
                .text('Search')
                .on('click', function(e) {
                    self.$table.empty();
                    var search = {};
                    var a = $(this).parent().serializeArray();
                    $.each(a, function() {
                        if(this.value){
                            search[this.name] = this.value;
                        }
                    });

                    self.find(search, 0, self.handleFind.bind(self));
                    e.preventDefault();
                });

            $('<form />')
                .append('
Filter results
')
                .append('Method: <select name="method"><option></option><option>GET</option><option>POST</option><option>PUT</option><option>DELETE</option></select>
')
                .append('Uri: <input type="text" name="uri">
')
                .append('IP: <input type="text" name="ip">
')
                .append(searchBtn)
                .appendTo(this.$actions);
        },

        handleFind: function(data) {
            var self = this;
            $.each(data, function(i, meta) {
               var a = $('')
                    .text('Load dataset')
                    .on('click', function(e) {
                       self.hide();
                       self.load(meta['id'], function(data) {
                           self.callback(meta['id'], data);
                       });
                       e.preventDefault();
                    });

                var method = $('')
                    .text(meta['method'])
                    .on('click', function(e) {
                        self.$table.empty();
                        self.find({method: meta['method']}, 0, self.handleFind.bind(self));
                        e.preventDefault();
                    });

                var uri = $('')
                    .text(meta['uri'])
                    .on('click', function(e) {
                        self.hide();
                        self.load(meta['id'], function(data) {
                            self.callback(meta['id'], data);
                        });
                        e.preventDefault();
                    });

                var ip = $('')
                    .text(meta['ip'])
                    .on('click', function(e) {
                        self.$table.empty();
                        self.find({ip: meta['ip']}, 0, self.handleFind.bind(self));
                        e.preventDefault();
                    });

                var search = $('')
                    .text('Show URL')
                    .on('click', function(e) {
                        self.$table.empty();
                        self.find({uri: meta['uri']}, 0, self.handleFind.bind(self));
                        e.preventDefault();
                    });

                $('
')
                    .append('' + meta['datetime'] + '	')
                    .append('' + meta['method'] + '	')
                    .append($('').append(uri))
                    .append($('').append(ip))
                    .append($('').append(search))
                    .appendTo(self.$table);
            });
            if (data.length < this.get('items_per_page')) {
                this.$loadmorebtn.hide();
            }
        },

        show: function(callback) {
            this.callback = callback;
            this.$el.show();
            this.$overlay.show();
            this.refresh();
        },

        hide: function() {
            this.$el.hide();
            this.$overlay.hide();
        },

        find: function(filters, offset, callback) {
            var data = $.extend({}, filters, {max: this.get('items_per_page'), offset: offset || 0});
            this.last_find_request = data;
            this.ajax(data, callback);
        },

        load: function(id, callback) {
            this.ajax({op: "get", id: id}, callback);
        },

        clear: function(callback) {
            this.ajax({op: "clear"}, callback);
        },

        ajax: function(data, callback) {
            $.ajax({
                dataType: 'json',
                url: this.get('url'),
                data: data,
                success: callback,
                ignoreDebugBarAjaxHandler: true
            });
        }

    });

})(PhpDebugBar.$);
<|endoftext|>


<commit_before>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

let err = false;

const majorNodeVersion = parseInt(/^(\d+)\./.exec(process.versions.node)[1]);

if (majorNodeVersion < 10 || majorNodeVersion >= 16) {
	console.error('\033[1;31m*** Please use node >=10 and <=16.\033[0;0m');
	err = true;
}

const cp = require('child_process');
const yarnVersion = cp.execSync('yarn -v', { encoding: 'utf8' }).trim();
const parsedYarnVersion = /^(\d+)\.(\d+)\./.exec(yarnVersion);
const majorYarnVersion = parseInt(parsedYarnVersion[1]);
const minorYarnVersion = parseInt(parsedYarnVersion[2]);

if (majorYarnVersion < 1 || minorYarnVersion < 10) {
	console.error('\033[1;31m*** Please use yarn >=1.10.1.\033[0;0m');
	err = true;
}

if (!/yarn[\w-.]*\.js$|yarnpkg$/.test(process.env['npm_execpath'])) {
	console.error('\033[1;31m*** Please use yarn to install dependencies.\033[0;0m');
	err = true;
}

if (process.platform === 'win32') {
	if (!hasSupportedVisualStudioVersion()) {
		console.error('\033[1;31m*** Invalid C/C++ Compiler Toolchain. Please check https://github.com/microsoft/vscode/wiki/How-to-Contribute.\033[0;0m');
		err = true;
	}
}

if (err) {
	console.error('');
	process.exit(1);
}

function hasSupportedVisualStudioVersion() {
	const fs = require('fs');
	const path = require('path');
	// Translated over from
	// https://source.chromium.org/chromium/chromium/src/+/master:build/vs_toolchain.py;l=140-175
	const supportedVersions = ['2019', '2017'];

	const availableVersions = [];
	for (const version of supportedVersions) {
		let vsPath = process.env[`vs${version}_install`];
		if (vsPath && fs.existsSync(vsPath)) {
			availableVersions.push(version);
			break;
		}
		const programFiles86Path = process.env['ProgramFiles(x86)'];
		if (programFiles86Path) {
			vsPath = `${programFiles86Path}/Microsoft Visual Studio/${version}`;
			const vsTypes = ['Enterprise', 'Professional', 'Community', 'Preview', 'BuildTools'];
			if (vsTypes.some(vsType => fs.existsSync(path.join(vsPath, vsType)))) {
				availableVersions.push(version);
				break;
			}
		}
	}
	return availableVersions.length;
}
<commit_msg>:chore: allow to use node.js 16 for developing vscode<commit_after>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

let err = false;

const majorNodeVersion = parseInt(/^(\d+)\./.exec(process.versions.node)[1]);

if (majorNodeVersion < 10 || majorNodeVersion >= 17) {
	console.error('\033[1;31m*** Please use node.js versions >=10 and <=17.\033[0;0m');
	err = true;
}

const cp = require('child_process');
const yarnVersion = cp.execSync('yarn -v', { encoding: 'utf8' }).trim();
const parsedYarnVersion = /^(\d+)\.(\d+)\./.exec(yarnVersion);
const majorYarnVersion = parseInt(parsedYarnVersion[1]);
const minorYarnVersion = parseInt(parsedYarnVersion[2]);

if (majorYarnVersion < 1 || minorYarnVersion < 10) {
	console.error('\033[1;31m*** Please use yarn >=1.10.1.\033[0;0m');
	err = true;
}

if (!/yarn[\w-.]*\.js$|yarnpkg$/.test(process.env['npm_execpath'])) {
	console.error('\033[1;31m*** Please use yarn to install dependencies.\033[0;0m');
	err = true;
}

if (process.platform === 'win32') {
	if (!hasSupportedVisualStudioVersion()) {
		console.error('\033[1;31m*** Invalid C/C++ Compiler Toolchain. Please check https://github.com/microsoft/vscode/wiki/How-to-Contribute.\033[0;0m');
		err = true;
	}
}

if (err) {
	console.error('');
	process.exit(1);
}

function hasSupportedVisualStudioVersion() {
	const fs = require('fs');
	const path = require('path');
	// Translated over from
	// https://source.chromium.org/chromium/chromium/src/+/master:build/vs_toolchain.py;l=140-175
	const supportedVersions = ['2019', '2017'];

	const availableVersions = [];
	for (const version of supportedVersions) {
		let vsPath = process.env[`vs${version}_install`];
		if (vsPath && fs.existsSync(vsPath)) {
			availableVersions.push(version);
			break;
		}
		const programFiles86Path = process.env['ProgramFiles(x86)'];
		if (programFiles86Path) {
			vsPath = `${programFiles86Path}/Microsoft Visual Studio/${version}`;
			const vsTypes = ['Enterprise', 'Professional', 'Community', 'Preview', 'BuildTools'];
			if (vsTypes.some(vsType => fs.existsSync(path.join(vsPath, vsType)))) {
				availableVersions.push(version);
				break;
			}
		}
	}
	return availableVersions.length;
}
<|endoftext|>


<commit_before>'use strict'

const TrailsApp = require('trails')

before(() => {
  global.app = new TrailsApp(require('./app'))
  return global.app.start().catch(global.app.stop)
})

after(() => {
  return global.app.stop()
})
<commit_msg>increase before all timeout<commit_after>'use strict'

const TrailsApp = require('trails')

before(function () {
  this.timeout(5000)
  global.app = new TrailsApp(require('./app'))
  return global.app.start().catch(global.app.stop)
})

after(() => {
  return global.app.stop()
})
<|endoftext|>


<commit_before>module.exports = (api, options, rootOptions) => {
  const mainVersion = require('./package.json').version
  const version = '^' + mainVersion
  api.extendPackage(pkg => {
    delete pkg.postcss
    delete pkg.browserslist
    return {
      scripts: {
        info: 'node node_modules/@dcloudio/vue-cli-plugin-uni/commands/info.js',
        serve: 'npm run dev:h5',
        build: 'npm run build:h5',
        'serve:quickapp-native': 'node node_modules/@dcloudio/uni-quickapp-native/bin/serve.js',
        'dev:h5': 'cross-env NODE_ENV=development UNI_PLATFORM=h5 vue-cli-service uni-serve',
        'dev:mp-qq': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-qq vue-cli-service uni-build --watch',
        'dev:mp-weixin': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-weixin vue-cli-service uni-build --watch',
        'dev:mp-baidu': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-baidu vue-cli-service uni-build --watch',
        'dev:mp-alipay': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-alipay vue-cli-service uni-build --watch',
        'dev:mp-toutiao': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-toutiao vue-cli-service uni-build --watch',
        'dev:mp-kuaishou': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-kuaishou vue-cli-service uni-build --watch',
        'dev:quickapp-native': 'cross-env NODE_ENV=development UNI_PLATFORM=quickapp-native vue-cli-service uni-build --watch',
        'dev:quickapp-webview': 'cross-env NODE_ENV=development UNI_PLATFORM=quickapp-webview vue-cli-service uni-build --watch',
        'dev:quickapp-webview-huawei': 'cross-env NODE_ENV=development UNI_PLATFORM=quickapp-webview-huawei vue-cli-service uni-build --watch',
        'dev:quickapp-webview-union': 'cross-env NODE_ENV=development UNI_PLATFORM=quickapp-webview-union vue-cli-service uni-build --watch',
        'build:h5': 'cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build',
        'build:mp-qq': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-qq vue-cli-service uni-build',
        'build:mp-weixin': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-weixin vue-cli-service uni-build',
        'build:mp-baidu': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-baidu vue-cli-service uni-build',
        'build:mp-alipay': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-alipay vue-cli-service uni-build',
        'build:mp-toutiao': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-toutiao vue-cli-service uni-build',
        'build:mp-kuaishou': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-kuaishou vue-cli-service uni-build',
        'build:quickapp-native': 'cross-env NODE_ENV=production UNI_PLATFORM=quickapp-native vue-cli-service uni-build',
        'build:quickapp-webview': 'cross-env NODE_ENV=production UNI_PLATFORM=quickapp-webview vue-cli-service uni-build',
        'build:quickapp-webview-huawei': 'cross-env NODE_ENV=production UNI_PLATFORM=quickapp-webview-huawei vue-cli-service uni-build',
        'build:quickapp-webview-union': 'cross-env NODE_ENV=production UNI_PLATFORM=quickapp-webview-union vue-cli-service uni-build',
        'dev:mp-360': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-360 vue-cli-service uni-build --watch',
        'build:mp-360': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-360 vue-cli-service uni-build',
        'dev:custom': 'cross-env NODE_ENV=development uniapp-cli custom',
        'build:custom': 'cross-env NODE_ENV=production uniapp-cli custom',
        'test:h5': 'cross-env UNI_PLATFORM=h5 jest -i',
        'test:ios': 'cross-env UNI_PLATFORM=app-plus UNI_OS_NAME=ios jest -i',
        'test:android': 'cross-env UNI_PLATFORM=app-plus UNI_OS_NAME=android jest -i',
        'test:mp-weixin': 'cross-env UNI_PLATFORM=mp-weixin jest -i',
        'test:mp-baidu': 'cross-env UNI_PLATFORM=mp-baidu jest -i'
      },
      'uni-app': {
        scripts: {}
      },
      dependencies: {
        '@dcloudio/uni-app-plus': version,
        '@dcloudio/uni-h5': version,
        '@dcloudio/uni-mp-vue': version,
        '@dcloudio/uni-mp-qq': version,
        '@dcloudio/uni-mp-weixin': version,
        '@dcloudio/uni-mp-baidu': version,
        '@dcloudio/uni-mp-alipay': version,
        '@dcloudio/uni-mp-toutiao': version,
        '@dcloudio/uni-mp-360': version,
        '@dcloudio/uni-mp-kuaishou': version,
        '@dcloudio/uni-quickapp-native': version,
        '@dcloudio/uni-quickapp-webview': version,
        '@dcloudio/uni-stat': version,
        '@dcloudio/uni-i18n': version,
        '@vue/shared': '^3.0.0',
        flyio: '^0.6.2',
        vuex: '^3.2.0'
      },
      devDependencies: {
        '@dcloudio/uni-automator': version,
        '@dcloudio/uni-cli-shared': version,
        '@dcloudio/uni-migration': version,
        '@dcloudio/uni-template-compiler': version,
        '@dcloudio/vue-cli-plugin-hbuilderx': version,
        '@dcloudio/vue-cli-plugin-uni': version,
        '@dcloudio/vue-cli-plugin-uni-optimize': version,
        '@dcloudio/webpack-uni-mp-loader': version,
        '@dcloudio/webpack-uni-pages-loader': version,
        'babel-plugin-import': '^1.11.0',
        'cross-env': '^7.0.2',
        jest: '^25.4.0'
      },
      browserslist: [
        'Android >= 4.4',
        'ios >= 9'
      ]
    }
  })
}
<commit_msg>feat(cli): add @dcloudio/uni-cli-shared<commit_after>module.exports = (api, options, rootOptions) => {
  const mainVersion = require('./package.json').version
  const version = '^' + mainVersion
  api.extendPackage(pkg => {
    delete pkg.postcss
    delete pkg.browserslist
    return {
      scripts: {
        info: 'node node_modules/@dcloudio/vue-cli-plugin-uni/commands/info.js',
        serve: 'npm run dev:h5',
        build: 'npm run build:h5',
        'serve:quickapp-native': 'node node_modules/@dcloudio/uni-quickapp-native/bin/serve.js',
        'dev:h5': 'cross-env NODE_ENV=development UNI_PLATFORM=h5 vue-cli-service uni-serve',
        'dev:mp-qq': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-qq vue-cli-service uni-build --watch',
        'dev:mp-weixin': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-weixin vue-cli-service uni-build --watch',
        'dev:mp-baidu': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-baidu vue-cli-service uni-build --watch',
        'dev:mp-alipay': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-alipay vue-cli-service uni-build --watch',
        'dev:mp-toutiao': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-toutiao vue-cli-service uni-build --watch',
        'dev:mp-kuaishou': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-kuaishou vue-cli-service uni-build --watch',
        'dev:quickapp-native': 'cross-env NODE_ENV=development UNI_PLATFORM=quickapp-native vue-cli-service uni-build --watch',
        'dev:quickapp-webview': 'cross-env NODE_ENV=development UNI_PLATFORM=quickapp-webview vue-cli-service uni-build --watch',
        'dev:quickapp-webview-huawei': 'cross-env NODE_ENV=development UNI_PLATFORM=quickapp-webview-huawei vue-cli-service uni-build --watch',
        'dev:quickapp-webview-union': 'cross-env NODE_ENV=development UNI_PLATFORM=quickapp-webview-union vue-cli-service uni-build --watch',
        'build:h5': 'cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build',
        'build:mp-qq': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-qq vue-cli-service uni-build',
        'build:mp-weixin': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-weixin vue-cli-service uni-build',
        'build:mp-baidu': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-baidu vue-cli-service uni-build',
        'build:mp-alipay': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-alipay vue-cli-service uni-build',
        'build:mp-toutiao': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-toutiao vue-cli-service uni-build',
        'build:mp-kuaishou': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-kuaishou vue-cli-service uni-build',
        'build:quickapp-native': 'cross-env NODE_ENV=production UNI_PLATFORM=quickapp-native vue-cli-service uni-build',
        'build:quickapp-webview': 'cross-env NODE_ENV=production UNI_PLATFORM=quickapp-webview vue-cli-service uni-build',
        'build:quickapp-webview-huawei': 'cross-env NODE_ENV=production UNI_PLATFORM=quickapp-webview-huawei vue-cli-service uni-build',
        'build:quickapp-webview-union': 'cross-env NODE_ENV=production UNI_PLATFORM=quickapp-webview-union vue-cli-service uni-build',
        'dev:mp-360': 'cross-env NODE_ENV=development UNI_PLATFORM=mp-360 vue-cli-service uni-build --watch',
        'build:mp-360': 'cross-env NODE_ENV=production UNI_PLATFORM=mp-360 vue-cli-service uni-build',
        'dev:custom': 'cross-env NODE_ENV=development uniapp-cli custom',
        'build:custom': 'cross-env NODE_ENV=production uniapp-cli custom',
        'test:h5': 'cross-env UNI_PLATFORM=h5 jest -i',
        'test:ios': 'cross-env UNI_PLATFORM=app-plus UNI_OS_NAME=ios jest -i',
        'test:android': 'cross-env UNI_PLATFORM=app-plus UNI_OS_NAME=android jest -i',
        'test:mp-weixin': 'cross-env UNI_PLATFORM=mp-weixin jest -i',
        'test:mp-baidu': 'cross-env UNI_PLATFORM=mp-baidu jest -i'
      },
      'uni-app': {
        scripts: {}
      },
      dependencies: {
        '@dcloudio/uni-app-plus': version,
        '@dcloudio/uni-h5': version,
        '@dcloudio/uni-mp-vue': version,
        '@dcloudio/uni-mp-qq': version,
        '@dcloudio/uni-mp-weixin': version,
        '@dcloudio/uni-mp-baidu': version,
        '@dcloudio/uni-mp-alipay': version,
        '@dcloudio/uni-mp-toutiao': version,
        '@dcloudio/uni-mp-360': version,
        '@dcloudio/uni-mp-kuaishou': version,
        '@dcloudio/uni-quickapp-native': version,
        '@dcloudio/uni-quickapp-webview': version,
        '@dcloudio/uni-stat': version,
        '@dcloudio/uni-i18n': version,
        '@vue/shared': '^3.0.0',
        flyio: '^0.6.2',
        vuex: '^3.2.0'
      },
      devDependencies: {
        '@dcloudio/uni-automator': version,
        '@dcloudio/uni-cli-i18n': version,
        '@dcloudio/uni-cli-shared': version,
        '@dcloudio/uni-migration': version,
        '@dcloudio/uni-template-compiler': version,
        '@dcloudio/vue-cli-plugin-hbuilderx': version,
        '@dcloudio/vue-cli-plugin-uni': version,
        '@dcloudio/vue-cli-plugin-uni-optimize': version,
        '@dcloudio/webpack-uni-mp-loader': version,
        '@dcloudio/webpack-uni-pages-loader': version,
        'babel-plugin-import': '^1.11.0',
        'cross-env': '^7.0.2',
        jest: '^25.4.0'
      },
      browserslist: [
        'Android >= 4.4',
        'ios >= 9'
      ]
    }
  })
}
<|endoftext|>


<commit_before>const semver = require('semver');

class Formatter {

  constructor (format, excludes, changelogs) {
    this.format = format;
    this.excludes = excludes;
    this.changelogs = changelogs;
  }

  run (json) {
    const packages = this.sortPackages(this.extractOutdatedPackages(json));
    const format   = this.format;

    let result;

    if (format === 'markdown') {
      result = this.toMarkdown(packages);
    } else if (format === 'json') {
      result = this.toJSON(packages);
    } else if (format === 'mackerel') {
      result = this.toMackerel(packages);
    } else if (format === 'csv') {
      result = this.toCsv(packages);
    }

    return result;
  }

  extractOutdatedPackages (json) {
    const packages = (json.data && json.data.body) ? json.data.body : this.extractPackagesFromNpmOutdatedJSON(json);
    return packages
      .filter((p) => !p.slice(1, 3).includes('exotic'))
      .filter((p) => !this.excludes.includes(p[0]))
      .map((p) => {
        p.push(this.changelogs[p[0]] || '');
        return p;
      });
  }

  /* convert { packageName: { current, wanted, latest, type }} to [ packageName, current, wanted, latest, type, url(null) ] */
  extractPackagesFromNpmOutdatedJSON (json) {
    return Object.keys(json).map(packageName => {
      const info = json[packageName];
      return [
        packageName,
        this.npmVersionToYarnVersion(info.current),
        this.npmVersionToYarnVersion(info.wanted),
        this.npmVersionToYarnVersion(info.latest),
        info.type,
        null,
      ];
    });
  }

  /* convert "git" to "exotic" */
  npmVersionToYarnVersion (version) {
    if (version === 'git') {
      return 'exotic';
    }
    return version;
  }

  sortPackages (packages) {
    const sortedPackages = {
      major : [],
      minor : [],
      patch : [],
    };

    packages.forEach((p) => {
      const current = p[1];
      const latest  = p[3];

      if (semver.major(current) !== semver.major(latest)) {
        sortedPackages.major.push(p);
      } else if (semver.minor(current) !== semver.minor(latest)) {
        sortedPackages.minor.push(p);
      } else if (semver.patch(current) !== semver.patch(latest)) {
        sortedPackages.patch.push(p);
      }
    });

    return sortedPackages;
  }

  toMarkdown (packages) {
    return [
      this._markdownSection(packages.major, 'Major'),
      this._markdownSection(packages.minor, 'Minor'),
      this._markdownSection(packages.patch, 'Patch'),
    ].join('\n\n');
  }

  _markdownSection (packages, header) {
    const section = [
      `# ${header}`,
      '| Package | Current | Wanted | Latest | Package Type | URL | CHANGELOG |',
      '|---|---|---|---|---|---|---|',
    ];
    packages.forEach((p) => { section.push(`| ${ p.join(' | ') } |`); });

    return section.join('\n');
  }

  toJSON (packages) {
    return JSON.stringify(packages);
  }

  toMackerel (packages) {
    const label = 'outdated_npm_packages';
    const epoch = Math.round((new Date()).getTime() / 1000);
    return [
      `${label}.major\t${packages.major.length}\t${epoch}`,
      `${label}.minor\t${packages.minor.length}\t${epoch}`,
      `${label}.patch\t${packages.patch.length}\t${epoch}`,
    ].join('\n');
  }

  _toCsvPackage(packages, header) {
    return [header, packages].join(",");
  }

  toCsv(packages) {
    return [
      "Version Change, Package, Current, Wanted, Latest, Package Type, URL, CHANGELOG",
      packages.major.map((p) => this._toCsvPackage(p, "Major")).join("\n"),
      packages.minor.map((p) => this._toCsvPackage(p, "Minor")).join("\n"),
      packages.patch.map((p) => this._toCsvPackage(p, "Patch")).join("\n"),
    ].join("\n");
  }
}

module.exports = Formatter;
<commit_msg>fix lint<commit_after>const semver = require('semver');

class Formatter {

  constructor (format, excludes, changelogs) {
    this.format = format;
    this.excludes = excludes;
    this.changelogs = changelogs;
  }

  run (json) {
    const packages = this.sortPackages(this.extractOutdatedPackages(json));
    const format   = this.format;

    let result;

    if (format === 'markdown') {
      result = this.toMarkdown(packages);
    } else if (format === 'json') {
      result = this.toJSON(packages);
    } else if (format === 'mackerel') {
      result = this.toMackerel(packages);
    } else if (format === 'csv') {
      result = this.toCsv(packages);
    }

    return result;
  }

  extractOutdatedPackages (json) {
    const packages = (json.data && json.data.body) ? json.data.body : this.extractPackagesFromNpmOutdatedJSON(json);
    return packages
      .filter((p) => !p.slice(1, 3).includes('exotic'))
      .filter((p) => !this.excludes.includes(p[0]))
      .map((p) => {
        p.push(this.changelogs[p[0]] || '');
        return p;
      });
  }

  /* convert { packageName: { current, wanted, latest, type }} to [ packageName, current, wanted, latest, type, url(null) ] */
  extractPackagesFromNpmOutdatedJSON (json) {
    return Object.keys(json).map(packageName => {
      const info = json[packageName];
      return [
        packageName,
        this.npmVersionToYarnVersion(info.current),
        this.npmVersionToYarnVersion(info.wanted),
        this.npmVersionToYarnVersion(info.latest),
        info.type,
        null,
      ];
    });
  }

  /* convert "git" to "exotic" */
  npmVersionToYarnVersion (version) {
    if (version === 'git') {
      return 'exotic';
    }
    return version;
  }

  sortPackages (packages) {
    const sortedPackages = {
      major : [],
      minor : [],
      patch : [],
    };

    packages.forEach((p) => {
      const current = p[1];
      const latest  = p[3];

      if (semver.major(current) !== semver.major(latest)) {
        sortedPackages.major.push(p);
      } else if (semver.minor(current) !== semver.minor(latest)) {
        sortedPackages.minor.push(p);
      } else if (semver.patch(current) !== semver.patch(latest)) {
        sortedPackages.patch.push(p);
      }
    });

    return sortedPackages;
  }

  toMarkdown (packages) {
    return [
      this._markdownSection(packages.major, 'Major'),
      this._markdownSection(packages.minor, 'Minor'),
      this._markdownSection(packages.patch, 'Patch'),
    ].join('\n\n');
  }

  _markdownSection (packages, header) {
    const section = [
      `# ${header}`,
      '| Package | Current | Wanted | Latest | Package Type | URL | CHANGELOG |',
      '|---|---|---|---|---|---|---|',
    ];
    packages.forEach((p) => { section.push(`| ${ p.join(' | ') } |`); });

    return section.join('\n');
  }

  toJSON (packages) {
    return JSON.stringify(packages);
  }

  toMackerel (packages) {
    const label = 'outdated_npm_packages';
    const epoch = Math.round((new Date()).getTime() / 1000);
    return [
      `${label}.major\t${packages.major.length}\t${epoch}`,
      `${label}.minor\t${packages.minor.length}\t${epoch}`,
      `${label}.patch\t${packages.patch.length}\t${epoch}`,
    ].join('\n');
  }

  _toCsvPackage (packages, header) {
    return [header, packages].join(',');
  }

  toCsv (packages) {
    return [
      'Version Change, Package, Current, Wanted, Latest, Package Type, URL, CHANGELOG',
      packages.major.map((p) => this._toCsvPackage(p, 'Major')).join('\n'),
      packages.minor.map((p) => this._toCsvPackage(p, 'Minor')).join('\n'),
      packages.patch.map((p) => this._toCsvPackage(p, 'Patch')).join('\n'),
    ].join('\n');
  }
}

module.exports = Formatter;
<|endoftext|>


<commit_before>'use strict';

var gulp = require('gulp');
var path = require('path');
var test = require('tap').test;
var scanner = require('../');

var toFixturePath = function(fileName) {
    var args = Array.prototype.slice.call(arguments);
    return path.resolve.apply(null, [__dirname, 'fixtures'].concat(args));
};

test('setup', function(t) {
    t.end();
});

test('teardown', function(t) {
    t.end();
});

test('Gulp usage', function(t) {
    gulp.src(toFixturePath('modules/**/*.{js,hbs}'), {base: 'fixtures'})
        .pipe(scanner({
            lngs: ['en','de'],
            defaultValue: '__STRING_NOT_TRANSLATED__',
            resGetPath: 'i18n/__lng__/__ns__.json',
            resSetPath: 'i18n/__lng__/__ns__.savedMissing.json',
            nsseparator: ':', // namespace separator
            keyseparator: '.', // key separator
            interpolationPrefix: '__',
            interpolationSuffix: '__',
            ns: {
                namespaces: [],
                defaultNs: 'translation'
            }
        }))
        .pipe(gulp.dest('./output'))
        .on('end', function() {
            t.end();
        });
});
<commit_msg>Update test script<commit_after>'use strict';

var _ = require('lodash');
var fs = require('fs');
var gulp = require('gulp');
var gutil = require('gulp-util');
var path = require('path');
var test = require('tap').test;
var i18nextScanner = require('../');
var hash = require('sha1');
var table = require('text-table');

var customTransform = function _transform(file, enc, done) {
    var parser = this.parser;
    var extname = path.extname(file.path);
    var content = fs.readFileSync(file.path, enc);
    var parseResults = [
        ['Key', 'Value']
    ];

    gutil.log('parsing ' + JSON.stringify(file.relative) + ':');

    // Using i18next-text
    (function() {
        var results = content.match(/i18n\._\(("[^"]*"|'[^']*')\s*[\,\)]/igm) || '';
        _.each(results, function(result) {
            var key, value;
            var r = result.match(/i18n\._\(("[^"]*"|'[^']*')/);

            if (r) {
                value = _.trim(r[1], '\'"');

                // Replace double backslash with single backslash
                value = value.replace(/\\\\/g, '\\');
                value = value.replace(/\\\'/, '\'');

                key = hash(value); // returns a hash value as its default key

                parser.parse(key, value);
                parseResults.push([key, _.isUndefined(value) ? '' : value ]);
            }
        });
    }());

    // i18n function helper
    (function() {
        var results = content.match(/{{i18n\s+("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')?([^}]*)}}/gm) || [];
        _.each(results, function(result) {
            var key, value;
            var r = result.match(/{{i18n\s+("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')?([^}]*)}}/m) || [];

            if ( ! _.isUndefined(r[1])) {
                value = _.trim(r[1], '\'"');

                // Replace double backslash with single backslash
                value = value.replace(/\\\\/g, '\\');
                value = value.replace(/\\\'/, '\'');
            }

            var params = parser.parseHashArguments(r[2]);
            if (_.has(params, 'defaultKey')) {
                key = params['defaultKey'];
            }

            if (_.isUndefined(key) && _.isUndefined(value)) {
                return;
            }

            if (_.isUndefined(key)) {
                key = hash(value); // returns a hash value as its default key
            }

            parser.parse(key, value);
            parseResults.push([key, _.isUndefined(value) ? '' : value ]);
        });
    }());

    // i18n block helper
    (function() {
        var results = content.match(/{{#i18n\s*([^}]*)}}((?:(?!{{\/i18n}})(?:.|\n))*){{\/i18n}}/gm) || [];
        _.each(results, function(result) {
            var key, value;
            var r = result.match(/{{#i18n\s*([^}]*)}}((?:(?!{{\/i18n}})(?:.|\n))*){{\/i18n}}/m) || [];

            if ( ! _.isUndefined(r[2])) {
                value = _.trim(r[2], '\'"');
            }

            if (_.isUndefined(value)) {
                return;
            }

            key = hash(value); // returns a hash value as its default key

            parser.parse(key, value);
            parseResults.push([key, _.isUndefined(value) ? '' : value ]);
        });
    }());

    if (_.size(parseResults) > 1) {
        gutil.log('result of ' + JSON.stringify(file.relative) + ':\n' + table(parseResults, {'hsep': ' | '}));
    }

    done();
};

test('setup', function(t) {
    t.end();
});

test('teardown', function(t) {
    t.end();
});

test('Gulp usage', function(t) {
    var options = {
        lngs: ['en','de'],
        defaultValue: '__STRING_NOT_TRANSLATED__',
        resGetPath: 'i18n/__lng__/__ns__.json',
        resSetPath: 'i18n/__lng__/__ns__.savedMissing.json',
        nsseparator: ':', // namespace separator
        keyseparator: '.', // key separator
        interpolationPrefix: '__',
        interpolationSuffix: '__',
        ns: {
            namespaces: [
                'translation',
                'locale'
            ],
            defaultNs: 'translation'
        }
    };
    gulp.src('test/fixtures/modules/**/*.{js,hbs}')
        .pipe(i18nextScanner(options, customTransform))
        .pipe(gulp.dest('./output'))
        .on('end', function() {
            t.end();
        });
});
<|endoftext|>


<commit_before>import path from 'path'
import makeDebug from 'debug'
import _ from 'lodash'
import logger from 'winston'
import 'winston-daily-rotate-file'
import proto from 'uberproto'
import elementMixins from './mixins'
import compress from 'compression'
import cors from 'cors'
import helmet from 'helmet'
import bodyParser from 'body-parser'
import feathers from '@feathersjs/feathers'
import errors from '@feathersjs/errors'
import configuration from '@feathersjs/configuration'
import express from '@feathersjs/express'
import rest from '@feathersjs/express/rest'
import socketio from '@feathersjs/socketio'
import authentication from '@feathersjs/authentication'
import jwt from '@feathersjs/authentication-jwt'
import local from '@feathersjs/authentication-local'
import oauth2 from '@feathersjs/authentication-oauth2'
import GithubStrategy from 'passport-github'
import GoogleStrategy from 'passport-google-oauth20'
import OpenIDStrategy from 'passport-openidconnect'
import CognitoStrategy from 'passport-oauth2-cognito'
import OAuth2Verifier from './verifier'
import mongo from 'mongodb'
import { Database } from './db'

const debug = makeDebug('weacast:weacast-core:application')

function auth () {
  const app = this
  const config = app.get('authentication')
  if (!config) return

  // Set up authentication with the secret
  app.configure(authentication(config))
  app.configure(jwt())
  app.configure(local())
  if (config.github) {
    app.configure(oauth2({
      name: 'github',
      Strategy: GithubStrategy,
      Verifier: OAuth2Verifier
    }))
  }
  if (config.google) {
    app.configure(oauth2({
      name: 'google',
      Strategy: GoogleStrategy,
      Verifier: OAuth2Verifier
    }))
  }
  if (config.oidc) {
    // We do not manage state using express-session as it does not seem to work well with Feathers
    let sessionInfos = Object.assign({}, config.oidc)
    Object.assign(sessionInfos, { params: { state: config.oidc.sessionKey } })
    app.configure(oauth2({
      name: 'oidc',
      Strategy: OpenIDStrategy,
      Verifier: OAuth2Verifier,
      store: {
        store (req, meta, cb) {
          return cb(null, sessionInfos.sessionKey)
        },
        verify (req, state, cb) {
          return cb(null, true, sessionInfos)
        }
      }
    }))
  }
  if (config.cognito) {
    app.configure(oauth2({
      name: 'cognito',
      Strategy: CognitoStrategy,
      Verifier: OAuth2Verifier
    }))
  }
  // The `authentication` service is used to create a JWT.
  // The before `create` hook registers strategies that can be used
  // to create a new valid JWT (e.g. local or oauth2)
  app.getService('authentication').hooks({
    before: {
      create: [
        authentication.hooks.authenticate(config.strategies)
      ],
      remove: [
        authentication.hooks.authenticate('jwt')
      ]
    }
  })
}

function declareService (name, app, service) {
  const path = app.get('apiPath') + '/' + name
  // Initialize our service
  app.use(path, service)
  debug('Service declared on path ' + path)

  return app.getService(name)
}

function configureService (name, service, servicesPath) {
  try {
    const hooks = require(path.join(servicesPath, name, name + '.hooks'))
    service.hooks(hooks)
    debug(name + ' service hooks configured on path ' + servicesPath)
  } catch (error) {
    debug('No ' + name + ' service hooks configured on path ' + servicesPath)
    if (error.code !== 'MODULE_NOT_FOUND') {
      // Log error in this case as this might be linked to a syntax error in required file
      debug(error)
    }
    // As this is optionnal this require has to fail silently
  }

  try {
    const channels = require(path.join(servicesPath, name, name + '.channels'))
    _.forOwn(channels, (publisher, event) => {
      if (event === 'all') service.publish(publisher)
      else service.publish(event, publisher)
    })
    debug(name + ' service channels configured on path ' + servicesPath)
  } catch (error) {
    debug('No ' + name + ' service channels configured on path ' + servicesPath)
    if (error.code !== 'MODULE_NOT_FOUND') {
      // Log error in this case as this might be linked to a syntax error in required file
      debug(error)
    }
    // As this is optionnal this require has to fail silently
  }

  return service
}

export function createService (name, app, modelsPath, servicesPath, options) {
  const createFeathersService = require('feathers-' + app.db.adapter)
  const configureModel = require(path.join(modelsPath, name + '.model.' + app.db.adapter))

  const paginate = app.get('paginate')
  const serviceOptions = Object.assign({
    name: name,
    paginate
  }, options || {})
  if (serviceOptions.disabled) return undefined
  configureModel(app, serviceOptions)

  // Initialize our service with any options it requires
  let service = createFeathersService(serviceOptions)
  // Get our initialized service so that we can register hooks and filters
  service = declareService(name, app, service)
  // Register hooks and filters
  service = configureService(name, service, servicesPath)
  // Optionnally a specific service mixin can be provided, apply it
  try {
    const serviceMixin = require(path.join(servicesPath, name, name + '.service'))
    service.mixin(serviceMixin)
  } catch (error) {
    debug('No ' + name + ' service mixin configured on path ' + servicesPath)
    if (error.code !== 'MODULE_NOT_FOUND') {
      // Log error in this case as this might be linked to a syntax error in required file
      debug(error)
    }
    // As this is optionnal this require has to fail silently
  }
  // Then configuration
  service.name = name
  service.app = app

  debug(service.name + ' service registration completed')
  return service
}

export function createElementService (forecast, element, app, servicesPath, options) {
  const createFeathersService = require('feathers-' + app.db.adapter)
  const configureModel = require(path.join(__dirname, 'models', 'elements.model.' + app.db.adapter))
  let serviceName = forecast.name + '/' + element.name

  const paginate = app.get('paginate')
  const serviceOptions = Object.assign({
    name: serviceName,
    paginate
  }, options || {})
  if (serviceOptions.disabled) return undefined
  configureModel(forecast, element, app, serviceOptions)

  // Initialize our service with any options it requires
  let service = createFeathersService(serviceOptions)
  // Get our initialized service so that we can register hooks and filters
  service = declareService(serviceName, app, service)
  // Register hooks and filters
  // If no service file path provided use default
  if (servicesPath) {
    service = configureService(forecast.model, service, servicesPath)
  } else {
    service = configureService('elements', service, path.join(__dirname, 'services'))
  }

  // Apply all element mixins
  elementMixins.forEach(mixin => { service.mixin(mixin) })
  // Optionnally a specific service mixin can be provided, apply it
  if (servicesPath) {
    const serviceMixin = require(path.join(servicesPath, forecast.model, forecast.model + '.service'))
    proto.mixin(serviceMixin, service)
  }
  // Then configuration
  service.app = app
  service.name = serviceName
  service.forecast = forecast
  service.element = element
  // Attach a GridFS storage element when required
  if (element.dataStore === 'gridfs') {
    if (app.get('db').adapter !== 'mongodb') {
      throw new errors.GeneralError('GridFS store is only available for MongoDB adapter')
    }
    service.gfs = new mongo.GridFSBucket(app.db.db(serviceOptions.dbName), {
      // GridFS is use to bypass the limit of 16MB documents in MongoDB
      // We are not specifically interested in splitting the file in small chunks
      chunkSizeBytes: 8 * 1024 * 1024,
      bucketName: `${forecast.name}-${element.name}`
    })
  }

  debug(service.name + ' element service registration completed')
  return service
}

// Get all element services
function getElementServices (app, name) {
  let forecasts = app.get('forecasts')
  if (name) {
    forecasts = forecasts.filter(forecast => forecast.name === name)
  }

  // Iterate over configured forecast models
  let services = []
  for (let forecast of forecasts) {
    for (let element of forecast.elements) {
      let service = app.getService(forecast.name + '/' + element.name)
      if (service) {
        services.push(service)
      }
    }
  }
  return services
}

function setupLogger (logsConfig) {
  // Remove winston defaults
  try {
    logger.remove(logger.transports.Console)
  } catch (error) {
    // Logger might be down, use console
    console.error('Could not remove default logger transport', error)
  }
  // We have one entry per log type
  let logsTypes = logsConfig ? Object.getOwnPropertyNames(logsConfig) : []
  // Create corresponding winston transports with options
  logsTypes.forEach(logType => {
    let options = logsConfig[logType]
    // Setup default log level if not defined
    if (!options.level) {
      options.level = (process.env.NODE_ENV === 'development' ? 'debug' : 'info')
    }
    try {
      logger.add(logger.transports[logType], options)
    } catch (error) {
      // Logger might be down, use console
      console.error('Could not setup default log levels', error)
    }
  })
}

export default function weacast () {
  let app = express(feathers())
  // Load app configuration first
  app.configure(configuration())
  // Then setup logger
  setupLogger(app.get('logs'))

  // This retrieve corresponding service options from app config if any
  app.getServiceOptions = function (name) {
    const services = app.get('services')
    if (!services) return {}
    return _.get(services, name, {})
  }
  // This avoid managing the API path before each service name
  app.getService = function (path) {
    return app.service(app.get('apiPath') + '/' + path)
  }
  // This is used to create standard services
  app.createService = function (name, modelsPath, servicesPath, options) {
    return createService(name, app, modelsPath, servicesPath, options)
  }
  // This is used to retrieve all element services registered by forecast model plugins
  app.getElementServices = function (name) {
    return getElementServices(app, name)
  }
  // This is used to create forecast element services
  app.createElementService = function (forecast, element, servicesPath, options) {
    return createElementService(forecast, element, app, servicesPath, options)
  }
  // Override Feathers configure that do not manage async operations,
  // here we also simply call the function given as parameter but await for it
  app.configure = async function (fn) {
    await fn.call(this, this)
    return this
  }

  // Enable CORS, security, compression, and body parsing
  app.use(cors())
  app.use(helmet())
  app.use(compress())
  app.use(bodyParser.json())
  app.use(bodyParser.urlencoded({ extended: true }))

  // Set up plugins and providers
  app.configure(rest())
  app.configure(socketio({ path: app.get('apiPath') + 'ws' }))
  app.configure(auth)

  // Initialize DB
  app.db = Database.create(app)

  return app
}
<commit_msg>Updated createElementService to allow to pass an existing service instead of a path to model/service files<commit_after>import path from 'path'
import makeDebug from 'debug'
import _ from 'lodash'
import logger from 'winston'
import 'winston-daily-rotate-file'
import proto from 'uberproto'
import elementMixins from './mixins'
import compress from 'compression'
import cors from 'cors'
import helmet from 'helmet'
import bodyParser from 'body-parser'
import feathers from '@feathersjs/feathers'
import errors from '@feathersjs/errors'
import configuration from '@feathersjs/configuration'
import express from '@feathersjs/express'
import rest from '@feathersjs/express/rest'
import socketio from '@feathersjs/socketio'
import authentication from '@feathersjs/authentication'
import jwt from '@feathersjs/authentication-jwt'
import local from '@feathersjs/authentication-local'
import oauth2 from '@feathersjs/authentication-oauth2'
import GithubStrategy from 'passport-github'
import GoogleStrategy from 'passport-google-oauth20'
import OpenIDStrategy from 'passport-openidconnect'
import CognitoStrategy from 'passport-oauth2-cognito'
import OAuth2Verifier from './verifier'
import mongo from 'mongodb'
import { Database } from './db'

const debug = makeDebug('weacast:weacast-core:application')

function auth () {
  const app = this
  const config = app.get('authentication')
  if (!config) return

  // Set up authentication with the secret
  app.configure(authentication(config))
  app.configure(jwt())
  app.configure(local())
  if (config.github) {
    app.configure(oauth2({
      name: 'github',
      Strategy: GithubStrategy,
      Verifier: OAuth2Verifier
    }))
  }
  if (config.google) {
    app.configure(oauth2({
      name: 'google',
      Strategy: GoogleStrategy,
      Verifier: OAuth2Verifier
    }))
  }
  if (config.oidc) {
    // We do not manage state using express-session as it does not seem to work well with Feathers
    let sessionInfos = Object.assign({}, config.oidc)
    Object.assign(sessionInfos, { params: { state: config.oidc.sessionKey } })
    app.configure(oauth2({
      name: 'oidc',
      Strategy: OpenIDStrategy,
      Verifier: OAuth2Verifier,
      store: {
        store (req, meta, cb) {
          return cb(null, sessionInfos.sessionKey)
        },
        verify (req, state, cb) {
          return cb(null, true, sessionInfos)
        }
      }
    }))
  }
  if (config.cognito) {
    app.configure(oauth2({
      name: 'cognito',
      Strategy: CognitoStrategy,
      Verifier: OAuth2Verifier
    }))
  }
  // The `authentication` service is used to create a JWT.
  // The before `create` hook registers strategies that can be used
  // to create a new valid JWT (e.g. local or oauth2)
  app.getService('authentication').hooks({
    before: {
      create: [
        authentication.hooks.authenticate(config.strategies)
      ],
      remove: [
        authentication.hooks.authenticate('jwt')
      ]
    }
  })
}

function declareService (name, app, service) {
  const path = app.get('apiPath') + '/' + name
  // Initialize our service
  app.use(path, service)
  debug('Service declared on path ' + path)

  return app.getService(name)
}

function configureService (name, service, servicesPath) {
  try {
    const hooks = require(path.join(servicesPath, name, name + '.hooks'))
    service.hooks(hooks)
    debug(name + ' service hooks configured on path ' + servicesPath)
  } catch (error) {
    debug('No ' + name + ' service hooks configured on path ' + servicesPath)
    if (error.code !== 'MODULE_NOT_FOUND') {
      // Log error in this case as this might be linked to a syntax error in required file
      debug(error)
    }
    // As this is optionnal this require has to fail silently
  }

  try {
    const channels = require(path.join(servicesPath, name, name + '.channels'))
    _.forOwn(channels, (publisher, event) => {
      if (event === 'all') service.publish(publisher)
      else service.publish(event, publisher)
    })
    debug(name + ' service channels configured on path ' + servicesPath)
  } catch (error) {
    debug('No ' + name + ' service channels configured on path ' + servicesPath)
    if (error.code !== 'MODULE_NOT_FOUND') {
      // Log error in this case as this might be linked to a syntax error in required file
      debug(error)
    }
    // As this is optionnal this require has to fail silently
  }

  return service
}

export function createService (name, app, modelsPath, servicesPath, options) {
  const createFeathersService = require('feathers-' + app.db.adapter)
  const configureModel = require(path.join(modelsPath, name + '.model.' + app.db.adapter))

  const paginate = app.get('paginate')
  const serviceOptions = Object.assign({
    name: name,
    paginate
  }, options || {})
  if (serviceOptions.disabled) return undefined
  configureModel(app, serviceOptions)

  // Initialize our service with any options it requires
  let service = createFeathersService(serviceOptions)
  // Get our initialized service so that we can register hooks and filters
  service = declareService(name, app, service)
  // Register hooks and filters
  service = configureService(name, service, servicesPath)
  // Optionnally a specific service mixin can be provided, apply it
  try {
    const serviceMixin = require(path.join(servicesPath, name, name + '.service'))
    service.mixin(serviceMixin)
  } catch (error) {
    debug('No ' + name + ' service mixin configured on path ' + servicesPath)
    if (error.code !== 'MODULE_NOT_FOUND') {
      // Log error in this case as this might be linked to a syntax error in required file
      debug(error)
    }
    // As this is optionnal this require has to fail silently
  }
  // Then configuration
  service.name = name
  service.app = app

  debug(service.name + ' service registration completed')
  return service
}

export function createElementService (forecast, element, app, servicesPath, options) {
  const createFeathersService = require('feathers-' + app.db.adapter)
  const configureModel = require(path.join(__dirname, 'models', 'elements.model.' + app.db.adapter))
  let serviceName = forecast.name + '/' + element.name
  // The service object can be directly provided
  const isService = servicesPath && (typeof servicesPath === 'object')
  const paginate = app.get('paginate')
  const serviceOptions = Object.assign({
    name: serviceName,
    paginate
  }, options || {})
  if (serviceOptions.disabled) return undefined
  if (!isService) configureModel(forecast, element, app, serviceOptions)

  // Initialize our service with any options it requires
  let service = (isService ? servicesPath : createFeathersService(serviceOptions))
  // Get our initialized service so that we can register hooks and filters
  service = declareService(serviceName, app, service)
  // Register hooks and filters
  // If no service file path provided use default
  if (servicesPath && !isService) {
    service = configureService(forecast.model, service, servicesPath)
  } else {
    service = configureService('elements', service, path.join(__dirname, 'services'))
  }

  // Apply all element mixins
  elementMixins.forEach(mixin => { service.mixin(mixin) })
  // Optionnally a specific service mixin can be provided, apply it
  if (servicesPath && !isService) {
    const serviceMixin = require(path.join(servicesPath, forecast.model, forecast.model + '.service'))
    proto.mixin(serviceMixin, service)
  }
  // Then configuration
  service.app = app
  service.name = serviceName
  service.forecast = forecast
  service.element = element
  // Attach a GridFS storage element when required
  if (element.dataStore === 'gridfs') {
    if (app.get('db').adapter !== 'mongodb') {
      throw new errors.GeneralError('GridFS store is only available for MongoDB adapter')
    }
    service.gfs = new mongo.GridFSBucket(app.db.db(serviceOptions.dbName), {
      // GridFS is use to bypass the limit of 16MB documents in MongoDB
      // We are not specifically interested in splitting the file in small chunks
      chunkSizeBytes: 8 * 1024 * 1024,
      bucketName: `${forecast.name}-${element.name}`
    })
  }

  debug(service.name + ' element service registration completed')
  return service
}

// Get all element services
function getElementServices (app, name) {
  let forecasts = app.get('forecasts')
  if (name) {
    forecasts = forecasts.filter(forecast => forecast.name === name)
  }

  // Iterate over configured forecast models
  let services = []
  for (let forecast of forecasts) {
    for (let element of forecast.elements) {
      let service = app.getService(forecast.name + '/' + element.name)
      if (service) {
        services.push(service)
      }
    }
  }
  return services
}

function setupLogger (logsConfig) {
  // Remove winston defaults
  try {
    logger.remove(logger.transports.Console)
  } catch (error) {
    // Logger might be down, use console
    console.error('Could not remove default logger transport', error)
  }
  // We have one entry per log type
  let logsTypes = logsConfig ? Object.getOwnPropertyNames(logsConfig) : []
  // Create corresponding winston transports with options
  logsTypes.forEach(logType => {
    let options = logsConfig[logType]
    // Setup default log level if not defined
    if (!options.level) {
      options.level = (process.env.NODE_ENV === 'development' ? 'debug' : 'info')
    }
    try {
      logger.add(logger.transports[logType], options)
    } catch (error) {
      // Logger might be down, use console
      console.error('Could not setup default log levels', error)
    }
  })
}

export default function weacast () {
  let app = express(feathers())
  // Load app configuration first
  app.configure(configuration())
  // Then setup logger
  setupLogger(app.get('logs'))

  // This retrieve corresponding service options from app config if any
  app.getServiceOptions = function (name) {
    const services = app.get('services')
    if (!services) return {}
    return _.get(services, name, {})
  }
  // This avoid managing the API path before each service name
  app.getService = function (path) {
    return app.service(app.get('apiPath') + '/' + path)
  }
  // This is used to create standard services
  app.createService = function (name, modelsPath, servicesPath, options) {
    return createService(name, app, modelsPath, servicesPath, options)
  }
  // This is used to retrieve all element services registered by forecast model plugins
  app.getElementServices = function (name) {
    return getElementServices(app, name)
  }
  // This is used to create forecast element services
  app.createElementService = function (forecast, element, servicesPath, options) {
    return createElementService(forecast, element, app, servicesPath, options)
  }
  // Override Feathers configure that do not manage async operations,
  // here we also simply call the function given as parameter but await for it
  app.configure = async function (fn) {
    await fn.call(this, this)
    return this
  }

  // Enable CORS, security, compression, and body parsing
  app.use(cors())
  app.use(helmet())
  app.use(compress())
  app.use(bodyParser.json())
  app.use(bodyParser.urlencoded({ extended: true }))

  // Set up plugins and providers
  app.configure(rest())
  app.configure(socketio({ path: app.get('apiPath') + 'ws' }))
  app.configure(auth)

  // Initialize DB
  app.db = Database.create(app)

  return app
}
<|endoftext|>