<commit_before>var fs = require('fs');

var express = require('express');
var app = express();
app.use(express.static('public'));

// var formidable = require('express-formidable');
// app.use(formidable());
// What was this used for in the node girls express workshop?

// var view = require(__dirname + '/views/view.js');

app.get('/', function (request, response) {
  // response.sendFile(__dirname + '/public/index.html'); // Redundant code
});

app.get('/testing', function (request, response) {
  response.sendFile(__dirname + '/public/wrapper.html');
});

app.get('/about', function (request, response) {
  response.sendFile(__dirname + '/public/about.html');
});

app.get('/skills', function (request, response) {
  response.sendFile(__dirname + '/public/skills.html');
});

app.get('/portfolio', function (request, response) {
  response.sendFile(__dirname + '/public/portfolio.html');
});

app.get('/contact', function (request, response) {
  response.sendFile(__dirname + '/public/contact.html');
});

app.listen(5500, function() {
  console.log('Server is listening on port 5500. Ready to accept requests!')
});
<commit_msg>Updating server.js<commit_after>var fs = require('fs');

var express = require('express');
var app = express();
app.use(express.static('public'));

var port = process.env.PORT || 5500;

// var formidable = require('express-formidable');
// app.use(formidable());
// What was this used for in the node girls express workshop?

// var view = require(__dirname + '/views/view.js');

app.get('/', function (request, response) {
  // response.sendFile(__dirname + '/public/index.html'); // Redundant code
});

app.get('/testing', function (request, response) {
  response.sendFile(__dirname + '/public/wrapper.html');
});

app.get('/about', function (request, response) {
  response.sendFile(__dirname + '/public/about.html');
});

app.get('/skills', function (request, response) {
  response.sendFile(__dirname + '/public/skills.html');
});

app.get('/portfolio', function (request, response) {
  response.sendFile(__dirname + '/public/portfolio.html');
});

app.get('/contact', function (request, response) {
  response.sendFile(__dirname + '/public/contact.html');
});

app.listen(5500, function() {
  console.log('Server is listening on port 5500. Ready to accept requests!')
});
<|endoftext|>


<commit_before>/**
 * PROJECT: jsTreeNodePicker
 * Version: 0.2
 * Note:    Recommended for Bootstrap >=3, JQuery >=1.11.3, JQuery UI >=1.11.4, tagit >=2.0, jsTree >=3.2.1
 * AUTHOR:  (Jason Steve Nguyen) Hau Nguyen Viet
 * Email:   nvconghau1995@gmail.com
 * (c) 2016 Hau Nguyen Viet.
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

(function( $ ) {

    $.fn.jsTreeNodePicker = function(options ) {

        var opts = $.extend( {}, $.fn.jsTreeNodePicker.defaults, options);
        var modalSelector;
        var btnOpen;
        var treeControl;
        var tagitControl;
        var errorMessageContainer;

        var pickerObj = this.each(function() {
            modalSelector = $("#"+opts.dialogId);

            // Append open picker dialog button
            var btnOpenContainer = $('

');
            $(this).append(btnOpenContainer);
            btnOpen = $('<button id="btnOpen'+opts.dialogId+'" type="button" class="btn btn-default" '
                + ' data-toggle="modal" data-target="#'+opts.dialogId+'"> </button>');

            btnOpenContainer.append(btnOpen);

            var modalBody = modalSelector.children(".modal-dialog").children(".modal-content").children(".modal-body");

            // Add place to show error message
            errorMessageContainer = $('

');
            modalBody.append(errorMessageContainer);

            var treeControlId = opts.dialogId + "_treeControl";
            var treeControlContainer = $('

');
            modalBody.append(treeControlContainer);
            treeControl = $('

');

            treeControlContainer.append(treeControl);

            treeControl.jstree({
                'core' : {
                    'data' : opts.data
                },
                "checkbox" : opts.jstreeOptions.checkbox,
                "plugins" : opts.jstreeOptions.plugins
            });

            treeControl.bind("loaded.jstree", function (event, data) {
                if (opts.expandAllNodes === true) {
                    $(this).jstree("open_all");
                } else {
                    $(this).jstree("close_all");
                }

            });

            // Append tagit control
            var tagitControlContainer = $('

');
            $(this).append(tagitControlContainer);

            tagitControl = $('

');
            tagitControlContainer.append(tagitControl);
            tagitControl.tagit({
                fieldName: opts.tagitOptions.fieldName,
                allowSpaces: opts.tagitOptions.allowSpaces,
                tagLimit: opts.tagLimit,
                showAutocompleteOnFocus:  opts.tagitOptions.showAutocompleteOnFocus,
                readOnly: opts.tagitOptions.readOnly
            });

            if (opts.selectedNodes.length > 0) {
                tagitControl.tagit("removeAll");
                for (x in opts.selectedNodes) {
                    tagitControl.tagit('createTag', opts.selectedNodes[x]);

                }
            }

        });

        pickerObj.modalSelector = modalSelector;
        pickerObj.btnOpen = btnOpen;
        pickerObj.treeControl = treeControl;
        pickerObj.tagitControl = tagitControl;
        pickerObj.errorMessageContainer = errorMessageContainer;

        pickerObj.opts = $.extend({}, opts);

        pickerObj.btnClearAll = pickerObj.modalSelector.children(".modal-dialog").children(".modal-content")
                                .children(".modal-footer").children(".btnTreeNodePickerClearAll");

        pickerObj.btnOK = pickerObj.modalSelector.children(".modal-dialog").children(".modal-content")
                                        .children(".modal-footer").children(".btnTreeNodePickerOK");
        pickerObj.btnCancel = pickerObj.modalSelector.children(".modal-dialog").children(".modal-content")
                                                .children(".modal-footer").children(".btnTreeNodePickerCancel");

        pickerObj.dialogTitle = pickerObj.modalSelector.children(".modal-dialog").children(".modal-content")
                                                .children(".modal-header").children(".modal-title");

        pickerObj.btnClearAll.text(pickerObj.opts.labels.buttons.btn_clear_all);
        pickerObj.btnOK.text(pickerObj.opts.labels.buttons.btn_ok);
        pickerObj.btnCancel.text(pickerObj.opts.labels.buttons.btn_cancel);
        pickerObj.btnCancel.text(pickerObj.opts.labels.buttons.btn_cancel);
        pickerObj.btnOpen.text(pickerObj.opts.labels.buttons.btn_open);
        pickerObj.dialogTitle.text(pickerObj.opts.labels.text.label_title);

        pickerObj.btnClearAll.click(function() {
             pickerObj.treeControl.jstree("deselect_all");
        });

        pickerObj.btnOK.click(function(){

            var selectedNodes = pickerObj.treeControl.jstree("get_selected");
            if (selectedNodes.length > pickerObj.opts.tagLimit) {
                return false;
            }
            pickerObj.tagitControl.tagit("removeAll");
            for (x in selectedNodes) {
                pickerObj.tagitControl.tagit('createTag', selectedNodes[x]);

            }

            $("#"+ pickerObj.opts.dialogId).modal("toggle");
            pickerObj.opts.selectedNodes = selectedNodes;
        });

        pickerObj.btnOpen.click(function () {
            pickerObj.treeControl.jstree(true).deselect_all();
            for (x in pickerObj.opts.selectedNodes) {
                treeControl.jstree(true).select_node(pickerObj.opts.selectedNodes[x]);
            }
        });

        pickerObj.treeControl.on("changed.jstree", function (e, data) {
            if (data.selected.length > pickerObj.opts.tagLimit) {
                pickerObj.errorMessageContainer.text(pickerObj.opts.errMessages.err_you_can_not_pick_more_than
                    + ' ' + pickerObj.opts.tagLimit + ' ' + pickerObj.opts.labels.text.label_node);
                pickerObj.errorMessageContainer.show();
            } else {
                pickerObj.errorMessageContainer.hide();
            }

        });

        return pickerObj;

    }

    $.fn.jsTreeNodePicker.defaults = {
        "dialogId": "pickerDlg",
        "tagLimit": 5,
        "expandAllNodes": true,
        "data": [],
        "selectedNodes": [],
        "tagitOptions": {
            "fieldName": "tagList",
            "allowSpaces": true,
            "showAutocompleteOnFocus": false,
            "readOnly": true
        },
        "jstreeOptions": {
            "checkbox" : {
                "keep_selected_style" : false,
                "three_state": false
            },
            "plugins" : [ "checkbox" ]
        },
        "labels": {
            "buttons": {
                "btn_ok": "OK",
                "btn_cancel": "Cancel",
                "btn_clear_all": "Clear All",
                "btn_open": "Click here to choose nodes"
            },
            "text": {
                "label_title": "Choose nodes",
                "label_node": "node"
            }

        },
        "errMessages": {
            "err_you_can_not_pick_more_than": "You cannot pick more than"
        }
    };

}( jQuery ));<commit_msg>add size options<commit_after>/**
 * PROJECT: jsTreeNodePicker
 * Version: 0.2
 * Note:    Recommended for Bootstrap >=3, JQuery >=1.11.3, JQuery UI >=1.11.4, tagit >=2.0, jsTree >=3.2.1
 * AUTHOR:  (Jason Steve Nguyen) Hau Nguyen Viet
 * Email:   nvconghau1995@gmail.com
 * (c) 2016 Hau Nguyen Viet.
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

(function( $ ) {

    $.fn.jsTreeNodePicker = function(options ) {

        var opts = $.extend( {}, $.fn.jsTreeNodePicker.defaults, options);
        var modalSelector;
        var btnOpen;
        var treeControl;
        var tagitControl;
        var errorMessageContainer;

        var pickerObj = this.each(function() {
            modalSelector = $("#"+opts.dialogId);

            // Append open picker dialog button
            var btnOpenContainer = $('

');
            $(this).append(btnOpenContainer);
            btnOpen = $('<button id="btnOpen'+opts.dialogId+'" type="button" class="btn btn-default" '
                + ' data-toggle="modal" data-target="#'+opts.dialogId+'"> </button>');

            btnOpenContainer.append(btnOpen);

            var modalBody = modalSelector.children(".modal-dialog").children(".modal-content").children(".modal-body");
            modalBody.css(opts.sizeCSS);

            // Add place to show error message
            errorMessageContainer = $('

');
            modalBody.append(errorMessageContainer);

            var treeControlId = opts.dialogId + "_treeControl";
            var treeControlContainer = $('

');
            modalBody.append(treeControlContainer);
            treeControl = $('

');

            treeControlContainer.append(treeControl);

            treeControl.jstree({
                'core' : {
                    'data' : opts.data
                },
                "checkbox" : opts.jstreeOptions.checkbox,
                "plugins" : opts.jstreeOptions.plugins
            });

            treeControl.bind("loaded.jstree", function (event, data) {
                if (opts.expandAllNodes === true) {
                    $(this).jstree("open_all");
                } else {
                    $(this).jstree("close_all");
                }

            });

            // Append tagit control
            var tagitControlContainer = $('

');
            $(this).append(tagitControlContainer);

            tagitControl = $('

');
            tagitControlContainer.append(tagitControl);
            tagitControl.tagit({
                fieldName: opts.tagitOptions.fieldName,
                allowSpaces: opts.tagitOptions.allowSpaces,
                tagLimit: opts.tagLimit,
                showAutocompleteOnFocus:  opts.tagitOptions.showAutocompleteOnFocus,
                readOnly: opts.tagitOptions.readOnly
            });

            if (opts.selectedNodes.length > 0) {
                tagitControl.tagit("removeAll");
                for (x in opts.selectedNodes) {
                    tagitControl.tagit('createTag', opts.selectedNodes[x]);

                }
            }

        });

        pickerObj.modalSelector = modalSelector;
        pickerObj.btnOpen = btnOpen;
        pickerObj.treeControl = treeControl;
        pickerObj.tagitControl = tagitControl;
        pickerObj.errorMessageContainer = errorMessageContainer;

        pickerObj.opts = $.extend({}, opts);

        pickerObj.btnClearAll = pickerObj.modalSelector.children(".modal-dialog").children(".modal-content")
                                .children(".modal-footer").children(".btnTreeNodePickerClearAll");

        pickerObj.btnOK = pickerObj.modalSelector.children(".modal-dialog").children(".modal-content")
                                        .children(".modal-footer").children(".btnTreeNodePickerOK");
        pickerObj.btnCancel = pickerObj.modalSelector.children(".modal-dialog").children(".modal-content")
                                                .children(".modal-footer").children(".btnTreeNodePickerCancel");

        pickerObj.dialogTitle = pickerObj.modalSelector.children(".modal-dialog").children(".modal-content")
                                                .children(".modal-header").children(".modal-title");

        pickerObj.btnClearAll.text(pickerObj.opts.labels.buttons.btn_clear_all);
        pickerObj.btnOK.text(pickerObj.opts.labels.buttons.btn_ok);
        pickerObj.btnCancel.text(pickerObj.opts.labels.buttons.btn_cancel);
        pickerObj.btnCancel.text(pickerObj.opts.labels.buttons.btn_cancel);
        pickerObj.btnOpen.text(pickerObj.opts.labels.buttons.btn_open);
        pickerObj.dialogTitle.text(pickerObj.opts.labels.text.label_title);

        pickerObj.btnClearAll.click(function() {
             pickerObj.treeControl.jstree("deselect_all");
        });

        pickerObj.btnOK.click(function(){

            var selectedNodes = pickerObj.treeControl.jstree("get_selected");
            if (selectedNodes.length > pickerObj.opts.tagLimit) {
                return false;
            }
            pickerObj.tagitControl.tagit("removeAll");
            for (x in selectedNodes) {
                pickerObj.tagitControl.tagit('createTag', selectedNodes[x]);

            }

            $("#dlgPickCategories").modal("toggle");
            pickerObj.opts.selectedNodes = selectedNodes;
        });

        pickerObj.btnOpen.click(function () {
            pickerObj.treeControl.jstree(true).deselect_all();
            for (x in pickerObj.opts.selectedNodes) {
                treeControl.jstree(true).select_node(pickerObj.opts.selectedNodes[x]);
            }
        });

        pickerObj.treeControl.on("changed.jstree", function (e, data) {
            if (data.selected.length > pickerObj.opts.tagLimit) {
                pickerObj.errorMessageContainer.text(pickerObj.opts.errMessages.err_you_can_not_pick_more_than
                    + ' ' + pickerObj.opts.tagLimit + ' ' + pickerObj.opts.labels.text.label_node);
                pickerObj.errorMessageContainer.show();
            } else {
                pickerObj.errorMessageContainer.hide();
            }

        });

        if (pickerObj.opts.expandChildOnSingleClick === true) {
            pickerObj.treeControl.on("select_node.jstree", function (e, data) { data.instance.toggle_node(data.node); });
            /* pickerObj.treeControl.on("click",function (e) {
              var li = $(e.target).closest("li");
              var node =  pickerObj.treeControl.jstree(true).get_node(li[0].id);

              console.log(node.state.opened);

               if(node.state.opened == true) {
                    pickerObj.treeControl.jstree(true).close_node(node);
                    node.state.opened = false;
               } else {
                    pickerObj.treeControl.jstree(true).open_node(node);
                    node.state.opened = true;
               }
            });*/
        }

        return pickerObj;

    }

    $.fn.jsTreeNodePicker.defaults = {
        "sizeCSS": {
            "min-height": "300px",
            "max-height": "300px",
            "height": "300px",
            "min-width": "600px",
            "max-width": "600px",
            "width": "600px",
        },
        "dialogId": "pickerDlg",
        "expandChildOnSingleClick": true,
        "tagLimit": 5,
        "expandAllNodes": true,
        "data": [],
        "selectedNodes": [],
        "tagitOptions": {
            "fieldName": "tagList",
            "allowSpaces": true,
            "showAutocompleteOnFocus": false,
            "readOnly": true
        },
        "jstreeOptions": {
            "checkbox" : {
                "keep_selected_style" : false,
                "three_state": false
            },
            "plugins" : [ "checkbox" ]
        },
        "labels": {
            "buttons": {
                "btn_ok": "OK",
                "btn_cancel": "Cancel",
                "btn_clear_all": "Clear All",
                "btn_open": "Click here to choose nodes"
            },
            "text": {
                "label_title": "Choose nodes",
                "label_node": "node"
            }

        },
        "errMessages": {
            "err_you_can_not_pick_more_than": "You cannot pick more than"
        }
    };

}( jQuery ));<|endoftext|>


