<commit_before>// LINK LIMITS
var GOOD_LINK_RSSI      = -70;
var MEDIUM_LINK_RSSI    = -80;
var GOOD_LINK_PDR       = 80;
var MEDIUM_LINK_PDR     = 50;

// LINK COLOR
var GOOD_LINK_COLOR     = "#00ff00"     // green
var MEDIUM_LINK_COLOR   = "#ffff00"     // orange
var BAD_LINK_COLOR      = "#ffff00"     // red
var UNKNOWN_LINK_COLOR  = "#ffffff"     // white

// Global variables
var map;
var motes   = [];         // a list of motes, indexed by id
var links   = [];         // a list of links
var timeout;
var infoWindow;
var SITE_TIME_OFFSET    = -3
var DEFAULT_PDR         = 101 // init to impossible value
var board_colors        = {"#c33c1c":null,"#dbd60d":null,"#acd2cd":null,"#ff9966":null}

//------------------ Init functions ------------------------------------------//

function initMap() {
    map = new google.maps.Map(document.getElementById('map'), {
        center: new google.maps.LatLng(0, 0),
        zoom: 18,
        scaleControl: true,
    });
    map.setMapTypeId(google.maps.MapTypeId.SATELLITE);

    // set date
    $( "#datepicker" ).datepicker();
    $( "#datepicker" ).datepicker('setDate', 'today');

    // set time
    defaultDate = new Date();
    defaultDate.setTime(defaultDate.getTime());
    $('#timepicker').timepicker({
        showNowButton: true,
        showDeselectButton: true,
        showCloseButton: true,
    });
    $('#timepicker').timepicker('setTime', defaultDate.toLocaleTimeString(
                                'es-AR', { hour: "numeric",
                                minute: "numeric"}));
    load_data(1);
}

function load_data(loop){
    clearLinks();

    // set default time to UTC time
    var date        = $("#datepicker").datepicker('getDate');
    var time        = $("#timepicker").timepicker('getTime').split(':');
    var localOffset = new Date().getTimezoneOffset()/60;
    date.setHours(parseInt(time[0]), time[1]);

    // get host and site name
    var host        = window.location.origin
    var path        = window.location.pathname.split("/map")[0]
    var sitename    = $("#sitename").val()

    // display motes and links
    get_motes(host, path, sitename, date);
    var delay = function() { get_links(host, path, sitename, date) };
    window.setTimeout(delay,500);

    if (loop == 1)
        timeout = setTimeout(load_data, 30000);
    else
        clearTimeout(timeout)
}

//------------------ Main functions ------------------------------------------//

// request the server for mote information
function get_motes(host, path, sitename, date){
    var solType     = "SOL_TYPE_DUST_SNAPSHOT";
    var encType     = encodeURIComponent(solType);
    var isoTime     = date.toISOString();
    var encTime     = encodeURIComponent(isoTime);
    $.getJSON(host+ path +
        "/api/v1/jsonp/"+sitename+"/" + encType +
        "/time/" + encTime, create_motes);
}

// request the server for links information
function get_links(host, path, sitename, date){
    var solType     = "SOL_TYPE_DUST_NOTIF_HRNEIGHBORS";
    var encType     = encodeURIComponent(solType);
    var isoTime     = date.toISOString();
    var encTime     = encodeURIComponent(isoTime);
    $.getJSON(host+ path +
        "/api/v1/jsonp/"+sitename+"/" + encType +
        "/time/" + encTime, create_links);
}

// populate the motes list
function create_motes(data){
    if (Object.keys(data).length > 0) {

        // manager
        motes[0] = {
            "mac"       : data[0].mac,
            "marker"    : null,
        }

        // motes
        mote_list = data[0].value.mote
        for (var i=0; i < Object.keys(mote_list).length; i++) {
            // populate table
            motes[mote_list[i].moteId] = {
                "mac"       : mote_list[i].macAddress,
                "marker"    : null
            }
        }
    }
}

function create_links(data){
    var bounds = new google.maps.LatLngBounds();
    var loc;

    // update motes location and board type

    //-- manager
    updateMote(
        data[0].mac,
        data[0].latitude,
        data[0].longitude,
        data[0].board
        );

    //-- motes
    for (var i=0; i < data.length; i++) {
        loc = new google.maps.LatLng(
            data[i].value.latitude,
            data[i].value.longitude
        );
        bounds.extend(loc);
        udpateMote(
            data[i].mac,
            data[i].value.latitude,
            data[i].value.longitude,
            data[i].value.board);
    }
    map.fitBounds(bounds);
    map.panToBounds(bounds);

    // create links
    for (var i=0; i < data.length; i++) {
        for (var n_id in data[i].value.neighbors){
            var neighbor = data[i].value.neighbors[n_id]
            if (neighbor.neighborId in motes){
                var crd1 = getLocationFromMac(data[i].mac);
                var crd2 = getLocationFromId(neighbor.neighborId)
                if (crd1 != null && crd2 != null){
                    var lineCoords = [crd1, crd2];
                    var link    = getLink(crd1, crd2);

                    // get metric
                    var pdr = DEFAULT_PDR //init to unpossible value
                    if (neighbor.numTxPackets > 0){
                        pdr     = ((neighbor.numTxPackets - neighbor.numTxFailures)
                                    /neighbor.numTxPackets
                                ) * 100;
                    }
                    var rssi    = neighbor.rssi;

                    // update link if already exists
                    if (link != null){
                        link.metric.rssi    = Math.min(rssi, link.metric.rssi)
                        link.metric.pdr     = Math.min(pdr, link.metric.pdr)

                        link.pline.setMap(null);
                        var color   = getLinkColor(link.metric.rssi, link.metric.pdr);
                        var dist    = calcDistance(lineCoords[0],lineCoords[1])
                        // set line parameters
                        if (link.metric.pdr == DEFAULT_PDR)
                          s_pdr = "No Tx"
                        else
                          s_pdr = link.metric.pdr + "%"
                        var content =   "RSSI: " + rssi + "dBm
" +
                                        "PDR: " + s_pdr + "
" +
                                        "Distance: " + dist + "m"
                        link.pline  = createPolyline(lineCoords, content, color);
                    } // create link if it does not already exists
                    else {
                        var color   = getLinkColor(rssi, pdr);
                        var dist    = calcDistance(lineCoords[0],lineCoords[1])
                        // set line parameters
                        // set line parameters
                        if (pdr == DEFAULT_PDR)
                          s_pdr = "No Tx"
                        else
                          s_pdr = pdr + "%"
                        var content =   "RSSI: " + rssi + "dBm
" +
                                        "PDR: " + s_pdr + "
" +
                                        "Distance: " + dist + "m"
                        var l = createPolyline(lineCoords, content, color);
                        var newLink = {
                            "pline" :   l,
                            "metric":   {
                                    "rssi"  : rssi,
                                    "pdr"   : pdr,
                                }
                        }
                        links.push(newLink);
                    }
                }
            }
            else {console.log("ID not found:" + neighbor.neighborId);}
        }
    }
}

//----------------Interface Listeners ---------------------------------------//

$(document).ready(function() {
    $("#next_time").click(function(event) {
        var selectedTime =  $('#timepicker').timepicker('getTimeAsDate');
        // add 5 minutes
        var newDate = new Date(selectedTime.getTime() + 5*60000)
        str_date = newDate.getHours().toString() + ":" + newDate.getMinutes().toString();
        $('#timepicker').timepicker('setTime', str_date);
        load_data(0);
    });
});

$(document).ready(function() {
    $("#prev_time").click(function(event) {
        var selectedTime =  $('#timepicker').timepicker('getTimeAsDate');
        // remove 5 minutes
        var newDate = new Date(selectedTime.getTime() - 5*60000)
        str_date = newDate.getHours().toString() + ":" + newDate.getMinutes().toString();
        $('#timepicker').timepicker('setTime', str_date);
        load_data(0)
    });
});

//------------------ Helpers ------------------------------------------------//

function clearLinks(){
    // remove links
    for (var i=0; i<links.length; i++) {
        if (i in links){
            links[i].pline.setMap(null);
        }
    }
    links = [];
    links.length = 0;
}

function getLinkColor(rssi, pdr){
    var metric = $("#metric").val()

    if (metric == "rssi"){
        if (rssi > GOOD_LINK_RSSI)
            return GOOD_LINK_COLOR;
        else if (rssi >= MEDIUM_LINK_RSSI && rssi <= GOOD_LINK_RSSI)
            return MEDIUM_LINK_COLOR;
        else
            return BAD_LINK_COLOR;
    }
    else if (metric == "pdr"){
        if (pdr == DEFAULT_PDR)
            return UNKNOWN_LINK_COLOR;
        if (pdr >= GOOD_LINK_PDR)
            return GOOD_LINK_COLOR;
        else if (pdr > MEDIUM_LINK_PDR && pdr < GOOD_LINK_PDR)
            return MEDIUM_LINK_COLOR;
    }
}

function getMoteColor(board){
    if (board == null)
        board = "unknown"
    for (var color in board_colors){
        if (board_colors[color] === null){
            board_colors[color] = board;
            return color;
        }
        else if (board_colors[color] === board){
            return color
        }
    }
    // return default color if board_color is too small
    return "#FFF"
}

function udpateMote(mac, lat, lng, board){
    var moteId  = null;
    var color   = getMoteColor(board)
    for (var i=0; i<motes.length; i++) {
        if (i in motes){
            if (motes[i].mac == mac){
                var content = mac + "
"
                if (board != null)
                  content += board + "
"
                if (motes[i].marker == null){
                    motes[i].marker = createMarker(lat, lng, content, color);
                } else if (motes[i].marker.position.lat() != lat ||
                            motes[i].marker.position.lng() != lng) {
                    motes[i].marker.setMap(null);
                    motes[i].marker = createMarker(lat, lng, content, color);
                }
            }
        }
    }
}

function createMarker(lat, lng, content, color){
    // create Markers
    var myLatLng = new google.maps.LatLng(lat, lng)
    var marker = new google.maps.Marker({
        position: myLatLng,
        map: map,
        icon: pinSymbol(color),
    });
    // add popup listener
    infoBox(map, marker, content);
    return marker;
}

function createPolyline(lineCoordinates, content, color){
    var line = new google.maps.Polyline({
          path: lineCoordinates,
          geodesic: true,
          strokeColor: color,
          strokeWeight: 2
    });
    if (color != UNKNOWN_LINK_COLOR){
        line.setMap(map);
        infoBox(map, line, content);
    }
    return line;
}

function getLink(LatLng1, LatLng2){
    for (i=0; i<links.length; i++) {
        var link = links[i].pline;
        var coord1 = "("+link.getPath().getAt(0).lat()+", "+link.getPath().getAt(0).lng()+")"
        var coord2 = "("+link.getPath().getAt(1).lat()+", "+link.getPath().getAt(1).lng()+")"
        if ( ((LatLng1.toString() == coord1) && (LatLng2.toString() == coord2)) ||
             ((LatLng2.toString() == coord1) && (LatLng1.toString() == coord2))
           ){
            return links[i]
        }
    }
    return null
}

function getMoteFromId(moteId){
    if (motes[moteId].marker != null)
        return motes[moteId].marker.position;
    else
        return null;
}

function getLocationFromId(moteId){
    if (motes[moteId].marker != null)
        return motes[moteId].marker.position;
    else
        return null;
}

