<commit_before>{{define "js-map2-setup"}} // Depends on: .Center (geo.Latlong), and .Zoom (int)

var map;
function initMap() {
    map = new google.maps.Map(document.getElementById('map'), {
        center: {lat: {{.Center.Lat}}, lng: {{.Center.Long}}},
        mapTypeId: google.maps.MapTypeId.TERRAIN,
        scaleControl: true,
        zoom: {{.Zoom}}
    });

    map.controls[google.maps.ControlPosition.RIGHT_TOP].push(
        document.getElementById('legend'));

    classBOverlay()
    {{if .WhiteOverlay}}
    var olay = new google.maps.Rectangle({
        strokeColor: '#ffffff',
        strokeOpacity: 0,
        strokeWeight: 0,
        fillColor: '#ffffff',
        fillOpacity: 0.6,
        zIndex: 0,
        map: map,
        bounds: new google.maps.LatLngBounds(
            new google.maps.LatLng(30,-130),
            new google.maps.LatLng(45,-112)),
    });
    {{end}}

    pathsOverlay()

    {{if .Legend}}
    var legend = document.getElementById('legend');
    var div = document.createElement('div');
    div.innerHTML = {{.Legend}};
    legend.appendChild(div);
    {{end}}

    {{if .Points}}pointsOverlay(){{end}}
    {{if .IdSpecs}}streamVectors(){{end}}
}

function classBOverlay() {
    var classb = [
//      { center: {lat:  37.6188172 , lng:  -122.3754281 }, boundaryMeters:  12964 }, //  7NM
//      { center: {lat:  37.6188172 , lng:  -122.3754281 }, boundaryMeters:  18520 }, // 10NM
//      { center: {lat:  37.6188172 , lng:  -122.3754281 }, boundaryMeters:  27780 }, // 15NM
        { center: {lat:  37.6188172 , lng:  -122.3754281 }, boundaryMeters:  37040 }, // 20NM
        { center: {lat:  37.6188172 , lng:  -122.3754281 }, boundaryMeters:  46300 }, // 25NM
        { center: {lat:  37.6188172 , lng:  -122.3754281 }, boundaryMeters:  55560 }, // 30NM
    ]

    for (var i=0; i< classb.length; i++) {
        // Add the circle for this city to the map.
        var cityCircle = new google.maps.Circle({
            strokeColor: '#0000FF',
            strokeOpacity: 0.8,
            strokeWeight: 0.3,
            fillColor: '#0000FF',
            fillOpacity: 0.08,
            zIndex: 10,
            map: map,
            center: classb[i].center,
            radius: classb[i].boundaryMeters
        });
    }
}

// These should come from geo/sfo
var waypoints = {
    // SERFR2
    "SERFR": {pos:{lat: 36.0683056 , lng:  -121.3646639}},
    "NRRLI": {pos:{lat: 36.4956000 , lng:  -121.6994000}},
    "WWAVS": {pos:{lat: 36.7415306 , lng:  -121.8942333}},
    "EPICK": {pos:{lat: 36.9508222 , lng:  -121.9526722}},
    "EDDYY": {pos:{lat: 37.3264500 , lng:  -122.0997083}},
    "SWELS": {pos:{lat: 37.3681556 , lng:  -122.1160806}},
    "MENLO": {pos:{lat: 37.4636861 , lng:  -122.1536583}},

    // WWAVS1 This is the rarely used 'bad weather' fork (uses the other runways)
    "WPOUT": {pos:{lat: 37.1194861 , lng:  -122.2927417}},
    "THEEZ": {pos:{lat: 37.5034694 , lng:  -122.4247528}},
    "WESLA": {pos:{lat: 37.6643722 , lng:  -122.4802917}},
    "MVRKK": {pos:{lat: 37.7369722 , lng:  -122.4544500}},

    // BRIXX1 (skip the first two, nothing flies along them anyway and they make a mess)
    //"CORKK": {pos:{lat: 37.7335889 , lng:  -122.4975500}},
    "BRIXX": {pos:{lat: 37.6178444 , lng:  -122.3745278}},
    "LUYTA": {pos:{lat: 37.2948889 , lng:  -122.2045528}},
    "JILNA": {pos:{lat: 37.2488056 , lng:  -122.1495000}},
    "YADUT": {pos:{lat: 37.2039889 , lng:  -122.0232778}},

    // http://flightaware.com/resources/airport/SFO/STAR/BIG+SUR+TWO/pdf
    "CARME": {pos:{lat: 36.4551833, lng: -121.8797139}},
    "ANJEE": {pos:{lat: 36.7462861, lng: -121.9648917}},
    "SKUNK": {pos:{lat: 37.0075944, lng: -122.0332278}},
    "BOLDR": {pos:{lat: 37.1708861, lng: -122.0761667}},

    // Things for SFO arrivals
    "HEMAN": {pos:{lat: 37.5338500, lng: -122.1733333}},
    "DUYET": {pos:{lat: 37.5674000, lng: -122.2529278}},
    "NEPIC": {pos:{lat: 37.5858944, lng: -122.2968833}},

    // Things for Oceanic
    "PPEGS": {pos:{lat: 37.3920722, lng: -122.2817222}},
    "ALLBE": {pos:{lat: 37.5063889, lng: -127.0000000}},
    "ALCOA": {pos:{lat: 37.8332528, lng: -125.8345250}},
    "CINNY": {pos:{lat: 36.1816667, lng: -124.7600000}},
    "PAINT": {pos:{lat: 38.0000000, lng: -125.5000000}},
    "OSI"  : {pos:{lat: 37.3925000, lng: -122.2813000}},
    "PIRAT": {pos:{lat: 37.2576500, lng: -122.8633528}},

    "PONKE": {pos:{lat: 37.4588167, lng: -121.9960528}},
    "WETOR": {pos:{lat: 37.4847194, lng: -122.0571417}},

    // Things for SILCN3
    "VLLEY": {pos:{lat: 36.5091667, lng:-121.4402778}},
    "GUUYY": {pos:{lat: 36.7394444, lng:-121.5411111}},
    "SSEBB": {pos:{lat: 36.9788889, lng:-121.6425000}},
    "GSTEE": {pos:{lat: 37.0708333, lng:-121.6716667}},
    "KLIDE": {pos:{lat: 37.1641667, lng:-121.7130556}},
    "BAXBE": {pos:{lat: 36.7730556, lng:-121.6263889}},
    "APLLE": {pos:{lat: 37.0338889, lng:-121.8050000}},

    // Randoms
    "PARIY": {pos:{lat: 37.3560056, lng:-121.9231222}},  // SJC ?
    "ZORSA": {pos:{lat: 37.3627583, lng:-122.0500306}},

    // Personal entries
    "X_RSH": {pos:{lat: 36.868582,  lng:-121.691934}},
    "X_BLH": {pos:{lat: 37.2199471, lng:-122.0425108}},
    "X_HBR": {pos:{lat: 37.309564,  lng:-122.112378}}
}

function pathsOverlay() {
    var infowindow = new google.maps.InfoWindow({});
    var marker = new google.maps.Marker({ map: map });

    for (var wp in waypoints) {
        var fixCircle = new google.maps.Circle({
            title: wp, // this attribute is for the mouse events below
            strokeWeight: 2,
            strokeColor: '#990099',
            //fillColor: '#990099',
            fillOpacity: 0.0,
            map: map,
            zIndex: 20,
            center: waypoints[wp].pos,
            radius: 300
        });

        // Add a tooltip thingy
        google.maps.event.addListener(fixCircle, 'mouseover', function () {
            if (typeof this.title !== "undefined") {
                marker.setPosition(this.getCenter()); // get circle's center
                infowindow.setContent("" + this.title + ""); // set content
                infowindow.open(map, marker); // open at marker's location
                marker.setVisible(false); // hide the marker
            }
        });
        google.maps.event.addListener(fixCircle, 'mouseout', function () {
            infowindow.close();
        });

        // Would be nice to render the waypoint's name on the map somehow ...
        // http://stackoverflow.com/questions/3953922/is-it-possible-to-write-custom-text-on-google-maps-api-v3
    }

    // These should come from geo/sfo/procedures
    var SERFR2 = ["SERFR", "NRRLI", "WWAVS", "EPICK", "EDDYY", "SWELS", "MENLO"];
    var WWAVS1 = ["WWAVS", "WPOUT", "THEEZ", "WESLA", "MVRKK"];
    var BRIXX1 = ["LUYTA", "JILNA", "YADUT"];
    var BSR2   = ["CARME", "ANJEE", "SKUNK", "BOLDR", "MENLO"];

    drawPath(SERFR2, '#990099')
    drawPath(WWAVS1, '#990099')
    drawPath(BRIXX1, '#990099')
    drawPath(BSR2,   '#007788')
}

function drawPath(fixes, color) {
    var pathLineCoords = []
    for (var fix in fixes) {
        pathLineCoords.push(waypoints[fixes[fix]].pos);
    }
    var pathLine = new google.maps.Polyline({
        path: pathLineCoords,
        geodesic: true,
        strokeColor: color,
        strokeOpacity: 0.8,
        zIndex: 20,
        strokeWeight: 1
    });
    pathLine.setMap(map)
}

{{end}}
<commit_msg>Add SSTIK and PORTE<commit_after>{{define "js-map2-setup"}} // Depends on: .Center (geo.Latlong), and .Zoom (int)

var map;
function initMap() {
    map = new google.maps.Map(document.getElementById('map'), {
        center: {lat: {{.Center.Lat}}, lng: {{.Center.Long}}},
        mapTypeId: google.maps.MapTypeId.TERRAIN,
        scaleControl: true,
        zoom: {{.Zoom}}
    });

    map.controls[google.maps.ControlPosition.RIGHT_TOP].push(
        document.getElementById('legend'));

    classBOverlay()
    {{if .WhiteOverlay}}
    var olay = new google.maps.Rectangle({
        strokeColor: '#ffffff',
        strokeOpacity: 0,
        strokeWeight: 0,
        fillColor: '#ffffff',
        fillOpacity: 0.6,
        zIndex: 0,
        map: map,
        bounds: new google.maps.LatLngBounds(
            new google.maps.LatLng(30,-130),
            new google.maps.LatLng(45,-112)),
    });
    {{end}}

    pathsOverlay()

    {{if .Legend}}
    var legend = document.getElementById('legend');
    var div = document.createElement('div');
    div.innerHTML = {{.Legend}};
    legend.appendChild(div);
    {{end}}

    {{if .Points}}pointsOverlay(){{end}}
    {{if .IdSpecs}}streamVectors(){{end}}
}

function classBOverlay() {
    var classb = [
//      { center: {lat:  37.6188172 , lng:  -122.3754281 }, boundaryMeters:  12964 }, //  7NM
//      { center: {lat:  37.6188172 , lng:  -122.3754281 }, boundaryMeters:  18520 }, // 10NM
//      { center: {lat:  37.6188172 , lng:  -122.3754281 }, boundaryMeters:  27780 }, // 15NM
        { center: {lat:  37.6188172 , lng:  -122.3754281 }, boundaryMeters:  37040 }, // 20NM
        { center: {lat:  37.6188172 , lng:  -122.3754281 }, boundaryMeters:  46300 }, // 25NM
        { center: {lat:  37.6188172 , lng:  -122.3754281 }, boundaryMeters:  55560 }, // 30NM
    ]

    for (var i=0; i< classb.length; i++) {
        // Add the circle for this city to the map.
        var cityCircle = new google.maps.Circle({
            strokeColor: '#0000FF',
            strokeOpacity: 0.8,
            strokeWeight: 0.3,
            fillColor: '#0000FF',
            fillOpacity: 0.08,
            zIndex: 10,
            map: map,
            center: classb[i].center,
            radius: classb[i].boundaryMeters
        });
    }
}