<commit_before>const db = require('./db')
const migrateTools = require('./migrate-tools')

exports.up = function (next) {
  return migrateTools.migrateNames()
  .then(updateSql => {
    const sql = [
      'alter table devices add column name text',
      updateSql,
      'alter table devices alter column name set not null'
    ]

    return db.multi(sql, next)
  })
}

exports.down = function (next) {
  const sql = ['alter table devices drop column name']
  db.multi(sql, next)
}
<commit_msg>don't fail on fresh install<commit_after>const db = require('./db')
const migrateTools = require('./migrate-tools')

exports.up = function (next) {
  return migrateTools.migrateNames()
  .then(updateSql => {
    const sql = [
      'alter table devices add column name text',
      updateSql,
      'alter table devices alter column name set not null'
    ]

    return db.multi(sql, next)
  })
  .catch(() => {
    const sql = [
      'alter table devices add column name text',
      'alter table devices alter column name set not null'
    ]

    return db.multi(sql, next)
  })
}

exports.down = function (next) {
  const sql = ['alter table devices drop column name']
  db.multi(sql, next)
}
<|endoftext|>


<commit_before>'use strict'

const express = require('express')
const Slapp = require('slapp')
const ConvoStore = require('slapp-convo-beepboop')
const Context = require('slapp-context-beepboop')

// use `PORT` env var on Beep Boop - default to 3000 locally
var port = process.env.PORT || 3000

var slapp = Slapp({
  // Beep Boop sets the SLACK_VERIFY_TOKEN env var
  verify_token: process.env.SLACK_VERIFY_TOKEN,
  convo_store: ConvoStore(),
  context: Context()
})

var HELP_TEXT = `
I will respond to the following messages:
\`help\` - to see this message.
\`hi\` - to demonstrate a conversation that tracks state.
\`thanks\` - to demonstrate a simple response.
\`<type-any-other-text>\` - to demonstrate a random emoticon response, some of the time :wink:.
\`attachment\` - to see a Slack attachment message.
`

//*********************************************
// Setup different handlers for messages
//*********************************************

// response to the user typing "help"
slapp.message('help', ['mention', 'direct_message'], (msg) => {
  msg.say(HELP_TEXT)
})

// "Conversation" flow that tracks state - kicks off when user says hi, hello or hey
slapp
  .message('^(hi|hello|hey)$', ['direct_mention', 'direct_message'], (msg, text) => {
    msg
      .say(`${text}, how are you?`)
      // sends next event from user to this route, passing along state
      .route('how-are-you', { greeting: text })
  })
  .route('how-are-you', (msg, state) => {
    var text = (msg.body.event && msg.body.event.text) || ''

    // user may not have typed text as their next action, ask again and re-route
    if (!text) {
      return msg
        .say("Whoops, I'm still waiting to hear how you're doing.")
        .say('How are you?')
        .route('how-are-you', state)
    }

    // add their response to state
    state.status = text

    msg
      .say(`Ok then. What's your favorite color?`)
      .route('color', state)
  })
  .route('color', (msg, state) => {
    var text = (msg.body.event && msg.body.event.text) || ''

    // user may not have typed text as their next action, ask again and re-route
    if (!text) {
      return msg
        .say("I'm eagerly awaiting to hear your favorite color.")
        .route('color', state)
    }

    // add their response to state
    state.color = text

    msg
      .say('Thanks for sharing.')
      .say(`Here's what you've told me so far: \`\`\`${JSON.stringify(state)}\`\`\``)
    // At this point, since we don't route anywhere, the "conversation" is over
  })

// Can use a regex as well
slapp.message(/^(thanks|thank you)/i, ['mention', 'direct_message'], (msg) => {
  // You can provide a list of responses, and a random one will be chosen
  // You can also include slack emoji in your responses
  msg.say([
    "You're welcome :smile:",
    'You bet',
    ':+1: Of course',
    'Anytime :sun_with_face: :full_moon_with_face:'
  ])
})

// demonstrate returning an attachment...
slapp.message('attachment', ['mention', 'direct_message'], (msg) => {
  msg.say({
    text: 'Check out this amazing attachment! :confetti_ball: ',
    attachments: [{
      text: 'Slapp is a robust open source library that sits on top of the Slack APIs',
      title: 'Slapp Library - Open Source',
      image_url: 'https://storage.googleapis.com/beepboophq/_assets/bot-1.22f6fb.png',
      title_link: 'https://beepboophq.com/',
      color: '#7CD197'
    }]
  })
})

// Catch-all for any other responses not handled above
slapp.message('.*', ['direct_mention', 'direct_message'], (msg) => {
  // respond only 40% of the time
  if (Math.random() < 0.4) {
    msg.say([':wave:', ':pray:', ':raised_hands:'])
  }
})

// LAN message
slapp.
  message('\\b(lan)\\b', 'ambient', (msg) => {
    var today = new Date();
    var lan = new Date('13/04/2017 18:00');
    var difference = (lan.getTime() - today.getTime());
    msg
      .say([
      'LAN starts at 18:00 on Thursday the 13th of April 2017.',
      'la la la la I\'m not listening',
      '6pm. Thursday. 13/04.',
      'Ask @vyper'
      ])
      .say('diff:' + lan.getTime())

  })

// attach Slapp to express server
var server = slapp.attachToExpress(express())

// start http server
server.listen(port, (err) => {
  if (err) {
    return console.error(err)
  }

  console.log(`Listening on port ${port}`)
})
<commit_msg>think I've cracked it<commit_after>'use strict'

const express = require('express')
const Slapp = require('slapp')
const ConvoStore = require('slapp-convo-beepboop')
const Context = require('slapp-context-beepboop')

// use `PORT` env var on Beep Boop - default to 3000 locally
var port = process.env.PORT || 3000

var slapp = Slapp({
  // Beep Boop sets the SLACK_VERIFY_TOKEN env var
  verify_token: process.env.SLACK_VERIFY_TOKEN,
  convo_store: ConvoStore(),
  context: Context()
})