function getLocationFromMac(mac){
    for( i=0; i<motes.length; i++ ) {
        if (i in motes && motes[i].mac == mac){
            return motes[i].marker.position;
        }
    }
    console.log("MAC not found:" + mac)
    return null;
}

// calculates distance between two points in meters
function calcDistance(p1, p2) {
    return (google.maps.geometry.spherical.computeDistanceBetween(p1, p2)).toFixed(2);
}

/*Function that shows a window with the content or info
 about the marker (sensor location)*/

function infoBox(map, marker, content) {
    infoWindow = new google.maps.InfoWindow();
    // Attaching a click event to the current marker
    google.maps.event.addListener(marker, "click", function(e) {
        infoWindow.setPosition(e.latLng);
        infoWindow.setContent(content);
        infoWindow.open(map, marker);
        var iw_container = $(".gm-style-iw").parent();
        iw_container.stop().hide();
        iw_container.fadeIn(300);
    });
}

// Function that create a vectorial image of a marker with the given color
function pinSymbol(color) {
    return {
        path: 'M 0,0 C -2,-20 -10,-22 -10,-30 A 10,10 0 1,1 10,-30 C 10,-22 2,-20 0,0 z M -2,-30 a 2,2 0 1,1 4,0 2,2 0 1,1 -4,0',
        fillColor: color,
        fillOpacity: 1,
        strokeColor: '#000',
        strokeWeight: 2,
        scale: 1,
   };
}
<commit_msg>#53 correcting updateMote func name<commit_after>// LINK LIMITS
var GOOD_LINK_RSSI      = -70;
var MEDIUM_LINK_RSSI    = -80;
var GOOD_LINK_PDR       = 80;
var MEDIUM_LINK_PDR     = 50;

// LINK COLOR
var GOOD_LINK_COLOR     = "#00ff00"     // green
var MEDIUM_LINK_COLOR   = "#ffff00"     // orange
var BAD_LINK_COLOR      = "#ffff00"     // red
var UNKNOWN_LINK_COLOR  = "#ffffff"     // white

// Global variables
var map;
var motes   = [];         // a list of motes, indexed by id
var links   = [];         // a list of links
var timeout;
var infoWindow;
var SITE_TIME_OFFSET    = -3
var DEFAULT_PDR         = 101 // init to impossible value
var board_colors        = {"#c33c1c":null,"#dbd60d":null,"#acd2cd":null,"#ff9966":null}

//------------------ Init functions ------------------------------------------//

function initMap() {
    map = new google.maps.Map(document.getElementById('map'), {
        center: new google.maps.LatLng(0, 0),
        zoom: 18,
        scaleControl: true,
    });
    map.setMapTypeId(google.maps.MapTypeId.SATELLITE);

    // set date
    $( "#datepicker" ).datepicker();
    $( "#datepicker" ).datepicker('setDate', 'today');

    // set time
    defaultDate = new Date();
    defaultDate.setTime(defaultDate.getTime());
    $('#timepicker').timepicker({
        showNowButton: true,
        showDeselectButton: true,
        showCloseButton: true,
    });
    $('#timepicker').timepicker('setTime', defaultDate.toLocaleTimeString(
                                'es-AR', { hour: "numeric",
                                minute: "numeric"}));
    load_data(1);
}

function load_data(loop){
    clearLinks();

    // set default time to UTC time
    var date        = $("#datepicker").datepicker('getDate');
    var time        = $("#timepicker").timepicker('getTime').split(':');
    var localOffset = new Date().getTimezoneOffset()/60;
    date.setHours(parseInt(time[0]), time[1]);

    // get host and site name
    var host        = window.location.origin
    var path        = window.location.pathname.split("/map")[0]
    var sitename    = $("#sitename").val()

    // display motes and links
    get_motes(host, path, sitename, date);
    var delay = function() { get_links(host, path, sitename, date) };
    window.setTimeout(delay,500);

    if (loop == 1)
        timeout = setTimeout(load_data, 30000);
    else
        clearTimeout(timeout)
}

//------------------ Main functions ------------------------------------------//

// request the server for mote information
function get_motes(host, path, sitename, date){
    var solType     = "SOL_TYPE_DUST_SNAPSHOT";
    var encType     = encodeURIComponent(solType);
    var isoTime     = date.toISOString();
    var encTime     = encodeURIComponent(isoTime);
    $.getJSON(host+ path +
        "/api/v1/jsonp/"+sitename+"/" + encType +
        "/time/" + encTime, create_motes);
}

// request the server for links information
function get_links(host, path, sitename, date){
    var solType     = "SOL_TYPE_DUST_NOTIF_HRNEIGHBORS";
    var encType     = encodeURIComponent(solType);
    var isoTime     = date.toISOString();
    var encTime     = encodeURIComponent(isoTime);
    $.getJSON(host+ path +
        "/api/v1/jsonp/"+sitename+"/" + encType +
        "/time/" + encTime, create_links);
}

// populate the motes list
function create_motes(data){
    if (Object.keys(data).length > 0) {

        // manager
        motes[0] = {
            "mac"       : data[0].mac,
            "marker"    : null,
        }

        // motes
        mote_list = data[0].value.mote
        for (var i=0; i < Object.keys(mote_list).length; i++) {
            // populate table
            motes[mote_list[i].moteId] = {
                "mac"       : mote_list[i].macAddress,
                "marker"    : null
            }
        }
    }
}

function create_links(data){
    var bounds = new google.maps.LatLngBounds();
    var loc;

    // update motes location and board type

    //-- manager
    updateMote(
        data[0].mac,
        data[0].latitude,
        data[0].longitude,
        data[0].board
        );

    //-- motes
    for (var i=0; i < data.length; i++) {
        loc = new google.maps.LatLng(
            data[i].value.latitude,
            data[i].value.longitude
        );
        bounds.extend(loc);
        updateMote(
            data[i].mac,
            data[i].value.latitude,
            data[i].value.longitude,
            data[i].value.board);
    }
    map.fitBounds(bounds);
    map.panToBounds(bounds);

    // create links
    for (var i=0; i < data.length; i++) {
        for (var n_id in data[i].value.neighbors){
            var neighbor = data[i].value.neighbors[n_id]
            if (neighbor.neighborId in motes){
                var crd1 = getLocationFromMac(data[i].mac);
                var crd2 = getLocationFromId(neighbor.neighborId)
                if (crd1 != null && crd2 != null){
                    var lineCoords = [crd1, crd2];
                    var link    = getLink(crd1, crd2);

                    // get metric
                    var pdr = DEFAULT_PDR //init to unpossible value
                    if (neighbor.numTxPackets > 0){
                        pdr     = ((neighbor.numTxPackets - neighbor.numTxFailures)
                                    /neighbor.numTxPackets
                                ) * 100;
                    }
                    var rssi    = neighbor.rssi;

                    // update link if already exists
                    if (link != null){
                        link.metric.rssi    = Math.min(rssi, link.metric.rssi)
                        link.metric.pdr     = Math.min(pdr, link.metric.pdr)

                        link.pline.setMap(null);
                        var color   = getLinkColor(link.metric.rssi, link.metric.pdr);
                        var dist    = calcDistance(lineCoords[0],lineCoords[1])
                        // set line parameters
                        if (link.metric.pdr == DEFAULT_PDR)
                          s_pdr = "No Tx"
                        else
                          s_pdr = link.metric.pdr + "%"
                        var content =   "RSSI: " + rssi + "dBm
" +
                                        "PDR: " + s_pdr + "
" +
                                        "Distance: " + dist + "m"
                        link.pline  = createPolyline(lineCoords, content, color);
                    } // create link if it does not already exists
                    else {
                        var color   = getLinkColor(rssi, pdr);
                        var dist    = calcDistance(lineCoords[0],lineCoords[1])
                        // set line parameters
                        // set line parameters
                        if (pdr == DEFAULT_PDR)
                          s_pdr = "No Tx"
                        else
                          s_pdr = pdr + "%"
                        var content =   "RSSI: " + rssi + "dBm
" +
                                        "PDR: " + s_pdr + "
" +
                                        "Distance: " + dist + "m"
                        var l = createPolyline(lineCoords, content, color);
                        var newLink = {
                            "pline" :   l,
                            "metric":   {
                                    "rssi"  : rssi,
                                    "pdr"   : pdr,
                                }
                        }
                        links.push(newLink);
                    }
                }
            }
            else {console.log("ID not found:" + neighbor.neighborId);}
        }
    }
}

//----------------Interface Listeners ---------------------------------------//

$(document).ready(function() {
    $("#next_time").click(function(event) {
        var selectedTime =  $('#timepicker').timepicker('getTimeAsDate');
        // add 5 minutes
        var newDate = new Date(selectedTime.getTime() + 5*60000)
        str_date = newDate.getHours().toString() + ":" + newDate.getMinutes().toString();
        $('#timepicker').timepicker('setTime', str_date);
        load_data(0);
    });
});

$(document).ready(function() {
    $("#prev_time").click(function(event) {
        var selectedTime =  $('#timepicker').timepicker('getTimeAsDate');
        // remove 5 minutes
        var newDate = new Date(selectedTime.getTime() - 5*60000)
        str_date = newDate.getHours().toString() + ":" + newDate.getMinutes().toString();
        $('#timepicker').timepicker('setTime', str_date);
        load_data(0)
    });
});

//------------------ Helpers ------------------------------------------------//

function clearLinks(){
    // remove links
    for (var i=0; i<links.length; i++) {
        if (i in links){
            links[i].pline.setMap(null);
        }
    }
    links = [];
    links.length = 0;
}

function getLinkColor(rssi, pdr){
    var metric = $("#metric").val()

    if (metric == "rssi"){
        if (rssi > GOOD_LINK_RSSI)
            return GOOD_LINK_COLOR;
        else if (rssi >= MEDIUM_LINK_RSSI && rssi <= GOOD_LINK_RSSI)
            return MEDIUM_LINK_COLOR;
        else
            return BAD_LINK_COLOR;
    }
    else if (metric == "pdr"){
        if (pdr == DEFAULT_PDR)
            return UNKNOWN_LINK_COLOR;
        if (pdr >= GOOD_LINK_PDR)
            return GOOD_LINK_COLOR;
        else if (pdr > MEDIUM_LINK_PDR && pdr < GOOD_LINK_PDR)
            return MEDIUM_LINK_COLOR;
    }
}

function getMoteColor(board){
    if (board == null)
        board = "unknown"
    for (var color in board_colors){
        if (board_colors[color] === null){
            board_colors[color] = board;
            return color;
        }
        else if (board_colors[color] === board){
            return color
        }
    }
    // return default color if board_color is too small
    return "#FFF"
}

function updateMote(mac, lat, lng, board){
    var moteId  = null;
    var color   = getMoteColor(board)
    for (var i=0; i<motes.length; i++) {
        if (i in motes){
            if (motes[i].mac == mac){
                var content = mac + "
"
                if (board != null)
                  content += board + "
"
                if (motes[i].marker == null){
                    motes[i].marker = createMarker(lat, lng, content, color);
                } else if (motes[i].marker.position.lat() != lat ||
                            motes[i].marker.position.lng() != lng) {
                    motes[i].marker.setMap(null);
                    motes[i].marker = createMarker(lat, lng, content, color);
                }
            }
        }
    }
}

function createMarker(lat, lng, content, color){
    // create Markers
    var myLatLng = new google.maps.LatLng(lat, lng)
    var marker = new google.maps.Marker({
        position: myLatLng,
        map: map,
        icon: pinSymbol(color),
    });
    // add popup listener
    infoBox(map, marker, content);
    return marker;
}