// These should come from geo/sfo
var waypoints = {
    // SERFR2
    "SERFR": {pos:{lat: 36.0683056 , lng:  -121.3646639}},
    "NRRLI": {pos:{lat: 36.4956000 , lng:  -121.6994000}},
    "WWAVS": {pos:{lat: 36.7415306 , lng:  -121.8942333}},
    "EPICK": {pos:{lat: 36.9508222 , lng:  -121.9526722}},
    "EDDYY": {pos:{lat: 37.3264500 , lng:  -122.0997083}},
    "SWELS": {pos:{lat: 37.3681556 , lng:  -122.1160806}},
    "MENLO": {pos:{lat: 37.4636861 , lng:  -122.1536583}},

    // WWAVS1 This is the rarely used 'bad weather' fork (uses the other runways)
    "WPOUT": {pos:{lat: 37.1194861 , lng:  -122.2927417}},
    "THEEZ": {pos:{lat: 37.5034694 , lng:  -122.4247528}},
    "WESLA": {pos:{lat: 37.6643722 , lng:  -122.4802917}},
    "MVRKK": {pos:{lat: 37.7369722 , lng:  -122.4544500}},

    // BRIXX1 (skip the first two, nothing flies along them anyway and they make a mess)
    //"CORKK": {pos:{lat: 37.7335889 , lng:  -122.4975500}},
    "BRIXX": {pos:{lat: 37.6178444 , lng:  -122.3745278}},
    "LUYTA": {pos:{lat: 37.2948889 , lng:  -122.2045528}},
    "JILNA": {pos:{lat: 37.2488056 , lng:  -122.1495000}},
    "YADUT": {pos:{lat: 37.2039889 , lng:  -122.0232778}},

    // http://flightaware.com/resources/airport/SFO/STAR/BIG+SUR+TWO/pdf
    "CARME": {pos:{lat: 36.4551833, lng: -121.8797139}},
    "ANJEE": {pos:{lat: 36.7462861, lng: -121.9648917}},
    "SKUNK": {pos:{lat: 37.0075944, lng: -122.0332278}},
    "BOLDR": {pos:{lat: 37.1708861, lng: -122.0761667}},

    // Things for SFO arrivals
    "HEMAN": {pos:{lat: 37.5338500, lng: -122.1733333}},
    "DUYET": {pos:{lat: 37.5674000, lng: -122.2529278}},
    "NEPIC": {pos:{lat: 37.5858944, lng: -122.2968833}},

    // Things for SFO departures
    "PORTE": {pos:{lat: 37.4897861, lng: -122.4745778}},
    "SSTIK": {pos:{lat: 37.6783444, lng: -122.3616583}},

    // Things for Oceanic
    "PPEGS": {pos:{lat: 37.3920722, lng: -122.2817222}},
    "ALLBE": {pos:{lat: 37.5063889, lng: -127.0000000}},
    "ALCOA": {pos:{lat: 37.8332528, lng: -125.8345250}},
    "CINNY": {pos:{lat: 36.1816667, lng: -124.7600000}},
    "PAINT": {pos:{lat: 38.0000000, lng: -125.5000000}},
    "OSI"  : {pos:{lat: 37.3925000, lng: -122.2813000}},
    "PIRAT": {pos:{lat: 37.2576500, lng: -122.8633528}},

    "PONKE": {pos:{lat: 37.4588167, lng: -121.9960528}},
    "WETOR": {pos:{lat: 37.4847194, lng: -122.0571417}},

    // Things for SILCN3
    "VLLEY": {pos:{lat: 36.5091667, lng:-121.4402778}},
    "GUUYY": {pos:{lat: 36.7394444, lng:-121.5411111}},
    "SSEBB": {pos:{lat: 36.9788889, lng:-121.6425000}},
    "GSTEE": {pos:{lat: 37.0708333, lng:-121.6716667}},
    "KLIDE": {pos:{lat: 37.1641667, lng:-121.7130556}},
    "BAXBE": {pos:{lat: 36.7730556, lng:-121.6263889}},
    "APLLE": {pos:{lat: 37.0338889, lng:-121.8050000}},

    // Randoms
    "PARIY": {pos:{lat: 37.3560056, lng:-121.9231222}},  // SJC ?
    "ZORSA": {pos:{lat: 37.3627583, lng:-122.0500306}},

    // Personal entries
    "X_RSH": {pos:{lat: 36.868582,  lng:-121.691934}},
    "X_BLH": {pos:{lat: 37.2199471, lng:-122.0425108}},
    "X_HBR": {pos:{lat: 37.309564,  lng:-122.112378}}
}

function pathsOverlay() {
    var infowindow = new google.maps.InfoWindow({});
    var marker = new google.maps.Marker({ map: map });

    for (var wp in waypoints) {
        var fixCircle = new google.maps.Circle({
            title: wp, // this attribute is for the mouse events below
            strokeWeight: 2,
            strokeColor: '#990099',
            //fillColor: '#990099',
            fillOpacity: 0.0,
            map: map,
            zIndex: 20,
            center: waypoints[wp].pos,
            radius: 300
        });

        // Add a tooltip thingy
        google.maps.event.addListener(fixCircle, 'mouseover', function () {
            if (typeof this.title !== "undefined") {
                marker.setPosition(this.getCenter()); // get circle's center
                infowindow.setContent("" + this.title + ""); // set content
                infowindow.open(map, marker); // open at marker's location
                marker.setVisible(false); // hide the marker
            }
        });
        google.maps.event.addListener(fixCircle, 'mouseout', function () {
            infowindow.close();
        });

        // Would be nice to render the waypoint's name on the map somehow ...
        // http://stackoverflow.com/questions/3953922/is-it-possible-to-write-custom-text-on-google-maps-api-v3
    }

    // These should come from geo/sfo/procedures
    var SERFR2 = ["SERFR", "NRRLI", "WWAVS", "EPICK", "EDDYY", "SWELS", "MENLO"];
    var WWAVS1 = ["WWAVS", "WPOUT", "THEEZ", "WESLA", "MVRKK"];
    var BRIXX1 = ["LUYTA", "JILNA", "YADUT"];
    var BSR2   = ["CARME", "ANJEE", "SKUNK", "BOLDR", "MENLO"];

    drawPath(SERFR2, '#990099')
    drawPath(WWAVS1, '#990099')
    drawPath(BRIXX1, '#990099')
    drawPath(BSR2,   '#007788')
}

function drawPath(fixes, color) {
    var pathLineCoords = []
    for (var fix in fixes) {
        pathLineCoords.push(waypoints[fixes[fix]].pos);
    }
    var pathLine = new google.maps.Polyline({
        path: pathLineCoords,
        geodesic: true,
        strokeColor: color,
        strokeOpacity: 0.8,
        zIndex: 20,
        strokeWeight: 1
    });
    pathLine.setMap(map)
}

{{end}}
<|endoftext|>