var HELP_TEXT = `
I will respond to the following messages:
\`help\` - to see this message.
\`hi\` - to demonstrate a conversation that tracks state.
\`thanks\` - to demonstrate a simple response.
\`<type-any-other-text>\` - to demonstrate a random emoticon response, some of the time :wink:.
\`attachment\` - to see a Slack attachment message.
`

//*********************************************
// Setup different handlers for messages
//*********************************************

// response to the user typing "help"
slapp.message('help', ['mention', 'direct_message'], (msg) => {
  msg.say(HELP_TEXT)
})

// "Conversation" flow that tracks state - kicks off when user says hi, hello or hey
slapp
  .message('^(hi|hello|hey)$', ['direct_mention', 'direct_message'], (msg, text) => {
    msg
      .say(`${text}, how are you?`)
      // sends next event from user to this route, passing along state
      .route('how-are-you', { greeting: text })
  })
  .route('how-are-you', (msg, state) => {
    var text = (msg.body.event && msg.body.event.text) || ''

    // user may not have typed text as their next action, ask again and re-route
    if (!text) {
      return msg
        .say("Whoops, I'm still waiting to hear how you're doing.")
        .say('How are you?')
        .route('how-are-you', state)
    }

    // add their response to state
    state.status = text

    msg
      .say(`Ok then. What's your favorite color?`)
      .route('color', state)
  })
  .route('color', (msg, state) => {
    var text = (msg.body.event && msg.body.event.text) || ''

    // user may not have typed text as their next action, ask again and re-route
    if (!text) {
      return msg
        .say("I'm eagerly awaiting to hear your favorite color.")
        .route('color', state)
    }

    // add their response to state
    state.color = text

    msg
      .say('Thanks for sharing.')
      .say(`Here's what you've told me so far: \`\`\`${JSON.stringify(state)}\`\`\``)
    // At this point, since we don't route anywhere, the "conversation" is over
  })

// Can use a regex as well
slapp.message(/^(thanks|thank you)/i, ['mention', 'direct_message'], (msg) => {
  // You can provide a list of responses, and a random one will be chosen
  // You can also include slack emoji in your responses
  msg.say([
    "You're welcome :smile:",
    'You bet',
    ':+1: Of course',
    'Anytime :sun_with_face: :full_moon_with_face:'
  ])
})

// demonstrate returning an attachment...
slapp.message('attachment', ['mention', 'direct_message'], (msg) => {
  msg.say({
    text: 'Check out this amazing attachment! :confetti_ball: ',
    attachments: [{
      text: 'Slapp is a robust open source library that sits on top of the Slack APIs',
      title: 'Slapp Library - Open Source',
      image_url: 'https://storage.googleapis.com/beepboophq/_assets/bot-1.22f6fb.png',
      title_link: 'https://beepboophq.com/',
      color: '#7CD197'
    }]
  })
})

// Catch-all for any other responses not handled above
slapp.message('.*', ['direct_mention', 'direct_message'], (msg) => {
  // respond only 40% of the time
  if (Math.random() < 0.4) {
    msg.say([':wave:', ':pray:', ':raised_hands:'])
  }
})

// LAN message
slapp.
  message('\\b(lan)\\b', 'ambient', (msg) => {
    var today = new Date();
    var lan = new Date('13/04/2017 18:00');
    var difference = (lan - today.getTime());
    msg
      .say([
      'LAN starts at 18:00 on Thursday the 13th of April 2017.',
      'la la la la I\'m not listening',
      '6pm. Thursday. 13/04.',
      'Ask @vyper'
      ])
      .say('diff:' + difference)

  })

// attach Slapp to express server
var server = slapp.attachToExpress(express())

// start http server
server.listen(port, (err) => {
  if (err) {
    return console.error(err)
  }

  console.log(`Listening on port ${port}`)
})
<|endoftext|>


<commit_before>// @flow

var packageInfo = require("../package.json");
var chalk = require("chalk");
var Version = require("./version.js");
var Install = require("./install.js");
var Compile = require("./Compile.js");
var Generate = require("./Generate.js");
var dns = require("dns");
var processTitle = "elm-test";

process.title = processTitle;

process.on("uncaughtException", function(error) {
  if (/ an argument in Javascript/.test(error)) {
    // Handle arg mismatch between js and elm code. Expected message from Elm:
    // "You are giving module `Main` an argument in JavaScript.
    // This module does not take arguments though! You probably need to change the
    // initialization code to something like `Elm.Test.Generated.Main.fullscreen()`]"
    console.error("Error starting the node-test-runner.");
    console.error(
      "Please check your Javascript 'elm-test' and Elm 'node-test-runner' package versions are compatible"
    );
    process.exit(1);
  } else {
    console.error("Unhandled exception while running the tests:", error);
    process.exit(1);
  }
});

var compile = require("node-elm-compiler").compile,
  fs = require("fs-extra"),
  os = require("os"),
  glob = require("glob"),
  path = require("path"),
  util = require("util"),
  _ = require("lodash"),
  spawn = require("cross-spawn"),
  minimist = require("minimist"),
  firstline = require("firstline"),
  chokidar = require("chokidar"),
  Runner = require("./runner.js"),
  Supervisor = require("./supervisor.js"),
  child_process = require("child_process");

// Check Node version
const nodeVersionString = process.versions.node;
const nodeVersion = _.map(_.split(nodeVersionString, "."), _.parseInt);

if (
  (nodeVersion[0] === 0 && nodeVersion[1] < 11) ||
  (nodeVersion[0] === 0 && nodeVersion[1] === 11 && nodeVersion[2] < 13)
) {
  console.log("using node v" + nodeVersionString);
  console.error(
    "elm-test requires node v4.7.0 or greater - upgrade the installed version of node and try again"
  );
  process.exit(1);
}

var args = minimist(process.argv.slice(2), {
  boolean: ["warn", "version", "help", "watch"],
  string: ["compiler", "seed", "report", "fuzz"]
});
var processes = Math.max(1, os.cpus().length);

// Recursively search directories for *.elm files, excluding elm-stuff/
function resolveFilePath(filename) {
  var candidates;

  if (!fs.existsSync(filename)) {
    candidates = [];
  } else if (fs.lstatSync(filename).isDirectory()) {
    candidates = _.flatMap(
      glob.sync("/**/*.elm", {
        root: filename,
        nocase: true,
        ignore: "/**/elm-stuff/**",
        nodir: true
      }),
      resolveFilePath
    );
  } else {
    candidates = [path.resolve(filename)];
  }

  // Exclude everything having anything to do with elm-stuff
  return candidates.filter(function(candidate) {
    return candidate.split(path.sep).indexOf("elm-stuff") === -1;
  });
}

let pathToElmBinary;

if (args.compiler === undefined) {
  pathToElmBinary = "elm";
} else {
  pathToElmBinary = path.resolve(args.compiler);

  if (!pathToElmBinary) {
    console.error(
      "The --compiler option must be given a path to an elm-make executable."
    );
    process.exit(1);
  }
}

function printUsage(str) {
  console.log("Usage: elm-test " + str + "\n");
}

if (args.help) {
  var exampleGlob = path.join("tests", "**", "*.elm");

  [
    "init # Create example tests",
    "install PACKAGE # Like `elm install PACKAGE`, except it installs to \"test-dependencies\" in your elm.json",
    "TESTFILES # Run TESTFILES, for example " + exampleGlob,
    "[--compiler /path/to/compiler] # Run tests",
    "[--seed integer] # Run with initial fuzzer seed",
    "[--fuzz integer] # Run with each fuzz test performing this many iterations",
    "[--report json, junit, or console (default)] # Print results to stdout in given format",
    "[--version] # Print version string and exit",
    "[--watch] # Run tests on file changes"
  ].forEach(printUsage);

  process.exit(1);
}

if (args.version) {
  console.log(require(path.join(__dirname, "..", "package.json")).version);
  process.exit(0);
}

if (args._[0] === "install") {
  var packageName = args._[1];

  if (typeof packageName === "string") {
    if (!fs.existsSync("elm.json")) {
      console.error("`elm-test install` must be run in the same directory as an existing elm.json file!");
      process.exit(1);
    }

    Install.install(pathToElmBinary, packageName);

    process.exit(0);
  } else {
    console.error(
      "What package should I install? I was expecting something like this:\n\n    elm-test install elm/regex\n"
    );
    process.exit(1);
  }
}
else if (args._[0] == "init") {
  if (!fs.existsSync("elm.json")) {
    console.error("`elm-test init` must be run in the same directory as an existing elm.json file! You can run `elm init` to initialize one.");
    process.exit(1);
  }

  Install.install(pathToElmBinary, "elm-explorations/test");
  fs.mkdirpSync("tests");
  fs.copySync(path.join(__dirname, "..", "templates", "tests", "Example.elm"), "tests/Example.elm");

  console.log("\nCheck out the documentation for getting started at https://package.elm-lang.org/packages/elm-explorations/test/latest");

  process.exit(0);
}

function runTests(generatedCodeDir/*:string*/, testFile/*:string*/) {
  const dest = path.resolve(path.join(generatedCodeDir, "elmTestOutput.js"));

  return Compile.compile(
    testFile, dest, args.verbose, pathToElmBinary, args.report
  ).then(function() {
    return Generate.prepareCompiledJsFile(dest).then(function() {
      return Supervisor.run(
        packageInfo.version,
        report,
        processes,
        dest,
        args.watch,
        Compile.isMachineReadableReporter(report)
      );
    });
  })
  .catch(function(exitCode) {
    console.error("Compilation failed for", testFile);
    return Promise.reject(exitCode);
  });
}

function globify(filename) {
  return glob.sync(filename, {
    nocase: true,
    ignore: "**/elm-stuff/**",
    nodir: false,
    absolute: true
  });
}

function globifyWithRoot(root, filename) {
  return glob.sync(filename, {
    root: root,
    nocase: true,
    ignore: "**/elm-stuff/**",
    nodir: false,
    absolute: true
  });
}

function resolveGlobs(fileGlobs) {
  let globs;

  if (fileGlobs.length > 0) {
    globs = _.flatMap(fileGlobs, globify);
  } else {
    var root = path.join(
      path.resolve(Runner.findNearestElmPackageDir([process.cwd()]))
    );

    globs = globifyWithRoot(root, "test?(s)/**/*.elm");
  }

  return _.flatMap(globs, resolveFilePath);
}

function getWatchPaths(projectRootDir/*:string*/) {
  var watchedSourcePaths;
  var elmJson = fs.readJsonSync(path.join(projectRootDir, "elm.json"), "utf8");
  if (elmJson["type"] === "package") {
    watchedSourcePaths = [ "./src" ];
  } else {
    watchedSourcePaths = elmJson["source-directories"];
  }
  var watchedTestPaths = path.join(projectRootDir, "tests");
  var watchedPaths = watchedSourcePaths.concat(watchedTestPaths).map(function(sourcePath) {
    return path.resolve(projectRootDir, sourcePath) + "/**/*.elm";
  });
  return watchedPaths;
}

var report;

if (
  args.report === "console" ||
  args.report === "json" ||
  args.report === "junit"
) {
  report = args.report;
} else if (args.report !== undefined) {
  console.error(
    "The --report option must be given either 'console', 'junit', or 'json'"
  );
  process.exit(1);
} else {
  report = "console";
}

function infoLog(msg) {
  if (report === "console") {
    console.log(msg);
  }
}