function createPolyline(lineCoordinates, content, color){
    var line = new google.maps.Polyline({
          path: lineCoordinates,
          geodesic: true,
          strokeColor: color,
          strokeWeight: 2
    });
    if (color != UNKNOWN_LINK_COLOR){
        line.setMap(map);
        infoBox(map, line, content);
    }
    return line;
}

function getLink(LatLng1, LatLng2){
    for (i=0; i<links.length; i++) {
        var link = links[i].pline;
        var coord1 = "("+link.getPath().getAt(0).lat()+", "+link.getPath().getAt(0).lng()+")"
        var coord2 = "("+link.getPath().getAt(1).lat()+", "+link.getPath().getAt(1).lng()+")"
        if ( ((LatLng1.toString() == coord1) && (LatLng2.toString() == coord2)) ||
             ((LatLng2.toString() == coord1) && (LatLng1.toString() == coord2))
           ){
            return links[i]
        }
    }
    return null
}

function getMoteFromId(moteId){
    if (motes[moteId].marker != null)
        return motes[moteId].marker.position;
    else
        return null;
}

function getLocationFromId(moteId){
    if (motes[moteId].marker != null)
        return motes[moteId].marker.position;
    else
        return null;
}

function getLocationFromMac(mac){
    for( i=0; i<motes.length; i++ ) {
        if (i in motes && motes[i].mac == mac){
            return motes[i].marker.position;
        }
    }
    console.log("MAC not found:" + mac)
    return null;
}

// calculates distance between two points in meters
function calcDistance(p1, p2) {
    return (google.maps.geometry.spherical.computeDistanceBetween(p1, p2)).toFixed(2);
}

/*Function that shows a window with the content or info
 about the marker (sensor location)*/

function infoBox(map, marker, content) {
    infoWindow = new google.maps.InfoWindow();
    // Attaching a click event to the current marker
    google.maps.event.addListener(marker, "click", function(e) {
        infoWindow.setPosition(e.latLng);
        infoWindow.setContent(content);
        infoWindow.open(map, marker);
        var iw_container = $(".gm-style-iw").parent();
        iw_container.stop().hide();
        iw_container.fadeIn(300);
    });
}

// Function that create a vectorial image of a marker with the given color
function pinSymbol(color) {
    return {
        path: 'M 0,0 C -2,-20 -10,-22 -10,-30 A 10,10 0 1,1 10,-30 C 10,-22 2,-20 0,0 z M -2,-30 a 2,2 0 1,1 4,0 2,2 0 1,1 -4,0',
        fillColor: color,
        fillOpacity: 1,
        strokeColor: '#000',
        strokeWeight: 2,
        scale: 1,
   };
}
<|endoftext|>


<commit_before>

/* Controllers */
function MeetingListCtrl($scope, socket){
    'use strict';
    socket.global('meetings:update', function(meetings){
       $scope.meetings = meetings.meetings;
    });
    $scope.leave = function(){
        socket.emit('unsubscribe');
    };

    $scope.limit = 10;
}

function HomeCtrl($scope, $location, socket) {
    $scope.create = function(){
        $location.url('/meeting/'+$scope.meetingName);
    };
}

function TimerCtrl($scope, timer){
    'use strict';
    $scope.timer = timer;
    $scope.start = function(){
        timer.start();
    };
    $scope.stop = function(){
        timer.stop();
    };
}

function MeetingCtrl($scope, $routeParams, socket, $location, localStorageService) {
    'use strict';
    var meetingNameParam = $routeParams.meetingName || '',
      localStorageUserKey = meetingNameParam + ".user",
      localStorageUser = localStorageService.get(localStorageUserKey);

    socket.cleanup();

    $scope.signout = function(){
      console.log("Leaving meeting...");
      socket.emit('unsubscribe');
      $location.url('/');
    };

  if (!localStorageUser) {
    socket.emit('unsubscribe');
  }
  socket.emit('subscribe', {
      meetingName: meetingNameParam,
      userName: localStorageUser || ""
  });

  $scope.meeting = {phase: 'submit'};
	$scope.topicOrderPrimary = '-voters.length';
  $scope.topicOrderSub = '-topic.id';
	$scope.userTopic = new Topic();
	socket.on('init', function (data)
	{
        $scope.user = data.user;
        $scope.meeting = data.meeting;
        localStorageService.add(localStorageUserKey, data.user.name);
        $scope.meetingPhase = phaseMap[$scope.meeting.phase.name];
        if($scope.meeting.phase.name == 'discuss'){
          $scope.meeting.topics.some(function(topic){
            if(topic.current){
              $scope.currentTopic = topic;
              return true;
            }
          });
        }
	});

	socket.on('user:join', function(data){
		$scope.meeting.participants.push(data.user);
	});

	socket.on('topic:post', function(data){
		$scope.meeting.topics.push(data.topic);
  });

	socket.on('user:left', function(data){
    if($scope.meeting === undefined){return;}
		var userToRemove = data.user;
		var allUsers = $scope.meeting.participants;
        allUsers.forEach(function(user, index){
            if(userToRemove === user){
                allUsers.splice(index,1);
            }
        });

        $scope.meeting.topics.forEach(function(topic, index){
            if(topic.author == userToRemove){
                $scope.meeting.topics.splice(index, 1);
                return;
            }

            topic.voters.forEach(function(voter, index){
                if(voter == userToRemove){
                    topic.voters.splice(index, 1);
                }
            });
        });

	});

	socket.on('topic:vote', function(data){
		var allTopics = $scope.meeting.topics;
        allTopics.forEach(function(topic, index){
            if(topic.author == data.topic.author && topic.body === data.topic.body){
                allTopics[index] = data.topic;
            }
        });
    if ($scope.user.name === data.voter.name) {
      $scope.user.votesRemaining = data.voter.votesRemaining;
    }
	});

	$scope.sendTopic = function(){
    var topicToPost = new Topic($scope.user.name);
    topicToPost.body = $scope.userTopic.body;
		socket.emit('topic:post',{
			topic: topicToPost
		});
		$scope.userTopic = {};
	};

  socket.on('topic:downvote', function(data) {
    var allTopics = $scope.meeting.topics;
    allTopics.forEach(function(topic, index){
        if(topic.author == data.topic.author && topic.body === data.topic.body){
            allTopics[index] = data.topic;
            if (data.voter.name == $scope.user.name) {
              $scope.user.votesRemaining = data.voter.votesRemaining;
            }
            return;
        }
    });
  });

	$scope.vote = function(topic){
		socket.emit('topic:vote', {
			topic: topic,
			voter: $scope.user
		});
	};

  $scope.downvote = function(topic, index) {
    socket.emit('topic:downvote', {
      topic: topic,
      voter: $scope.user
    });
  };

  $scope.userVotedForThisTopic = function(topic, userName) {
    var userVotedForThisTopic = false;
    topic.voters.forEach(function(voter, user) {
      if (userName === voter.name) {
        userVotedForThisTopic = true;
      }
    });
    return userVotedForThisTopic;
  };

  $scope.calculateVotesRemainingForRoom = function() {
    var currentNumberOfVotesOnTopics = 0;
    var currentNumberOfUsersVotesAvailable = $scope.meeting.participants.length * 3;
    $scope.meeting.topics.forEach(function(topic) {
      if (topic.voters.length > 0) {
        currentNumberOfVotesOnTopics += topic.voters.length;
      }
    });
    return currentNumberOfUsersVotesAvailable - currentNumberOfVotesOnTopics;
  };

	function Topic(author){
		this.body = '';
		this.voters = [];
		this.author = author;
		this.votes = function(){
            return this.voters.length;
        };
	}

  var phaseMap = {
    submit: 'partials/submit.html',
    merge: 'partials/merge.html',
    voting: 'partials/voting.html',
    discuss: 'partials/discuss.html',
    complete: 'partials/email.html'
  };

  $scope.changePhase = function(){
    socket.emit('update:phase');
  };

  $scope.hasContinueVoted = function(){
    var currentTopic = $scope.currentTopic;
    if(!currentTopic) return false;
    var hasVoted = currentTopic.continue.concat(currentTopic.stop).some(function(vote){
      if(vote.user.name == $scope.user.name)
        return true;
    });
    return hasVoted;
  };

  socket.on('topic:continue', function(data){
    $scope.meeting.topics.some(function(topic, index){
      if(data.topic.id == topic.id && data.topic.id == $scope.currentTopic.id){
        $scope.meeting.topics[index] = data.topic;
        $scope.currentTopic = $scope.meeting.topics[index];
        return true;
      }
    });
  });

  socket.on('topic:current', function(data){
    $scope.meeting.topics.forEach(function(topic){
      if(topic.current) topic.current = false;
      if(topic.id == data.topic.id){
        topic.current = true;
        $scope.currentTopic = topic;
      }
    });
  });

  $scope.nextTopic = function(){
    socket.emit('topic:current');
  };

  $scope.continueVote = function(){
    socket.emit('topic:continue', {
      vote: 'continue'
    });
  };

  $scope.stopVote = function(){
    socket.emit('topic:continue', {
      vote: 'stop'
    });
  };

  socket.on('update:phase', function(data){
    $scope.meeting.phase = data.phase;
    $scope.meetingPhase = phaseMap[data.phase.name];
  });

  //Merge Functionality Starts
  $scope.topicSelected=[];
  $scope.newMergeText = {value:""};

  $scope.topicsSelectedToMerge= function(topic){
    var index= $scope.topicSelected.indexOf(topic);
    if(index==-1){
      $scope.topicSelected.push(topic);
    }else{
      $scope.topicSelected.splice(index, 1);
    }

    var text='';
    angular.forEach($scope.topicSelected, function(value){
     text += value.body+'\n';
    });
    $scope.newMergeText = {
      value:text.trim()
    };
  };

  $scope.mergeTopicsButtonClk = function(){
    var newMergeTopic = new Topic();
    var removedTopics = [];

    var authorArray=[];
    for (var i=0; i<$scope.topicSelected.length; i++) {
     for(var j=0; j<$scope.meeting.topics.length ; j++){
      if($scope.topicSelected[i].body == $scope.meeting.topics[j].body){

        if(authorArray.indexOf($scope.meeting.topics[j].author) == -1) {
         authorArray.push($scope.meeting.topics[j].author);
        }
        removedTopics.push($scope.meeting.topics[j]);
        $scope.meeting.topics.splice(j,1);
      }
      }
    }

   //thread safety issue. This would clobber other people's changes.
   socket.emit('remove:meeting:topics', removedTopics);

   newMergeTopic.body = $scope.newMergeText.value;
   newMergeTopic.author = authorArray.toString();

   socket.emit('topic:post',{
    topic: newMergeTopic
   });

  $scope.topicSelected =[];
  $scope.newMergeText = '';

 };

 socket.on('update:meeting:topics', function(data){
   $scope.meeting.topics=data;
  });

 $scope.cancelMerge = function(){
  //Uncheck all checked checkboxes
  var checkboxes = document.getElementsByName('mergeCheckBoxes');
  for(var i=0, n=checkboxes.length;i<n;i++) {
   checkboxes[i].checked = false;
  }
  $scope.topicSelected =[];
  $scope.newMergeText = '';
 };

  $scope.toggleSelected = function(topic) {
     topic.selected = !topic.selected;
  };
// End
  $scope.email= {
    to : ''
  };

$scope.sendEmail = function(){
    var emailBody='Hi\n';
    emailBody+='Topics:\n\n';

    for(var p=0;p<$scope.meeting.topics.length;p++){
      var topic = $scope.meeting.topics[p];
      emailBody+='Topic: ';
      emailBody+=topic.body+'\n';
      if(topic.notes){
        emailBody+='Notes: ';
        emailBody+=topic.notes+'\n\n';
      }

    }
    emailBody += '\nThanks';

    var link = "mailto:"+$scope.email.to+
             "?subject=Meeting%20Notes%20MeetingId:%20"+$scope.meeting.name+
             "&body="+escape(emailBody);
    window.location.href = link;
 };

}
<commit_msg>Removed references to socket.global and socket.cleanup from the controllers.<commit_after>