<commit_before>!function (Processor, linq, number, path, replaceMultiple, BufferAppender) {
    'use strict';

    module.exports = function (inputs, outputs, outputFilename, callback) {
        if (arguments.length === 3) {
            outputFilename = null;
            callback = arguments[2];
        }

        if (!linq(inputs.newOrChanged).count().run()) { return callback(null, outputs); }

        var inputMap = sortAndSplitIntoMap(inputs.all),
            sorted;

        rankFilesInplace(inputMap, 0, this.log);

        sorted = linq(flattenRecursive(inputMap))
            .toArray(function (entry, filename) { return { filename: filename, entry: entry }; })
            .where(function (kvp) {
                return kvp.entry.rank !== false;
            })
            .run()
            .sort(compareRank);

        if (sorted.length === 0) {
            this.log('Nothing to merge');

            return callback(null, outputs);
        }

        if (!outputFilename) {
            outputFilename = linq(sorted).first(function (kvp) { return !isDirective(kvp.filename); }).run() || 'unnamed';
            outputFilename = path.join(path.dirname(outputFilename) + 'merge-' + path.basename(outputFilename));
        }

        var merged = new BufferAppender(sorted.map(function (kvp) { return kvp.entry.buffer; })).join('\n'),
            outputs = {};

        this.log(sorted.map(function (kvp) { return kvp.filename + ' (' + number.bytes(kvp.entry.buffer.length) + ')'; }).join('\n+ ') + '\n= ' + outputFilename + ' (' + number.bytes(merged.length) + ')');

        outputs[outputFilename] = merged;

        callback(null, outputs);
    };

    function isDirective(filename) {
        return /([\/\\]|^).merge$/.test(filename);
    }

    function walkFileMapBreadth(root, walker) {
        var next = [root],
            walking,
            filenames;

        while (next.length) {
            filenames = [];
            walking = next.pop();

            linq(walking)
                .select(function (entry, filename) {
                    if (/\/$/.test(filename)) {
                        next.push(entry);
                    } else {
                        filenames.push(filename);
                    }
                })
                .run();

            filenames
                .sort()
                .map(function (filename) {
                    return walking[filename];
                })
                .forEach(walker);
        }
    }

    function sortAndSplitIntoMap(inputs) {
        var inputMap = {};

        linq(inputs)
            .select(function (entry, filename) {
                var map = inputMap,
                    segments = filename.split('/'),
                    lastSegment = segments.pop();

                segments.forEach(function (segment) {
                    segment += '/';
                    map = map[segment] || (map[segment] = {});
                });

                map[lastSegment] = {
                    buffer: entry
                };
            })
            .run();

        // assign "unrank"

        var unrank = 0;

        walkFileMapBreadth(inputMap, function (file) {
            file.unrank = ++unrank;
        });

        return inputMap;
    }

    function parseDirectiveLine(line) {
        line = line.replace(/(^\s*)|(\s*$)/g, '');

        var result = {
            operator: line[0]
        };

        line = line.substr(1);

        var regexp = /^\/(.*?)\/$/.exec(line);

        if (regexp) {
            result.pattern = new RegExp(regexp[1]);
        } else {
            result.pattern = new RegExp(
                '^' +
                replaceMultiple(
                    line,
                    [
                        [/\./, '\\.'],
                        [/(\/)/, '(?:\\/)'],
                        [/\*/, '.*?']
                    ]
                ) +
                '$'
            );
        }

        return result;
    }

    function flattenRecursive(map, prefix, newMap) {
        prefix = prefix || '';

        return Object.getOwnPropertyNames(map).sort().reduce(function (newMap, name) {
            var file = map[name];

            if (name[name.length - 1] === '/') {
                flattenRecursive(file, prefix + name, newMap);
            } else {
                newMap[prefix + name] = file;
            }

            return newMap;
        }, newMap || {});
    }

    function rankFilesInplace(map, rank, log) {
        var flatten = flattenRecursive(map);

        Object.getOwnPropertyNames(map).sort().forEach(function (name) {
            var file = map[name];

            if (name === '.merge') {
                var mergeRank = file.rank || [];

                file.rank = false;

                file.buffer.toString().split('\n').forEach(function (line, lineNumber) {
                    if (!line) { return; }

                    var directive = parseDirectiveLine(line),
                        directiveOperator = directive.operator,
                        directivePattern = directive.pattern;

                    if (directiveOperator !== '+' && directiveOperator !== '-') {
                        throw new Error('unknown directive in ' + file.path + ':' + (lineNumber + 1));
                    }

                    var found;

                    Object.getOwnPropertyNames(flatten).sort().forEach(function (name) {
                        if (directivePattern.test(name)) {
                            var file = flatten[name];

                            if (file.rank) {
                                log && log('Warning, file ' + name + ' is already defined in another .merge file, file order will be overwritten');
                            }

                            switch (directiveOperator) {
                            case '+':
                                file.rank = mergeRank.slice();
                                file.rank.splice(Infinity, 0, ++rank);
                                break;

                            case '-':
                                file.rank = false;
                                break;
                            }

                            found = 1;
                        }
                    });

                    if (!found) {
                        if (directivePattern) {
                            console.log('Merge   : Cannot find any files named like ' + directivePattern);
                        } else {
                            console.log('Merge   : Cannot find any files named "' + directiveExact + '"');
                        }
                    }
                });
            } else if (name[name.length - 1] === '/') {
                // is directory
                rank = rankFilesInplace(file, rank, log);
            }
        });

        return rank;
    }

    function compareRank(x, y) {
        var rx = x && x.rank,
            ry = y && y.rank;

        if (rx && ry) {
            for (var i = 0, nrx, nry, length = Math.min(rx.length, ry.length); i < length; i++) {
                nrx = rx[i];
                nry = ry[i];

                if (nrx > nry) {
                    return 1;
                } else if (nrx < nry) {
                    return -1;
                }
            }

            if (rx.length < ry.length) {
                return 1;
            } else if (rx.length > ry.length) {
                return -1;
            } else {
                return 0;
            }
        } else if (rx) {
            return -1;
        } else if (ry) {
            return 1;
        } else {
            x = x.unrank;
            y = y.unrank;

            return x > y ? 1 : x < y ? -1 : 0;
        }
    }

    // Functions exposed for unit testing
    module.exports._sortAndSplitIntoMap = sortAndSplitIntoMap;
    module.exports._flattenRecursive = flattenRecursive;
    module.exports._rankFilesInplace = rankFilesInplace;
    module.exports._parseDirectiveLine = parseDirectiveLine;
    module.exports._compareRank = compareRank;
}(
    require('../processor'),
    require('async-linq'),
    require('../util/number'),
    require('path'),
    require('../util/regexp').replaceMultiple,
    require('../util/bufferappender')
);<commit_msg>Fix merge rank sorting issue<commit_after>!function (Processor, linq, number, path, replaceMultiple, BufferAppender) {
    'use strict';

    module.exports = function (inputs, outputs, outputFilename, callback) {
        if (arguments.length === 3) {
            outputFilename = null;
            callback = arguments[2];
        }

        if (!linq(inputs.newOrChanged).count().run()) { return callback(null, outputs); }

        var inputMap = sortAndSplitIntoMap(inputs.all),
            sorted;

        rankFilesInplace(inputMap, 0, this.log);

        sorted = linq(flattenRecursive(inputMap))
            .toArray(function (entry, filename) {
                return {
                    filename: filename,
                    buffer: entry.buffer,
                    rank: entry.rank,
                    unrank: entry.unrank
                };
            })
            .where(function (kvp) {
                return kvp.rank !== false;
            })
            .run()
            .sort(compareRank);

        if (sorted.length === 0) {
            this.log('Nothing to merge');

            return callback(null, outputs);
        }

        if (!outputFilename) {
            outputFilename = linq(sorted).first(function (kvp) { return !isDirective(kvp.filename); }).run() || 'unnamed';
            outputFilename = path.join(path.dirname(outputFilename) + 'merge-' + path.basename(outputFilename));
        }

        var merged = new BufferAppender(sorted.map(function (kvp) { return kvp.buffer; })).join('\n'),
            outputs = {};

        this.log([
            sorted.map(function (kvp) {
                return kvp.filename + ' (' + number.bytes(kvp.buffer.length) + ')';
            }).join('\n+ '),
            '\n= ',
            outputFilename,
            ' (',
            number.bytes(merged.length),
            ')'
        ].join(''));

        outputs[outputFilename] = merged;

        callback(null, outputs);
    };

    function isDirective(filename) {
        return /([\/\\]|^).merge$/.test(filename);
    }

    function walkFileMapBreadth(root, walker) {
        var next = [root],
            walking,
            filenames;

        while (next.length) {
            filenames = [];
            walking = next.pop();

            linq(walking)
                .select(function (entry, filename) {
                    if (/\/$/.test(filename)) {
                        next.push(entry);
                    } else {
                        filenames.push(filename);
                    }
                })
                .run();

            filenames
                .sort()
                .map(function (filename) {
                    return walking[filename];
                })
                .forEach(walker);
        }
    }

    function sortAndSplitIntoMap(inputs) {
        var inputMap = {};

        linq(inputs)
            .select(function (entry, filename) {
                var map = inputMap,
                    segments = filename.split('/'),
                    lastSegment = segments.pop();

                segments.forEach(function (segment) {
                    segment += '/';
                    map = map[segment] || (map[segment] = {});
                });

                map[lastSegment] = {
                    buffer: entry
                };
            })
            .run();

        // assign "unrank"

        var unrank = 0;

        walkFileMapBreadth(inputMap, function (file) {
            file.unrank = ++unrank;
        });

        return inputMap;
    }

    function parseDirectiveLine(line) {
        line = line.replace(/(^\s*)|(\s*$)/g, '');

        var result = {
            operator: line[0]
        };

        line = line.substr(1);

        var regexp = /^\/(.*?)\/$/.exec(line);

        if (regexp) {
            result.pattern = new RegExp(regexp[1]);
        } else {
            result.pattern = new RegExp(
                '^' +
                replaceMultiple(
                    line,
                    [
                        [/\./, '\\.'],
                        [/(\/)/, '(?:\\/)'],
                        [/\*/, '.*?']
                    ]
                ) +
                '$'
            );
        }

        return result;
    }

    function flattenRecursive(map, prefix, newMap) {
        prefix = prefix || '';

        return Object.getOwnPropertyNames(map).sort().reduce(function (newMap, name) {
            var file = map[name];

            if (name[name.length - 1] === '/') {
                flattenRecursive(file, prefix + name, newMap);
            } else {
                newMap[prefix + name] = file;
            }

            return newMap;
        }, newMap || {});
    }

    function rankFilesInplace(map, rank, log) {
        var flatten = flattenRecursive(map);

        Object.getOwnPropertyNames(map).sort().forEach(function (name) {
            var file = map[name];

            if (name === '.merge') {
                var mergeRank = file.rank || [];

                file.rank = false;

                file.buffer.toString().split('\n').forEach(function (line, lineNumber) {
                    if (!line) { return; }

                    var directive = parseDirectiveLine(line),
                        directiveOperator = directive.operator,
                        directivePattern = directive.pattern;

                    if (directiveOperator !== '+' && directiveOperator !== '-') {
                        throw new Error('unknown directive in ' + file.path + ':' + (lineNumber + 1));
                    }

                    var found;

                    Object.getOwnPropertyNames(flatten).sort().forEach(function (name) {
                        if (directivePattern.test(name)) {
                            var file = flatten[name];

                            if (file.rank) {
                                log && log('Warning, file ' + name + ' is already defined in another .merge file, file order will be overwritten');
                            }

                            switch (directiveOperator) {
                            case '+':
                                file.rank = mergeRank.slice();
                                file.rank.splice(Infinity, 0, ++rank);
                                break;

                            case '-':
                                file.rank = false;
                                break;
                            }

                            found = 1;
                        }
                    });

                    if (!found) {
                        if (directivePattern) {
                            log && log('Cannot find any files named like ' + directivePattern);
                        } else {
                            log && log('Cannot find any files named "' + directiveExact + '"');
                        }
                    }
                });
            } else if (name[name.length - 1] === '/') {
                // is directory
                rank = rankFilesInplace(file, rank, log);
            }
        });

        return rank;
    }

    function compareRank(x, y) {
        var rx = x && x.rank,
            ry = y && y.rank;

        if (rx && ry) {
            for (var i = 0, nrx, nry, length = Math.min(rx.length, ry.length); i < length; i++) {
                nrx = rx[i];
                nry = ry[i];

                if (nrx > nry) {
                    return 1;
                } else if (nrx < nry) {
                    return -1;
                }
            }

            if (rx.length < ry.length) {
                return 1;
            } else if (rx.length > ry.length) {
                return -1;
            } else {
                return 0;
            }
        } else if (rx) {
            return -1;
        } else if (ry) {
            return 1;
        } else {
            x = x.unrank;
            y = y.unrank;

            return x > y ? 1 : x < y ? -1 : 0;
        }
    }

    // Functions exposed for unit testing
    module.exports._sortAndSplitIntoMap = sortAndSplitIntoMap;
    module.exports._flattenRecursive = flattenRecursive;
    module.exports._rankFilesInplace = rankFilesInplace;
    module.exports._parseDirectiveLine = parseDirectiveLine;
    module.exports._compareRank = compareRank;
}(
    require('../processor'),
    require('async-linq'),
    require('../util/number'),
    require('path'),
    require('../util/regexp').replaceMultiple,
    require('../util/bufferappender')
);<|endoftext|>