function getProjectRootDir(filePaths) {
  return path.resolve(Runner.findNearestElmPackageDir(filePaths));
}

function getTestRootDir(projectRootDir/*:string*/) {
  return path.resolve(path.join(projectRootDir, "tests"));
}

if (args._[0] === "make") {
  const files = args._.slice(1);

  // It's important to globify all the arguments.
  // On Bash 4.x (or zsh), if you give it a glob as its last argument, Bash
  // translates that into a list of file paths. On bash 3.x it's just a string.
  // Ergo, globify all the arguments we receive.
  const fileGlobs = files.length > 0 ? files : [];
  const testFilePaths = resolveGlobs(files);
  const projectRootDir = getProjectRootDir(testFilePaths);
  const testRootDir = getTestRootDir(projectRootDir);
  const generatedCodeDir = Generate.generateElmJson(projectRootDir, testRootDir, pathToElmBinary, testFilePaths, fileGlobs.length > 0)[0];

  Compile.compileAll(testFilePaths, generatedCodeDir, args.verbose, pathToElmBinary, args.report).then(function() {
    process.exit(0);
  }).catch(function(err) {
    process.exit(1);
  });
} else {
  // It's important to globify all the arguments.
  // On Bash 4.x (or zsh), if you give it a glob as its last argument, Bash
  // translates that into a list of file paths. On bash 3.x it's just a string.
  // Ergo, globify all the arguments we receive.
  const fileGlobs = args._.length > 0 ? args._ : [];
  const testFilePaths = resolveGlobs(fileGlobs);

  if (testFilePaths.length === 0) {
    var errorMessage =
      fileGlobs.length > 0
        ? 'No tests found for the file pattern "' +
          fileGlobs.toString() +
          '"\n\nMaybe try running elm-test with no arguments?'
        : "No tests found in the tests/ directory.\n\nNOTE: Make sure you're running elm-test from your project's root directory, where its elm.json lives.\n\nTo generate some initial tests to get things going, run elm-test init.\n\nAlternatively, if your application has tests in a different directory, try calling elm-test with a glob: elm-test 'frontend-app/**/*Tests.elm'.";

    console.error(errorMessage);
    process.exit(1);
  }

  const projectRootDir = getProjectRootDir(testFilePaths);
  const testRootDir = getTestRootDir(projectRootDir);
  const returnValues = Generate.generateElmJson(projectRootDir, testRootDir, pathToElmBinary, testFilePaths, fileGlobs.length > 0);
  const generatedCodeDir = returnValues[0];
  const generatedSrc = returnValues[1];
  const sourceDirs = returnValues[2];

  function clearConsole() {
    process.stdout.write(
      process.platform === 'win32' ? '\x1B[2J\x1B[0f' : '\x1B[2J\x1B[3J\x1B[H'
    );
  }

  function run() {
    // This compiles all the tests so that we generate *.elmi files for them,
    // which we can then read to determine which tests need to be run.
    return Compile.compileAll(testFilePaths, generatedCodeDir, args.verbose, pathToElmBinary, args.report)
      .then(function() {
        return Runner.findTests(
          generatedCodeDir,
          testFilePaths,
          sourceDirs,
          !Compile.isMachineReadableReporter(report)
        )
        .then(function(runnableTests) {
          process.chdir(generatedCodeDir);

          const mainFile = Generate.generateMainModule(
            parseInt(args.fuzz),
            parseInt(args.seed),
            args.report,
            testFilePaths,
            runnableTests,
            generatedSrc,
            processes
          );

          return runTests(generatedCodeDir, mainFile);
        })
        .catch(function(err) {
            console.error(err);
            process.exit(1);
          });
        })
    .catch(function(err) {
      console.error(err);
      if (!args.watch) {
        process.exit(1);
      }
    })
    .then(function() {
      console.log(chalk.blue("Watching for changes..."));
    })
  }

  var currentRun = run();

  if (args.watch) {
    clearConsole();
    infoLog("Running in watch mode");

    var watchedPaths = getWatchPaths(projectRootDir);
    var watcher = chokidar.watch(watchedPaths, {
      awaitWriteFinish: {
        stabilityThreshold: 500
      },
      ignoreInitial: true,
      ignored: /(\/|^)elm-stuff(\/|$)/
    });

    var eventNameMap = {
      add: "added",
      addDir: "added",
      change: "changed",
      unlink: "removed",
      unlinkDir: "removed"
    };

    watcher.on("all", function(event, filePath) {
      var relativePath = path.relative(testRootDir, filePath);
      var eventName = eventNameMap[event] || event;
      clearConsole();
      infoLog("\n" + relativePath + " " + eventName + ". Rebuilding!");

      // TODO if a previous run is in progress, wait until it's done.
      currentRun = currentRun.then(run);
    });
  }
}
<commit_msg>only show extra test error for apps<commit_after>// @flow

var packageInfo = require("../package.json");
var chalk = require("chalk");
var Version = require("./version.js");
var Install = require("./install.js");
var Compile = require("./Compile.js");
var Generate = require("./Generate.js");
var dns = require("dns");
var processTitle = "elm-test";

process.title = processTitle;

process.on("uncaughtException", function(error) {
  if (/ an argument in Javascript/.test(error)) {
    // Handle arg mismatch between js and elm code. Expected message from Elm:
    // "You are giving module `Main` an argument in JavaScript.
    // This module does not take arguments though! You probably need to change the
    // initialization code to something like `Elm.Test.Generated.Main.fullscreen()`]"
    console.error("Error starting the node-test-runner.");
    console.error(
      "Please check your Javascript 'elm-test' and Elm 'node-test-runner' package versions are compatible"
    );
    process.exit(1);
  } else {
    console.error("Unhandled exception while running the tests:", error);
    process.exit(1);
  }
});

var compile = require("node-elm-compiler").compile,
  fs = require("fs-extra"),
  os = require("os"),
  glob = require("glob"),
  path = require("path"),
  util = require("util"),
  _ = require("lodash"),
  spawn = require("cross-spawn"),
  minimist = require("minimist"),
  firstline = require("firstline"),
  chokidar = require("chokidar"),
  Runner = require("./runner.js"),
  Supervisor = require("./supervisor.js"),
  child_process = require("child_process");

// Check Node version
const nodeVersionString = process.versions.node;
const nodeVersion = _.map(_.split(nodeVersionString, "."), _.parseInt);

if (
  (nodeVersion[0] === 0 && nodeVersion[1] < 11) ||
  (nodeVersion[0] === 0 && nodeVersion[1] === 11 && nodeVersion[2] < 13)
) {
  console.log("using node v" + nodeVersionString);
  console.error(
    "elm-test requires node v4.7.0 or greater - upgrade the installed version of node and try again"
  );
  process.exit(1);
}

var args = minimist(process.argv.slice(2), {
  boolean: ["warn", "version", "help", "watch"],
  string: ["compiler", "seed", "report", "fuzz"]
});
var processes = Math.max(1, os.cpus().length);

// Recursively search directories for *.elm files, excluding elm-stuff/
function resolveFilePath(filename) {
  var candidates;

  if (!fs.existsSync(filename)) {
    candidates = [];
  } else if (fs.lstatSync(filename).isDirectory()) {
    candidates = _.flatMap(
      glob.sync("/**/*.elm", {
        root: filename,
        nocase: true,
        ignore: "/**/elm-stuff/**",
        nodir: true
      }),
      resolveFilePath
    );
  } else {
    candidates = [path.resolve(filename)];
  }

  // Exclude everything having anything to do with elm-stuff
  return candidates.filter(function(candidate) {
    return candidate.split(path.sep).indexOf("elm-stuff") === -1;
  });
}

let pathToElmBinary;

if (args.compiler === undefined) {
  pathToElmBinary = "elm";
} else {
  pathToElmBinary = path.resolve(args.compiler);

  if (!pathToElmBinary) {
    console.error(
      "The --compiler option must be given a path to an elm-make executable."
    );
    process.exit(1);
  }
}

function printUsage(str) {
  console.log("Usage: elm-test " + str + "\n");
}

if (args.help) {
  var exampleGlob = path.join("tests", "**", "*.elm");

  [
    "init # Create example tests",
    "install PACKAGE # Like `elm install PACKAGE`, except it installs to \"test-dependencies\" in your elm.json",
    "TESTFILES # Run TESTFILES, for example " + exampleGlob,
    "[--compiler /path/to/compiler] # Run tests",
    "[--seed integer] # Run with initial fuzzer seed",
    "[--fuzz integer] # Run with each fuzz test performing this many iterations",
    "[--report json, junit, or console (default)] # Print results to stdout in given format",
    "[--version] # Print version string and exit",
    "[--watch] # Run tests on file changes"
  ].forEach(printUsage);

  process.exit(1);
}

if (args.version) {
  console.log(require(path.join(__dirname, "..", "package.json")).version);
  process.exit(0);
}

if (args._[0] === "install") {
  var packageName = args._[1];

  if (typeof packageName === "string") {
    if (!fs.existsSync("elm.json")) {
      console.error("`elm-test install` must be run in the same directory as an existing elm.json file!");
      process.exit(1);
    }

    Install.install(pathToElmBinary, packageName);

    process.exit(0);
  } else {
    console.error(
      "What package should I install? I was expecting something like this:\n\n    elm-test install elm/regex\n"
    );
    process.exit(1);
  }
}
else if (args._[0] == "init") {
  if (!fs.existsSync("elm.json")) {
    console.error("`elm-test init` must be run in the same directory as an existing elm.json file! You can run `elm init` to initialize one.");
    process.exit(1);
  }

  Install.install(pathToElmBinary, "elm-explorations/test");
  fs.mkdirpSync("tests");
  fs.copySync(path.join(__dirname, "..", "templates", "tests", "Example.elm"), "tests/Example.elm");

  console.log("\nCheck out the documentation for getting started at https://package.elm-lang.org/packages/elm-explorations/test/latest");

  process.exit(0);
}

function runTests(generatedCodeDir/*:string*/, testFile/*:string*/) {
  const dest = path.resolve(path.join(generatedCodeDir, "elmTestOutput.js"));

  return Compile.compile(
    testFile, dest, args.verbose, pathToElmBinary, args.report
  ).then(function() {
    return Generate.prepareCompiledJsFile(dest).then(function() {
      return Supervisor.run(
        packageInfo.version,
        report,
        processes,
        dest,
        args.watch,
        Compile.isMachineReadableReporter(report)
      );
    });
  })
  .catch(function(exitCode) {
    console.error("Compilation failed for", testFile);
    return Promise.reject(exitCode);
  });
}

function globify(filename) {
  return glob.sync(filename, {
    nocase: true,
    ignore: "**/elm-stuff/**",
    nodir: false,
    absolute: true
  });
}

function globifyWithRoot(root, filename) {
  return glob.sync(filename, {
    root: root,
    nocase: true,
    ignore: "**/elm-stuff/**",
    nodir: false,
    absolute: true
  });
}

function resolveGlobs(fileGlobs) {
  let globs;

  if (fileGlobs.length > 0) {
    globs = _.flatMap(fileGlobs, globify);
  } else {
    var root = path.join(
      path.resolve(Runner.findNearestElmPackageDir([process.cwd()]))
    );

    globs = globifyWithRoot(root, "test?(s)/**/*.elm");
  }

  return _.flatMap(globs, resolveFilePath);
}