/* Controllers */
function MeetingListCtrl($scope, socket){
    'use strict';
    socket.on('meetings:update', function(meetings){
       $scope.meetings = meetings.meetings;
    });
    $scope.leave = function(){
        socket.emit('unsubscribe');
    };

    $scope.limit = 10;
}

function HomeCtrl($scope, $location, socket) {
    $scope.create = function(){
        $location.url('/meeting/'+$scope.meetingName);
    };
}

function TimerCtrl($scope, timer){
    'use strict';
    $scope.timer = timer;
    $scope.start = function(){
        timer.start();
    };
    $scope.stop = function(){
        timer.stop();
    };
}

function MeetingCtrl($scope, $routeParams, socket, $location, localStorageService) {
    'use strict';
    var meetingNameParam = $routeParams.meetingName || '',
      localStorageUserKey = meetingNameParam + ".user",
      localStorageUser = localStorageService.get(localStorageUserKey);

    $scope.signout = function(){
      socket.emit('unsubscribe');
      $location.url('/');
    };

  if (!localStorageUser) {
    socket.emit('unsubscribe');
  }
  socket.emit('subscribe', {
      meetingName: meetingNameParam,
      userName: localStorageUser || ""
  });

  $scope.meeting = {phase: 'submit'};
	$scope.topicOrderPrimary = '-voters.length';
  $scope.topicOrderSub = '-topic.id';
	$scope.userTopic = new Topic();
	socket.on('init', function (data)
	{
        $scope.user = data.user;
        $scope.meeting = data.meeting;
        localStorageService.add(localStorageUserKey, data.user.name);
        $scope.meetingPhase = phaseMap[$scope.meeting.phase.name];
        if($scope.meeting.phase.name == 'discuss'){
          $scope.meeting.topics.some(function(topic){
            if(topic.current){
              $scope.currentTopic = topic;
              return true;
            }
          });
        }
	});

	socket.on('user:join', function(data){
		$scope.meeting.participants.push(data.user);
	});

	socket.on('topic:post', function(data){
		$scope.meeting.topics.push(data.topic);
  });

	socket.on('user:left', function(data){
    if($scope.meeting === undefined){return;}
		var userToRemove = data.user;
		var allUsers = $scope.meeting.participants;
        allUsers.forEach(function(user, index){
            if(userToRemove === user){
                allUsers.splice(index,1);
            }
        });

        $scope.meeting.topics.forEach(function(topic, index){
            if(topic.author == userToRemove){
                $scope.meeting.topics.splice(index, 1);
                return;
            }

            topic.voters.forEach(function(voter, index){
                if(voter == userToRemove){
                    topic.voters.splice(index, 1);
                }
            });
        });

	});

	socket.on('topic:vote', function(data){
		var allTopics = $scope.meeting.topics;
        allTopics.forEach(function(topic, index){
            if(topic.author == data.topic.author && topic.body === data.topic.body){
                allTopics[index] = data.topic;
            }
        });
    if ($scope.user.name === data.voter.name) {
      $scope.user.votesRemaining = data.voter.votesRemaining;
    }
	});

	$scope.sendTopic = function(){
    var topicToPost = new Topic($scope.user.name);
    topicToPost.body = $scope.userTopic.body;
		socket.emit('topic:post',{
			topic: topicToPost
		});
		$scope.userTopic = {};
	};

  socket.on('topic:downvote', function(data) {
    var allTopics = $scope.meeting.topics;
    allTopics.forEach(function(topic, index){
        if(topic.author == data.topic.author && topic.body === data.topic.body){
            allTopics[index] = data.topic;
            if (data.voter.name == $scope.user.name) {
              $scope.user.votesRemaining = data.voter.votesRemaining;
            }
            return;
        }
    });
  });

	$scope.vote = function(topic){
		socket.emit('topic:vote', {
			topic: topic,
			voter: $scope.user
		});
	};

  $scope.downvote = function(topic, index) {
    socket.emit('topic:downvote', {
      topic: topic,
      voter: $scope.user
    });
  };

  $scope.userVotedForThisTopic = function(topic, userName) {
    var userVotedForThisTopic = false;
    topic.voters.forEach(function(voter, user) {
      if (userName === voter.name) {
        userVotedForThisTopic = true;
      }
    });
    return userVotedForThisTopic;
  };

  $scope.calculateVotesRemainingForRoom = function() {
    var currentNumberOfVotesOnTopics = 0;
    var currentNumberOfUsersVotesAvailable = $scope.meeting.participants.length * 3;
    $scope.meeting.topics.forEach(function(topic) {
      if (topic.voters.length > 0) {
        currentNumberOfVotesOnTopics += topic.voters.length;
      }
    });
    return currentNumberOfUsersVotesAvailable - currentNumberOfVotesOnTopics;
  };

	function Topic(author){
		this.body = '';
		this.voters = [];
		this.author = author;
		this.votes = function(){
            return this.voters.length;
        };
	}

  var phaseMap = {
    submit: 'partials/submit.html',
    merge: 'partials/merge.html',
    voting: 'partials/voting.html',
    discuss: 'partials/discuss.html',
    complete: 'partials/email.html'
  };

  $scope.changePhase = function(){
    socket.emit('update:phase');
  };

  $scope.hasContinueVoted = function(){
    var currentTopic = $scope.currentTopic;
    if(!currentTopic) return false;
    var hasVoted = currentTopic.continue.concat(currentTopic.stop).some(function(vote){
      if(vote.user.name == $scope.user.name)
        return true;
    });
    return hasVoted;
  };

  socket.on('topic:continue', function(data){
    $scope.meeting.topics.some(function(topic, index){
      if(data.topic.id == topic.id && data.topic.id == $scope.currentTopic.id){
        $scope.meeting.topics[index] = data.topic;
        $scope.currentTopic = $scope.meeting.topics[index];
        return true;
      }
    });
  });

  socket.on('topic:current', function(data){
    $scope.meeting.topics.forEach(function(topic){
      if(topic.current) topic.current = false;
      if(topic.id == data.topic.id){
        topic.current = true;
        $scope.currentTopic = topic;
      }
    });
  });

  $scope.nextTopic = function(){
    socket.emit('topic:current');
  };

  $scope.continueVote = function(){
    socket.emit('topic:continue', {
      vote: 'continue'
    });
  };

  $scope.stopVote = function(){
    socket.emit('topic:continue', {
      vote: 'stop'
    });
  };

  socket.on('update:phase', function(data){
    $scope.meeting.phase = data.phase;
    $scope.meetingPhase = phaseMap[data.phase.name];
  });

  //Merge Functionality Starts
  $scope.topicSelected=[];
  $scope.newMergeText = {value:""};

  $scope.topicsSelectedToMerge= function(topic){
    var index= $scope.topicSelected.indexOf(topic);
    if(index==-1){
      $scope.topicSelected.push(topic);
    }else{
      $scope.topicSelected.splice(index, 1);
    }

    var text='';
    angular.forEach($scope.topicSelected, function(value){
     text += value.body+'\n';
    });
    $scope.newMergeText = {
      value:text.trim()
    };
  };

  $scope.mergeTopicsButtonClk = function(){
    var newMergeTopic = new Topic();
    var removedTopics = [];

    var authorArray=[];
    for (var i=0; i<$scope.topicSelected.length; i++) {
     for(var j=0; j<$scope.meeting.topics.length ; j++){
      if($scope.topicSelected[i].body == $scope.meeting.topics[j].body){

        if(authorArray.indexOf($scope.meeting.topics[j].author) == -1) {
         authorArray.push($scope.meeting.topics[j].author);
        }
        removedTopics.push($scope.meeting.topics[j]);
        $scope.meeting.topics.splice(j,1);
      }
      }
    }

   //thread safety issue. This would clobber other people's changes.
   socket.emit('remove:meeting:topics', removedTopics);

   newMergeTopic.body = $scope.newMergeText.value;
   newMergeTopic.author = authorArray.toString();

   socket.emit('topic:post',{
    topic: newMergeTopic
   });

  $scope.topicSelected =[];
  $scope.newMergeText = '';

 };

 socket.on('update:meeting:topics', function(data){
   $scope.meeting.topics=data;
  });

 $scope.cancelMerge = function(){
  //Uncheck all checked checkboxes
  var checkboxes = document.getElementsByName('mergeCheckBoxes');
  for(var i=0, n=checkboxes.length;i<n;i++) {
   checkboxes[i].checked = false;
  }
  $scope.topicSelected =[];
  $scope.newMergeText = '';
 };

  $scope.toggleSelected = function(topic) {
     topic.selected = !topic.selected;
  };
// End
  $scope.email= {
    to : ''
  };

  $scope.sendEmail = function(){
      var emailBody='Hi\n';
      emailBody+='Topics:\n\n';

      for(var p=0;p<$scope.meeting.topics.length;p++){
        var topic = $scope.meeting.topics[p];
        emailBody+='Topic: ';
        emailBody+=topic.body+'\n';
        if(topic.notes){
          emailBody+='Notes: ';
          emailBody+=topic.notes+'\n\n';
        }

      }
      emailBody += '\nThanks';

      var link = "mailto:"+$scope.email.to+
               "?subject=Meeting%20Notes%20MeetingId:%20"+$scope.meeting.name+
               "&body="+escape(emailBody);
      window.location.href = link;
  };

}
<|endoftext|>


<commit_before>/* global angular, document, window, console, Promise */
'use strict';

var webresponseDirectives = angular.module('webresponseDirectives', []);

webresponseDirectives.directive('contenteditable', function() {
    return {
        restrict: "A",
        require: "?ngModel",
        link: function(scope, elem, attrs, ngModel) {
            if (!ngModel) {return;}

            var read = function() {
                ngModel.$setViewValue(elem.html());
            };

            ngModel.$render = function() {
                elem.html(ngModel.$viewValue || "");
            };

            elem.bind("blur keyup change", function() {
                scope.$apply(read);
            });
        }
    };
});

webresponseDirectives.directive('modal', function() {
    return {
        restrict: "E",
        scope: {
            "templateUrl": "@",
            "show": "=",
            "toHide": "="
        },
        template: "
\

\

",
        link: function($scope, elem, attrs) {}
    };
});

webresponseDirectives.directive('convoCard', function() {
    return {
        restrict: 'E',
        transclude: true,
        template: "

",
        link: function($scope, elem, attrs) {}
    };
});

webresponseDirectives.directive('cardHeader', function() {
    return {
        restrict: 'E',
        transclude: true,
        template: "

",
        link: function($scope, elem, attrs) {}
    };
});

webresponseDirectives.directive('cardHeaderInput', function() {
    return {
        restrict: 'E',
        scope: {
            'label': '@',
            'ngModel': '='
        },
        template: "
{{label}}

",
        link: function($scope, elem, attrs) {}
    };
});