<commit_before>import path from "path";
import MagicString from "magic-string";
import { types as t } from "@marko/compiler";
import { loadFileForImport, resolveRelativePath } from "@marko/babel-utils";
export default (entryFile, isHydrate) => {
  const {
    modules,
    resolveVirtualDependency,
    hydrateIncludeImports
  } = entryFile.markoOpts;
  const program = entryFile.path;
  const shouldIncludeImport = toTestFn(hydrateIncludeImports);

  if (!isHydrate) {
    addBrowserDeps(entryFile);
    return;
  }

  const registerId = t.identifier("register");
  const watchFiles = new Set();
  let hasComponents = false;
  let splitComponentIndex = 0;
  program.set("body", []);
  program.skip();

  addHydrateDeps(entryFile);
  entryFile.metadata.marko.watchFiles = Array.from(watchFiles);

  if (hasComponents) {
    const initId = t.identifier("init");
    const markoComponentsImport = importPath(
      entryFile,
      "marko/src/runtime/components"
    );
    if (splitComponentIndex) {
      markoComponentsImport.specifiers.push(
        t.importSpecifier(registerId, registerId)
      );
    }
    markoComponentsImport.specifiers.push(t.importSpecifier(initId, initId));
    program.unshiftContainer("body", markoComponentsImport);
    program.pushContainer(
      "body",
      t.expressionStatement(
        t.callExpression(
          initId,
          entryFile.markoOpts.runtimeId
            ? [t.stringLiteral(entryFile.markoOpts.runtimeId)]
            : []
        )
      )
    );
  }

  function addHydrateDeps(file) {
    const meta = file.metadata.marko;

    if (meta.component) {
      hasComponents = true;

      if (
        path.basename(meta.component) ===
        path.basename(file.opts.sourceFileName)
      ) {
        // Stateful component.
        program.pushContainer("body", importPath(file, meta.component));
        return;
      }
    }

    watchFiles.add(file.opts.sourceFileName);

    for (const watchFile of meta.watchFiles) {
      watchFiles.add(watchFile);
    }

    addBrowserDeps(file);

    for (const imported of meta.imports) {
      if (shouldIncludeImport(imported)) {
        program.pushContainer("body", importPath(file, imported));
      }
    }

    for (const tag of meta.tags) {
      if (tag.endsWith(".marko")) {
        addHydrateDeps(loadFileForImport(file, tag));
      }
    }

    if (meta.component) {
      // Split component
      const splitComponentId = t.identifier(
        `component_${splitComponentIndex++}`
      );
      const splitComponentImport = importPath(file, meta.component);
      splitComponentImport.specifiers.push(
        t.importDefaultSpecifier(splitComponentId)
      );
      program.pushContainer("body", splitComponentImport);
      program.pushContainer(
        "body",
        t.expressionStatement(
          t.callExpression(registerId, [
            t.stringLiteral(meta.id),
            splitComponentId
          ])
        )
      );
    }
  }

  function addBrowserDeps(file) {
    const { sourceFileName, sourceMaps } = file.opts;
    let s;

    for (let dep of file.metadata.marko.deps) {
      if (typeof dep !== "string") {
        const { virtualPath } = dep;
        let { code } = dep;
        let map;

        if (sourceMaps && dep.startPos !== undefined) {
          s = s || new MagicString(file.code, { source: sourceFileName });
          map = s.snip(dep.startPos, dep.endPos).generateMap({
            source: sourceFileName,
            includeContent: true
          });

          if (sourceMaps === "inline" || sourceMaps === "both") {
            code += dep.style
              ? `\n/*# sourceMappingURL=${map.toUrl()}*/`
              : `\n//# sourceMappingURL=${map.toUrl()}`;

            if (sourceMaps === "inline") {
              map = undefined;
            }
          }
        }

        dep = resolveVirtualDependency(sourceFileName, {
          map,
          code,
          virtualPath
        });
      }

      program.pushContainer("body", importPath(file, dep));
    }
  }

  function importPath(file, req) {
    let resolved = req;

    if (file !== entryFile) {
      resolved = resolveRelativePath(
        entryFile,
        path.join(file.opts.sourceFileName, "..", req)
      );
    }

    if (modules === "cjs") {
      return t.expressionStatement(
        t.callExpression(t.identifier("require"), [t.stringLiteral(resolved)])
      );
    }

    return t.importDeclaration([], t.stringLiteral(resolved));
  }
};

function toTestFn(val) {
  if (typeof val === "function") {
    return val;
  }

  return val.test.bind(val);
}
<commit_msg>fix(translator-default): resolve correct production paths with hydrate output<commit_after>import path from "path";
import MagicString from "magic-string";
import { types as t } from "@marko/compiler";
import { loadFileForImport, resolveRelativePath } from "@marko/babel-utils";
export default (entryFile, isHydrate) => {
  const {
    modules,
    resolveVirtualDependency,
    hydrateIncludeImports
  } = entryFile.markoOpts;
  const program = entryFile.path;
  const shouldIncludeImport = toTestFn(hydrateIncludeImports);

  if (!isHydrate) {
    addBrowserDeps(entryFile);
    return;
  }

  const registerId = t.identifier("register");
  const watchFiles = new Set();
  let hasComponents = false;
  let splitComponentIndex = 0;
  program.set("body", []);
  program.skip();

  addHydrateDeps(entryFile);
  entryFile.metadata.marko.watchFiles = Array.from(watchFiles);

  if (hasComponents) {
    const initId = t.identifier("init");
    const markoComponentsImport = importPath(
      entryFile,
      "marko/src/runtime/components"
    );
    if (splitComponentIndex) {
      markoComponentsImport.specifiers.push(
        t.importSpecifier(registerId, registerId)
      );
    }
    markoComponentsImport.specifiers.push(t.importSpecifier(initId, initId));
    program.unshiftContainer("body", markoComponentsImport);
    program.pushContainer(
      "body",
      t.expressionStatement(
        t.callExpression(
          initId,
          entryFile.markoOpts.runtimeId
            ? [t.stringLiteral(entryFile.markoOpts.runtimeId)]
            : []
        )
      )
    );
  }

  function addHydrateDeps(file) {
    const meta = file.metadata.marko;

    if (meta.component) {
      hasComponents = true;

      if (
        path.basename(meta.component) ===
        path.basename(file.opts.sourceFileName)
      ) {
        // Stateful component.
        program.pushContainer("body", importPath(file, meta.component));
        return;
      }
    }

    watchFiles.add(file.opts.sourceFileName);

    for (const watchFile of meta.watchFiles) {
      watchFiles.add(watchFile);
    }

    addBrowserDeps(file);

    for (const imported of meta.imports) {
      if (shouldIncludeImport(imported)) {
        program.pushContainer("body", importPath(file, imported));
      }
    }

    for (const tag of meta.tags) {
      if (tag.endsWith(".marko")) {
        addHydrateDeps(loadFileForImport(file, tag));
      }
    }

    if (meta.component) {
      // Split component
      const splitComponentId = t.identifier(
        `component_${splitComponentIndex++}`
      );
      const splitComponentImport = importPath(file, meta.component);
      splitComponentImport.specifiers.push(
        t.importDefaultSpecifier(splitComponentId)
      );
      program.pushContainer("body", splitComponentImport);
      program.pushContainer(
        "body",
        t.expressionStatement(
          t.callExpression(registerId, [
            t.stringLiteral(meta.id),
            splitComponentId
          ])
        )
      );
    }
  }

  function addBrowserDeps(file) {
    const { sourceFileName, sourceMaps } = file.opts;
    let s;

    for (let dep of file.metadata.marko.deps) {
      if (typeof dep !== "string") {
        const { virtualPath } = dep;
        let { code } = dep;
        let map;

        if (sourceMaps && dep.startPos !== undefined) {
          s = s || new MagicString(file.code, { source: sourceFileName });
          map = s.snip(dep.startPos, dep.endPos).generateMap({
            source: sourceFileName,
            includeContent: true
          });

          if (sourceMaps === "inline" || sourceMaps === "both") {
            code += dep.style
              ? `\n/*# sourceMappingURL=${map.toUrl()}*/`
              : `\n//# sourceMappingURL=${map.toUrl()}`;

            if (sourceMaps === "inline") {
              map = undefined;
            }
          }
        }

        dep = resolveVirtualDependency(sourceFileName, {
          map,
          code,
          virtualPath
        });
      }

      program.pushContainer("body", importPath(file, dep));
    }
  }

  function importPath(file, req) {
    const resolved =
      file === entryFile
        ? resolveRelativePath(file, req)
        : resolveRelativePath(
            entryFile,
            path.join(file.opts.sourceFileName, "..", req)
          );

    if (modules === "cjs") {
      return t.expressionStatement(
        t.callExpression(t.identifier("require"), [t.stringLiteral(resolved)])
      );
    }

    return t.importDeclaration([], t.stringLiteral(resolved));
  }
};

function toTestFn(val) {
  if (typeof val === "function") {
    return val;
  }

  return val.test.bind(val);
}
<|endoftext|>


<commit_before>//
// NodeJS global stubs
//

function require(module) {

}

var process = {
	pid: 0
};

var console = {
	log: function(text) {

	}
};

var exports = {};

var module = {
	exports: exports
};
<commit_msg>part of #6<commit_after>//
// NodeJS global stubs
//

/**
 * To require modules. See the {module}. require isn't actually a global but rather local to each module.
 */
function require(module)
{
}

/**
 * Run callback cb repeatedly every ms milliseconds.
 * Note that the actual interval may vary, depending on external factors like OS timer granularity and system load.
 * It's never less than ms but it may be longer.
 * The interval must be in the range of 1-2,147,483,647 inclusive. If the value is outside that range, it's changed to 1 millisecond.
 * Broadly speaking, a timer cannot span more than 24.8 days.
 * Returns an opaque value that represents the timer.
 */
function setInterval(cb, ms)
{
}

/**
 * Stop a timer that was previously created with setInterval(). The callback will not execute.
 */
function clearInterval(t)
{
}

/**
 * Run callback cb after at least ms milliseconds.
 * The actual delay depends on external factors like OS timer granularity and system load.
 * The timeout must be in the range of 1-2,147,483,647 inclusive.
 * If the value is outside that range, it's changed to 1 millisecond.
 * Broadly speaking, a timer cannot span more than 24.8 days.
 * Returns an opaque value that represents the timer.
 */
function setTimeout(cb, ms)
{
}

/**
 * Stop a timer that was previously created with setTimeout(). The callback will not execute.
 */
function clearTimeout(t)
{
}

/**
 * The name of the directory that the currently executing script resides in.
 */
var __dirname = "";

/**
 * The filename of the code being executed.
 * This is the resolved absolute path of this code file.
 * For a main program this is not necessarily the same filename used in the command line.
 * The value inside a module is the path to that module file.
 */
var __filename = "";

var process = {
	/**
	 * The PID of the process
	 */
	pid: 0,

	/**
	 * What platform you're running on: 'darwin', 'freebsd', 'linux', 'sunos' or 'win32'
	 */
	platform: "",

	/**
	 * Number of seconds Node.js has been running
	 */
	uptime: function()
	{
	},

	/**
	 * Note: this function is only available on POSIX platforms (i.e. not Windows, Android)
	 * Sets the supplementary group IDs. This is a privileged operation, meaning you need to be root or have the CAP_SETGID capability.
	 * The list can contain group IDs, group names or both.
	 */
	setgroups: function(groups)
	{
	},

	/**
	 * A compiled-in property that exposes NODE_VERSION
	 */
	version: "",

	/**
	 * A property exposing version strings of Node.js and its dependencies
	 */
	versions: {}
};

/**
 * In browsers, the top-level scope is the global scope.
 * That means that in browsers if you're in the global scope var something will define a global variable.
 * In Node.js this is different. The top-level scope is not the global scope; var something inside an Node.js module will be local to that module.
 */
var global = {};

/**
 * For printing to stdout and stderr.
 * Similar to the console object functions provided by most web browsers, here the output is sent to stdout or stderr.
 * The console functions are synchronous when the destination is a terminal or a file (to avoid lost messages in case of premature exit)
 * and asynchronous when it's a pipe (to avoid blocking for long periods of time).
 */
var console = {
	/**
	 * Prints to stdout with newline
	 */
	log: function(text)
	{
	},

	/**
	 * Prints to stdout with newline
	 */
	info: function(text)
	{
	},

	/**
	 * Prints to stderr with newline
	 */
	error: function(text)
	{
	},

	/**
	 * Prints to stderr with newline
	 */
	warn: function(text)
	{
	},

	/**
	 * Print to stderr 'Trace :', followed by the formatted message and stack trace to the current position.
	 */
	trace: function(text)
	{
	},

	/**
	 * Starts a timer that can be used to compute the duration of an operation.
	 * Timers are identified by a unique name.
	 * Use the same name when you call console.timeEnd() to stop the timer and output the elapsed time in milliseconds.
	 * Timer durations are accurate to the sub-millisecond.
	 */
	time: function(label)
	{
	},

	/**
	 * Stops a timer that was previously started by calling console.time() and prints the result to the console
	 */
	timeEnd: function(label)
	{
	}
};