function getWatchPaths(projectRootDir/*:string*/) {
  var watchedSourcePaths;
  var elmJson = fs.readJsonSync(path.join(projectRootDir, "elm.json"), "utf8");
  if (elmJson["type"] === "package") {
    watchedSourcePaths = [ "./src" ];
  } else {
    watchedSourcePaths = elmJson["source-directories"];
  }
  var watchedTestPaths = path.join(projectRootDir, "tests");
  var watchedPaths = watchedSourcePaths.concat(watchedTestPaths).map(function(sourcePath) {
    return path.resolve(projectRootDir, sourcePath) + "/**/*.elm";
  });
  return watchedPaths;
}

var report;

if (
  args.report === "console" ||
  args.report === "json" ||
  args.report === "junit"
) {
  report = args.report;
} else if (args.report !== undefined) {
  console.error(
    "The --report option must be given either 'console', 'junit', or 'json'"
  );
  process.exit(1);
} else {
  report = "console";
}

function infoLog(msg) {
  if (report === "console") {
    console.log(msg);
  }
}

function getProjectRootDir(filePaths) {
  return path.resolve(Runner.findNearestElmPackageDir(filePaths));
}

function getTestRootDir(projectRootDir/*:string*/) {
  return path.resolve(path.join(projectRootDir, "tests"));
}

if (args._[0] === "make") {
  const files = args._.slice(1);

  // It's important to globify all the arguments.
  // On Bash 4.x (or zsh), if you give it a glob as its last argument, Bash
  // translates that into a list of file paths. On bash 3.x it's just a string.
  // Ergo, globify all the arguments we receive.
  const fileGlobs = files.length > 0 ? files : [];
  const testFilePaths = resolveGlobs(files);
  const projectRootDir = getProjectRootDir(testFilePaths);
  const testRootDir = getTestRootDir(projectRootDir);
  const generatedCodeDir = Generate.generateElmJson(projectRootDir, testRootDir, pathToElmBinary, testFilePaths, fileGlobs.length > 0)[0];

  Compile.compileAll(testFilePaths, generatedCodeDir, args.verbose, pathToElmBinary, args.report).then(function() {
    process.exit(0);
  }).catch(function(err) {
    process.exit(1);
  });
} else {
  // It's important to globify all the arguments.
  // On Bash 4.x (or zsh), if you give it a glob as its last argument, Bash
  // translates that into a list of file paths. On bash 3.x it's just a string.
  // Ergo, globify all the arguments we receive.
  const fileGlobs = args._.length > 0 ? args._ : [];
  const testFilePaths = resolveGlobs(fileGlobs);
  const projectRootDir = getProjectRootDir(testFilePaths);

  const elmJsonPath = path.resolve(path.join(projectRootDir, "elm.json"));
  var projectElmJson = {};

  try {
    projectElmJson = fs.readJsonSync(elmJsonPath);
  } catch (err) {
    console.error("Error reading elm.json: " + err);
    process.exit(1);
  }

  var isPackageProject = projectElmJson.type === "package";

  if (testFilePaths.length === 0) {
    var extraAppError = "\n\nAlternatively, if your application has tests in a different directory, try calling elm-test with a glob: elm-test 'frontend-app/**/*Tests.elm'.";

    var errorMessage =
      fileGlobs.length > 0
        ? 'No tests found for the file pattern "' +
          fileGlobs.toString() +
          '"\n\nMaybe try running elm-test with no arguments?'
        : "No tests found in the tests/ directory.\n\nNOTE: Make sure you're running elm-test from your project's root directory, where its elm.json lives.\n\nTo generate some initial tests to get things going, run elm-test init." + (isPackageProject ? '' : extraAppError);

    console.error(errorMessage);
    process.exit(1);
  }

  const testRootDir = getTestRootDir(projectRootDir);
  const returnValues = Generate.generateElmJson(projectRootDir, testRootDir, pathToElmBinary, testFilePaths, fileGlobs.length > 0);
  const generatedCodeDir = returnValues[0];
  const generatedSrc = returnValues[1];
  const sourceDirs = returnValues[2];

  function clearConsole() {
    process.stdout.write(
      process.platform === 'win32' ? '\x1B[2J\x1B[0f' : '\x1B[2J\x1B[3J\x1B[H'
    );
  }

  function run() {
    // This compiles all the tests so that we generate *.elmi files for them,
    // which we can then read to determine which tests need to be run.
    return Compile.compileAll(testFilePaths, generatedCodeDir, args.verbose, pathToElmBinary, args.report)
      .then(function() {
        return Runner.findTests(
          generatedCodeDir,
          testFilePaths,
          sourceDirs,
          !Compile.isMachineReadableReporter(report)
        )
        .then(function(runnableTests) {
          process.chdir(generatedCodeDir);

          const mainFile = Generate.generateMainModule(
            parseInt(args.fuzz),
            parseInt(args.seed),
            args.report,
            testFilePaths,
            runnableTests,
            generatedSrc,
            processes
          );

          return runTests(generatedCodeDir, mainFile);
        })
        .catch(function(err) {
            console.error(err);
            process.exit(1);
          });
        })
    .catch(function(err) {
      console.error(err);
      if (!args.watch) {
        process.exit(1);
      }
    })
    .then(function() {
      console.log(chalk.blue("Watching for changes..."));
    })
  }

  var currentRun = run();

  if (args.watch) {
    clearConsole();
    infoLog("Running in watch mode");

    var watchedPaths = getWatchPaths(projectRootDir);
    var watcher = chokidar.watch(watchedPaths, {
      awaitWriteFinish: {
        stabilityThreshold: 500
      },
      ignoreInitial: true,
      ignored: /(\/|^)elm-stuff(\/|$)/
    });

    var eventNameMap = {
      add: "added",
      addDir: "added",
      change: "changed",
      unlink: "removed",
      unlinkDir: "removed"
    };

    watcher.on("all", function(event, filePath) {
      var relativePath = path.relative(testRootDir, filePath);
      var eventName = eventNameMap[event] || event;
      clearConsole();
      infoLog("\n" + relativePath + " " + eventName + ". Rebuilding!");

      // TODO if a previous run is in progress, wait until it's done.
      currentRun = currentRun.then(run);
    });
  }
}
<|endoftext|>


<commit_before>'use strict';

// Summary:
//  Load plugins

// Set the node_modules of Rekit Studio as the NODE_PATH to find modules.
// So that plugin could use dependencies of Rekit Studio and Rekit Core.
const utils = require('./utils');
const nodeModulesPath = require.resolve('lodash').replace('/lodash/lodash.js', '');
utils.addNodePath(nodeModulesPath);
try {
  // If rekit studio is installed globally, add rekit-studio's deps to NODE_PATH
  const rsPath = require.resolve('rekit-studio/package.json').replace(/[/\\]package\.json$/, '');
  utils.addNodePath(rsPath + '/node_modules');
  utils.addNodePath(rsPath.replace(/[/\\]rekit-studio$/, ''));
} catch (err) {
  // Do nothing if not found rekit studio
}

const fs = require('fs-extra');
const path = require('path');
const spawn = require('child_process').spawn;
const _ = require('lodash');
const os = require('os');
const paths = require('./paths');
const config = require('./config');
const logger = require('./logger');
const downloadNpmPackage = require('download-npm-package');

let appliedPlugins = undefined;
let allPlugins = [];
let loaded = false;
let needFilterPlugin = true;

const DEFAULT_PLUGIN_DIR = path.join(os.homedir(), '.rekit/plugins');

const pluginsDirs = [DEFAULT_PLUGIN_DIR];
function addPluginsDir(dir) {
  pluginsDirs.push(dir);
}
function getPluginsDir() {
  return DEFAULT_PLUGIN_DIR;
}

function getPlugins(prop) {
  getAllPlugins();

  filterPluginsIfNecessary();
  appliedPlugins.forEach(p => {
    if (p.initialize && !p.__initialized) {
      p.initialize();
      p.__initialized = true;
    }
  });
  return prop ? appliedPlugins.filter(_.property(prop)) : appliedPlugins;
}

function sortPlugins() {
  // Sort plugins according dep relations and Rekit config.
  const rekitConfig = config.getRekitConfig();
  const pluginOrder = rekitConfig.pluginOrder || [];

  allPlugins.sort((p1, p2) => {
    const p1Index = pluginOrder.indexOf(p1.name);
    const p2Index = pluginOrder.indexOf(p2.name);
    if (p1.dependencies && p1.dependencies.includes(p2.name)) {
      // If p1 depends on p2, load p2 first
      return 1;
    }
    if (p2.dependencies && p2.dependencies.includes(p1.name)) {
      // If p2 depends on p1, load p1 first
      return -1;
    }
    if (p1Index >= 0 && p2Index === -1) {
      // If only p1 configed, load it first
      return -1;
    }
    if (p2Index >= 0 && p1Index === -1) {
      // If only p2 configed, load it first
      return 1;
    }
    if (p1Index >= 0 && p2Index >= 0) {
      // If both configed, load before first
      return p1Index - p2Index;
    }
    // No order specified.
    return 0;
  });
}

function filterPluginsIfNecessary() {
  initPluginsIfNecessary();
  if (!needFilterPlugin) return;
  const rekitConfig = config.getRekitConfig();

  // A plugin could decide if it's fit for the current project by feature files
  logger.info('All plugins:', allPlugins.map(p => p.name));
  const appType = rekitConfig.appType;
  appliedPlugins = allPlugins.filter(
    p =>
      (!p.shouldUse || p.shouldUse(paths.getProjectRoot())) &&
      (!p.appType || _.castArray(p.appType).includes(appType)) &&
      !(rekitConfig.excludePlugins || []).map(s => s.replace('rekit-plugin', '')).includes(p.name),
  );
  logger.info('Applied plugins for appType ' + appType + ': ', appliedPlugins.map(p => p.name));
  needFilterPlugin = false;
}

function initPluginsIfNecessary() {
  allPlugins = allPlugins.map(plugin => {
    if (!plugin.inherit) return plugin;
    const newPlugin = { uiInherit: [] };
    _.castArray(plugin.inherit).forEach(name => {
      // currently only one level inherit supported?
      const p = getPlugin(name);
      if (!p) {
        throw new Error('INHERIT_PLUGIN_NOT_FOUND: ' + name + ' inherited by ' + plugin.name);
      }
      newPlugin.uiInherit.push(name);
      _.merge(newPlugin, p);
    });
    _.merge(newPlugin, plugin);
    newPlugin.__originalInherit = plugin.inherit;
    delete newPlugin.inherit; // only inherit once
    return newPlugin;
  });
}

function getPlugin(name) {
  return _.find(allPlugins, { name }) || null;
}