webresponseDirectives.directive('cardBody', function() {
    return {
        restrict: 'E',
        transclude: true,
        template: "

",
        link: function($scope, elem, attrs) {}
    };
});

webresponseDirectives.directive('cardBodyInput', function() {
    return {
        restrict: 'E',
        scope: {
            'ngModel': '='
        },
        template: "

",
        link: function($scope, elem, attrs) {}
    };
});

webresponseDirectives.directive('cardFooter', function() {
    return {
        restrict: 'E',
        transclude: true,
        template: "

",
        link: function($scope, elem, attrs) {}
    };
});
<commit_msg>Stop directive from closing when clicked on body<commit_after>/* global angular, document, window, console, Promise */
'use strict';

var webresponseDirectives = angular.module('webresponseDirectives', []);

webresponseDirectives.directive('contenteditable', function() {
    return {
        restrict: "A",
        require: "?ngModel",
        link: function(scope, elem, attrs, ngModel) {
            if (!ngModel) {return;}

            var read = function() {
                ngModel.$setViewValue(elem.html());
            };

            ngModel.$render = function() {
                elem.html(ngModel.$viewValue || "");
            };

            elem.bind("blur keyup change", function() {
                scope.$apply(read);
            });
        }
    };
});

webresponseDirectives.directive('modal', function() {
    return {
        restrict: "E",
        scope: {
            "templateUrl": "@",
            "show": "=",
            "toHide": "="
        },
        template: "
\

\

",
        link: function($scope, elem, attrs) {}
    };
});

webresponseDirectives.directive('convoCard', function() {
    return {
        restrict: 'E',
        transclude: true,
        template: "

",
        link: function($scope, elem, attrs) {}
    };
});

webresponseDirectives.directive('cardHeader', function() {
    return {
        restrict: 'E',
        transclude: true,
        template: "

",
        link: function($scope, elem, attrs) {}
    };
});

webresponseDirectives.directive('cardHeaderInput', function() {
    return {
        restrict: 'E',
        scope: {
            'label': '@',
            'ngModel': '='
        },
        template: "
{{label}}

",
        link: function($scope, elem, attrs) {}
    };
});

webresponseDirectives.directive('cardBody', function() {
    return {
        restrict: 'E',
        transclude: true,
        template: "

",
        link: function($scope, elem, attrs) {}
    };
});

webresponseDirectives.directive('cardBodyInput', function() {
    return {
        restrict: 'E',
        scope: {
            'ngModel': '='
        },
        template: "

",
        link: function($scope, elem, attrs) {}
    };
});

webresponseDirectives.directive('cardFooter', function() {
    return {
        restrict: 'E',
        transclude: true,
        template: "

",
        link: function($scope, elem, attrs) {}
    };
});
<|endoftext|>


<commit_before>module.exports.command = "startup";
module.exports.run = function(remainder, parts, reply, command, from, to, text, raw) {

  var services = [
    'Pandora', 'Foursquare', 'Facebook', 'Netflix', 'Gmail', 'LinkedIn', 'NASA',
    'Eclipse', 'Spotify', 'Paypal', 'Twitter', 'AI', 'SB', 'GitHub', 'Google Glass',
    'Maps', 'Quora', 'Groupon', 'RSS', 'Redis', 'MapReduce', 'the iPhone',
    'Weedmaps', 'SnapChat', 'drones', 'WordPress', 'Napster', 'Tumblr', 'AirBnB',
    'cloud storage', 'a jQuery plugin', 'Reddit', 'Cash4Gold', 'Flickr', 'dongs',
    'Wikipedia', 'eHarmony', 'Amazon', 'Adult Friend Finder', 'EC2', 'S3',
    '4chan', 'Blogger', 'Pinterest', 'The PS3', 'The XBOX', 'Craigslist', 'XHamster',
    'CNN', 'A new Programming language', 'A Webbrowser', 'Ads', 'The Pirate Bay', 'Ebay',
    'Deviant Art', 'Mail order bombs', 'Crowdsourced retirement funding', 'Siri',
    'A personal assistant', 'Robot replacements', 'Fingerboxes', 'Concealed weaponry',
    'An iPhone app', 'Complaint management', 'Easy blogging', 'A pyramid scheme', 'Fleshlights',
    'Farmlogs', 'Red Nova Labs', 'Threat Stack', 'graduate school'
  ];
  var markets = [
    'finance', 'music', 'movies', 'pictures', 'gifs', 'pirated content', 'education',
    'hairstyling', 'red wine', 'literature', 'adult dancers', 'food', 'math',
    'hard engineering problems', 'botany', 'drugs', 'network administration',
    'shopping', 'cougars', 'MILFs', 'good looking people', 'the army', 'interns',
    'whiskey', 'retirement planning', 'beer', 'traveling', 'funerals', 'dongs',
    'presentations', 'online food delivery', 'the homeless', 'managing exes',
    'small businesses', 'coffee', 'textbooks', 'politics', 'your mom',
    'gay people', 'cats', 'dogs', 'Germans', 'Christians', 'Athiests',
    'redditors', 'guns', 'ladies', 'men', 'programmers', 'ninjas', 'pirates',
    'criminals', 'prisoners', 'autists', 'artists', 'emo teens', 'babies',
    'republicans', 'people like ek', 'Amazon employees', 'B movies', 'pornstars',
    'hipsters', 'barbarians', 'native americans', 'hackers', 'retired strippers',
    'people like reed', 'snipers', 'devoted Christians', 'atheists', 'cats',
    'the unemployed', 'the 1%', 'business purposes', 'amputees', 'panda lovers',
    'recipes', 'writers', 'dogs', 'birds', 'anime', 'the POTUS', 'sick horses',
    'girls that look like brigid', "people who can't read good", 'family photos'
  ];

  var startup_pitches = [
    '-service- for -market-',
    '-service- for -market-',
    '-service- for -market-',
    '-service- for -market-',
    '-service- for -market-', // yolo 50% x for y
    '-market- as a -service-',
    '-service- for -market-, but like -service-',
    '-service- for -market-, in the style of -service-',
    '-service- for -market-, marketed at -market-',
    '-service- to combine -market- with -market-',
    '-service- as a service'
  ];

  var pitch = startup_pitches[Math.floor(Math.random() * startup_pitches.length)];

  while (pitch.indexOf('-service-') > -1) {
  	var random_service = services[Math.floor(Math.random() * services.length)];
  	pitch = pitch.replace('-service-', random_service);
  }

  while (pitch.indexOf('-market-') > -1) {
  	var random_market = markets[Math.floor(Math.random() * markets.length)];
  	pitch = pitch.replace('-market-', random_market);
  }

  reply('Random startup idea: ' + pitch);
};

<commit_msg>Patent clause<commit_after>module.exports.command = "startup";
module.exports.run = function(remainder, parts, reply, command, from, to, text, raw) {

  var services = [
    'Pandora', 'Foursquare', 'Facebook', 'Netflix', 'Gmail', 'LinkedIn', 'NASA',
    'Eclipse', 'Spotify', 'Paypal', 'Twitter', 'AI', 'SB', 'GitHub', 'Google Glass',
    'Maps', 'Quora', 'Groupon', 'RSS', 'Redis', 'MapReduce', 'the iPhone',
    'Weedmaps', 'SnapChat', 'drones', 'WordPress', 'Napster', 'Tumblr', 'AirBnB',
    'cloud storage', 'a jQuery plugin', 'Reddit', 'Cash4Gold', 'Flickr', 'dongs',
    'Wikipedia', 'eHarmony', 'Amazon', 'Adult Friend Finder', 'EC2', 'S3',
    '4chan', 'Blogger', 'Pinterest', 'The PS3', 'The XBOX', 'Craigslist', 'XHamster',
    'CNN', 'A new Programming language', 'A Webbrowser', 'Ads', 'The Pirate Bay', 'Ebay',
    'Deviant Art', 'Mail order bombs', 'Crowdsourced retirement funding', 'Siri',
    'A personal assistant', 'Robot replacements', 'Fingerboxes', 'Concealed weaponry',
    'An iPhone app', 'Complaint management', 'Easy blogging', 'A pyramid scheme', 'Fleshlights',
    'Farmlogs', 'Red Nova Labs', 'Threat Stack', 'graduate school'
  ];
  var markets = [
    'finance', 'music', 'movies', 'pictures', 'gifs', 'pirated content', 'education',
    'hairstyling', 'red wine', 'literature', 'adult dancers', 'food', 'math',
    'hard engineering problems', 'botany', 'drugs', 'network administration',
    'shopping', 'cougars', 'MILFs', 'good looking people', 'the army', 'interns',
    'whiskey', 'retirement planning', 'beer', 'traveling', 'funerals', 'dongs',
    'presentations', 'online food delivery', 'the homeless', 'managing exes',
    'small businesses', 'coffee', 'textbooks', 'politics', 'your mom',
    'gay people', 'cats', 'dogs', 'Germans', 'Christians', 'Athiests',
    'redditors', 'guns', 'ladies', 'men', 'programmers', 'ninjas', 'pirates',
    'criminals', 'prisoners', 'autists', 'artists', 'emo teens', 'babies',
    'republicans', 'people like ek', 'Amazon employees', 'B movies', 'pornstars',
    'hipsters', 'barbarians', 'native americans', 'hackers', 'retired strippers',
    'people like reed', 'snipers', 'devoted Christians', 'atheists', 'cats',
    'the unemployed', 'the 1%', 'business purposes', 'amputees', 'panda lovers',
    'recipes', 'writers', 'dogs', 'birds', 'anime', 'the POTUS', 'sick horses',
    'girls that look like brigid', "people who can't read good", 'family photos'
  ];

  var startup_pitches = [
    '-service- for -market-',
    '-service- for -market-',
    '-service- for -market-',
    '-service- for -market-',
    '-service- for -market-', // yolo 50% x for y
    '-market- as a -service-',
    '-service- for -market-, but like -service-',
    '-service- for -market-, in the style of -service-',
    '-service- for -market-, marketed at -market-',
    '-service- to combine -market- with -market-',
    '-service- as a service',
    'a method for performing -service- using a computer'
  ];

  var pitch = startup_pitches[Math.floor(Math.random() * startup_pitches.length)];

  while (pitch.indexOf('-service-') > -1) {
  	var random_service = services[Math.floor(Math.random() * services.length)];
  	pitch = pitch.replace('-service-', random_service);
  }

  while (pitch.indexOf('-market-') > -1) {
  	var random_market = markets[Math.floor(Math.random() * markets.length)];
  	pitch = pitch.replace('-market-', random_market);
  }

  reply('Random startup idea: ' + pitch);
};

<|endoftext|>


<commit_before>"use strict";

var should = require('should');
var debug = require('debug')('OSMBC:routes:index');
var express = require('express');
var async = require('async');
var router = express.Router();
var help = require('../routes/help.js');
var config = require('../config.js');
var logModule = require('../model/logModule.js');
var userModule = require('../model/user.js');
var pgMap = require('../model/pgMap.js');

/* GET home page. */