/**
 * A reference to the module.exports that is shorter to type.
 * See module system documentation for details on when to use exports and when to use module.exports.
 * exports isn't actually a global but rather local to each module.
 */
var exports = {};

/**
 * A reference to the current module. In particular module.exports is used for defining what a module exports and makes available through require().
 * module isn't actually a global but rather local to each module.
 */
var module = {
	/**
	 * The identifier for the module. Typically this is the fully resolved filename.
	 */
	id: "",

	/**
	 * The fully resolved filename to the module.
	 */
	filename: "",

	/**
	 * Whether or not the module is done loading, or is in the process of loading.
	 */
	loaded: false,

	/**
	 * The module that first required this one.
	 */
	parent: {},

	/**
	 * The module objects required by this one.
	 */
	children: [],

	/**
	 * The module.exports object is created by the Module system.
	 * Sometimes this is not acceptable; many want their module to be an instance of some class.
	 * To do this, assign the desired export object to module.exports.
	 * Note that assigning the desired object to exports will simply rebind the local exports variable, which is probably not what you want to do.
	 */
	exports: exports
};
<|endoftext|>


<commit_before>var http = require('http')
, path = require('path')
, fs = require('fs')
, url = require('url')
, dir = path.dirname(require.main.filename)
, requireFile = function(filename,callback){
  var name = path.resolve(dir,filename)
  if (name != require.main.filename) {
    if (path.extname(name) === '.js') {
      if (require.cache[name]) delete require.cache[name]
      try {
        require(name)
        console.log('Requiring '+name)
      }
      catch (e) {
        console.log('Error requiring '+name)
      }
      if (callback) callback()
    }
  }
}
, requireDirectory = function(callback){
  fs.readdir(dir,function(e,files){
    if (e) console.log('Error reading '+dir)
    else {
      files.forEach(function(filename,filenumber){
        requireFile(filename,function(){
          if (filenumber === files.length-1) callback()
        })
      })
    }
  })
}
, watchDirectory = function(){
  fs.watch(dir,function(event,filename){
    requireFile(filename)
  })
}
module.exports = function(port){
  var args = Array.prototype.slice.call(arguments)
  requireDirectory(function(){
    watchDirectory()
    http.createServer(function(req,res){
      var urlparts = url.parse(req.url).pathname.split('/').slice(1)
      , method = req.method.toLowerCase()
      , defaultCallback = function(data){
        if (typeof data === 'string') res.write(data)
        else {
          res.writeHead(200,{"Content-Type":"application/json"})
          res.write(JSON.stringify(data))
        }
        res.end()
      }
      if (typeof args[args.length-1]==='function') callback = function(data){
        args[args.length-1](data,defaultCallback)
      }
      else callback = defaultCallback
      if (urlparts[urlparts.length-1]==="") urlparts.pop()
      args.slice(1).forEach(function(arg){
        if (!urlparts.length) return
        if (require.cache[path.resolve(dir,urlparts[0]+".js")]) return
        if (typeof arg !== "string") return
        this[arg] = urlparts.shift()
      })
      this.request = req
      this.response = res
      if ((modu=require.cache[path.resolve(dir,urlparts[0]+'.js')])) {
        modu.exports[method].apply(this,urlparts.slice(1).concat([callback]))
      }
      else require.main.exports[method].apply(this,urlparts.concat([callback]))
    }).listen(port)
  })
}
<commit_msg>Watch directory first<commit_after>var http = require('http')
, path = require('path')
, fs = require('fs')
, url = require('url')
, dir = path.dirname(require.main.filename)
, requireFile = function(filename,callback){
  var name = path.resolve(dir,filename)
  if (name != require.main.filename) {
    if (path.extname(name) === '.js') {
      if (require.cache[name]) delete require.cache[name]
      try {
        require(name)
        console.log('Requiring '+name)
      }
      catch (e) {
        console.log('Error requiring '+name)
      }
      if (callback) callback()
    }
  }
}
, requireDirectory = function(callback){
  fs.readdir(dir,function(e,files){
    if (e) console.log('Error reading '+dir)
    else {
      files.forEach(function(filename,filenumber){
        requireFile(filename,function(){
          if (filenumber === files.length-1) callback()
        })
      })
    }
  })
}
, watchDirectory = function(){
  fs.watch(dir,function(event,filename){
    console.log('Watching '+dir)
    requireFile(filename)
  })
}
module.exports = function(port){
  var args = Array.prototype.slice.call(arguments)
  watchDirectory()
  requireDirectory(function(){
    http.createServer(function(req,res){
      var urlparts = url.parse(req.url).pathname.split('/').slice(1)
      , method = req.method.toLowerCase()
      , defaultCallback = function(data){
        if (typeof data === 'string') res.write(data)
        else {
          res.writeHead(200,{"Content-Type":"application/json"})
          res.write(JSON.stringify(data))
        }
        res.end()
      }
      if (typeof args[args.length-1]==='function') callback = function(data){
        args[args.length-1](data,defaultCallback)
      }
      else callback = defaultCallback
      if (urlparts[urlparts.length-1]==="") urlparts.pop()
      args.slice(1).forEach(function(arg){
        if (!urlparts.length) return
        if (require.cache[path.resolve(dir,urlparts[0]+".js")]) return
        if (typeof arg !== "string") return
        this[arg] = urlparts.shift()
      })
      this.request = req
      this.response = res
      if ((modu=require.cache[path.resolve(dir,urlparts[0]+'.js')])) {
        modu.exports[method].apply(this,urlparts.slice(1).concat([callback]))
      }
      else require.main.exports[method].apply(this,urlparts.concat([callback]))
    }).listen(port)
  })
}
<|endoftext|>


<commit_before>// Copyright (c) Jonathan Frederic, see the LICENSE file for more info.

var utils = require('../utils.js');
var row = require('./row.js');
var config = require('../config.js');
config = config.config;

/**
 * Render the text rows of a DocumentModel.
 * @param {DocumentModel} model instance
 */
var HighlightedRowRenderer = function(model, scrolling_canvas, style) {
    row.RowRenderer.call(this, model, scrolling_canvas);
    this.style = style;

    var that = this;
    model.on('tags_changed', function(rows) {
        var visible_rows = that.get_visible_rows();
        var row_visible = false;
        for (var i = 0; i < rows.length; i++) {
            if (visible_rows.top_row <= rows[i] && rows[i] <= visible_rows.bottom_row) {
                row_visible = true;
                break;
            }
        }

        // If at least one of the rows whos tags changed is visible,
        // re-render.
        if (row_visible) {
            that.render();
            that.trigger('changed');
        }
    });
};
utils.inherit(HighlightedRowRenderer, row.RowRenderer);

/**
 * Render a single row
 * @param  {integer} index
 * @param  {float} x
 * @param  {float} y
 * @return {null}
 */
HighlightedRowRenderer.prototype._render_row = function(index, x ,y) {
    if (index < 0 || this._model._rows.length <= index) return;

    var groups = this._get_groups(index);
    var left = x;
    for (var i=0; i<groups.length; i++) {
        var width = this._text_canvas.measure_text(groups[i].text, groups[i].options);

        if (config.highlight_draw) {
            this._text_canvas.draw_rectangle(left, y, width, this.get_row_height(i), {
                fill_color: utils.random_color(),
            });
        }

        this._text_canvas.draw_text(left, y, groups[i].text, groups[i].options);
        left += width;
    }
};

/**
 * Get render groups for a row.
 * @param  {integer} index of the row
 * @return {array} array of renderings, each rendering is an array of
 *                 the form {options, text}.
 */
HighlightedRowRenderer.prototype._get_groups = function(index) {
    if (index < 0 || this._model._rows.length <= index) return;

    var row_text = this._model._rows[index];
    var groups = [];
    var last_syntax = null;
    var char_index = 0;
    var start = 0;
    for (char_index; char_index<row_text.length; char_index++) {
        var syntax = this._model.get_tag_value('syntax', index, char_index);
        if (!this._compare_syntax(last_syntax,syntax)) {
            if (char_index !== 0) {
                groups.push({options: this._get_options(last_syntax), text: row_text.substring(start, char_index)});
            }
            last_syntax = syntax;
            start = char_index;
        }
    }
    groups.push({options: this._get_options(last_syntax), text: row_text.substring(start)});

    return groups;
};

/**
 * Creates a style options dictionary from a syntax tag.
 * @param  {string} syntax
 * @return {null}
 */
HighlightedRowRenderer.prototype._get_options = function(syntax) {
    var render_options = utils.shallow_copy(this._base_options);

    // Highlight if a sytax item and style are provided.
    if (this.style) {

        // If this is a nested syntax item, use the most specific part
        // which is defined in the active style.
        if (syntax && syntax.indexOf(' ') != -1) {
            var parts = syntax.split(' ');
            for (var i = parts.length - 1; i >= 0; i--) {
                if (this.style[parts[i]]) {
                    syntax = parts[i];
                    break;
                }
            }
        }

        // Style if the syntax item is defined in the style.
        if (syntax && this.style[syntax]) {
            render_options.color = this.style[syntax];
        } else {
            render_options.color = this.style.text || 'black';
        }
    }

    return render_options;
};

/**
 * Compare two syntaxs.
 * @param  {string} a - syntax
 * @param  {string} b - syntax
 * @return {bool} true if a and b are equal
 */
HighlightedRowRenderer.prototype._compare_syntax = function(a, b) {
    return a === b;
};