// Load plugin instance, plugin depends on project config
function loadPlugin(pluginRoot, noUI) {
  // noUI flag is used for loading dev plugins whose ui is from webpack dev server
  try {
    // const pkgJson = require(paths.join(pluginRoot, 'package.json'));
    const pluginInstance = { root: pluginRoot };
    // Core part
    const coreIndex = paths.join(pluginRoot, 'core/index.js');
    if (fs.existsSync(coreIndex)) {
      Object.assign(pluginInstance, require(coreIndex));
    }

    // UI part
    if (!noUI) {
      let entry = 'main.js';
      if (
        process.env.NODE_ENV === 'development' &&
        fs.existsSync(path.join(pluginRoot, 'build', 'main-dev.js'))
      ) {
        entry = 'main-dev.js';
      }
      if (fs.existsSync(path.join(pluginRoot, 'build', entry))) {
        pluginInstance.ui = {
          root: path.join(pluginRoot, 'build'),
          entry,
        };
      }
    }

    // Plugin meta defined in package.json
    const pkgJsonPath = path.join(pluginRoot, 'package.json');
    let pkgJson = null;
    if (fs.existsSync(pkgJsonPath)) {
      pkgJson = fs.readJsonSync(pkgJsonPath);

      ['appType', 'name', 'version'].forEach(key => {
        if (!pluginInstance.hasOwnProperty(key) && pkgJson.hasOwnProperty(key)) {
          if (key === 'name') {
            let name = pkgJson.name;
            if (name.startsWith('rekit-plugin')) name = name.replace('rekit-plugin-', '');
            pluginInstance.name = name;
          } else {
            pluginInstance[key] = pkgJson[key] || null;
          }
        }
      });
      if (pkgJson.rekitPlugin) {
        Object.keys(pkgJson.rekitPlugin).forEach(key => {
          if (!pluginInstance.hasOwnProperty(key)) {
            pluginInstance[key] = pkgJson.rekitPlugin[key];
          }
        });
      }
    }
    if (!pluginInstance.version) pluginInstance.version = '0.0.1';
    return pluginInstance;
  } catch (e) {
    logger.warn(`Failed to load plugin: ${pluginRoot}`, e);
  }

  return null;
}

function loadPlugins(dir) {
  // At rekit studio dev time, do not load dist plugins from dir.
  // Because Rekit Studio doesn't support it at dev time.
  if (process.env.REKIT_STUDIO_DEVELOPMENT) return;
  fs.readdirSync(dir)
    .map(d => path.join(dir, d))
    .filter(d => fs.statSync(d).isDirectory())
    .forEach(d => addPluginByPath(d));
}

// Dynamically add an plugin
function addPlugin(plugin) {
  if (!plugin) {
    return;
  }
  if (!needFilterPlugin) {
    console.warn('You are adding a plugin after getPlugins is called.');
  }
  if (!plugin.getModule) {
    plugin.getModule = mid => {
      try {
        return require(path.join(plugin.root, mid));
      } catch (err) {
        logger.debug('Faied to load module: ' + mid, err);
        return null;
      }
    };
  }
  needFilterPlugin = true;
  if (!plugin.name) {
    logger.info('plugin: ', plugin);
    throw new Error('Each plugin should have a name.');
  }
  if (_.find(allPlugins, { name: plugin.name })) {
    console.warn('You should not add a plugin with same name: ' + plugin.name);
    return;
  }
  allPlugins.push(plugin);
}

function addPluginByPath(pluginRoot, noUI) {
  addPlugin(loadPlugin(pluginRoot, noUI));
}

function removePlugin(pluginName) {
  const removed = _.remove(allPlugins, { name: pluginName });
  needFilterPlugin = true;
  if (!removed.length) console.warn('No plugin was removed: ' + pluginName);
}

function listInstalledPlugins() {
  // Only get plugins from standard rekit plugin folder
  const dir = paths.configFile('plugins2');
  const plugins = [];

  if (fs.existsSync(dir))
    fs.readdirSync(dir)
      .filter(name => /^rekit-plugin-/.test(name))
      .map(name => path.join(dir, name))
      .filter(d => fs.statSync(d).isDirectory())
      .forEach(pluginRoot => {
        try {
          const pkgJson = require(paths.join(pluginRoot, 'package.json'));
          // Plugin info
          const pluginInfo = {};
          Object.assign(pluginInfo, pkgJson);

          plugins.push(pluginInfo);
        } catch (err) {
          console.log('Failed to load plugin info: ', pluginRoot);
        }
      });

  return plugins;
}

const getInstalledPlugins = listInstalledPlugins;

function getAllPlugins() {
  if (!loaded) {
    // load built-in plugins
    fs.readdirSync(path.join(__dirname, '../plugins')).forEach(d => {
      d = path.join(__dirname, '../plugins', d);
      if (fs.statSync(d).isDirectory() && fs.existsSync(path.join(d, 'index.js'))) {
        const p = require(d);
        p.root = d;
        addPlugin(p);
      }
    });
    if (fs.existsSync(DEFAULT_PLUGIN_DIR)) loadPlugins(DEFAULT_PLUGIN_DIR);
    // Load plugin from environment variable: REKIT_PLUGIN_DIR , used in plugin dev time
    // This doesn't load UI part, only for cli testing purpose
    if (process.env.REKIT_PLUGIN_DIR) {
      const d = process.env.REKIT_PLUGIN_DIR;
      if (!path.isAbsolute(d))
        throw new Error(`REKIT_PLUGIN_DIR should be absolute path, got: ${d}`);
      addPluginByPath(d, true);
    }
    sortPlugins();
    loaded = true;
  }

  return allPlugins;
}

function installPlugin(name) {
  if (!/^rekit-plugin-/.test(name)) {
    name = 'rekit-plugin-' + name;
  }
  logger.info('Installing plugin: ' + name);
  const destDir = paths.configFile('plugins/' + name);
  if (fs.existsSync(destDir)) {
    logger.info('Plugin already installed, reinstalling it...');
    fs.removeSync(destDir);
  }
  downloadNpmPackage({ arg: name, dir: paths.configFile('plugins') })
    .then(() => {
      const pkgJson = require(path.join(destDir, 'package.json'));
      if (!_.isEmpty(pkgJson.dependencies)) {
        console.log('Plugin downloaded, installing its dependencies...');
        const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
        const child = spawn(npmCmd, ['install', '--colors', '--only=production'], {
          stdio: 'inherit',
          cwd: destDir,
        });
        let failed = false;
        child.on('exit', () => {
          if (!failed) logger.info(`Plugin installed successfully: ${name}@${pkgJson.version}.`);
        });
        child.on('error', err => {
          failed = true;
          logger.error('Failed to install deps of the plugin. Remove plugin.', err);
          fs.removeSync(destDir);
        });
      } else {
        logger.info(`Plugin installed successfully: ${name}@${pkgJson.version}.`);
      }
    })
    .catch(err => {
      logger.error('Failed to download plugin.', err);
    });
}

function uninstallPlugin(name) {
  if (!/^rekit-plugin-/.test(name)) {
    name = 'rekit-plugin-' + name;
  }
  logger.info('Uninstalling plugin: ', name);
  const destDir = paths.configFile('plugins/' + name);
  if (fs.existsSync(destDir)) {
    fs.removeSync(destDir);
    logger.info('Done.');
  } else {
    logger.info('Plugin not exist: ' + name);
  }
}

module.exports = {
  getPlugins,
  getPlugin,
  loadPlugins,
  addPlugin,
  addPluginByPath,
  removePlugin,
  getPluginsDir,
  addPluginsDir,
  installPlugin,
  uninstallPlugin,
  listInstalledPlugins,
  getInstalledPlugins,
  getAllPlugins,
};
<commit_msg>Add logo prop.<commit_after>'use strict';

// Summary:
//  Load plugins

// Set the node_modules of Rekit Studio as the NODE_PATH to find modules.
// So that plugin could use dependencies of Rekit Studio and Rekit Core.
const utils = require('./utils');
const nodeModulesPath = require.resolve('lodash').replace('/lodash/lodash.js', '');
utils.addNodePath(nodeModulesPath);
try {
  // If rekit studio is installed globally, add rekit-studio's deps to NODE_PATH
  const rsPath = require.resolve('rekit-studio/package.json').replace(/[/\\]package\.json$/, '');
  utils.addNodePath(rsPath + '/node_modules');
  utils.addNodePath(rsPath.replace(/[/\\]rekit-studio$/, ''));
} catch (err) {
  // Do nothing if not found rekit studio
}

const fs = require('fs-extra');
const path = require('path');
const spawn = require('child_process').spawn;
const _ = require('lodash');
const os = require('os');
const paths = require('./paths');
const config = require('./config');
const logger = require('./logger');
const downloadNpmPackage = require('download-npm-package');

let appliedPlugins = undefined;
let allPlugins = [];
let loaded = false;
let needFilterPlugin = true;

const DEFAULT_PLUGIN_DIR = path.join(os.homedir(), '.rekit/plugins');

const pluginsDirs = [DEFAULT_PLUGIN_DIR];
function addPluginsDir(dir) {
  pluginsDirs.push(dir);
}
function getPluginsDir() {
  return DEFAULT_PLUGIN_DIR;
}

function getPlugins(prop) {
  getAllPlugins();

  filterPluginsIfNecessary();
  appliedPlugins.forEach(p => {
    if (p.initialize && !p.__initialized) {
      p.initialize();
      p.__initialized = true;
    }
  });
  return prop ? appliedPlugins.filter(_.property(prop)) : appliedPlugins;
}

function sortPlugins() {
  // Sort plugins according dep relations and Rekit config.
  const rekitConfig = config.getRekitConfig();
  const pluginOrder = rekitConfig.pluginOrder || [];

  allPlugins.sort((p1, p2) => {
    const p1Index = pluginOrder.indexOf(p1.name);
    const p2Index = pluginOrder.indexOf(p2.name);
    if (p1.dependencies && p1.dependencies.includes(p2.name)) {
      // If p1 depends on p2, load p2 first
      return 1;
    }
    if (p2.dependencies && p2.dependencies.includes(p1.name)) {
      // If p2 depends on p1, load p1 first
      return -1;
    }
    if (p1Index >= 0 && p2Index === -1) {
      // If only p1 configed, load it first
      return -1;
    }
    if (p2Index >= 0 && p1Index === -1) {
      // If only p2 configed, load it first
      return 1;
    }
    if (p1Index >= 0 && p2Index >= 0) {
      // If both configed, load before first
      return p1Index - p2Index;
    }
    // No order specified.
    return 0;
  });
}

function filterPluginsIfNecessary() {
  initPluginsIfNecessary();
  if (!needFilterPlugin) return;
  const rekitConfig = config.getRekitConfig();

  // A plugin could decide if it's fit for the current project by feature files
  logger.info('All plugins:', allPlugins.map(p => p.name));
  const appType = rekitConfig.appType;
  appliedPlugins = allPlugins.filter(
    p =>
      (!p.shouldUse || p.shouldUse(paths.getProjectRoot())) &&
      (!p.appType || _.castArray(p.appType).includes(appType)) &&
      !(rekitConfig.excludePlugins || []).map(s => s.replace('rekit-plugin', '')).includes(p.name),
  );
  logger.info('Applied plugins for appType ' + appType + ': ', appliedPlugins.map(p => p.name));
  needFilterPlugin = false;
}

function initPluginsIfNecessary() {
  allPlugins = allPlugins.map(plugin => {
    if (!plugin.inherit) return plugin;
    const newPlugin = { uiInherit: [] };
    _.castArray(plugin.inherit).forEach(name => {
      // currently only one level inherit supported?
      const p = getPlugin(name);
      if (!p) {
        throw new Error('INHERIT_PLUGIN_NOT_FOUND: ' + name + ' inherited by ' + plugin.name);
      }
      newPlugin.uiInherit.push(name);
      _.merge(newPlugin, p);
    });
    _.merge(newPlugin, plugin);
    newPlugin.__originalInherit = plugin.inherit;
    delete newPlugin.inherit; // only inherit once
    return newPlugin;
  });
}