function renderHome(req,res,next) {
  debug('renderHome');
  should.exist(res.rendervar.layout);
  var date = new Date();
  date.setTime(date.getTime()-1000*60*10);

  var todayStart = new Date();
  todayStart.setHours(0);
  todayStart.setMinutes(0);
  todayStart.setSeconds(0);

  async.auto({
    "historie":logModule.find.bind(logModule,{table:"IN('blog','article')"},{column:"id",desc :true,limit:20}),
    "activeUser":userModule.find.bind(userModule,{lastAccess:">"+date.toISOString()},{column:"lastAccess",desc :true}),
    "visitorsToday":userModule.find.bind(userModule,{lastAccess:">"+todayStart.toISOString()},{column:"OSMUser",desc :false}),
  },function(err,result) {
    if (err) return next(err);
    res.set('content-type', 'text/html');
    //console.log(res.get('content-type'));
    res.render('index', { title: config.getValue("AppName") ,
      layout:res.rendervar.layout,
      activeUserList:result.activeUser,
      visitorsToday:result.visitorsToday,
      changes:result.historie});
    }
  );
}

function renderAdminHome(req,res,next) {
  debug('renderAdminHome');
  should.exist(res.rendervar.layout);
  async.auto({
    "historie":logModule.find.bind(logModule,{table:"IN('usert','config')"},{column:"id",desc :true,limit:20})
    },function(err,result) {
      if (err) return next(err);
      res.set('content-type', 'text/html');
      res.render('adminindex', { title: config.getValue("AppName") ,
        layout:res.rendervar.layout,

        changes:result.historie});
    }
  );
}

function renderLongRunningQueries(req,res,next) {
  debug('renderLongRunningQueries');
  res.end(JSON.stringify(pgMap.longRunningQueries,null,3));
}

function languageSwitcher(req,res,next) {
  debug('languageSwitcher');
  var lang = req.user.getMainLang();
  var lang2 = req.user.getSecondLang();

  if (req.query.lang) lang = req.query.lang;
  if (req.query.lang2) lang2 = req.query.lang2;

  if (lang2 === lang) lang2 = "none";

  if (config.getLanguages().indexOf(lang)>=0) {
    req.user.mainLang = lang;
  }
  if (config.getLanguages().indexOf(lang2)>=0) {
    req.user.secondLang = lang2;
  }
  if (lang2==="none") {req.user.secondLang=null;}
  req.user.save(function finalLanguageSwitcher(err){
    if (err) return next(err);
    var referer = req.get('referer');
    if (referer) res.redirect(referer); else res.end("changed");
  });
}

function setUserConfig(req,res,next) {
  debug('setUserConfig');

  var user = req.user;
  if (!req.query.view) return next(new Error("missing view in option"));
  if (!req.query.option) return next(new Error("missing option in option"));
  if (!req.query.value) return next(new Error("missing value in option"));

  user.setOption(req.query.view,req.query.option,req.query.value);

  req.user.save(function finalLanguageSwitcher(err){
    if (err) return next(err);
    var referer = req.get('referer');
    if (referer) res.redirect(referer); else res.end("changed");
  });
}

function renderHelp(req,res) {
  debug('help');
  should.exist(res.rendervar.layout);
  var title = req.params.title;
  var text = help.getText("menu."+title+".md");
  res.set('content-type', 'text/html');
  res.render('help',{layout:res.rendervar.layout,text:text});
}
function createBlog(req,res) {
  debug('createBlog');
  should.exist(res.rendervar.layout);
  res.render('createblog',{layout:res.rendervar.layout});
}

function renderChangelog(req,res,next) {
  debug('renderChangelog');
  should.exist(res.rendervar.layout);
  var text = help.getText("CHANGELOG.md");
  req.user.lastChangeLogView = res.rendervar.layout.osmbc_version;
  req.user.save(function(err){
    if (err) return next(err);
    res.set('content-type', 'text/html');
    res.render('help',{layout:res.rendervar.layout,text:text});
  });
}

router.get('/', renderHome);
router.get('/osmbc.html', renderHome);
router.get('/osmbc', renderHome);
router.get('/sql/longRunningQueries',renderLongRunningQueries);
router.get('/osmbc/admin',renderAdminHome);
router.get('/help/:title', renderHelp);
router.get('/changelog', renderChangelog);
router.get('/language',languageSwitcher);
router.get('/userconfig',setUserConfig);
router.get('/createblog',createBlog);

module.exports.router = router;
module.exports.renderHome = renderHome;
<commit_msg>Route Change.<commit_after>"use strict";

var should = require('should');
var debug = require('debug')('OSMBC:routes:index');
var express = require('express');
var async = require('async');
var router = express.Router();
var help = require('../routes/help.js');
var config = require('../config.js');
var logModule = require('../model/logModule.js');
var userModule = require('../model/user.js');
var pgMap = require('../model/pgMap.js');

/* GET home page. */

function renderHome(req,res,next) {
  debug('renderHome');
  should.exist(res.rendervar.layout);
  var date = new Date();
  date.setTime(date.getTime()-1000*60*10);

  var todayStart = new Date();
  todayStart.setHours(0);
  todayStart.setMinutes(0);
  todayStart.setSeconds(0);

  async.auto({
    "historie":logModule.find.bind(logModule,{table:"IN('blog','article')"},{column:"id",desc :true,limit:20}),
    "activeUser":userModule.find.bind(userModule,{lastAccess:">"+date.toISOString()},{column:"lastAccess",desc :true}),
    "visitorsToday":userModule.find.bind(userModule,{lastAccess:">"+todayStart.toISOString()},{column:"OSMUser",desc :false}),
  },function(err,result) {
    if (err) return next(err);
    res.set('content-type', 'text/html');
    //console.log(res.get('content-type'));
    res.render('index', { title: config.getValue("AppName") ,
      layout:res.rendervar.layout,
      activeUserList:result.activeUser,
      visitorsToday:result.visitorsToday,
      changes:result.historie});
    }
  );
}

function renderAdminHome(req,res,next) {
  debug('renderAdminHome');
  should.exist(res.rendervar.layout);
  async.auto({
    "historie":logModule.find.bind(logModule,{table:"IN('usert','config')"},{column:"id",desc :true,limit:20})
    },function(err,result) {
      if (err) return next(err);
      res.set('content-type', 'text/html');
      res.render('adminindex', { title: config.getValue("AppName") ,
        layout:res.rendervar.layout,

        changes:result.historie});
    }
  );
}

function renderLongRunningQueries(req,res) {
  debug('renderLongRunningQueries');
  res.end(JSON.stringify(pgMap.longRunningQueries,null,3));
}

function languageSwitcher(req,res,next) {
  debug('languageSwitcher');
  var lang = req.user.getMainLang();
  var lang2 = req.user.getSecondLang();

  if (req.query.lang) lang = req.query.lang;
  if (req.query.lang2) lang2 = req.query.lang2;

  if (lang2 === lang) lang2 = "none";

  if (config.getLanguages().indexOf(lang)>=0) {
    req.user.mainLang = lang;
  }
  if (config.getLanguages().indexOf(lang2)>=0) {
    req.user.secondLang = lang2;
  }
  if (lang2==="none") {req.user.secondLang=null;}
  req.user.save(function finalLanguageSwitcher(err){
    if (err) return next(err);
    var referer = req.get('referer');
    if (referer) res.redirect(referer); else res.end("changed");
  });
}

function setUserConfig(req,res,next) {
  debug('setUserConfig');

  var user = req.user;
  if (!req.query.view) return next(new Error("missing view in option"));
  if (!req.query.option) return next(new Error("missing option in option"));
  if (!req.query.value) return next(new Error("missing value in option"));

  user.setOption(req.query.view,req.query.option,req.query.value);

  req.user.save(function finalLanguageSwitcher(err){
    if (err) return next(err);
    var referer = req.get('referer');
    if (referer) res.redirect(referer); else res.end("changed");
  });
}

function renderHelp(req,res) {
  debug('help');
  should.exist(res.rendervar.layout);
  var title = req.params.title;
  var text = help.getText("menu."+title+".md");
  res.set('content-type', 'text/html');
  res.render('help',{layout:res.rendervar.layout,text:text});
}
function createBlog(req,res) {
  debug('createBlog');
  should.exist(res.rendervar.layout);
  res.render('createblog',{layout:res.rendervar.layout});
}

function renderChangelog(req,res,next) {
  debug('renderChangelog');
  should.exist(res.rendervar.layout);
  var text = help.getText("CHANGELOG.md");
  req.user.lastChangeLogView = res.rendervar.layout.osmbc_version;
  req.user.save(function(err){
    if (err) return next(err);
    res.set('content-type', 'text/html');
    res.render('help',{layout:res.rendervar.layout,text:text});
  });
}

router.get('/', renderHome);
router.get('/osmbc.html', renderHome);
router.get('/osmbc', renderHome);
router.get('/osmbc/sql/longRunningQueries',renderLongRunningQueries);
router.get('/osmbc/admin',renderAdminHome);
router.get('/help/:title', renderHelp);
router.get('/changelog', renderChangelog);
router.get('/language',languageSwitcher);
router.get('/userconfig',setUserConfig);
router.get('/createblog',createBlog);

module.exports.router = router;
module.exports.renderHome = renderHome;
<|endoftext|>


<commit_before>var Config = function()
{
	return {
		// An easy flag to turn of logging completely
		devFlag:			false,
		// Number of ms to wait before the API cancels a call
		// Only applies to "cancellable" calls
		apiHangWait:		5000,
		apiCancelWait:		10000
	};
};<commit_msg>Removed redundant code<commit_after>var Config = function()
{
	return {
		// Number of ms to wait before the API cancels a call
		// Only applies to "cancellable" calls
		apiHangWait:		5000,
		apiCancelWait:		10000
	};
};<|endoftext|>


<commit_before>/*
 * patternlab-node https://github.com/pattern-lab/patternlab-node
 *
 * Brian Muenzenmeyer, Geoff Pursell, Raphael Okon, tburny and the web community.
 * Licensed under the MIT license.
 *
 * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice.
 *
 */

"use strict";

const packageInfo = require('../package.json');

const path = require('path');
const updateNotifier = require('update-notifier');

const logger = require('./lib/log');
const PatternGraph = require('./lib/pattern_graph').PatternGraph;
const CompileState = require('./lib/object_factory').CompileState;
const pa = require('./lib/pattern_assembler');
const pe = require('./lib/pattern_exporter');
const lh = require('./lib/lineage_hunter');

const defaultConfig = require('../patternlab-config.json');

let fs = require('fs-extra'); // eslint-disable-line
let ui_builder = require('./lib/ui_builder'); // eslint-disable-line
let assetCopier = require('./lib/asset_copy'); // eslint-disable-line
let pattern_exporter = new pe(); // eslint-disable-line
let serve = require('./lib/serve'); // eslint-disable-line

const pattern_assembler = new pa();
const lineage_hunter = new lh();

//bootstrap update notifier
updateNotifier({
  pkg: packageInfo,
  updateCheckInterval: 1000 * 60 * 60 * 24 // notify at most once a day
}).notify();

/**
 * Returns the standardized default config
 *
 * @return {object} Returns the object representation of the patternlab-config.json
 */
const getDefaultConfig = function () {
  return defaultConfig;
};