// Exports
exports.HighlightedRowRenderer = HighlightedRowRenderer;
<commit_msg>Handle undefined (didn't actually cause a bug not handling it, but might as well..)<commit_after>// Copyright (c) Jonathan Frederic, see the LICENSE file for more info.

var utils = require('../utils.js');
var row = require('./row.js');
var config = require('../config.js');
config = config.config;

/**
 * Render the text rows of a DocumentModel.
 * @param {DocumentModel} model instance
 */
var HighlightedRowRenderer = function(model, scrolling_canvas, style) {
    row.RowRenderer.call(this, model, scrolling_canvas);
    this.style = style;

    var that = this;
    model.on('tags_changed', function(rows) {
        var row_visible = false;
        if (rows) {
            var visible_rows = that.get_visible_rows();
            for (var i = 0; i < rows.length; i++) {
                if (visible_rows.top_row <= rows[i] && rows[i] <= visible_rows.bottom_row) {
                    row_visible = true;
                    break;
                }
            }
        }

        // If at least one of the rows whos tags changed is visible,
        // re-render.
        if (row_visible) {
            that.render();
            that.trigger('changed');
        }
    });
};
utils.inherit(HighlightedRowRenderer, row.RowRenderer);

/**
 * Render a single row
 * @param  {integer} index
 * @param  {float} x
 * @param  {float} y
 * @return {null}
 */
HighlightedRowRenderer.prototype._render_row = function(index, x ,y) {
    if (index < 0 || this._model._rows.length <= index) return;

    var groups = this._get_groups(index);
    var left = x;
    for (var i=0; i<groups.length; i++) {
        var width = this._text_canvas.measure_text(groups[i].text, groups[i].options);

        if (config.highlight_draw) {
            this._text_canvas.draw_rectangle(left, y, width, this.get_row_height(i), {
                fill_color: utils.random_color(),
            });
        }

        this._text_canvas.draw_text(left, y, groups[i].text, groups[i].options);
        left += width;
    }
};

/**
 * Get render groups for a row.
 * @param  {integer} index of the row
 * @return {array} array of renderings, each rendering is an array of
 *                 the form {options, text}.
 */
HighlightedRowRenderer.prototype._get_groups = function(index) {
    if (index < 0 || this._model._rows.length <= index) return;

    var row_text = this._model._rows[index];
    var groups = [];
    var last_syntax = null;
    var char_index = 0;
    var start = 0;
    for (char_index; char_index<row_text.length; char_index++) {
        var syntax = this._model.get_tag_value('syntax', index, char_index);
        if (!this._compare_syntax(last_syntax,syntax)) {
            if (char_index !== 0) {
                groups.push({options: this._get_options(last_syntax), text: row_text.substring(start, char_index)});
            }
            last_syntax = syntax;
            start = char_index;
        }
    }
    groups.push({options: this._get_options(last_syntax), text: row_text.substring(start)});

    return groups;
};

/**
 * Creates a style options dictionary from a syntax tag.
 * @param  {string} syntax
 * @return {null}
 */
HighlightedRowRenderer.prototype._get_options = function(syntax) {
    var render_options = utils.shallow_copy(this._base_options);

    // Highlight if a sytax item and style are provided.
    if (this.style) {

        // If this is a nested syntax item, use the most specific part
        // which is defined in the active style.
        if (syntax && syntax.indexOf(' ') != -1) {
            var parts = syntax.split(' ');
            for (var i = parts.length - 1; i >= 0; i--) {
                if (this.style[parts[i]]) {
                    syntax = parts[i];
                    break;
                }
            }
        }

        // Style if the syntax item is defined in the style.
        if (syntax && this.style[syntax]) {
            render_options.color = this.style[syntax];
        } else {
            render_options.color = this.style.text || 'black';
        }
    }

    return render_options;
};

/**
 * Compare two syntaxs.
 * @param  {string} a - syntax
 * @param  {string} b - syntax
 * @return {bool} true if a and b are equal
 */
HighlightedRowRenderer.prototype._compare_syntax = function(a, b) {
    return a === b;
};

// Exports
exports.HighlightedRowRenderer = HighlightedRowRenderer;
<|endoftext|>


<commit_before>
Elm.Native.Signal = {};
Elm.Native.Signal.make = function(elm) {

  elm.Native = elm.Native || {};
  elm.Native.Signal = elm.Native.Signal || {};
  if (elm.Native.Signal.values) return elm.Native.Signal.values;

  var Utils = Elm.Native.Utils.make(elm);
  var foldr1 = Elm.List.make(elm).foldr1;

  function send(node, timestep, changed) {
    var kids = node.kids;
    for (var i = kids.length; i--; ) {
      kids[i].recv(timestep, changed, node.id);
    }
  }

  function Input(base) {
    this.nodeType = "input";

    this.id = Utils.guid();
    this.value = base;
    this.kids = [];
    this.defaultNumberOfKids = 0;
    this.recv = function(timestep, eid, v) {
      var changed = eid === this.id;
      if (changed) { this.value = v; }
      send(this, timestep, changed);
      return changed;
    };
    elm.inputs.push(this);
  }

  function LiftN(update, args) {
    this.nodeType = "lift";

    this.id = Utils.guid();
    this.value = update();
    this.kids = [];

    var n = args.length;
    var count = 0;
    var isChanged = false;

    this.recv = function(timestep, changed, parentID) {
      ++count;
      if (changed) { isChanged = true; }
      if (count == n) {
        if (isChanged) { this.value = update(); }
        send(this, timestep, isChanged);
        isChanged = false;
        count = 0;
      }
    };
    for (var i = n; i--; ) { args[i].kids.push(this); }
  }

  function lift(func, a) {
    function update() { return func(a.value); }
    return new LiftN(update, [a]);
  }
  function lift2(func, a, b) {
    function update() { return A2( func, a.value, b.value ); }
    return new LiftN(update, [a,b]);
  }
  function lift3(func, a, b, c) {
    function update() { return A3( func, a.value, b.value, c.value ); }
    return new LiftN(update, [a,b,c]);
  }
  function lift4(func, a, b, c, d) {
    function update() { return A4( func, a.value, b.value, c.value, d.value ); }
    return new LiftN(update, [a,b,c,d]);
  }
  function lift5(func, a, b, c, d, e) {
    function update() { return A5( func, a.value, b.value, c.value, d.value, e.value ); }
    return new LiftN(update, [a,b,c,d,e]);
  }
  function lift6(func, a, b, c, d, e, f) {
    function update() { return A6( func, a.value, b.value, c.value, d.value, e.value, f.value ); }
    return new LiftN(update, [a,b,c,d,e,f]);
  }
  function lift7(func, a, b, c, d, e, f, g) {
    function update() { return A7( func, a.value, b.value, c.value, d.value, e.value, f.value, g.value ); }
    return new LiftN(update, [a,b,c,d,e,f,g]);
  }
  function lift8(func, a, b, c, d, e, f, g, h) {
    function update() { return A8( func, a.value, b.value, c.value, d.value, e.value, f.value, g.value, h.value ); }
    return new LiftN(update, [a,b,c,d,e,f,g,h]);
  }

  function Foldp(step, state, input) {
    this.nodeType = "foldp";

    this.id = Utils.guid();
    this.value = state;
    this.kids = [];

    this.recv = function(timestep, changed, parentID) {
      if (changed) {
          this.value = A2( step, input.value, this.value );
      }
      send(this, timestep, changed);
    };
    input.kids.push(this);
  }

  function foldp(step, state, input) {
      return new Foldp(step, state, input);
  }

  function DropIf(pred,base,input) {
    this.nodeType = "dropIf";

    this.id = Utils.guid();
    this.value = pred(input.value) ? base : input.value;
    this.kids = [];
    this.recv = function(timestep, changed, parentID) {
      var chng = changed && !pred(input.value);
      if (chng) { this.value = input.value; }
      send(this, timestep, chng);
    };
    input.kids.push(this);
  }

  function DropRepeats(input) {
    this.nodeType = "dropRepeats";

    this.id = Utils.guid();
    this.value = input.value;
    this.kids = [];
    this.recv = function(timestep, changed, parentID) {
      var chng = changed && !Utils.eq(this.value,input.value);
      if (chng) { this.value = input.value; }
      send(this, timestep, chng);
    };
    input.kids.push(this);
  }

  function timestamp(a) {
    function update() { return Utils.Tuple2(elm.timer.now(), a.value); }
    return new LiftN(update, [a]);
  }

  function SampleOn(s1,s2) {
    this.nodeType = "sampleOn";
    this.indirectParent = s1;

    this.id = Utils.guid();
    this.value = s2.value;
    this.kids = [];

    var count = 0;
    var isChanged = false;

    this.recv = function(timestep, changed, parentID) {
      if (parentID === s1.id) isChanged = changed;
      ++count;
      if (count == 2) {
        if (isChanged) { this.value = s2.value; }
        send(this, timestep, isChanged);
        count = 0;
        isChanged = false;
      }
    };
    s1.kids.push(this);
    s2.kids.push(this);
  }

  function sampleOn(s1,s2) { return new SampleOn(s1,s2); }

  function delay(t,s) {
      this.nodeType = "delay";

      var delayed = new Input(s.value);
      var firstEvent = true;
      function update(v) {
        if (firstEvent) { firstEvent = false; return; }
        setTimeout(function() { elm.notify(delayed.id, v); }, t);
      }
      function first(a,b) { return a; }
      return new SampleOn(delayed, lift2(F2(first), delayed, lift(update,s)));
  }

  function Merge(s1,s2) {
      this.nodeType = "merge";

      this.id = Utils.guid();
      this.value = s1.value;
      this.kids = [];

      var next = null;
      var count = 0;
      var isChanged = false;

      this.recv = function(timestep, changed, parentID) {
        ++count;
        if (changed) {
            isChanged = true;
            if (parentID == s2.id && next === null) { next = s2.value; }
            if (parentID == s1.id) { next = s1.value; }
        }

        if (count == 2) {
            if (isChanged) { this.value = next; next = null; }
            send(this, timestep, isChanged);
            isChanged = false;
            count = 0;
        }
      };
      s1.kids.push(this);
      s2.kids.push(this);
  }

  function merge(s1,s2) { return new Merge(s1,s2); }
  function merges(ss) { return A2(foldr1, F2(merge), ss); }

  return elm.Native.Signal.values = {
    input: function(v) { return new Input(v); },
    constant : function(v) {
      var s = new Input(v);
      s.nodeType = "constant";
      return s;
    },
    lift  : F2(lift ),
    lift2 : F3(lift2),
    lift3 : F4(lift3),
    lift4 : F5(lift4),
    lift5 : F6(lift5),
    lift6 : F7(lift6),
    lift7 : F8(lift7),
    lift8 : F9(lift8),
    foldp : F3(foldp),
    delay : F2(delay),
    merge : F2(merge),
    merges : merges,
    count : function(s) { return foldp(F2(function(_,c) { return c+1; }), 0, s); },
    countIf : F2(function(pred,s) {
      return foldp(F2(function(x,c){
        return pred(x) ? c+1 : c; }), 0, s)}),
    keepIf : F3(function(pred,base,sig) {
      return new DropIf(function(x) {return !pred(x);},base,sig); }),
    dropIf : F3(function(pred,base,sig) { return new DropIf(pred,base,sig); }),
    dropRepeats : function(s) { return new DropRepeats(s);},
    sampleOn : F2(sampleOn),
    timestamp : timestamp
  };
};
<commit_msg>Get rid of nodeType variable<commit_after>
Elm.Native.Signal = {};
Elm.Native.Signal.make = function(elm) {

  elm.Native = elm.Native || {};
  elm.Native.Signal = elm.Native.Signal || {};
  if (elm.Native.Signal.values) return elm.Native.Signal.values;

  var Utils = Elm.Native.Utils.make(elm);
  var foldr1 = Elm.List.make(elm).foldr1;

  function send(node, timestep, changed) {
    var kids = node.kids;
    for (var i = kids.length; i--; ) {
      kids[i].recv(timestep, changed, node.id);
    }
  }

  function Input(base) {
    this.id = Utils.guid();
    this.value = base;
    this.kids = [];
    this.defaultNumberOfKids = 0;
    this.recv = function(timestep, eid, v) {
      var changed = eid === this.id;
      if (changed) { this.value = v; }
      send(this, timestep, changed);
      return changed;
    };
    elm.inputs.push(this);
  }

  function LiftN(update, args) {
    this.id = Utils.guid();
    this.value = update();
    this.kids = [];

    var n = args.length;
    var count = 0;
    var isChanged = false;

    this.recv = function(timestep, changed, parentID) {
      ++count;
      if (changed) { isChanged = true; }
      if (count == n) {
        if (isChanged) { this.value = update(); }
        send(this, timestep, isChanged);
        isChanged = false;
        count = 0;
      }
    };
    for (var i = n; i--; ) { args[i].kids.push(this); }
  }

  function lift(func, a) {
    function update() { return func(a.value); }
    return new LiftN(update, [a]);
  }
  function lift2(func, a, b) {
    function update() { return A2( func, a.value, b.value ); }
    return new LiftN(update, [a,b]);
  }
  function lift3(func, a, b, c) {
    function update() { return A3( func, a.value, b.value, c.value ); }
    return new LiftN(update, [a,b,c]);
  }
  function lift4(func, a, b, c, d) {
    function update() { return A4( func, a.value, b.value, c.value, d.value ); }
    return new LiftN(update, [a,b,c,d]);
  }
  function lift5(func, a, b, c, d, e) {
    function update() { return A5( func, a.value, b.value, c.value, d.value, e.value ); }
    return new LiftN(update, [a,b,c,d,e]);
  }
  function lift6(func, a, b, c, d, e, f) {
    function update() { return A6( func, a.value, b.value, c.value, d.value, e.value, f.value ); }
    return new LiftN(update, [a,b,c,d,e,f]);
  }
  function lift7(func, a, b, c, d, e, f, g) {
    function update() { return A7( func, a.value, b.value, c.value, d.value, e.value, f.value, g.value ); }
    return new LiftN(update, [a,b,c,d,e,f,g]);
  }
  function lift8(func, a, b, c, d, e, f, g, h) {
    function update() { return A8( func, a.value, b.value, c.value, d.value, e.value, f.value, g.value, h.value ); }
    return new LiftN(update, [a,b,c,d,e,f,g,h]);
  }

  function Foldp(step, state, input) {
    this.id = Utils.guid();
    this.value = state;
    this.kids = [];

    this.recv = function(timestep, changed, parentID) {
      if (changed) {
          this.value = A2( step, input.value, this.value );
      }
      send(this, timestep, changed);
    };
    input.kids.push(this);
  }

  function foldp(step, state, input) {
      return new Foldp(step, state, input);
  }

  function DropIf(pred,base,input) {
    this.id = Utils.guid();
    this.value = pred(input.value) ? base : input.value;
    this.kids = [];
    this.recv = function(timestep, changed, parentID) {
      var chng = changed && !pred(input.value);
      if (chng) { this.value = input.value; }
      send(this, timestep, chng);
    };
    input.kids.push(this);
  }

  function DropRepeats(input) {
    this.id = Utils.guid();
    this.value = input.value;
    this.kids = [];
    this.recv = function(timestep, changed, parentID) {
      var chng = changed && !Utils.eq(this.value,input.value);
      if (chng) { this.value = input.value; }
      send(this, timestep, chng);
    };
    input.kids.push(this);
  }

  function timestamp(a) {
    function update() { return Utils.Tuple2(elm.timer.now(), a.value); }
    return new LiftN(update, [a]);
  }

  function SampleOn(s1,s2) {
    this.id = Utils.guid();
    this.value = s2.value;
    this.kids = [];

    var count = 0;
    var isChanged = false;

    this.recv = function(timestep, changed, parentID) {
      if (parentID === s1.id) isChanged = changed;
      ++count;
      if (count == 2) {
        if (isChanged) { this.value = s2.value; }
        send(this, timestep, isChanged);
        count = 0;
        isChanged = false;
      }
    };
    s1.kids.push(this);
    s2.kids.push(this);
  }

  function sampleOn(s1,s2) { return new SampleOn(s1,s2); }

  function delay(t,s) {
      var delayed = new Input(s.value);
      var firstEvent = true;
      function update(v) {
        if (firstEvent) { firstEvent = false; return; }
        setTimeout(function() { elm.notify(delayed.id, v); }, t);
      }
      function first(a,b) { return a; }
      return new SampleOn(delayed, lift2(F2(first), delayed, lift(update,s)));
  }

  function Merge(s1,s2) {
      this.id = Utils.guid();
      this.value = s1.value;
      this.kids = [];

      var next = null;
      var count = 0;
      var isChanged = false;

      this.recv = function(timestep, changed, parentID) {
        ++count;
        if (changed) {
            isChanged = true;
            if (parentID == s2.id && next === null) { next = s2.value; }
            if (parentID == s1.id) { next = s1.value; }
        }

        if (count == 2) {
            if (isChanged) { this.value = next; next = null; }
            send(this, timestep, isChanged);
            isChanged = false;
            count = 0;
        }
      };
      s1.kids.push(this);
      s2.kids.push(this);
  }

  function merge(s1,s2) { return new Merge(s1,s2); }
  function merges(ss) { return A2(foldr1, F2(merge), ss); }

  return elm.Native.Signal.values = {
    input: function(v) { return new Input(v); },
    constant : function(v) { return new Input(v); },
    lift  : F2(lift ),
    lift2 : F3(lift2),
    lift3 : F4(lift3),
    lift4 : F5(lift4),
    lift5 : F6(lift5),
    lift6 : F7(lift6),
    lift7 : F8(lift7),
    lift8 : F9(lift8),
    foldp : F3(foldp),
    delay : F2(delay),
    merge : F2(merge),
    merges : merges,
    count : function(s) { return foldp(F2(function(_,c) { return c+1; }), 0, s); },
    countIf : F2(function(pred,s) {
      return foldp(F2(function(x,c){
        return pred(x) ? c+1 : c; }), 0, s)}),
    keepIf : F3(function(pred,base,sig) {
      return new DropIf(function(x) {return !pred(x);},base,sig); }),
    dropIf : F3(function(pred,base,sig) { return new DropIf(pred,base,sig); }),
    dropRepeats : function(s) { return new DropRepeats(s);},
    sampleOn : F2(sampleOn),
    timestamp : timestamp
  };
};
<|endoftext|>


<commit_before>/*!
 * jQuery UI Controlgroup @VERSION
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Controlgroup
//>>group: Widgets
//>>description: Visually groups form control widgets
//>>docs: http://api.jqueryui.com/controlgroup/
//>>demos: http://jqueryui.com/controlgroup/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/controlgroup.css
//>>css.theme: ../../themes/base/theme.css

( function( factory ) {
	if ( typeof define === "function" && define.amd ) {

		// AMD. Register as an anonymous module.
		define( [
			"jquery",
			"../widget"
		], factory );
	} else {

		// Browser globals
		factory( jQuery );
	}
}( function( $ ) {
var controlgroupCornerRegex = /ui-corner-([a-z]){2,6}/g;

return $.widget( "ui.controlgroup", {
	version: "@VERSION",
	defaultElement: "
",
	options: {
		direction: "horizontal",
		disabled: null,
		onlyVisible: true,
		items: {
			"button": "input[type=button], input[type=submit], input[type=reset], button, a",
			"controlgroupLabel": ".ui-controlgroup-label",
			"checkboxradio": "input[type='checkbox'], input[type='radio']",
			"selectmenu": "select",
			"spinner": ".ui-spinner-input"
		}
	},

	_create: function() {
		this._enhance();
	},

	// To support the enhanced option in jQuery Mobile, we isolate DOM manipulation
	_enhance: function() {
		this.element.attr( "role", "toolbar" );
		this.refresh();
	},

	_destroy: function() {
		this._callChildMethod( "destroy" );
		this.childWidgets.removeData( "ui-controlgroup-data" );
		this.element.removeAttr( "role" );
		if ( this.options.items.controlgroupLabel ) {
			this.element
				.find( this.options.items.controlgroupLabel )
				.find( ".ui-controlgroup-label-contents" )
				.contents().unwrap();
		}
	},

	_initWidgets: function() {
		var that = this,
			childWidgets = [];

		// First we iterate over each of the items options
		$.each( this.options.items, function( widget, selector ) {
			var labels;
			var options = {};

			// Make sure the widget has a selector set
			if ( !selector ) {
				return;
			}

			if ( widget === "controlgroupLabel" ) {
				labels = that.element.find( selector );
				labels.each( function() {
					var element = $( this );

					if ( element.children( ".ui-controlgroup-label-contents" ).length ) {
						return;
					}
					element.contents()
						.wrapAll( "" );
				} );
				that._addClass( labels, null, "ui-widget ui-widget-content ui-state-default" );
				childWidgets = childWidgets.concat( labels.get() );
				return;
			}

			// Make sure the widget actually exists
			if ( !$.fn[ widget ] ) {
				return;
			}

			// We assume everything is in the middle to start because we can't determine
			// first / last elements until all enhancments are done.
			if ( that[ "_" + widget + "Options" ] ) {
				options = that[ "_" + widget + "Options" ]( "middle" );
			} else {
				options = { classes: {} };
			}

			// Find instances of this widget inside controlgroup and init them
			that.element
				.find( selector )
				.each( function() {
					var element = $( this );
					var instance = element[ widget ]( "instance" );

					// We need to clone the default options for this type of widget to avoid
					// polluting the variable options which has a wider scope than a single widget.
					var instanceOptions = $.widget.extend( {}, options );

					// If the button is the child of a spinner ignore it
					// TODO: Find a more generic solution
					if ( widget === "button" && element.parent( ".ui-spinner" ).length ) {
						return;
					}

					// Create the widget if it doesn't exist
					if ( !instance ) {
						instance = element[ widget ]()[ widget ]( "instance" );
					}
					if ( instance ) {
						instanceOptions.classes =
							that._resolveClassesValues( instanceOptions.classes, instance );
					}
					element[ widget ]( instanceOptions );

					// Store an instance of the controlgroup to be able to reference
					// from the outermost element for changing options and refresh
					var widgetElement = element[ widget ]( "widget" );
					$.data( widgetElement[ 0 ], "ui-controlgroup-data",
						instance ? instance : element[ widget ]( "instance" ) );

					childWidgets.push( widgetElement[ 0 ] );
				} );
		} );

		this.childWidgets = $( $.unique( childWidgets ) );
		this._addClass( this.childWidgets, "ui-controlgroup-item" );
	},

	_callChildMethod: function( method ) {
		this.childWidgets.each( function() {
			var element = $( this ),
				data = element.data( "ui-controlgroup-data" );
			if ( data && data[ method ] ) {
				data[ method ]();
			}
		} );
	},

	_updateCornerClass: function( element, position ) {
		var remove = "ui-corner-top ui-corner-bottom ui-corner-left ui-corner-right ui-corner-all";
		var add = this._buildSimpleOptions( position, "label" ).classes.label;

		this._removeClass( element, null, remove );
		this._addClass( element, null, add );
	},

	_buildSimpleOptions: function( position, key ) {
		var direction = this.options.direction === "vertical";
		var result = {
			classes: {}
		};
		result.classes[ key ] = {
			"middle": "",
			"first": "ui-corner-" + ( direction ? "top" : "left" ),
			"last": "ui-corner-" + ( direction ? "bottom" : "right" ),
			"only": "ui-corner-all"
		}[ position ];

		return result;
	},

	_spinnerOptions: function( position ) {
		var options = this._buildSimpleOptions( position, "ui-spinner" );

		options.classes[ "ui-spinner-up" ] = "";
		options.classes[ "ui-spinner-down" ] = "";

		return options;
	},

	_buttonOptions: function( position ) {
		return this._buildSimpleOptions( position, "ui-button" );
	},

	_checkboxradioOptions: function( position ) {
		return this._buildSimpleOptions( position, "ui-checkboxradio-label" );
	},

	_selectmenuOptions: function( position ) {
		var direction = this.options.direction === "vertical";
		return {
			width: direction ? "auto" : false,
			classes: {
				middle: {
					"ui-selectmenu-button-open": "",
					"ui-selectmenu-button-closed": ""
				},
				first: {
					"ui-selectmenu-button-open": "ui-corner-" + ( direction ? "top" : "tl" ),
					"ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "top" : "left" )
				},
				last: {
					"ui-selectmenu-button-open": direction ? "" : "ui-corner-tr",
					"ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "bottom" : "right" )
				},
				only: {
					"ui-selectmenu-button-open": "ui-corner-top",
					"ui-selectmenu-button-closed": "ui-corner-all"
				}

			}[ position ]
		};
	},

	_resolveClassesValues: function( classes, instance ) {
		var result = {};
		$.each( classes, function( key ) {
			var current = instance.options.classes[ key ] || "";
			current = current.replace( controlgroupCornerRegex, "" ).trim();
			result[ key ] = ( current + " " + classes[ key ] ).replace( /\s+/g, " " );
		} );
		return result;
	},

	_setOption: function( key, value ) {
		if ( key === "direction" ) {
			this._removeClass( "ui-controlgroup-" + this.options.direction );
		}

		this._super( key, value );
		if ( key === "disabled" ) {
			this._callChildMethod( value ? "disable" : "enable" );
			return;
		}

		this.refresh();
	},

	refresh: function() {
		var children,
			that = this;

		this._addClass( "ui-controlgroup ui-controlgroup-" + this.options.direction );

		if ( this.options.direction === "horizontal" ) {
			this._addClass( null, "ui-helper-clearfix" );
		}
		this._initWidgets();

		children = this.childWidgets;

		// We filter here because we need to track all childWidgets not just the visible ones
		if ( this.options.onlyVisible ) {
			children = children.filter( ":visible" );
		}

		if ( children.length ) {

			// We do this last because we need to make sure all enhancment is done
			// before determining first and last
			$.each( [ "first", "last" ], function( index, value ) {
				var instance = children[ value ]().data( "ui-controlgroup-data" );

				if ( instance && that[ "_" + instance.widgetName + "Options" ] ) {
					var options = that[ "_" + instance.widgetName + "Options" ](
						children.length === 1 ? "only" : value
					);
					options.classes = that._resolveClassesValues( options.classes, instance );
					instance.element[ instance.widgetName ]( options );
				} else {
					that._updateCornerClass( children[ value ](), value );
				}
			} );

			// Finally call the refresh method on each of the child widgets.
			this._callChildMethod( "refresh" );
		}
	}
} );
} ) );
<commit_msg>Controlgroup: Don't use `String.prototype.trim()`<commit_after>/*!
 * jQuery UI Controlgroup @VERSION
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Controlgroup
//>>group: Widgets
//>>description: Visually groups form control widgets
//>>docs: http://api.jqueryui.com/controlgroup/
//>>demos: http://jqueryui.com/controlgroup/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/controlgroup.css
//>>css.theme: ../../themes/base/theme.css

( function( factory ) {
	if ( typeof define === "function" && define.amd ) {

		// AMD. Register as an anonymous module.
		define( [
			"jquery",
			"../widget"
		], factory );
	} else {

		// Browser globals
		factory( jQuery );
	}
}( function( $ ) {
var controlgroupCornerRegex = /ui-corner-([a-z]){2,6}/g;

return $.widget( "ui.controlgroup", {
	version: "@VERSION",
	defaultElement: "
",
	options: {
		direction: "horizontal",
		disabled: null,
		onlyVisible: true,
		items: {
			"button": "input[type=button], input[type=submit], input[type=reset], button, a",
			"controlgroupLabel": ".ui-controlgroup-label",
			"checkboxradio": "input[type='checkbox'], input[type='radio']",
			"selectmenu": "select",
			"spinner": ".ui-spinner-input"
		}
	},

	_create: function() {
		this._enhance();
	},

	// To support the enhanced option in jQuery Mobile, we isolate DOM manipulation
	_enhance: function() {
		this.element.attr( "role", "toolbar" );
		this.refresh();
	},

	_destroy: function() {
		this._callChildMethod( "destroy" );
		this.childWidgets.removeData( "ui-controlgroup-data" );
		this.element.removeAttr( "role" );
		if ( this.options.items.controlgroupLabel ) {
			this.element
				.find( this.options.items.controlgroupLabel )
				.find( ".ui-controlgroup-label-contents" )
				.contents().unwrap();
		}
	},

	_initWidgets: function() {
		var that = this,
			childWidgets = [];

		// First we iterate over each of the items options
		$.each( this.options.items, function( widget, selector ) {
			var labels;
			var options = {};

			// Make sure the widget has a selector set
			if ( !selector ) {
				return;
			}

			if ( widget === "controlgroupLabel" ) {
				labels = that.element.find( selector );
				labels.each( function() {
					var element = $( this );

					if ( element.children( ".ui-controlgroup-label-contents" ).length ) {
						return;
					}
					element.contents()
						.wrapAll( "" );
				} );
				that._addClass( labels, null, "ui-widget ui-widget-content ui-state-default" );
				childWidgets = childWidgets.concat( labels.get() );
				return;
			}

			// Make sure the widget actually exists
			if ( !$.fn[ widget ] ) {
				return;
			}

			// We assume everything is in the middle to start because we can't determine
			// first / last elements until all enhancments are done.
			if ( that[ "_" + widget + "Options" ] ) {
				options = that[ "_" + widget + "Options" ]( "middle" );
			} else {
				options = { classes: {} };
			}

			// Find instances of this widget inside controlgroup and init them
			that.element
				.find( selector )
				.each( function() {
					var element = $( this );
					var instance = element[ widget ]( "instance" );

					// We need to clone the default options for this type of widget to avoid
					// polluting the variable options which has a wider scope than a single widget.
					var instanceOptions = $.widget.extend( {}, options );

					// If the button is the child of a spinner ignore it
					// TODO: Find a more generic solution
					if ( widget === "button" && element.parent( ".ui-spinner" ).length ) {
						return;
					}

					// Create the widget if it doesn't exist
					if ( !instance ) {
						instance = element[ widget ]()[ widget ]( "instance" );
					}
					if ( instance ) {
						instanceOptions.classes =
							that._resolveClassesValues( instanceOptions.classes, instance );
					}
					element[ widget ]( instanceOptions );

					// Store an instance of the controlgroup to be able to reference
					// from the outermost element for changing options and refresh
					var widgetElement = element[ widget ]( "widget" );
					$.data( widgetElement[ 0 ], "ui-controlgroup-data",
						instance ? instance : element[ widget ]( "instance" ) );

					childWidgets.push( widgetElement[ 0 ] );
				} );
		} );

		this.childWidgets = $( $.unique( childWidgets ) );
		this._addClass( this.childWidgets, "ui-controlgroup-item" );
	},

	_callChildMethod: function( method ) {
		this.childWidgets.each( function() {
			var element = $( this ),
				data = element.data( "ui-controlgroup-data" );
			if ( data && data[ method ] ) {
				data[ method ]();
			}
		} );
	},

	_updateCornerClass: function( element, position ) {
		var remove = "ui-corner-top ui-corner-bottom ui-corner-left ui-corner-right ui-corner-all";
		var add = this._buildSimpleOptions( position, "label" ).classes.label;

		this._removeClass( element, null, remove );
		this._addClass( element, null, add );
	},

	_buildSimpleOptions: function( position, key ) {
		var direction = this.options.direction === "vertical";
		var result = {
			classes: {}
		};
		result.classes[ key ] = {
			"middle": "",
			"first": "ui-corner-" + ( direction ? "top" : "left" ),
			"last": "ui-corner-" + ( direction ? "bottom" : "right" ),
			"only": "ui-corner-all"
		}[ position ];

		return result;
	},

	_spinnerOptions: function( position ) {
		var options = this._buildSimpleOptions( position, "ui-spinner" );

		options.classes[ "ui-spinner-up" ] = "";
		options.classes[ "ui-spinner-down" ] = "";

		return options;
	},

	_buttonOptions: function( position ) {
		return this._buildSimpleOptions( position, "ui-button" );
	},

	_checkboxradioOptions: function( position ) {
		return this._buildSimpleOptions( position, "ui-checkboxradio-label" );
	},

	_selectmenuOptions: function( position ) {
		var direction = this.options.direction === "vertical";
		return {
			width: direction ? "auto" : false,
			classes: {
				middle: {
					"ui-selectmenu-button-open": "",
					"ui-selectmenu-button-closed": ""
				},
				first: {
					"ui-selectmenu-button-open": "ui-corner-" + ( direction ? "top" : "tl" ),
					"ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "top" : "left" )
				},
				last: {
					"ui-selectmenu-button-open": direction ? "" : "ui-corner-tr",
					"ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "bottom" : "right" )
				},
				only: {
					"ui-selectmenu-button-open": "ui-corner-top",
					"ui-selectmenu-button-closed": "ui-corner-all"
				}

			}[ position ]
		};
	},

	_resolveClassesValues: function( classes, instance ) {
		var result = {};
		$.each( classes, function( key ) {
			var current = instance.options.classes[ key ] || "";
			current = $.trim( current.replace( controlgroupCornerRegex, "" ) );
			result[ key ] = ( current + " " + classes[ key ] ).replace( /\s+/g, " " );
		} );
		return result;
	},

	_setOption: function( key, value ) {
		if ( key === "direction" ) {
			this._removeClass( "ui-controlgroup-" + this.options.direction );
		}

		this._super( key, value );
		if ( key === "disabled" ) {
			this._callChildMethod( value ? "disable" : "enable" );
			return;
		}

		this.refresh();
	},

	refresh: function() {
		var children,
			that = this;

		this._addClass( "ui-controlgroup ui-controlgroup-" + this.options.direction );

		if ( this.options.direction === "horizontal" ) {
			this._addClass( null, "ui-helper-clearfix" );
		}
		this._initWidgets();

		children = this.childWidgets;

		// We filter here because we need to track all childWidgets not just the visible ones
		if ( this.options.onlyVisible ) {
			children = children.filter( ":visible" );
		}

		if ( children.length ) {

			// We do this last because we need to make sure all enhancment is done
			// before determining first and last
			$.each( [ "first", "last" ], function( index, value ) {
				var instance = children[ value ]().data( "ui-controlgroup-data" );

				if ( instance && that[ "_" + instance.widgetName + "Options" ] ) {
					var options = that[ "_" + instance.widgetName + "Options" ](
						children.length === 1 ? "only" : value
					);
					options.classes = that._resolveClassesValues( options.classes, instance );
					instance.element[ instance.widgetName ]( options );
				} else {
					that._updateCornerClass( children[ value ](), value );
				}
			} );

			// Finally call the refresh method on each of the child widgets.
			this._callChildMethod( "refresh" );
		}
	}
} );
} ) );
<|endoftext|>