function getPlugin(name) {
  return _.find(allPlugins, { name }) || null;
}

// Load plugin instance, plugin depends on project config
function loadPlugin(pluginRoot, noUI) {
  // noUI flag is used for loading dev plugins whose ui is from webpack dev server
  try {
    // const pkgJson = require(paths.join(pluginRoot, 'package.json'));
    const pluginInstance = { root: pluginRoot };
    // Core part
    const coreIndex = paths.join(pluginRoot, 'core/index.js');
    if (fs.existsSync(coreIndex)) {
      Object.assign(pluginInstance, require(coreIndex));
    }

    if (fs.existsSync(path.join(pluginRoot, 'logo.png'))) {
      pluginInstance.logo = path.join(pluginRoot, 'logo.png');
    }

    // UI part
    if (!noUI) {
      let entry = 'main.js';
      if (
        process.env.NODE_ENV === 'development' &&
        fs.existsSync(path.join(pluginRoot, 'build', 'main-dev.js'))
      ) {
        entry = 'main-dev.js';
      }
      if (fs.existsSync(path.join(pluginRoot, 'build', entry))) {
        pluginInstance.ui = {
          root: path.join(pluginRoot, 'build'),
          entry,
        };
      }
    }

    // Plugin meta defined in package.json
    const pkgJsonPath = path.join(pluginRoot, 'package.json');
    let pkgJson = null;
    if (fs.existsSync(pkgJsonPath)) {
      pkgJson = fs.readJsonSync(pkgJsonPath);

      ['appType', 'name', 'version', 'description', 'author', 'homepage', 'repository'].forEach(key => {
        if (!pluginInstance.hasOwnProperty(key) && pkgJson.hasOwnProperty(key)) {
          if (key === 'name') {
            let name = pkgJson.name;
            if (name.startsWith('rekit-plugin')) name = name.replace('rekit-plugin-', '');
            pluginInstance.name = name;
          } else {
            pluginInstance[key] = pkgJson[key] || null;
          }
        }
      });
      if (pkgJson.rekitPlugin) {
        Object.keys(pkgJson.rekitPlugin).forEach(key => {
          if (!pluginInstance.hasOwnProperty(key)) {
            pluginInstance[key] = pkgJson.rekitPlugin[key];
          }
        });
      }
    }
    if (!pluginInstance.version) pluginInstance.version = '0.0.1';
    return pluginInstance;
  } catch (e) {
    logger.warn(`Failed to load plugin: ${pluginRoot}`, e);
  }

  return null;
}

function loadPlugins(dir) {
  // At rekit studio dev time, do not load dist plugins from dir.
  // Because Rekit Studio doesn't support it at dev time.
  if (process.env.REKIT_STUDIO_DEVELOPMENT) return;
  fs.readdirSync(dir)
    .map(d => path.join(dir, d))
    .filter(d => fs.statSync(d).isDirectory())
    .forEach(d => addPluginByPath(d));
}

// Dynamically add an plugin
function addPlugin(plugin) {
  if (!plugin) {
    return;
  }
  if (!needFilterPlugin) {
    console.warn('You are adding a plugin after getPlugins is called.');
  }
  if (!plugin.getModule) {
    plugin.getModule = mid => {
      try {
        return require(path.join(plugin.root, mid));
      } catch (err) {
        logger.debug('Faied to load module: ' + mid, err);
        return null;
      }
    };
  }
  needFilterPlugin = true;
  if (!plugin.name) {
    logger.info('plugin: ', plugin);
    throw new Error('Each plugin should have a name.');
  }
  if (_.find(allPlugins, { name: plugin.name })) {
    console.warn('You should not add a plugin with same name: ' + plugin.name);
    return;
  }
  allPlugins.push(plugin);
}

function addPluginByPath(pluginRoot, noUI) {
  addPlugin(loadPlugin(pluginRoot, noUI));
}

function removePlugin(pluginName) {
  const removed = _.remove(allPlugins, { name: pluginName });
  needFilterPlugin = true;
  if (!removed.length) console.warn('No plugin was removed: ' + pluginName);
}

function listInstalledPlugins() {
  // Only get plugins from standard rekit plugin folder
  const dir = paths.configFile('plugins2');
  const plugins = [];

  if (fs.existsSync(dir))
    fs.readdirSync(dir)
      .filter(name => /^rekit-plugin-/.test(name))
      .map(name => path.join(dir, name))
      .filter(d => fs.statSync(d).isDirectory())
      .forEach(pluginRoot => {
        try {
          const pkgJson = require(paths.join(pluginRoot, 'package.json'));
          // Plugin info
          const pluginInfo = {};
          Object.assign(pluginInfo, pkgJson);

          plugins.push(pluginInfo);
        } catch (err) {
          console.log('Failed to load plugin info: ', pluginRoot);
        }
      });

  return plugins;
}

const getInstalledPlugins = listInstalledPlugins;

function getAllPlugins() {
  if (!loaded) {
    // load built-in plugins
    fs.readdirSync(path.join(__dirname, '../plugins')).forEach(d => {
      d = path.join(__dirname, '../plugins', d);
      if (fs.statSync(d).isDirectory() && fs.existsSync(path.join(d, 'index.js'))) {
        const p = require(d);
        p.root = d;
        addPlugin(p);
      }
    });
    if (fs.existsSync(DEFAULT_PLUGIN_DIR)) loadPlugins(DEFAULT_PLUGIN_DIR);
    // Load plugin from environment variable: REKIT_PLUGIN_DIR , used in plugin dev time
    // This doesn't load UI part, only for cli testing purpose
    if (process.env.REKIT_PLUGIN_DIR) {
      const d = process.env.REKIT_PLUGIN_DIR;
      if (!path.isAbsolute(d))
        throw new Error(`REKIT_PLUGIN_DIR should be absolute path, got: ${d}`);
      addPluginByPath(d, true);
    }
    sortPlugins();
    loaded = true;
  }

  return allPlugins;
}

function installPlugin(name) {
  if (!/^rekit-plugin-/.test(name)) {
    name = 'rekit-plugin-' + name;
  }
  logger.info('Installing plugin: ' + name);
  const destDir = paths.configFile('plugins/' + name);
  if (fs.existsSync(destDir)) {
    logger.info('Plugin already installed, reinstalling it...');
    fs.removeSync(destDir);
  }
  downloadNpmPackage({ arg: name, dir: paths.configFile('plugins') })
    .then(() => {
      const pkgJson = require(path.join(destDir, 'package.json'));
      if (!_.isEmpty(pkgJson.dependencies)) {
        console.log('Plugin downloaded, installing its dependencies...');
        const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
        const child = spawn(npmCmd, ['install', '--colors', '--only=production'], {
          stdio: 'inherit',
          cwd: destDir,
        });
        let failed = false;
        child.on('exit', () => {
          if (!failed) logger.info(`Plugin installed successfully: ${name}@${pkgJson.version}.`);
        });
        child.on('error', err => {
          failed = true;
          logger.error('Failed to install deps of the plugin. Remove plugin.', err);
          fs.removeSync(destDir);
        });
      } else {
        logger.info(`Plugin installed successfully: ${name}@${pkgJson.version}.`);
      }
    })
    .catch(err => {
      logger.error('Failed to download plugin.', err);
    });
}

function uninstallPlugin(name) {
  if (!/^rekit-plugin-/.test(name)) {
    name = 'rekit-plugin-' + name;
  }
  logger.info('Uninstalling plugin: ', name);
  const destDir = paths.configFile('plugins/' + name);
  if (fs.existsSync(destDir)) {
    fs.removeSync(destDir);
    logger.info('Done.');
  } else {
    logger.info('Plugin not exist: ' + name);
  }
}

module.exports = {
  getPlugins,
  getPlugin,
  loadPlugins,
  addPlugin,
  addPluginByPath,
  removePlugin,
  getPluginsDir,
  addPluginsDir,
  installPlugin,
  uninstallPlugin,
  listInstalledPlugins,
  getInstalledPlugins,
  getAllPlugins,
};
<|endoftext|>


<commit_before>/* eslint-env mocha */

const { expect } = require('chai')
const Specla = require('specla')

describe('Specla.setupDefaultPort', () => {
  it('Should set the default port to 3000', () => {
    const { app } = new Specla({})
    expect(app.settings.port).to.be.equal(3000)
  })

  it('Should overwrite the default port with the config', () => {
    const { app } = new Specla({
      port: 8080
    })
    expect(app.settings.port).to.be.equal(8080)
  })
})
<commit_msg>Fixed path to specla<commit_after>/* eslint-env mocha */

const { expect } = require('chai')
const Specla = require('../lib/Specla')

describe('Specla.setupDefaultPort', () => {
  it('Should set the default port to 3000', () => {
    const { app } = new Specla({})
    expect(app.settings.port).to.be.equal(3000)
  })

  it('Should overwrite the default port with the config', () => {
    const { app } = new Specla({
      port: 8080
    })
    expect(app.settings.port).to.be.equal(8080)
  })
})
<|endoftext|>


<commit_before>'use strict';

var assertionUrl = 'http://localhost:8000/persona'