const patternlab_module = function (config) {
  const PatternLab = require('./lib/patternlab');
  const patternlab = new PatternLab(config);
  const paths = patternlab.config.paths;

  function help() {

    logger.info('');

    logger.info('Pattern Lab Node v' + patternlab.package.version);

    logger.info('');
    logger.info('Usage: patternlab.<FUNCTION_NAME>()');
    logger.info('');

    logger.info(' build');
    logger.info('   > builds patterns, copies assets, and constructs ui into config.paths.public');
    logger.info('');

    logger.info(' patternsonly');
    logger.info('   > builds patterns only, leaving existing public files intact');
    logger.info('');

    logger.info(' version');
    logger.info('   > logs current version');
    logger.info('');

    logger.info(' v');
    logger.info('   > return current version as a string');
    logger.info('');

    logger.info(' help');
    logger.info('   > logs more information about patternlab-node, pattern lab in general, and where to report issues.');
    logger.info('');

    logger.info(' liststarterkits');
    logger.info('   > fetches starterkit repos from pattern-lab github org that contain "starterkit" in their name');
    logger.info('');

    logger.info(' loadstarterkit');
    logger.info('   > loads starterkit already available via `node_modules/` into config.paths.source/*');
    logger.info('   > NOTE: Overwrites existing content, and only cleans out existing directory if --clean=true argument is passed.');
    logger.info('   > NOTE: In most cases, `npm install starterkit-name` will precede this call.');
    logger.info('   > parameters:');
    logger.info('      kit:string ');
    logger.info('      > the name of the starter kit to load');
    logger.info('      clean:bool ');
    logger.info('      > whether or not to remove all files from config.paths.source/ prior to load');
    logger.info('   > example:');
    logger.info('    `patternlab.loadstarterkit("starterkit-mustache-demo", true)');
    logger.info('');

    // installplugin
    // serve
    // getSupportedTemplateExtensions
    // events
    // getDefaultConfig

    logger.info('===============================');
    logger.info('');
    logger.info('Visit http://patternlab.io/ for more info about Pattern Lab');
    logger.info('Visit https://github.com/pattern-lab/patternlab-node/issues to open an issue.');
    logger.info('Visit https://github.com/pattern-lab/patternlab-node/wiki to view the changelog, roadmap, and other info.');
    logger.info('');
    logger.info('===============================');
  }

  /**
   * If a graph was serialized and then {@code deletePatternDir == true}, there is a mismatch in the
   * pattern metadata and not all patterns might be recompiled.
   * For that reason an empty graph is returned in this case, so every pattern will be flagged as
   * "needs recompile". Otherwise the pattern graph is loaded from the meta data.
   *
   * @param patternlab
   * @param {boolean} deletePatternDir When {@code true}, an empty graph is returned
   * @return {PatternGraph}
   */
  function loadPatternGraph(deletePatternDir) {
    // Sanity check to prevent problems when code is refactored
    if (deletePatternDir) {
      return PatternGraph.empty();
    }
    return PatternGraph.loadFromFile(patternlab);
  }

  function cleanBuildDirectory(incrementalBuildsEnabled) {
    if (incrementalBuildsEnabled) {
      logger.log.info("Incremental builds enabled.");
    } else {
      // needs to be done BEFORE processing patterns
      fs.removeSync(paths.public.patterns);
      fs.emptyDirSync(paths.public.patterns);
    }
  }

  function buildPatterns(deletePatternDir) {
    patternlab.events.emit('patternlab-build-pattern-start', patternlab);

    //
    // CHECK INCREMENTAL BUILD GRAPH
    //
    const graph = patternlab.graph = loadPatternGraph(deletePatternDir);
    const graphNeedsUpgrade = !PatternGraph.checkVersion(graph);
    if (graphNeedsUpgrade) {
      logger.log.info("Due to an upgrade, a complete rebuild is required and the public/patterns directory was deleted. " +
                       "Incremental build is available again on the next successful run.");

      // Ensure that the freshly built graph has the latest version again.
      patternlab.graph.upgradeVersion();
    }

    // Flags
    patternlab.incrementalBuildsEnabled = !(deletePatternDir || graphNeedsUpgrade);

    //
    // CLEAN BUILD DIRECTORY, maybe
    //
    cleanBuildDirectory(patternlab.incrementalBuildsEnabled);

    patternlab.buildGlobalData();

    // diveSync once to perform iterative populating of patternlab object
    return patternlab.processAllPatternsIterative(paths.source.patterns).then(() => {

      patternlab.events.emit('patternlab-pattern-iteration-end', patternlab);

      //now that all the main patterns are known, look for any links that might be within data and expand them
      //we need to do this before expanding patterns & partials into extendedTemplates, otherwise we could lose the data -> partial reference
      pattern_assembler.parse_data_links(patternlab);

      //diveSync again to recursively include partials, filling out the
      //extendedTemplate property of the patternlab.patterns elements
      // TODO we can reduce the time needed by only processing changed patterns and their partials
      patternlab.processAllPatternsRecursive(paths.source.patterns, patternlab);

      //take the user defined head and foot and process any data and patterns that apply
      // GTP: should these really be invoked from outside?
      patternlab.processHeadPattern();
      patternlab.processFootPattern();

      //cascade any patternStates
      lineage_hunter.cascade_pattern_states(patternlab);

      //set pattern-specific header if necessary
      let head;
      if (patternlab.userHead) {
        head = patternlab.userHead;
      } else {
        head = patternlab.header;
      }

      //set the pattern-specific header by compiling the general-header with data, and then adding it to the meta header
      patternlab.data.patternLabHead = pattern_assembler.renderPattern(patternlab.header, {
        cacheBuster: patternlab.cacheBuster
      });

      // If deletePatternDir == true or graph needs to be updated
      // rebuild all patterns
      let patternsToBuild = null;

      // If deletePatternDir == true or graph needs to be updated
      // rebuild all patterns
      patternsToBuild = null;

      if (patternlab.incrementalBuildsEnabled) {
        // When the graph was loaded from file, some patterns might have been moved/deleted between runs
        // so the graph data become out of sync
        patternlab.graph.sync().forEach(n => {
          logger.log.info("[Deleted/Moved] " + n);
        });

        // TODO Find created or deleted files
        const now = new Date().getTime();
        pattern_assembler.mark_modified_patterns(now, patternlab);
        patternsToBuild = patternlab.graph.compileOrder();
      } else {
        // build all patterns, mark all to be rebuilt
        patternsToBuild = patternlab.patterns;
        for (const p of patternsToBuild) {
          p.compileState = CompileState.NEEDS_REBUILD;
        }
      }

      //render all patterns last, so lineageR works
      return patternsToBuild
        .reduce((previousPromise, pattern) => {
          return previousPromise.then(() => patternlab.renderSinglePattern(pattern, head));
        }, Promise.resolve())
        .then(() => {
          // Saves the pattern graph when all files have been compiled
          PatternGraph.storeToFile(patternlab);
          if (patternlab.config.exportToGraphViz) {
            PatternGraph.exportToDot(patternlab, "dependencyGraph.dot");
            logger.log.info(`Exported pattern graph to ${path.join(config.paths.public.root, "dependencyGraph.dot")}`);
          }

          //export patterns if necessary
          pattern_exporter.export_patterns(patternlab);
        });
    }).catch((err) => {
      logger.info('Error in buildPatterns():', err);
    });
  }

  return {
    /**
     * logs current version
     *
     * @returns {void} current patternlab-node version as defined in package.json, as console output
     */
    version: function () {
      return patternlab.logVersion();
    },

    /**
     * return current version
     *
     * @returns {string} current patternlab-node version as defined in package.json, as string
     */
    v: function () {
      return patternlab.getVersion();
    },

    /**
     * build patterns, copy assets, and construct ui
     *
     * @param {object} options an object used to control build behavior
     * @returns {Promise} a promise fulfilled when build is complete
     */
    build: function (options) {
      if (patternlab && patternlab.isBusy) {
        logger.info('Pattern Lab is busy building a previous run - returning early.');
        return Promise.resolve();
      }
      patternlab.isBusy = true;
      return buildPatterns(options.cleanPublic).then(() => {

        new ui_builder().buildFrontend(patternlab);
        assetCopier().copyAssets(patternlab.config.paths, patternlab, options);

        this.events.on('patternlab-pattern-change', () => {
          if (!patternlab.isBusy) {
            options.cleanPublic = false;
            return this.build(options);
          }
          return Promise.resolve();
        });

        this.events.on('patternlab-global-change', () => {
          if (!patternlab.isBusy) {
            options.cleanPublic = true; //rebuild everything
            return this.build(options);
          }
          return Promise.resolve();
        });

        patternlab.isBusy = false;
      });
    },

    /**
     * logs usage
     *
     * @returns {void} pattern lab API usage, as console output
     */
    help: function () {
      help();
    },

    /**
     * build patterns only, leaving existing public files intact
     *
     * @param {object} options an object used to control build behavior
     * @returns {Promise} a promise fulfilled when build is complete
     */
    patternsonly: function (options) {
      if (patternlab && patternlab.isBusy) {
        logger.info('Pattern Lab is busy building a previous run - returning early.');
        return Promise.resolve();
      }
      patternlab.isBusy = true;
      return buildPatterns(options.cleanPublic).then(() => {
        patternlab.isBusy = false;
      });
    },

    /**
     * fetches starterkit repos from pattern-lab github org that contain 'starterkit' in their name
     *
     * @returns {Promise} Returns an Array<{name,url}> for the starterkit repos
     */
    liststarterkits: function () {
      return patternlab.listStarterkits();
    },

    /**
     * load starterkit already available via `node_modules/`
     *
     * @param {string} starterkitName name of starterkit
     * @param {boolean} clean whether or not to delete contents of source/ before load
     * @returns {void}
     */
    loadstarterkit: function (starterkitName, clean) {
      patternlab.loadStarterKit(starterkitName, clean);
    },

    /**
     * install plugin already available via `node_modules/`
     *
     * @param {string} pluginName name of plugin
     * @returns {void}
     */
    installplugin: function (pluginName) {
      patternlab.installPlugin(pluginName);
    },

    /**
     * returns all file extensions supported by installed PatternEngines
     *
     * @returns {Array<string>} all supported file extensions
     */
    getSupportedTemplateExtensions: function () {
      return patternlab.getSupportedTemplateExtensions();
    },

    /**
     * build patterns, copy assets, and construct ui, watch source files, and serve locally
     *
     * @param {object} options an object used to control build, copy, and serve behavior
     * @returns {Promise} TODO: validate
     */
    serve: function (options) {
      options.watch = true;
      return this.build(options).then(function () {
        serve(patternlab);
      });
    },

    events: patternlab.events
  };
};

patternlab_module.getDefaultConfig = getDefaultConfig;

module.exports = patternlab_module;
<commit_msg>chore(index): Alphabetize exported functions<commit_after>/*
 * patternlab-node https://github.com/pattern-lab/patternlab-node
 *
 * Brian Muenzenmeyer, Geoff Pursell, Raphael Okon, tburny and the web community.
 * Licensed under the MIT license.
 *
 * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice.
 *
 */

"use strict";

const packageInfo = require('../package.json');

const path = require('path');
const updateNotifier = require('update-notifier');

const logger = require('./lib/log');
const PatternGraph = require('./lib/pattern_graph').PatternGraph;
const CompileState = require('./lib/object_factory').CompileState;
const pa = require('./lib/pattern_assembler');
const pe = require('./lib/pattern_exporter');
const lh = require('./lib/lineage_hunter');

const defaultConfig = require('../patternlab-config.json');

let fs = require('fs-extra'); // eslint-disable-line
let ui_builder = require('./lib/ui_builder'); // eslint-disable-line
let assetCopier = require('./lib/asset_copy'); // eslint-disable-line
let pattern_exporter = new pe(); // eslint-disable-line
let serve = require('./lib/serve'); // eslint-disable-line

const pattern_assembler = new pa();
const lineage_hunter = new lh();

//bootstrap update notifier
updateNotifier({
  pkg: packageInfo,
  updateCheckInterval: 1000 * 60 * 60 * 24 // notify at most once a day
}).notify();

const getDefaultConfig = function () {
  return defaultConfig;
};

const patternlab_module = function (config) {
  const PatternLab = require('./lib/patternlab');
  const patternlab = new PatternLab(config);
  const paths = patternlab.config.paths;

  function help() {

    logger.info('');

    logger.info('Pattern Lab Node v' + patternlab.package.version);

    logger.info('');
    logger.info('Usage: patternlab.<FUNCTION_NAME>()');
    logger.info('');

    logger.info(' build');
    logger.info('   > builds patterns, copies assets, and constructs ui into config.paths.public');
    logger.info('');

    logger.info(' patternsonly');
    logger.info('   > builds patterns only, leaving existing public files intact');
    logger.info('');

    logger.info(' version');
    logger.info('   > logs current version');
    logger.info('');

    logger.info(' v');
    logger.info('   > return current version as a string');
    logger.info('');

    logger.info(' help');
    logger.info('   > logs more information about patternlab-node, pattern lab in general, and where to report issues.');
    logger.info('');

    logger.info(' liststarterkits');
    logger.info('   > fetches starterkit repos from pattern-lab github org that contain "starterkit" in their name');
    logger.info('');

    logger.info(' loadstarterkit');
    logger.info('   > loads starterkit already available via `node_modules/` into config.paths.source/*');
    logger.info('   > NOTE: Overwrites existing content, and only cleans out existing directory if --clean=true argument is passed.');
    logger.info('   > NOTE: In most cases, `npm install starterkit-name` will precede this call.');
    logger.info('   > parameters:');
    logger.info('      kit:string ');
    logger.info('      > the name of the starter kit to load');
    logger.info('      clean:bool ');
    logger.info('      > whether or not to remove all files from config.paths.source/ prior to load');
    logger.info('   > example:');
    logger.info('    `patternlab.loadstarterkit("starterkit-mustache-demo", true)');
    logger.info('');

    // installplugin
    // serve
    // getSupportedTemplateExtensions
    // events
    // getDefaultConfig

    logger.info('===============================');
    logger.info('');
    logger.info('Visit http://patternlab.io/ for more info about Pattern Lab');
    logger.info('Visit https://github.com/pattern-lab/patternlab-node/issues to open an issue.');
    logger.info('Visit https://github.com/pattern-lab/patternlab-node/wiki to view the changelog, roadmap, and other info.');
    logger.info('');
    logger.info('===============================');
  }

  /**
   * If a graph was serialized and then {@code deletePatternDir == true}, there is a mismatch in the
   * pattern metadata and not all patterns might be recompiled.
   * For that reason an empty graph is returned in this case, so every pattern will be flagged as
   * "needs recompile". Otherwise the pattern graph is loaded from the meta data.
   *
   * @param patternlab
   * @param {boolean} deletePatternDir When {@code true}, an empty graph is returned
   * @return {PatternGraph}
   */
  function loadPatternGraph(deletePatternDir) {
    // Sanity check to prevent problems when code is refactored
    if (deletePatternDir) {
      return PatternGraph.empty();
    }
    return PatternGraph.loadFromFile(patternlab);
  }

  function cleanBuildDirectory(incrementalBuildsEnabled) {
    if (incrementalBuildsEnabled) {
      logger.log.info("Incremental builds enabled.");
    } else {
      // needs to be done BEFORE processing patterns
      fs.removeSync(paths.public.patterns);
      fs.emptyDirSync(paths.public.patterns);
    }
  }

  function buildPatterns(deletePatternDir) {
    patternlab.events.emit('patternlab-build-pattern-start', patternlab);

    //
    // CHECK INCREMENTAL BUILD GRAPH
    //
    const graph = patternlab.graph = loadPatternGraph(deletePatternDir);
    const graphNeedsUpgrade = !PatternGraph.checkVersion(graph);
    if (graphNeedsUpgrade) {
      logger.log.info("Due to an upgrade, a complete rebuild is required and the public/patterns directory was deleted. " +
                       "Incremental build is available again on the next successful run.");

      // Ensure that the freshly built graph has the latest version again.
      patternlab.graph.upgradeVersion();
    }

    // Flags
    patternlab.incrementalBuildsEnabled = !(deletePatternDir || graphNeedsUpgrade);

    //
    // CLEAN BUILD DIRECTORY, maybe
    //
    cleanBuildDirectory(patternlab.incrementalBuildsEnabled);

    patternlab.buildGlobalData();

    // diveSync once to perform iterative populating of patternlab object
    return patternlab.processAllPatternsIterative(paths.source.patterns).then(() => {

      patternlab.events.emit('patternlab-pattern-iteration-end', patternlab);

      //now that all the main patterns are known, look for any links that might be within data and expand them
      //we need to do this before expanding patterns & partials into extendedTemplates, otherwise we could lose the data -> partial reference
      pattern_assembler.parse_data_links(patternlab);

      //diveSync again to recursively include partials, filling out the
      //extendedTemplate property of the patternlab.patterns elements
      // TODO we can reduce the time needed by only processing changed patterns and their partials
      patternlab.processAllPatternsRecursive(paths.source.patterns, patternlab);

      //take the user defined head and foot and process any data and patterns that apply
      // GTP: should these really be invoked from outside?
      patternlab.processHeadPattern();
      patternlab.processFootPattern();

      //cascade any patternStates
      lineage_hunter.cascade_pattern_states(patternlab);

      //set pattern-specific header if necessary
      let head;
      if (patternlab.userHead) {
        head = patternlab.userHead;
      } else {
        head = patternlab.header;
      }

      //set the pattern-specific header by compiling the general-header with data, and then adding it to the meta header
      patternlab.data.patternLabHead = pattern_assembler.renderPattern(patternlab.header, {
        cacheBuster: patternlab.cacheBuster
      });

      // If deletePatternDir == true or graph needs to be updated
      // rebuild all patterns
      let patternsToBuild = null;

      // If deletePatternDir == true or graph needs to be updated
      // rebuild all patterns
      patternsToBuild = null;

      if (patternlab.incrementalBuildsEnabled) {
        // When the graph was loaded from file, some patterns might have been moved/deleted between runs
        // so the graph data become out of sync
        patternlab.graph.sync().forEach(n => {
          logger.log.info("[Deleted/Moved] " + n);
        });

        // TODO Find created or deleted files
        const now = new Date().getTime();
        pattern_assembler.mark_modified_patterns(now, patternlab);
        patternsToBuild = patternlab.graph.compileOrder();
      } else {
        // build all patterns, mark all to be rebuilt
        patternsToBuild = patternlab.patterns;
        for (const p of patternsToBuild) {
          p.compileState = CompileState.NEEDS_REBUILD;
        }
      }

      //render all patterns last, so lineageR works
      return patternsToBuild
        .reduce((previousPromise, pattern) => {
          return previousPromise.then(() => patternlab.renderSinglePattern(pattern, head));
        }, Promise.resolve())
        .then(() => {
          // Saves the pattern graph when all files have been compiled
          PatternGraph.storeToFile(patternlab);
          if (patternlab.config.exportToGraphViz) {
            PatternGraph.exportToDot(patternlab, "dependencyGraph.dot");
            logger.log.info(`Exported pattern graph to ${path.join(config.paths.public.root, "dependencyGraph.dot")}`);
          }

          //export patterns if necessary
          pattern_exporter.export_patterns(patternlab);
        });
    }).catch((err) => {
      logger.info('Error in buildPatterns():', err);
    });
  }

  return {
    /**
     * build patterns, copy assets, and construct ui
     *
     * @param {object} options an object used to control build behavior
     * @returns {Promise} a promise fulfilled when build is complete
     */
    build: function (options) {
      if (patternlab && patternlab.isBusy) {
        logger.info('Pattern Lab is busy building a previous run - returning early.');
        return Promise.resolve();
      }
      patternlab.isBusy = true;
      return buildPatterns(options.cleanPublic).then(() => {

        new ui_builder().buildFrontend(patternlab);
        assetCopier().copyAssets(patternlab.config.paths, patternlab, options);

        this.events.on('patternlab-pattern-change', () => {
          if (!patternlab.isBusy) {
            options.cleanPublic = false;
            return this.build(options);
          }
          return Promise.resolve();
        });

        this.events.on('patternlab-global-change', () => {
          if (!patternlab.isBusy) {
            options.cleanPublic = true; //rebuild everything
            return this.build(options);
          }
          return Promise.resolve();
        });

        patternlab.isBusy = false;
      });
    },

    /**
     * Returns the standardized default config
     *
     * @return {object} Returns the object representation of the patternlab-config.json
     */
    getDefaultConfig: function () {
      return getDefaultConfig();
    },

    /**
     * returns all file extensions supported by installed PatternEngines
     *
     * @returns {Array<string>} all supported file extensions
     */
    getSupportedTemplateExtensions: function () {
      return patternlab.getSupportedTemplateExtensions();
    },

    /**
     * logs usage
     *
     * @returns {void} pattern lab API usage, as console output
     */
    help: function () {
      help();
    },

    /**
     * install plugin already available via `node_modules/`
     *
     * @param {string} pluginName name of plugin
     * @returns {void}
     */
    installplugin: function (pluginName) {
      patternlab.installPlugin(pluginName);
    },

    /**
     * fetches starterkit repos from pattern-lab github org that contain 'starterkit' in their name
     *
     * @returns {Promise} Returns an Array<{name,url}> for the starterkit repos
     */
    liststarterkits: function () {
      return patternlab.listStarterkits();
    },

    /**
     * load starterkit already available via `node_modules/`
     *
     * @param {string} starterkitName name of starterkit
     * @param {boolean} clean whether or not to delete contents of source/ before load
     * @returns {void}
     */
    loadstarterkit: function (starterkitName, clean) {
      patternlab.loadStarterKit(starterkitName, clean);
    },

    /**
     * return current version
     *
     * @returns {string} current patternlab-node version as defined in package.json, as string
     */
    v: function () {
      return patternlab.getVersion();
    },

    /**
     * logs current version
     *
     * @returns {void} current patternlab-node version as defined in package.json, as console output
     */
    version: function () {
      return patternlab.logVersion();
    },

    /**
     * build patterns only, leaving existing public files intact
     *
     * @param {object} options an object used to control build behavior
     * @returns {Promise} a promise fulfilled when build is complete
     */
    patternsonly: function (options) {
      if (patternlab && patternlab.isBusy) {
        logger.info('Pattern Lab is busy building a previous run - returning early.');
        return Promise.resolve();
      }
      patternlab.isBusy = true;
      return buildPatterns(options.cleanPublic).then(() => {
        patternlab.isBusy = false;
      });
    },

    /**
     * build patterns, copy assets, and construct ui, watch source files, and serve locally
     *
     * @param {object} options an object used to control build, copy, and serve behavior
     * @returns {Promise} TODO: validate
     */
    serve: function (options) {
      options.watch = true;
      return this.build(options).then(function () {
        serve(patternlab);
      });
    },

    events: patternlab.events
  };
};

patternlab_module.getDefaultConfig = getDefaultConfig;

module.exports = patternlab_module;
<|endoftext|>


<commit_before>
/*
 * GET home page.
 */

exports.index = function(req, res){
  res.render('index', { title: 'Todo App|Express + MongoDB' });
};<commit_msg>check token<commit_after>
/*
 * GET home page.
 */

exports.index = function(req, res){
  if(req.query.token!=='pivotal'){
    res.send("Please provide token to access!");
    return;
  }
  res.render('index', { title: 'Todo App|Express + MongoDB' });
};<|endoftext|>