$(document).ready(function(){
	var loggedInUser = null;

	function logout(){
		loggedInUser = null;
		var response = $.post(assertionUrl + '/logout');
		response.always(showPersona);
	}

	function verify(assertion){
		var response = $.post(assertionUrl + '/verify', {assertion: assertion});
		response.done(login);
		response.fail(navigator.id.logout);
	}

	function login(data){
		showCommentForm(data.email);
	}

	navigator.id.watch({
		loggedInUser: loggedInUser,
		onlogin: verify,
		onlogout: logout
	});

	function showPersona(){
		$('#comment').html('
To comment, please sign in — you can use an existing email address.

');
		$('.signinButton').click(function(){ navigator.id.request(); }).css('cursor', 'pointer');
	}

	function showCommentForm(email){
		$('#comment').html('
Commenting as ' + email + ' (Not your email address?)
<form class="commentForm"><fieldset></fieldset>
<textarea name="comment" id="commentField" required class="input-xxlarge"></textarea>

<button class="btn btn-primary" id="postComment">Comment</button>
</form>');
		$('.commentForm').submit(function(e){
			var response = $.post('/post/comment', {comment: $('#commentField').val()});
			response.done(showConfirmation);
			response.fail(showError);
			e.preventDefault();
		});
		$('.signoutButton').click(function(){ navigator.id.logout(); });
	}

	function showConfirmation(){
		$('#comment').html('Your comment has been submitted. Thank you!');
	}

	function showError(){
		$('#comment').prepend('
<button type="button" class="close" data-dismiss="alert">×</button>Something went wrong saving your comment, did you fill in all the fields?
');
	}

	showPersona();
});
<commit_msg>Include cookies with post requests cross-origin.<commit_after>'use strict';

var assertionUrl = 'http://localhost:8000/persona';
var postCommentUrl = 'http://localhost:8000/post/comment';

$(document).ready(function(){
	var loggedInUser = null;

	function logout(){
		loggedInUser = null;
		var response = $.post(assertionUrl + '/logout');
		response.always(showPersona);
	}

	function verify(assertion){
		var response = $.ajax(assertionUrl + '/verify', {data: {assertion: assertion}, type: 'POST', xhrFields: {withCredentials: true}});
		response.done(login);
		response.fail(function(){
			navigator.id.logout();
		});
	}

	function login(data){
		showCommentForm(data.email);
	}

	navigator.id.watch({
		loggedInUser: loggedInUser,
		onlogin: verify,
		onlogout: logout
	});

	function showPersona(){
		$('#comment').html('
To comment, please sign in — you can use an existing email address.

');
		$('.signinButton').click(function(){ navigator.id.request(); }).css('cursor', 'pointer');
	}

	function showCommentForm(email){
		$('#comment').html('
Commenting as ' + email + ' (Not your email address?)
<form class="commentForm"><fieldset></fieldset>
<textarea name="comment" id="commentField" required class="input-xxlarge"></textarea>

<button class="btn btn-primary" id="postComment">Comment</button>
</form>');
		$('.commentForm').submit(function(e){
			var response = $.ajax(postCommentUrl, {data: {comment: $('#commentField').val()}, type: 'POST', xhrFields: {withCredentials: true}});
			response.done(showConfirmation);
			response.fail(showError);
			e.preventDefault();
		});
		$('.signoutButton').click(function(){ navigator.id.logout(); });
	}

	function showConfirmation(){
		$('#comment').html('Your comment has been submitted. Thank you!');
	}

	function showError(){
		$('#comment').prepend('
<button type="button" class="close" data-dismiss="alert">×</button>Something went wrong saving your comment, did you fill in all the fields?
');
	}

	showPersona();
});
<|endoftext|>


<commit_before>import loggerCreator from "app/utils/logger";
//noinspection JSUnresolvedVariable
var moduleLogger = loggerCreator("NavSidebar");

import React, { Component } from "react";
import { StyleSheet, View, Platform, Animated } from "react-native";
import { autorun } from "mobx";
import { observer } from "mobx-react";

import { masterStore } from "app/stores/master_store";
import { colors } from "app/styles/styles";
import NavSidebarMenuItem from "./nav_sidebar_menu_item";
import NavSidebarMenuTitle from "./nav_sidebar_menu_title";
import BackHandler from "app/utils/back_handler/back_handler";
import { player } from "app/stores/player/player";

import playIcon from "app/images/play.png";
import pencilIcon from "app/images/pencil-icon.png";
import { playlistsStore } from "app/stores/playlists_store";
import { navigator } from "app/stores/navigator.js";

const WIDTH = 336;
const OPEN_LEFT = -2;
const CLOSED_LEFT = OPEN_LEFT - WIDTH;

const styles = StyleSheet.create({
  sidebar: {
    position: "absolute",
    backgroundColor: colors.CONTAINER_BACKGROUND_NORMAL,
    top: 54,
    bottom: -1,
    width: WIDTH,
    borderColor: colors.CYAN_BRIGHT,
    borderStyle: "solid",
    borderWidth: 1,
    borderTopRightRadius: 5,
  },
});

@observer
export default class NavSidebar extends Component {
  componentWillMount() {
    this.state = {
      leftAnimation: new Animated.Value(masterStore.isNavigationSidebarOpen ? OPEN_LEFT : CLOSED_LEFT),
    };

    this.autorunDisposer = autorun(() => {
      const logger = loggerCreator("autorun", moduleLogger);
      logger.info(`new value of isNavigationSidebarOpen: ${masterStore.isNavigationSidebarOpen}`);
      this.onSidebarToggled(masterStore.isNavigationSidebarOpen);
    });
  }

  componentWillUnmount() {
    this.autorunDisposer();
  }

  onSidebarToggled(isOpen) {
    Animated.timing(this.state.leftAnimation, {
      toValue: isOpen ? OPEN_LEFT : CLOSED_LEFT,
      duration: 200,
    }).start();
  }

  onPlaylistPress = async playlistName => {
    await player.changePlaylist(playlistName);
    player.play();
    navigator.navigateToPlayer();
    masterStore.closeSidebars();
  };

  onPlaylistEditPress = playlist => {
    masterStore.closeSidebars();
    navigator.navigateToSearch(playlist.query, playlist.name);
  };

  onPlayerPress = () => {
    masterStore.closeSidebars();
    navigator.navigateToPlayer();
  };

  onSearchPress = () => {
    masterStore.closeSidebars();
    navigator.navigateToSearch();
  };

  onSettingsPress = () => {
    masterStore.closeSidebars();
    navigator.navigateToSettings();
  };

  onExitPress = () => {
    loggerCreator("onExitPress", moduleLogger);

    player.stop();
    BackHandler.exitApp();
  };

  render() {
    loggerCreator(this.render.name, moduleLogger);

    return (
      <Animated.View style={[styles.sidebar, { left: this.state.leftAnimation }]}>
        <NavSidebarMenuTitle text="Radio Stream" />
        <NavSidebarMenuItem text="Player" leftImage={playIcon} onPress={this.onPlayerPress} />
        <NavSidebarMenuItem text="Search" leftImage={playIcon} onPress={this.onSearchPress} />
        <NavSidebarMenuItem text="Settings" leftImage={playIcon} onPress={this.onSettingsPress} />
        {Platform.OS !== "web"
          ? <NavSidebarMenuItem text="Exit" leftImage={playIcon} onPress={this.onExitPress} />
          : null}
        <NavSidebarMenuTitle text="Playlists" />
        {playlistsStore.playlists.map(playlist =>
          <NavSidebarMenuItem
            key={playlist.name}
            text={playlist.name}
            leftImage={playIcon}
            rightImage={pencilIcon}
            onPress={() => this.onPlaylistPress(playlist.name)}
            onRightImagePress={() => this.onPlaylistEditPress(playlist)}
          />
        )}
      </Animated.View>
    );
  }
}

NavSidebar.propTypes = {};
<commit_msg>navmenu - using PanResponder<commit_after>import loggerCreator from "app/utils/logger";
//noinspection JSUnresolvedVariable
var moduleLogger = loggerCreator("NavSidebar");

import React, { Component } from "react";
import { StyleSheet, View, Platform, Animated, PanResponder } from "react-native";
import { autorun } from "mobx";
import { observer } from "mobx-react";

import { masterStore } from "app/stores/master_store";
import { colors } from "app/styles/styles";
import NavSidebarMenuItem from "./nav_sidebar_menu_item";
import NavSidebarMenuTitle from "./nav_sidebar_menu_title";
import BackHandler from "app/utils/back_handler/back_handler";
import { player } from "app/stores/player/player";

import playIcon from "app/images/play.png";
import pencilIcon from "app/images/pencil-icon.png";
import { playlistsStore } from "app/stores/playlists_store";
import { navigator } from "app/stores/navigator.js";

const WIDTH = 336;
const OPEN_LEFT = -2;
const CLOSED_LEFT = OPEN_LEFT - WIDTH;

const styles = StyleSheet.create({
  sidebar: {
    position: "absolute",
    backgroundColor: colors.CONTAINER_BACKGROUND_NORMAL,
    top: 54,
    bottom: -1,
    width: WIDTH,
    borderColor: colors.CYAN_BRIGHT,
    borderStyle: "solid",
    borderWidth: 1,
    borderTopRightRadius: 5,
  },
});

@observer
export default class NavSidebar extends Component {
  componentWillMount() {
    this.state = {
      leftAnimation: new Animated.Value(masterStore.isNavigationSidebarOpen ? OPEN_LEFT : CLOSED_LEFT),
    };

    this.autorunDisposer = autorun(() => {
      const logger = loggerCreator("autorun", moduleLogger);
      logger.info(`new value of isNavigationSidebarOpen: ${masterStore.isNavigationSidebarOpen}`);
      this.toggleSidebar(masterStore.isNavigationSidebarOpen);
    });

    this.panResponder = PanResponder.create({
      onMoveShouldSetPanResponder: (evt, gestureState) => {
        loggerCreator("onMoveShouldSetPanResponder", moduleLogger);
        return gestureState.numberActiveTouches > 0 && Math.abs(gestureState.dx) > 10;
      },
      onPanResponderGrant: () => {
        loggerCreator("onPanResponderGrant", moduleLogger);
        this.state.leftAnimation.setOffset(this.state.leftAnimation._value);
        this.state.leftAnimation.setValue(0);
      },
      onPanResponderMove: Animated.event([null, { dx: this.state.leftAnimation }]),
      onPanResponderRelease: (evt, gestureState) => {
        loggerCreator("onPanResponderRelease", moduleLogger);

        this.state.leftAnimation.flattenOffset();
        masterStore.isNavigationSidebarOpen = gestureState.vx > 0;
      },
    });
  }

  componentWillUnmount() {
    this.autorunDisposer();
  }

  toggleSidebar(isOpen) {
    Animated.timing(this.state.leftAnimation, {
      toValue: isOpen ? OPEN_LEFT : CLOSED_LEFT,
      duration: 200,
    }).start();
  }

  onPlaylistPress = async playlistName => {
    await player.changePlaylist(playlistName);
    player.play();
    navigator.navigateToPlayer();
    masterStore.closeSidebars();
  };

  onPlaylistEditPress = playlist => {
    masterStore.closeSidebars();
    navigator.navigateToSearch(playlist.query, playlist.name);
  };

  onPlayerPress = () => {
    masterStore.closeSidebars();
    navigator.navigateToPlayer();
  };

  onSearchPress = () => {
    masterStore.closeSidebars();
    navigator.navigateToSearch();
  };

  onSettingsPress = () => {
    masterStore.closeSidebars();
    navigator.navigateToSettings();
  };

  onExitPress = () => {
    loggerCreator("onExitPress", moduleLogger);

    player.stop();
    BackHandler.exitApp();
  };

  render() {
    loggerCreator(this.render.name, moduleLogger);

    return (
      <Animated.View
        style={[
          styles.sidebar,
          {
            left: this.state.leftAnimation.interpolate({
              inputRange: [CLOSED_LEFT, OPEN_LEFT],
              outputRange: [CLOSED_LEFT, OPEN_LEFT],
              extrapolate: "clamp",
            }),
          },
        ]}
        {...this.panResponder.panHandlers}>
        <NavSidebarMenuTitle text="Radio Stream" />
        <NavSidebarMenuItem text="Player" leftImage={playIcon} onPress={this.onPlayerPress} />
        <NavSidebarMenuItem text="Search" leftImage={playIcon} onPress={this.onSearchPress} />
        <NavSidebarMenuItem text="Settings" leftImage={playIcon} onPress={this.onSettingsPress} />
        {Platform.OS !== "web"
          ? <NavSidebarMenuItem text="Exit" leftImage={playIcon} onPress={this.onExitPress} />
          : null}
        <NavSidebarMenuTitle text="Playlists" />
        {playlistsStore.playlists.map(playlist =>
          <NavSidebarMenuItem
            key={playlist.name}
            text={playlist.name}
            leftImage={playIcon}
            rightImage={pencilIcon}
            onPress={() => this.onPlaylistPress(playlist.name)}
            onRightImagePress={() => this.onPlaylistEditPress(playlist)}
          />
        )}
      </Animated.View>
    );
  }
}

NavSidebar.propTypes = {};
<|endoftext|>