<commit_before>var express = require('express'),
    path    = require('path'),
    exec    = require('child_process').exec,
    i18n    = require('i18n-abide'),
    _       = require('underscore'),
    backboneio = require('backbone.io'),
    mbc = require('mbc-common'),
    conf = mbc.config.Caspa,
    search_options = mbc.config.Search,
    collections = mbc.config.Common.Collections,
    moment = require('moment'),
    App = require("mbc-common/models/App"),
    maxage = 365 * 24 * 60 * 60 * 1000
 ;

/* make sure at runtime that we atempt to get the dirs we need */
for (d in conf.Dirs) {
    /* HACK: but I'm not going to waist time writing mkdir -p */
    exec ('mkdir -p ' + conf.Dirs[d], function (error, stdout, stderr) {
        if (error !== null) {
            console.log('exec error: ' + error);
        }
    });
}

var app = express();

app.configure(function () {
    app.use(i18n.abide({
        supported_languages: ['en-US', 'es', 'db-LB', 'it-CH'],
        default_lang: 'es',
        debug_lang: 'it-CH',
        translation_directory: 'locale'
    }));
    app.set('port', process.env.PORT || 3000);
    app.set('views', conf.Dirs.views);
    app.set('view engine', 'jade');
    app.use(express.logger('dev'));
    app.use(express.compress());
/*    app.use('/uploads', upload({
        tmpDir:    conf.Dirs.uploads + '/incoming',
        uploadDir: conf.Dirs.upolads,
        uploadUrl: '/uploads/',
        safeFileTypes: /\.(webm|mkv|mov|mp4|avi|ogg)$/i,
    }));*/
    app.use(express.bodyParser({
            uploadDir: conf.Dirs.uploads,
            maxFieldsSize: 10 * 1024 * 1024
    }));
    app.use(express.methodOverride());
    app.use(express.cookieParser('your secret here'));
    app.use(express.session());
    app.use(app.router);
    app.use(require('less-middleware')({
        src:  conf.Dirs.styles,
        dest: conf.Dirs.pub,
        compress: true}
    ));
    app.use(express.static(conf.Dirs.pub, {maxAge: maxage}));
    app.use('/models', express.static(conf.Dirs.models, {maxAge: maxage}));
    app.use('/lib',    express.static(conf.Dirs.vendor, {maxAge: maxage}));
});

app.configure('development', function(){
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
  app.set('io.loglevel', 100);
  app.set('minify', false);
});

app.configure('production', function(){
  app.use(express.errorHandler());
  app.set('io.loglevel', 1);
  app.set('minify', true);
});

var appModel = require('./routes')(app);
var media = require('./routes/media')(app);

function debug_backend (backend) {
        console.log ('Debugging backend: ', backend);
        backend.use(function(req, res, next) {
                console.log(req.backend);
                console.log(req.method);
                console.log(JSON.stringify(req.model));
                next();
        });
}

var db = mbc.db();

var publisher = mbc.pubsub();
var listener = mbc.pubsub();

// Override mongoStore read method with custom
var searchWrapper = require('./searchWrapper.js');

var mediabackend = backboneio.createBackend();
mediabackend.use(searchWrapper(backboneio.middleware.mongoStore(db, collections.Medias, { search: search_options.Medias })));

var piecebackend = backboneio.createBackend();
piecebackend.use(searchWrapper(backboneio.middleware.mongoStore(db, collections.Pieces, { search: search_options.Pieces })));

var transformbackend = backboneio.createBackend();
transformbackend.use(searchWrapper(backboneio.middleware.mongoStore(db, collections.Transforms, { search: search_options.Transforms })));

var listbackend = backboneio.createBackend();
listbackend.use(searchWrapper(backboneio.middleware.mongoStore (db, collections.Lists, { search: search_options.Lists })));

function id_middleware(req, res, next) {
    if( req.method == 'create' && req.model._id === undefined) {
        req.model._id = moment().valueOf().toString();
    }
    next();
}

var schedbackend = backboneio.createBackend();
schedbackend.use(id_middleware);
schedbackend.use(function (req, res, next) {
    console.log ("schedbackend handler", req);
    publisher.publishJSON([req.backend, req.method].join('.'), { model: req.model });
    next();
});
schedbackend.use(searchWrapper(backboneio.middleware.mongoStore(db, collections.Scheds, { search: search_options.Scheds })));

var statusbackend = backboneio.createBackend();
listener.on('JSONmessage', function(chan, status) {

    if( chan != "mostoStatus" ) // we can ignore this message
        return;

    // This receives messages from mosto and propagates the message through
    //  backbone.io
    var emit = _.after(6, function() {
        console.log('emitting', status);
        statusbackend.emit('updated', status)
    });
    ['previous', 'current', 'next'].forEach(function(pos) {
        db.collection(collections.Scheds).findEach({ _id: status.show[pos]._id }, function(err, res) {
            if( res ) {
                status.show[pos] = {
                    name: res.title,
                    _id: res._id,
                };
            }
            emit();
        });
        //db.collection('lists').findEach({ "models._id": status.piece[pos]._id }, function(err, res) {
        db.collection(collections.Pieces).findById(status.piece[pos]._id, function(err, piece) {
            if( err ) {
                // we still want to call emit() even if there was a DB error
                console.error(err);
            }

            if( piece ) {
                /*
                var piece = _.chain(res.models).filter(function(p) {
                    return p._id == status.piece[pos]._id;
                }).value();
                console.log("[mosto status] filtered pieces", piece)
                if( !piece ) {
                    var message = "[mosto status] error: this shouldn't be empty";
                    console.log(message);
                    return new Error(message);
                }
                if( piece.length != 1 ) {
                    var message = "[mosto status] error: there must only be one!";
                    console.log(message)
                    return new Error(message);
                }

                piece = piece[0];
                */
                status.piece[pos] = piece;
                // default name to id
                if( !status.piece[pos].name ) {
                    var file = piece.file;
                    status.piece[pos].name = path.basename(file).replace(path.extname(file), '');
                }
            }
            emit();
        });
    });
});
listener.subscribe('mostoStatus');
statusbackend.use(backboneio.middleware.mongoStore(db, collections.Status, { search: search_options.Status }));

var framebackend = backboneio.createBackend();
listener.on('JSONmessage', function(chan, msg) {
    if( !(chan == 'mostoStatus.progress' ) )
        return;

    var status = new App.ProgressStatus(msg);
    framebackend.emit('updated', status);
});
listener.subscribe('mostoStatus.progress');
framebackend.use(backboneio.middleware.memoryStore(db, 'progress', {}));

var appbackend = backboneio.createBackend();
appbackend.use(backboneio.middleware.configStore());

// there should probably be two backends or two collections or both, or something, one for
// one-time momentary messages like warnings and such to be dismissed by the frontend,
// and another one for "sticky" messages like long-lived status problems, like if melted died
// or the DB has a problem
var mostomessagesbackend = backboneio.createBackend();
listener.on('JSONpmessage', function(pattern, chan, msg) {
    switch( chan ) {
        case "mostoMessage.emit":
            return mostomessagesbackend.emit('created', msg.model);
        case "mostoMessage.create":
            return mostomessagesbackend.emit('created', msg.model);
        case "mostoMessage.delete":
            return mostomessagesbackend.emit('deleted', msg.model);
    }
});
listener.psubscribe('mostoMessage*');
mostomessagesbackend.use(backboneio.middleware.mongoStore(db, collections.Mostomessages, { search: search_options.Mostomessages }));

_([mediabackend, listbackend, appbackend, piecebackend, transformbackend]).each (debug_backend);

var io = backboneio.listen(app.listen(app.get('port'), function(){
    console.log("Express server listening on port %d in %s mode", app.get('port'), app.settings.env);
}), { mediabackend: mediabackend,
      piecebackend: piecebackend,
      transformbackend: transformbackend,
      listbackend:  listbackend,
      schedbackend: schedbackend,
      statusbackend: statusbackend,
      framebackend: framebackend,
      appbackend: appbackend
    });

io.configure('production', function(){
    io.enable('browser client minification');  // send minified client
    io.enable('browser client etag');          // apply etag caching logic based on version number
    io.enable('browser client gzip');          // gzip the file
});

var utils = require('./utils');

if (process.env.MBC_SCRAPE) {
    setTimeout(function () {
        utils.scrape_files (conf.Dirs.scrape, function (model) {
            db.collection('medias').insert(model, {safe:true}, function(err, result) {
                if (err) {
                    console.error ('error','An error has occurred' + err);
                } else {
                    mediabackend.emit('created', model);
                }
            });
        });
    }, 300);
} else {
    console.log ("not scrapping");
}
<commit_msg>Use connect session middleware to avoid memory store warning:<commit_after>var express = require('express'),
    path    = require('path'),
    exec    = require('child_process').exec,
    i18n    = require('i18n-abide'),
    _       = require('underscore'),
    backboneio = require('backbone.io'),
    mbc = require('mbc-common'),
    conf = mbc.config.Caspa,
    search_options = mbc.config.Search,
    collections = mbc.config.Common.Collections,
    moment = require('moment'),
    App = require("mbc-common/models/App"),
    maxage = 365 * 24 * 60 * 60 * 1000
 ;

/* make sure at runtime that we atempt to get the dirs we need */
for (d in conf.Dirs) {
    /* HACK: but I'm not going to waist time writing mkdir -p */
    exec ('mkdir -p ' + conf.Dirs[d], function (error, stdout, stderr) {
        if (error !== null) {
            console.log('exec error: ' + error);
        }
    });
}

var app = express();

app.configure(function () {
    app.use(i18n.abide({
        supported_languages: ['en-US', 'es', 'db-LB', 'it-CH'],
        default_lang: 'es',
        debug_lang: 'it-CH',
        translation_directory: 'locale'
    }));
    app.set('port', process.env.PORT || 3000);
    app.set('views', conf.Dirs.views);
    app.set('view engine', 'jade');
    app.use(express.logger('dev'));
    app.use(express.compress());
/*    app.use('/uploads', upload({
        tmpDir:    conf.Dirs.uploads + '/incoming',
        uploadDir: conf.Dirs.upolads,
        uploadUrl: '/uploads/',
        safeFileTypes: /\.(webm|mkv|mov|mp4|avi|ogg)$/i,
    }));*/
    app.use(express.bodyParser({
            uploadDir: conf.Dirs.uploads,
            maxFieldsSize: 10 * 1024 * 1024
    }));
    app.use(express.methodOverride());
    app.use(express.cookieParser());
    app.use(express.cookieSession({ secret: 'your secret here', cookie: { maxAge: maxage }}));
    app.use(app.router);
    app.use(require('less-middleware')({
        src:  conf.Dirs.styles,
        dest: conf.Dirs.pub,
        compress: true}
    ));
    app.use(express.static(conf.Dirs.pub, {maxAge: maxage}));
    app.use('/models', express.static(conf.Dirs.models, {maxAge: maxage}));
    app.use('/lib',    express.static(conf.Dirs.vendor, {maxAge: maxage}));
});

app.configure('development', function(){
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
  app.set('io.loglevel', 100);
  app.set('minify', false);
});

app.configure('production', function(){
  app.use(express.errorHandler());
  app.set('io.loglevel', 1);
  app.set('minify', true);
});

var appModel = require('./routes')(app);
var media = require('./routes/media')(app);

function debug_backend (backend) {
        console.log ('Debugging backend: ', backend);
        backend.use(function(req, res, next) {
                console.log(req.backend);
                console.log(req.method);
                console.log(JSON.stringify(req.model));
                next();
        });
}

var db = mbc.db();

var publisher = mbc.pubsub();
var listener = mbc.pubsub();

// Override mongoStore read method with custom
var searchWrapper = require('./searchWrapper.js');

var mediabackend = backboneio.createBackend();
mediabackend.use(searchWrapper(backboneio.middleware.mongoStore(db, collections.Medias, { search: search_options.Medias })));

var piecebackend = backboneio.createBackend();
piecebackend.use(searchWrapper(backboneio.middleware.mongoStore(db, collections.Pieces, { search: search_options.Pieces })));

var transformbackend = backboneio.createBackend();
transformbackend.use(searchWrapper(backboneio.middleware.mongoStore(db, collections.Transforms, { search: search_options.Transforms })));

var listbackend = backboneio.createBackend();
listbackend.use(searchWrapper(backboneio.middleware.mongoStore (db, collections.Lists, { search: search_options.Lists })));

function id_middleware(req, res, next) {
    if( req.method == 'create' && req.model._id === undefined) {
        req.model._id = moment().valueOf().toString();
    }
    next();
}

var schedbackend = backboneio.createBackend();
schedbackend.use(id_middleware);
schedbackend.use(function (req, res, next) {
    console.log ("schedbackend handler", req);
    publisher.publishJSON([req.backend, req.method].join('.'), { model: req.model });
    next();
});
schedbackend.use(searchWrapper(backboneio.middleware.mongoStore(db, collections.Scheds, { search: search_options.Scheds })));

var statusbackend = backboneio.createBackend();
listener.on('JSONmessage', function(chan, status) {

    if( chan != "mostoStatus" ) // we can ignore this message
        return;

    // This receives messages from mosto and propagates the message through
    //  backbone.io
    var emit = _.after(6, function() {
        console.log('emitting', status);
        statusbackend.emit('updated', status)
    });
    ['previous', 'current', 'next'].forEach(function(pos) {
        db.collection(collections.Scheds).findEach({ _id: status.show[pos]._id }, function(err, res) {
            if( res ) {
                status.show[pos] = {
                    name: res.title,
                    _id: res._id,
                };
            }
            emit();
        });
        //db.collection('lists').findEach({ "models._id": status.piece[pos]._id }, function(err, res) {
        db.collection(collections.Pieces).findById(status.piece[pos]._id, function(err, piece) {
            if( err ) {
                // we still want to call emit() even if there was a DB error
                console.error(err);
            }

            if( piece ) {
                /*
                var piece = _.chain(res.models).filter(function(p) {
                    return p._id == status.piece[pos]._id;
                }).value();
                console.log("[mosto status] filtered pieces", piece)
                if( !piece ) {
                    var message = "[mosto status] error: this shouldn't be empty";
                    console.log(message);
                    return new Error(message);
                }
                if( piece.length != 1 ) {
                    var message = "[mosto status] error: there must only be one!";
                    console.log(message)
                    return new Error(message);
                }

                piece = piece[0];
                */
                status.piece[pos] = piece;
                // default name to id
                if( !status.piece[pos].name ) {
                    var file = piece.file;
                    status.piece[pos].name = path.basename(file).replace(path.extname(file), '');
                }
            }
            emit();
        });
    });
});
listener.subscribe('mostoStatus');
statusbackend.use(backboneio.middleware.mongoStore(db, collections.Status, { search: search_options.Status }));

var framebackend = backboneio.createBackend();
listener.on('JSONmessage', function(chan, msg) {
    if( !(chan == 'mostoStatus.progress' ) )
        return;

    var status = new App.ProgressStatus(msg);
    framebackend.emit('updated', status);
});
listener.subscribe('mostoStatus.progress');
framebackend.use(backboneio.middleware.memoryStore(db, 'progress', {}));

var appbackend = backboneio.createBackend();
appbackend.use(backboneio.middleware.configStore());

// there should probably be two backends or two collections or both, or something, one for
// one-time momentary messages like warnings and such to be dismissed by the frontend,
// and another one for "sticky" messages like long-lived status problems, like if melted died
// or the DB has a problem
var mostomessagesbackend = backboneio.createBackend();
listener.on('JSONpmessage', function(pattern, chan, msg) {
    switch( chan ) {
        case "mostoMessage.emit":
            return mostomessagesbackend.emit('created', msg.model);
        case "mostoMessage.create":
            return mostomessagesbackend.emit('created', msg.model);
        case "mostoMessage.delete":
            return mostomessagesbackend.emit('deleted', msg.model);
    }
});
listener.psubscribe('mostoMessage*');
mostomessagesbackend.use(backboneio.middleware.mongoStore(db, collections.Mostomessages, { search: search_options.Mostomessages }));

_([mediabackend, listbackend, appbackend, piecebackend, transformbackend]).each (debug_backend);

var io = backboneio.listen(app.listen(app.get('port'), function(){
    console.log("Express server listening on port %d in %s mode", app.get('port'), app.settings.env);
}), { mediabackend: mediabackend,
      piecebackend: piecebackend,
      transformbackend: transformbackend,
      listbackend:  listbackend,
      schedbackend: schedbackend,
      statusbackend: statusbackend,
      framebackend: framebackend,
      appbackend: appbackend
    });

io.configure('production', function(){
    io.enable('browser client minification');  // send minified client
    io.enable('browser client etag');          // apply etag caching logic based on version number
    io.enable('browser client gzip');          // gzip the file
});

var utils = require('./utils');

if (process.env.MBC_SCRAPE) {
    setTimeout(function () {
        utils.scrape_files (conf.Dirs.scrape, function (model) {
            db.collection('medias').insert(model, {safe:true}, function(err, result) {
                if (err) {
                    console.error ('error','An error has occurred' + err);
                } else {
                    mediabackend.emit('created', model);
                }
            });
        });
    }, 300);
} else {
    console.log ("not scrapping");
}
<|endoftext|>


<commit_before>import { mount } from '@vue/test-utils';
import ViewPanel from '../components/commands/CommandViewPanel.vue';

describe('view-panel', ()=>{
    let wrapper;
    beforeEach(()=>{
        wrapper = mount(ViewPanel);
    });

    test('mount ViewPanel', ()=>{
        expect(wrapper.html()).toMatchSnapshot();
    });

    test('mount "visible with content" ViewPanel', ()=>{
        wrapper.setProps({ content: 'SOME HTML MARKUP' });
        expect(wrapper.html()).toMatchSnapshot();
    });

    test('emit "change" to false on clicked background glasspane', ()=>{
        wrapper.setProps({ show: true });
        let glasspane = wrapper.find('.SharpViewPanel__glasspane');
        glasspane.trigger('click');
        expect(wrapper.emitted().close).toHaveLength(1);
    });

});<commit_msg>Fix tests<commit_after>import { mount } from '@vue/test-utils';
import ViewPanel from '../components/commands/CommandViewPanel.vue';

describe('view-panel', ()=>{
    let wrapper;
    beforeEach(()=>{
        wrapper = mount(ViewPanel, {
            directives: {
                srcdoc() {}
            }
        });
    });

    test('mount ViewPanel', ()=>{
        expect(wrapper.html()).toMatchSnapshot();
    });

    test('mount "visible with content" ViewPanel', ()=>{
        wrapper.setProps({ content: 'SOME HTML MARKUP' });
        expect(wrapper.html()).toMatchSnapshot();
    });

    test('emit "change" to false on clicked background glasspane', ()=>{
        wrapper.setProps({ show: true });
        let glasspane = wrapper.find('.SharpViewPanel__glasspane');
        glasspane.trigger('click');
        expect(wrapper.emitted().close).toHaveLength(1);
    });

});<|endoftext|>


<commit_before>#!/usr/bin/env node
"use strict";

// increase the libuv threadpool size to 1.5x the number of logical CPUs.
process.env.UV_THREADPOOL_SIZE = process.env.UV_THREADPOOL_SIZE || Math.ceil(Math.max(4, require('os').cpus().length * 1.5));

var cors = require("cors"),
    express = require("express"),
    Peechee = require('peechee'),
    spawnasync = require('spawn-async'),
    bunyan = require('bunyan'),
    config = require("config"),
    bodyParser = require('body-parser'),
    responseTime = require("response-time"),
    koop = require('koop-server')(config);

global['config'] = config;

// Scan package for koop plugins and require them .
try { koop.register(require("koop-github")); } catch (e) {}
try { koop.register(require("koop-gist")); } catch (e) {}
try { koop.register(require("koop-socrata")); } catch (e) {}
try { koop.register(require("koop-agol")); } catch (e) {}

var app = express();

app.disable("x-powered-by");
app.use(responseTime());
app.use(cors());

app.set('view engine', 'ejs');
app.set('view options', {layout: 'layout.ejs'});

if (process.env.NODE_ENV === "development") {
  app.use(express.logger());
}

// handle POST requests
app.use(bodyParser());

//app.use(express.static(__dirname + "/public"));

// add koop middleware
app.use(koop);

//console.log(koop);

app.listen(process.env.PORT || config.server.port,  function() {
  console.log("Listening at http://%s:%d/", this.address().address, this.address().port);

  // Start the Cache DB with the conn string from config
  if ( config.db.postgis ){
    Cache.db = PostGIS.connect( config.db.postgis.conn );
  } else {
    Cache.db = Local;
  }

  //config.defaultStyle = fs.readFileSync( __dirname + '/templates/renderers/style.mss', 'utf8' );

  // A bunyan log is required for the async workers
  config.log = new bunyan({
    'name': 'koop-log',
    streams: [{
      type: 'rotating-file',
      path: config.logfile,
      period: '1d',
      count: 3
    }]
  });

  // allow us to kick off system commands w/o blocking
  config.worker = spawnasync.createWorker({'log': config.log});

  // set up an instance of peechee for saving files (downloads)
  if ( config.peechee && config.peechee.type == 's3' ){
    global['peechee'] = new Peechee( config.peechee );
  }

});

<commit_msg>cleaning up functionality<commit_after>#!/usr/bin/env node
"use strict";

// increase the libuv threadpool size to 1.5x the number of logical CPUs.
process.env.UV_THREADPOOL_SIZE = process.env.UV_THREADPOOL_SIZE || Math.ceil(Math.max(4, require('os').cpus().length * 1.5));

var cors = require("cors"),
    express = require("express"),
    Peechee = require('peechee'),
    spawnasync = require('spawn-async'),
    bunyan = require('bunyan'),
    config = require("config"),
    fs = require('fs'),
    bodyParser = require('body-parser'),
    responseTime = require("response-time"),
    koop = require('koop-server')(config);

global['config'] = config;

// Scan package for koop plugins and require them
var files = fs.readdirSync('node_modules');
files.forEach(function(f){
  if ( f.match(/koop-*.+/) ){
    try { koop.register(require(f)); } catch (e) {}
  }
});

var app = express();

app.disable("x-powered-by");
app.use(responseTime());
app.use(cors());

app.set('view engine', 'ejs');
app.set('view options', {layout: 'layout.ejs'});

if (process.env.NODE_ENV === "development") {
  app.use(express.logger());
}

// handle POST requests
app.use(bodyParser());

// add koop middleware
app.use(koop);

app.listen(process.env.PORT || config.server.port,  function() {
  console.log("Listening at http://%s:%d/", this.address().address, this.address().port);

  // Start the Cache DB with the conn string from config
  if ( config.db.postgis ){
    Cache.db = PostGIS.connect( config.db.postgis.conn );
  } else {
    Cache.db = Local;
  }

  //config.defaultStyle = fs.readFileSync( __dirname + '/templates/renderers/style.mss', 'utf8' );

  // A bunyan log is required for the async workers
  config.log = new bunyan({
    'name': 'koop-log',
    streams: [{
      type: 'rotating-file',
      path: config.logfile,
      period: '1d',
      count: 3
    }]
  });

  // allow us to kick off system commands w/o blocking
  config.worker = spawnasync.createWorker({'log': config.log});

  // set up an instance of peechee for saving files (downloads)
  if ( config.peechee && config.peechee.type == 's3' ){
    global['peechee'] = new Peechee( config.peechee );
  }

});

<|endoftext|>


<commit_before>"use strict";

const app = require("express")();
const bodyParser = require("body-parser");
const mongoose = require('mongoose');

const routes = require('./routes/');

const PORT = process.env.PORT || 3000;

const MONGODB_HOST = process.env.MONGODB_HOST || 'localhost';
const MONGODB_PORT = process.env.MONGODB_PORT || 27017;
const MONGODB_USER = process.env.MONGODB_USER || '';
const MONGODB_PASS = process.env.MONGODB_PASS || '';
const MONGODB_NAME = process.env.MONGODB_NAME || 'node-webserver';

const MONGODB_AUTH = MONGODB_USER
  ? `${MONGODB_USER}:${MONGODB_PASS}@`
  : '';

const MONGODB_URL = `mongodb://${MONGODB_AUTH}${MONGODB_HOST}:${MONGODB_PORT}/${MONGODB_NAME}`;

//if (process.env.NODE_ENV === 'production') {
//  const MONGODB_URL = `mongodb://${MONGODB_USER}:${MONGODB_PASS}@${MONGODB_HOST}:${MONGODB_PORT}/${MONGODB_DB}`;
//} else {
  //const MONGODB_URL = 'mongodb://localhost:27017/node-webserver';
//}

app.set('view engine', 'jade');

app.locals.title = "Super Cool Calendar App";

app.use(express.static(path.join(__dirname, 'public')));

app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());

app.use(routes);

// Message for terminal to list current port
mongoose.connect(MONGODB_URL);

mongoose.connection.on('open', () => {
  console.log("MONGO OPEN");

  app.listen(PORT, () => {
    console.log(`Node.js server started. Listening on port ${PORT}`);
  });
});

// END

//const fs = require('fs');
//const multer = require('multer');

//const storage = multer.diskStorage({
    //destination: function (req, file, cb) {
      //cb(null, 'tmp/uploads')
   //},
    //filename: function (req, file, cb) {
    //const beforeDot = file.fieldname + '-' + Date.now();
    //const getFileType = file.originalname;
    //const afterDot = getFileType.slice(-4);

    //const newFileName = beforeDot + afterDot;

    //cb(null, newFileName)
    //}
//});

//const upload = multer({ storage: storage });

//const imgur = require('imgur');
//const path = require('path');
//const request = require('request');
//const _ = require('lodash');
//const cheerio = require('cheerio');

//const News = require('./models/news');
//const AllCaps = require('./models/allcaps');
//const Contact = require('./models/contact');

//const MongoClient = require('mongodb').MongoClient;

//let db;

<commit_msg>Add express and path<commit_after>"use strict";

const app = require("express")();
const express = require("express");
const path = require('path');
const bodyParser = require("body-parser");
const mongoose = require('mongoose');

const routes = require('./routes/');

const PORT = process.env.PORT || 3000;

const MONGODB_HOST = process.env.MONGODB_HOST || 'localhost';
const MONGODB_PORT = process.env.MONGODB_PORT || 27017;
const MONGODB_USER = process.env.MONGODB_USER || '';
const MONGODB_PASS = process.env.MONGODB_PASS || '';
const MONGODB_NAME = process.env.MONGODB_NAME || 'node-webserver';

const MONGODB_AUTH = MONGODB_USER
  ? `${MONGODB_USER}:${MONGODB_PASS}@`
  : '';

const MONGODB_URL = `mongodb://${MONGODB_AUTH}${MONGODB_HOST}:${MONGODB_PORT}/${MONGODB_NAME}`;

//if (process.env.NODE_ENV === 'production') {
//  const MONGODB_URL = `mongodb://${MONGODB_USER}:${MONGODB_PASS}@${MONGODB_HOST}:${MONGODB_PORT}/${MONGODB_DB}`;
//} else {
  //const MONGODB_URL = 'mongodb://localhost:27017/node-webserver';
//}

app.set('view engine', 'jade');

app.locals.title = "Super Cool Calendar App";

app.use(express.static(path.join(__dirname, 'public')));

app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());

app.use(routes);

// Message for terminal to list current port
mongoose.connect(MONGODB_URL);

mongoose.connection.on('open', () => {
  console.log("MONGO OPEN");

  app.listen(PORT, () => {
    console.log(`Node.js server started. Listening on port ${PORT}`);
  });
});

// END

//const fs = require('fs');
//const multer = require('multer');

//const storage = multer.diskStorage({
    //destination: function (req, file, cb) {
      //cb(null, 'tmp/uploads')
   //},
    //filename: function (req, file, cb) {
    //const beforeDot = file.fieldname + '-' + Date.now();
    //const getFileType = file.originalname;
    //const afterDot = getFileType.slice(-4);

    //const newFileName = beforeDot + afterDot;

    //cb(null, newFileName)
    //}
//});

//const upload = multer({ storage: storage });

//const imgur = require('imgur');
//const request = require('request');
//const _ = require('lodash');
//const cheerio = require('cheerio');

//const News = require('./models/news');
//const AllCaps = require('./models/allcaps');
//const Contact = require('./models/contact');

//const MongoClient = require('mongodb').MongoClient;

//let db;

<|endoftext|>


<commit_before>export default Em.Component.extend({
  tagName: "ul",
  classNames: ["results"],

  options: function() {
    const voters = this.get("signup.voters");

    this.get("signup.options").forEach(option => {
      const percentage = voters === 0 ? 0 : Math.floor(100 * option.get("votes") / voters),
            style = "width: " + percentage + "%".htmlSafe();

      const names = option.get("voters").map(user => "" + user + "").join(', ');

      option.setProperties({
        percentage,
        style,
        names,
        title: I18n.t("signup.option_title", { count: option.get("votes") })
      });
    });

    return this.get("signup.options");
  }.property("signup.voters", "signup.options.[]")

});
<commit_msg>Maybe getting closer to showing the user card<commit_after>export default Em.Component.extend({
  tagName: "ul",
  classNames: ["results"],

  options: function() {
    const voters = this.get("signup.voters");

    this.get("signup.options").forEach(option => {
      const percentage = voters === 0 ? 0 : Math.floor(100 * option.get("votes") / voters),
            style = "width: " + percentage + "%".htmlSafe();

      const names = option.get("voters").map(
          user => "" + user + ""
      ).join(', ');

      option.setProperties({
        percentage,
        style,
        names,
        title: I18n.t("signup.option_title", { count: option.get("votes") })
      });
    });

    return this.get("signup.options");
  }.property("signup.voters", "signup.options.[]")

});
<|endoftext|>


<commit_before>'use strict';

if (process.env.NEW_RELIC_LICENSE_KEY) require('newrelic');

let koa      = require('koa');
let gzip     = require('koa-gzip');
let r        = require('koa-route');
let morgan   = require('koa-morgan');
let parse    = require('co-body');
let fs       = require('fs');
let packages = require('./lib/packages');
let tarballs = require('./lib/tarballs');
let config   = require('./lib/config');
let user     = require('./lib/user');
let app      = koa();

app.name = 'elephant';
app.port = config.port;

app.use(morgan.middleware(config.production ? 'combined' : 'dev'));
app.use(gzip());

// static root page
app.use(r.get('/', function* () {
  this.type = 'text/html';
  this.body = fs.createReadStream(__dirname + '/public/index.html');
}));

// error middleware
app.use(function* (next) {
  try { yield next; }
  catch (err) {
    this.status = err.status || 500;
    this.body   = {error: err.message};
    this.app.emit('error', err, this);
  }
});

// get package metadata
app.use(r.get('/:name', function *(name) {
  let etag = this.req.headers['if-none-match'];
  let pkg = yield packages.get(name, etag);
  if (pkg === 304) {
    this.status = 304;
    return;
  }
  if (pkg === 404) {
    this.status = 404;
    this.body   = {error: 'no such package available'};
    return;
  }
  let host = this.headers.host;
  if (this.headers['user-agent'] === 'Amazon CloudFront') {
    host = config.cloudfrontHost;
  }
  packages.rewriteHost(pkg, config.uplink.hostname, host);
  // TODO: find out why this happens
  packages.rewriteHost(pkg, 'localhost:3000', host);
  this.set('ETag', pkg.etag);
  this.set('Cache-Control', `public, max-age=${config.cache.packageTTL}`);
  this.body = pkg;
}));

// get package tarball
app.use(r.get('/:name/-/:filename', function *(name, filename) {
  let tarball = yield tarballs.get(name, filename);
  if (!tarball) {
    this.status = 404;
    this.body   = {error: 'no tarball found'};
    return;
  }
  this.set('Content-Length', tarball.size);
  this.set('Cache-Control', 'public, max-age=21600');
  this.body = tarball;
}));

// login
app.use(r.put('/-/user/:user', function *() {
  let auth = yield user.authenticate(yield parse(this));
  if (auth) {
    this.status = 201;
    this.body   = {token: auth};
  } else {
    this.status = 401;
    this.body   = {error: "invalid credentials"};
  }
}));

// authenticate
app.use(function* (next) {
  if (!this.headers.authorization) {
    this.status = 401;
    this.body   = {error: 'no credentials provided'};
    return;
  }
  let token = this.headers.authorization.split(' ')[1];
  this.username = yield user.findByToken(token);
  if (!this.username) {
    this.status = 401;
    this.body   = {error: 'invalid credentials'};
    return;
  }
  yield next;
});

// whoami
app.use(r.get('/-/whoami', function *() {
  this.body = {username: this.username};
}));

// npm publish
app.use(r.put('/:name', function *() {
  let pkg = yield parse(this);
  try {
    yield packages.upload(pkg);
    this.body = yield packages.get(pkg.name);
  } catch (err) {
    if (err === packages.errors.versionExists) {
      this.body   = {error: err.toString()};
      this.status = 409;
    } else {
      throw err;
    }
  }
}));

module.exports = app;
if (!module.parent) {
  app.listen(app.port, function () {
    console.log(`${app.name} listening on port ${app.port} [${app.env}]`);
  });
}
<commit_msg>added ping endpoint<commit_after>'use strict';

if (process.env.NEW_RELIC_LICENSE_KEY) require('newrelic');

let koa      = require('koa');
let gzip     = require('koa-gzip');
let r        = require('koa-route');
let morgan   = require('koa-morgan');
let parse    = require('co-body');
let fs       = require('fs');
let packages = require('./lib/packages');
let tarballs = require('./lib/tarballs');
let config   = require('./lib/config');
let user     = require('./lib/user');
let app      = koa();

app.name = 'elephant';
app.port = config.port;

app.use(morgan.middleware(config.production ? 'combined' : 'dev'));
app.use(gzip());

// static root page
app.use(r.get('/', function* () {
  this.type = 'text/html';
  this.body = fs.createReadStream(__dirname + '/public/index.html');
}));

// ping
app.use(r.get('/-/ping', function *() {
  this.body = {};
}));

// error middleware
app.use(function* (next) {
  try { yield next; }
  catch (err) {
    this.status = err.status || 500;
    this.body   = {error: err.message};
    this.app.emit('error', err, this);
  }
});

// get package metadata
app.use(r.get('/:name', function *(name) {
  let etag = this.req.headers['if-none-match'];
  let pkg = yield packages.get(name, etag);
  if (pkg === 304) {
    this.status = 304;
    return;
  }
  if (pkg === 404) {
    this.status = 404;
    this.body   = {error: 'no such package available'};
    return;
  }
  let host = this.headers.host;
  if (this.headers['user-agent'] === 'Amazon CloudFront') {
    host = config.cloudfrontHost;
  }
  packages.rewriteHost(pkg, config.uplink.hostname, host);
  // TODO: find out why this happens
  packages.rewriteHost(pkg, 'localhost:3000', host);
  this.set('ETag', pkg.etag);
  this.set('Cache-Control', `public, max-age=${config.cache.packageTTL}`);
  this.body = pkg;
}));

// get package tarball
app.use(r.get('/:name/-/:filename', function *(name, filename) {
  let tarball = yield tarballs.get(name, filename);
  if (!tarball) {
    this.status = 404;
    this.body   = {error: 'no tarball found'};
    return;
  }
  this.set('Content-Length', tarball.size);
  this.set('Cache-Control', 'public, max-age=21600');
  this.body = tarball;
}));

// login
app.use(r.put('/-/user/:user', function *() {
  let auth = yield user.authenticate(yield parse(this));
  if (auth) {
    this.status = 201;
    this.body   = {token: auth};
  } else {
    this.status = 401;
    this.body   = {error: "invalid credentials"};
  }
}));

// authenticate
app.use(function* (next) {
  if (!this.headers.authorization) {
    this.status = 401;
    this.body   = {error: 'no credentials provided'};
    return;
  }
  let token = this.headers.authorization.split(' ')[1];
  this.username = yield user.findByToken(token);
  if (!this.username) {
    this.status = 401;
    this.body   = {error: 'invalid credentials'};
    return;
  }
  yield next;
});

// whoami
app.use(r.get('/-/whoami', function *() {
  this.body = {username: this.username};
}));

// npm publish
app.use(r.put('/:name', function *() {
  let pkg = yield parse(this);
  try {
    yield packages.upload(pkg);
    this.body = yield packages.get(pkg.name);
  } catch (err) {
    if (err === packages.errors.versionExists) {
      this.body   = {error: err.toString()};
      this.status = 409;
    } else {
      throw err;
    }
  }
}));

module.exports = app;
if (!module.parent) {
  app.listen(app.port, function () {
    console.log(`${app.name} listening on port ${app.port} [${app.env}]`);
  });
}
<|endoftext|>


<commit_before>/*
 * Copyright 2020 Google LLC
 *
 * 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
 *
 *     https://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.
 */

/**
 * External dependencies
 */
import { useRef } from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';

/**
 * WordPress dependencies
 */
import { __, sprintf } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import generatePatternStyles from '../../utils/generatePatternStyles';
import { ColorStopPropType } from '../../types';
import Pointer from './pointer';
import GradientStop from './gradientStop';
import useKeyMoveStop from './useKeyMoveStop';
import useKeyAddStop from './useKeyAddStop';
import useKeyDeleteStop from './useKeyDeleteStop';
import useKeyFocus from './useKeyFocus';
import usePointerAddStop from './usePointerAddStop';
import usePointerMoveStop from './usePointerMoveStop';
import { LINE_LENGTH, LINE_WIDTH } from './constants';

const LINE_FULL_LENGTH = LINE_LENGTH + LINE_WIDTH;

const Line = styled.div.attrs(({ stops }) => ({
  tabIndex: -1,
  style: generatePatternStyles({
    type: 'linear',
    // "Push" the ends of the gradient in, so it starts and
    // ends at (LINE_WIDTH / 2) px
    stops: stops.map(({ color, position }) => ({
      color,
      position: (position * LINE_LENGTH + LINE_WIDTH / 2) / LINE_FULL_LENGTH,
    })),
    // And fix rotation to .75 to make it go left-to-right
    rotation: 0.75,
  }),
}))`
  width: ${LINE_FULL_LENGTH}px;
  height: ${LINE_WIDTH}px;
  border-radius: ${LINE_WIDTH / 2}px;
  position: relative;

  &:focus {
    /* The line will only have temporary focus while deleting stops */
    outline: none;
  }
`;

const TempPointer = styled(Pointer).attrs(({ x }) => ({
  style: {
    left: `${x}px`,
  },
  offset: -LINE_WIDTH / 2,
}))`
  opacity: 0.6;
  top: ${LINE_WIDTH / 2}px;
  pointer-events: none;
`;

function GradientLine({
  stops,
  currentStopIndex,

  onSelect,
  onAdd,
  onDelete,
  onMove,
}) {
  const line = useRef();

  useKeyMoveStop(line, onMove, stops, currentStopIndex);
  useKeyAddStop(line, onAdd, stops, currentStopIndex);
  useKeyDeleteStop(line, onDelete);
  const stopRefs = useKeyFocus(line, stops, currentStopIndex);

  usePointerMoveStop(line, onMove, onDelete);
  const tempPointerPosition = usePointerAddStop(line, onAdd);

  return (
    <Line
      stops={stops}
      ref={line}
      aria-label={__('Gradient line', 'web-stories')}
    >
      {stops.map(({ position }, index) => (
        <GradientStop
          ref={(ref) => (stopRefs[index].current = ref)}
          key={position}
          index={index}
          isSelected={index === currentStopIndex}
          position={position}
          onSelect={onSelect}
        >
          <Pointer offset={-LINE_WIDTH / 2} />
        </GradientStop>
      ))}
      {tempPointerPosition && (
        <TempPointer
          aria-label={sprintf(
            /* translators: %d: stop percentage */
            __('Temporary gradient stop at %1$d%%', 'web-stories'),
            Math.round(
              (100 * (tempPointerPosition - LINE_WIDTH / 2)) / LINE_LENGTH
            )
          )}
          x={tempPointerPosition}
        />
      )}
    </Line>
  );
}

GradientLine.propTypes = {
  stops: PropTypes.arrayOf(ColorStopPropType),
  currentStopIndex: PropTypes.number.isRequired,

  onSelect: PropTypes.func.isRequired,
  onAdd: PropTypes.func.isRequired,
  onDelete: PropTypes.func.isRequired,
  onMove: PropTypes.func.isRequired,
};

export default GradientLine;
<commit_msg>Undo change in `GradientLine`<commit_after>/*
 * Copyright 2020 Google LLC
 *
 * 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
 *
 *     https://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.
 */

/**
 * External dependencies
 */
import { useRef } from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';

/**
 * WordPress dependencies
 */
import { __, sprintf } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import generatePatternStyles from '../../utils/generatePatternStyles';
import { ColorStopPropType } from '../../types';
import Pointer from './pointer';
import GradientStop from './gradientStop';
import useKeyMoveStop from './useKeyMoveStop';
import useKeyAddStop from './useKeyAddStop';
import useKeyDeleteStop from './useKeyDeleteStop';
import useKeyFocus from './useKeyFocus';
import usePointerAddStop from './usePointerAddStop';
import usePointerMoveStop from './usePointerMoveStop';
import { LINE_LENGTH, LINE_WIDTH } from './constants';

const LINE_FULL_LENGTH = LINE_LENGTH + LINE_WIDTH;

const Line = styled.div.attrs(({ stops }) => ({
  tabIndex: -1,
  style: generatePatternStyles({
    type: 'linear',
    // "Push" the ends of the gradient in, so it starts and
    // ends at (LINE_WIDTH / 2) px
    stops: stops.map(({ color, position }) => ({
      color,
      position: (position * LINE_LENGTH + LINE_WIDTH / 2) / LINE_FULL_LENGTH,
    })),
    // And fix rotation to .75 to make it go left-to-right
    rotation: 0.75,
  }),
}))`
  width: ${LINE_FULL_LENGTH}px;
  height: ${LINE_WIDTH}px;
  border-radius: ${LINE_WIDTH / 2}px;
  position: relative;

  &:focus {
    /* The line will only have temporary focus while deleting stops */
    outline: none;
  }
`;

const TempPointer = styled(Pointer).attrs(({ x }) => ({
  style: {
    left: `${x}px`,
  },
  offset: -LINE_WIDTH / 2,
}))`
  opacity: 0.6;
  top: ${LINE_WIDTH / 2}px;
  pointer-events: none;
`;

function GradientLine({
  stops,
  currentStopIndex,

  onSelect,
  onAdd,
  onDelete,
  onMove,
}) {
  const line = useRef();

  useKeyMoveStop(line, onMove, stops, currentStopIndex);
  useKeyAddStop(line, onAdd, stops, currentStopIndex);
  useKeyDeleteStop(line, onDelete);
  const stopRefs = useKeyFocus(line, stops, currentStopIndex);

  usePointerMoveStop(line, onMove, onDelete);
  const tempPointerPosition = usePointerAddStop(line, onAdd);

  return (
    <Line
      stops={stops}
      ref={line}
      aria-label={__('Gradient line', 'web-stories')}
    >
      {stops.map(({ position }, index) => (
        <GradientStop
          ref={(ref) => (stopRefs[index].current = ref)}
          key={index}
          index={index}
          isSelected={index === currentStopIndex}
          position={position}
          onSelect={onSelect}
        >
          <Pointer offset={-LINE_WIDTH / 2} />
        </GradientStop>
      ))}
      {tempPointerPosition && (
        <TempPointer
          aria-label={sprintf(
            /* translators: %d: stop percentage */
            __('Temporary gradient stop at %1$d%%', 'web-stories'),
            Math.round(
              (100 * (tempPointerPosition - LINE_WIDTH / 2)) / LINE_LENGTH
            )
          )}
          x={tempPointerPosition}
        />
      )}
    </Line>
  );
}

GradientLine.propTypes = {
  stops: PropTypes.arrayOf(ColorStopPropType),
  currentStopIndex: PropTypes.number.isRequired,

  onSelect: PropTypes.func.isRequired,
  onAdd: PropTypes.func.isRequired,
  onDelete: PropTypes.func.isRequired,
  onMove: PropTypes.func.isRequired,
};

export default GradientLine;
<|endoftext|>


<commit_before>var bot = require("./index.js")
var touch =  require("./touch.js")

bot(touch).listen(5563)
<commit_msg>add port<commit_after>var bot = require("./index.js")
var touch =  require("./touch.js")

bot(touch).listen(process.env.PORT || 5563)
<|endoftext|>


<commit_before>/*
 * Copyright 2020 Google LLC
 *
 * 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
 *
 *     https://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.
 */

/**
 * External dependencies
 */
import styled, { css } from 'styled-components';
import PropTypes from 'prop-types';

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';
import { useEffect, useRef } from 'react';

const TimeWrapper = styled.div`
  margin-bottom: 1em;
  padding: 0 20px;
`;

const Fieldset = styled.fieldset`
  margin-top: 0.5em;
  position: relative;
`;

const Legend = styled.legend`
  position: absolute;
  top: -999em;
  left: -999em;
`;

const InputRow = styled.div`
  display: flex;
`;

const inputCSS = css`
  min-height: 30px;
  box-shadow: 0 0 0 transparent;
  transition: box-shadow 0.1s linear;
  border-radius: 4px;
  border: 1px solid #7e8993;
  box-sizing: border-box;
  height: 28px;
  vertical-align: middle;
  background-color: #fff;
  color: #32373c;
`;

const NumberInput = styled.input`
  ${inputCSS}
  padding: 0;
  margin-right: 4px;
  text-align: center;
  width: 50%;
  max-width: 50px;
  ::-webkit-inner-spin-button,
  ::-webkit-outer-spin-button {
    margin: 0;
    appearance: none;
  }
`;

const TimeSeparator = styled.span`
  padding: 0 3px 0 0;
  color: #555d66;
`;

const Button = styled.button`
  display: inline-flex;
  text-decoration: none;
  font-size: 13px;
  margin: 0;
  border: 0;
  cursor: pointer;
  transition: box-shadow 0.1s linear;
  padding: 0 10px;
  line-height: 2;
  height: 30px;
  border-radius: 3px;
  white-space: nowrap;
  border-width: 1px;
  border-style: solid;
  color: rgb(0, 117, 175);
  border-color: rgb(0, 117, 175);
  background: #f3f5f6;

  &:focus {
    outline: 2px solid transparent;
    background: #f3f5f6;
    color: rgb(0, 93, 140);
    border-color: rgb(0, 118, 177);
    box-shadow: 0 0 0 1px rgb(0, 118, 177);
    text-decoration: none;
  }
  ${({ isToggled }) =>
    isToggled &&
    `
  background: #edeff0;
  border-color: #8f98a1;
  box-shadow: inset 0 2px 5px -3px #555d66;
  `}
`;

const InputGroup = styled.div`
  flex-basis: 100%;
`;

const AMButton = styled(Button)`
  margin-right: -1px;
  border-radius: 3px 0 0 3px;
`;

const PMButton = styled(Button)`
  margin-left: -1px;
  border-radius: 0 3px 3px 0;
`;

function TimePicker({ onChange, is12Hour, localData, setLocalData }) {
  const onChangeEvent = (prop) => (evt) => {
    setLocalData({
      ...localData,
      [prop]: parseInt(evt.target.value),
    });
  };

  const getMaxHours = () => {
    return is12Hour ? 12 : 23;
  };

  const getMinHours = () => {
    return is12Hour ? 1 : 0;
  };

  const getHours = (value) => {
    const { am } = localData;
    if (!is12Hour) {
      return value;
    }
    return am === 'AM' ? value % 12 : ((value % 12) + 12) % 24;
  };

  const changeDate = (newDate, props = {}) => {
    setLocalData({ ...localData, ...props, date: newDate });
    onChange(newDate.toISOString());
  };

  const updateMinutes = () => {
    const { minutes, date } = localData;
    const value = parseInt(minutes);
    if (isNaN(value) || value < 0 || value > 59) {
      return;
    }
    const newDate = date;
    newDate.setMinutes(minutes);
    changeDate(newDate);
  };

  const updateHours = () => {
    const { hours, date } = localData;
    const value = parseInt(hours);
    if (isNaN(value) || value < getMinHours() || value > getMaxHours()) {
      return;
    }

    const newDate = date;
    newDate.setHours(getHours(hours));
    changeDate(newDate);
  };

  const updateAmPm = (value) => () => {
    const { am, date, hours } = localData;
    if (am === value) {
      return;
    }
    const newDate = date;
    if (value === 'PM') {
      newDate.setHours(((hours % 12) + 12) % 24);
    } else {
      newDate.setHours(hours % 12);
    }
    changeDate(newDate, { am: value });
  };

  const hours = useRef();
  useEffect(() => {
    hours.current.focus();
  }, []);

  return (
    <TimeWrapper>
      <Fieldset>
        <Legend>{__('Time', 'web-stories')}</Legend>
        <InputRow>
          <InputGroup>
            <NumberInput
              ref={hours}
              aria-label={__('Hours', 'web-stories')}
              type="number"
              step={1}
              min={getMinHours()}
              max={getMaxHours()}
              value={parseInt(localData.hours)}
              onChange={onChangeEvent('hours')}
              onBlur={updateHours}
            />
            <TimeSeparator>{':'}</TimeSeparator>
            <NumberInput
              aria-label={__('Minutes', 'web-stories')}
              type="number"
              min={0}
              max={59}
              value={parseInt(localData.minutes)}
              onChange={onChangeEvent('minutes')}
              onBlur={updateMinutes}
            />
          </InputGroup>
          {is12Hour && (
            <InputGroup>
              <AMButton
                type="button"
                isToggled={localData.am === 'AM'}
                onClick={updateAmPm('AM')}
              >
                {__('AM', 'web-stories')}
              </AMButton>
              <PMButton
                type="button"
                isToggled={localData.am === 'PM'}
                onClick={updateAmPm('PM')}
              >
                {__('PM', 'web-stories')}
              </PMButton>
            </InputGroup>
          )}
        </InputRow>
      </Fieldset>
    </TimeWrapper>
  );
}

TimePicker.propTypes = {
  onChange: PropTypes.func.isRequired,
  is12Hour: PropTypes.bool,
  localData: PropTypes.shape({
    am: PropTypes.string.isRequired,
    hours: PropTypes.number.isRequired,
    minutes: PropTypes.number.isRequired,
    date: PropTypes.instanceOf(Date).isRequired,
  }).isRequired,
  setLocalData: PropTypes.func.isRequired,
};

export default TimePicker;
<commit_msg>Add aria-pressed to am-pm toggles.<commit_after>/*
 * Copyright 2020 Google LLC
 *
 * 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
 *
 *     https://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.
 */

/**
 * External dependencies
 */
import styled, { css } from 'styled-components';
import PropTypes from 'prop-types';

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';
import { useEffect, useRef } from 'react';

const TimeWrapper = styled.div`
  margin-bottom: 1em;
  padding: 0 20px;
`;

const Fieldset = styled.fieldset`
  margin-top: 0.5em;
  position: relative;
`;

const Legend = styled.legend`
  position: absolute;
  top: -999em;
  left: -999em;
`;

const InputRow = styled.div`
  display: flex;
`;

const inputCSS = css`
  min-height: 30px;
  box-shadow: 0 0 0 transparent;
  transition: box-shadow 0.1s linear;
  border-radius: 4px;
  border: 1px solid #7e8993;
  box-sizing: border-box;
  height: 28px;
  vertical-align: middle;
  background-color: #fff;
  color: #32373c;
`;

const NumberInput = styled.input`
  ${inputCSS}
  padding: 0;
  margin-right: 4px;
  text-align: center;
  width: 50%;
  max-width: 50px;
  ::-webkit-inner-spin-button,
  ::-webkit-outer-spin-button {
    margin: 0;
    appearance: none;
  }
`;

const TimeSeparator = styled.span`
  padding: 0 3px 0 0;
  color: #555d66;
`;

const Button = styled.button`
  display: inline-flex;
  text-decoration: none;
  font-size: 13px;
  margin: 0;
  border: 0;
  cursor: pointer;
  transition: box-shadow 0.1s linear;
  padding: 0 10px;
  line-height: 2;
  height: 30px;
  border-radius: 3px;
  white-space: nowrap;
  border-width: 1px;
  border-style: solid;
  color: rgb(0, 117, 175);
  border-color: rgb(0, 117, 175);
  background: #f3f5f6;

  &:focus {
    outline: 2px solid transparent;
    background: #f3f5f6;
    color: rgb(0, 93, 140);
    border-color: rgb(0, 118, 177);
    box-shadow: 0 0 0 1px rgb(0, 118, 177);
    text-decoration: none;
  }
  ${({ isToggled }) =>
    isToggled &&
    `
  background: #edeff0;
  border-color: #8f98a1;
  box-shadow: inset 0 2px 5px -3px #555d66;
  `}
`;

const InputGroup = styled.div`
  flex-basis: 100%;
`;

const AMButton = styled(Button)`
  margin-right: -1px;
  border-radius: 3px 0 0 3px;
`;

const PMButton = styled(Button)`
  margin-left: -1px;
  border-radius: 0 3px 3px 0;
`;

function TimePicker({ onChange, is12Hour, localData, setLocalData }) {
  const onChangeEvent = (prop) => (evt) => {
    setLocalData({
      ...localData,
      [prop]: parseInt(evt.target.value),
    });
  };

  const getMaxHours = () => {
    return is12Hour ? 12 : 23;
  };

  const getMinHours = () => {
    return is12Hour ? 1 : 0;
  };

  const getHours = (value) => {
    const { am } = localData;
    if (!is12Hour) {
      return value;
    }
    return am === 'AM' ? value % 12 : ((value % 12) + 12) % 24;
  };

  const changeDate = (newDate, props = {}) => {
    setLocalData({ ...localData, ...props, date: newDate });
    onChange(newDate.toISOString());
  };

  const updateMinutes = () => {
    const { minutes, date } = localData;
    const value = parseInt(minutes);
    if (isNaN(value) || value < 0 || value > 59) {
      return;
    }
    const newDate = date;
    newDate.setMinutes(minutes);
    changeDate(newDate);
  };

  const updateHours = () => {
    const { hours, date } = localData;
    const value = parseInt(hours);
    if (isNaN(value) || value < getMinHours() || value > getMaxHours()) {
      return;
    }

    const newDate = date;
    newDate.setHours(getHours(hours));
    changeDate(newDate);
  };

  const updateAmPm = (value) => () => {
    const { am, date, hours } = localData;
    if (am === value) {
      return;
    }
    const newDate = date;
    if (value === 'PM') {
      newDate.setHours(((hours % 12) + 12) % 24);
    } else {
      newDate.setHours(hours % 12);
    }
    changeDate(newDate, { am: value });
  };

  const hours = useRef();
  useEffect(() => {
    hours.current.focus();
  }, []);

  const isAM = localData.am === 'AM';
  const isPM = localData.am === 'PM';
  return (
    <TimeWrapper>
      <Fieldset>
        <Legend>{__('Time', 'web-stories')}</Legend>
        <InputRow>
          <InputGroup>
            <NumberInput
              ref={hours}
              aria-label={__('Hours', 'web-stories')}
              type="number"
              step={1}
              min={getMinHours()}
              max={getMaxHours()}
              value={parseInt(localData.hours)}
              onChange={onChangeEvent('hours')}
              onBlur={updateHours}
            />
            <TimeSeparator>{':'}</TimeSeparator>
            <NumberInput
              aria-label={__('Minutes', 'web-stories')}
              type="number"
              min={0}
              max={59}
              value={parseInt(localData.minutes)}
              onChange={onChangeEvent('minutes')}
              onBlur={updateMinutes}
            />
          </InputGroup>
          {is12Hour && (
            <InputGroup>
              <AMButton
                aria-pressed={isAM}
                type="button"
                isToggled={isAM}
                onClick={updateAmPm('AM')}
              >
                {__('AM', 'web-stories')}
              </AMButton>
              <PMButton
                aria-pressed={isPM}
                type="button"
                isToggled={isPM}
                onClick={updateAmPm('PM')}
              >
                {__('PM', 'web-stories')}
              </PMButton>
            </InputGroup>
          )}
        </InputRow>
      </Fieldset>
    </TimeWrapper>
  );
}

TimePicker.propTypes = {
  onChange: PropTypes.func.isRequired,
  is12Hour: PropTypes.bool,
  localData: PropTypes.shape({
    am: PropTypes.string.isRequired,
    hours: PropTypes.number.isRequired,
    minutes: PropTypes.number.isRequired,
    date: PropTypes.instanceOf(Date).isRequired,
  }).isRequired,
  setLocalData: PropTypes.func.isRequired,
};

export default TimePicker;
<|endoftext|>


<commit_before>// Requires dependencies
var express = require("express");
var expressHandlebars = require("express-handlebars");
var bodyParser = require("body-parser");
var mongoose = require("mongoose");
// Morgan logs server nd db interactions
var logger = require("morgan");

// Require request and cheerio for scraping
var request = require("request");
var cheerio = require("cheerio");

// Route the models
var Note = require("./models/Note.js");
var Article = require("./models/Article.js");

// Set mongoose to leverage built in JavaScript ES6 Promises
mongoose.Promise = Promise;

// Initializes express
var app = express();

// Use body parser & morgan with our app
app.use(logger("dev"));
app.use(bodyParser.urlencoded({
  extended: false
}));

// Make views a static dir
app.use(express.static("views"));

app.engine("handlebars", expressHandlebars({
  defaultLayout: "main"
}));
app.set("view engine", "handlebars");

// Database configuration with mongoose
var db = process.env.MONGODB_URI || "mongodb://localhost/scraped-websites";
mongoose.connect(db, function(error) {
	if(error){
		console.log(error);
	}
	else {
		console.log("Mongoose connection successful.");
	}
});

//===========================================
//Routes
//===========================================

app.get("/", function(req, res) {

	res.render("index");
})

// Scrape data from the New York Times
app.get("/scrape", function(req, res){
	request("http://www.echojs.com/", function(error, response, html) {

		var $ = cheerio.load(html);

		$("article h2").each(function(i, element) {
	    var result = {};

	    result.title = $(this).children("a").text();
      	result.link = $(this).children("a").attr("href");

      	// Create a new entry and save to the db
      	var entry = new Article(result);

	      entry.save(function(err, doc) {
	        if (err) {
	          console.log(err);
	        }
	        else {
	          console.log(doc);
	        }
	  	  });

		});
	});
	// Send browser back to root directory
	 Article.find({}, function(error, found) {
    if (error) {
      console.log(error);
    }
    else {
      // alert("Found "+found.length+" new articles.");
	var results = { articles : found }
      res.render("index", results);
    }
  });

});

// Retrieve all data from the scrapedData collection and send it to the browser
app.get("/articles", function(req, res) {
  Article.find({}, function(error, found) {
    if (error) {
      console.log(error);
    }
    else {
      // alert("Found "+found.length+" new articles.");
	var results = { articles : found }
      res.render("index", results);
    }
  });
});

// Retrieve data from one article in the scrapedData collection & send to browser
app.get("/articles/:id", function(req, res) {
	Article.findOneAndUpdate({ "_id": req.params.id }
		// , {$inc: { "note": res.body}}
		)
	//Populate the note and execute query
	.populate("note")
	.exec(function(error, doc) {
	    if (error) {
	      console.log(error);
	    }
	    else {
	      res.json(doc);
		}
	});
});

// Send new comment to the browser
app.post("/articles/:id", function(req, res) {

  var userComment = new Note(req.body);

  userComment.save(function(error, doc) {
    if (error) {
      res.send(error);
    }
    else {
      res.send(doc);
    }
  });
});

app.listen(8080, function() {
  console.log("App running on port 8080!");
});<commit_msg>makes mongoose connection compatible with heroku<commit_after>// Requires dependencies
var express = require("express");
var expressHandlebars = require("express-handlebars");
var bodyParser = require("body-parser");
var mongoose = require("mongoose");
// Morgan logs server nd db interactions
var logger = require("morgan");

// Require request and cheerio for scraping
var request = require("request");
var cheerio = require("cheerio");

// Route the models
var Note = require("./models/Note.js");
var Article = require("./models/Article.js");

// Set mongoose to leverage built in JavaScript ES6 Promises
mongoose.Promise = Promise;

// Initializes express
var app = express();

// Use body parser & morgan with our app
app.use(logger("dev"));
app.use(bodyParser.urlencoded({
  extended: false
}));

// Make views a static dir
app.use(express.static("views"));

app.engine("handlebars", expressHandlebars({
  defaultLayout: "main"
}));
app.set("view engine", "handlebars");

//-----------Define Local MongoDB URI-------------
var databaseUri = "mongodb://localhost/scraped-websites";

// Database configuration with mongoose
if (process.env.MONGODB_URI) {
	// HEROKU EXECUTION
	mongoose.connect(process.env.MONGODB_URI);
}
else {
	// LOCAL MACHINE EXECUTION
	mongoose.connect(databaseUri);
}

var db = mongoose.connection;

db.on("error", function(err) {
	console.log('Mongoose error: ', err);
});

db.once("open", function() {
	console.log("Mongoose connection successful.");
});

//===========================================
//Routes
//===========================================

app.get("/", function(req, res) {

	res.render("index");
})

// Scrape data from the New York Times
app.get("/scrape", function(req, res){
	request("http://www.echojs.com/", function(error, response, html) {

		var $ = cheerio.load(html);

		$("article h2").each(function(i, element) {
	    var result = {};

	    result.title = $(this).children("a").text();
      	result.link = $(this).children("a").attr("href");

      	// Create a new entry and save to the db
      	var entry = new Article(result);

	      entry.save(function(err, doc) {
	        if (err) {
	          console.log(err);
	        }
	        else {
	          console.log(doc);
	        }
	  	  });

		});
	});
	// Send browser back to root directory
	 Article.find({}, function(error, found) {
    if (error) {
      console.log(error);
    }
    else {
      // alert("Found "+found.length+" new articles.");
	var results = { articles : found }
      res.render("index", results);
    }
  });

});

// Retrieve all data from the scrapedData collection and send it to the browser
app.get("/articles", function(req, res) {
  Article.find({}, function(error, found) {
    if (error) {
      console.log(error);
    }
    else {
      // alert("Found "+found.length+" new articles.");
	var results = { articles : found }
      res.render("index", results);
    }
  });
});

// Retrieve data from one article in the scrapedData collection & send to browser
app.get("/articles/:id", function(req, res) {
	Article.findOneAndUpdate({ "_id": req.params.id }
		// , {$inc: { "note": res.body}}
		)
	//Populate the note and execute query
	.populate("note")
	.exec(function(error, doc) {
	    if (error) {
	      console.log(error);
	    }
	    else {
	      res.json(doc);
		}
	});
});

// Send new comment to the browser
app.post("/articles/:id", function(req, res) {

  var userComment = new Note(req.body);

  userComment.save(function(error, doc) {
    if (error) {
      res.send(error);
    }
    else {
      res.send(doc);
    }
  });
});

app.listen(8080, function() {
  console.log("App running on port 8080!");
});<|endoftext|>


<commit_before>/*
 * Copyright 2020 Google LLC
 *
 * 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
 *
 *     https://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.
 */

/**
 * External dependencies
 */
import styled, { css } from 'styled-components';
import PropTypes from 'prop-types';

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';

const TimeWrapper = styled.div`
  margin-bottom: 1em;
  padding: 0 20px;
`;

const Fieldset = styled.fieldset`
  margin-top: 0.5em;
  position: relative;
`;

const Legend = styled.legend`
  position: absolute;
  top: -999em;
  left: -999em;
`;

const InputRow = styled.div`
  display: flex;
`;

const inputCSS = css`
  min-height: 30px;
  box-shadow: 0 0 0 transparent;
  transition: box-shadow 0.1s linear;
  border-radius: 4px;
  border: 1px solid #7e8993;
  box-sizing: border-box;
  height: 28px;
  vertical-align: middle;
  background-color: #fff;
  color: #32373c;
`;

const NumberInput = styled.input`
  ${inputCSS}
  padding: 0;
  margin-right: 4px;
  text-align: center;
  width: 50%;
  max-width: 50px;
  ::-webkit-inner-spin-button,
  ::-webkit-outer-spin-button {
    margin: 0;
    appearance: none;
  }
`;

const TimeSeparator = styled.span`
  padding: 0 3px 0 0;
  color: #555d66;
`;

const Button = styled.button`
  display: inline-flex;
  text-decoration: none;
  font-size: 13px;
  margin: 0;
  border: 0;
  cursor: pointer;
  transition: box-shadow 0.1s linear;
  padding: 0 10px;
  line-height: 2;
  height: 30px;
  border-radius: 3px;
  white-space: nowrap;
  border-width: 1px;
  border-style: solid;
  color: rgb(0, 117, 175);
  border-color: rgb(0, 117, 175);
  background: #f3f5f6;

  &:focus {
    outline: 2px solid transparent;
    background: #f3f5f6;
    color: rgb(0, 93, 140);
    border-color: rgb(0, 118, 177);
    box-shadow: 0 0 0 1px rgb(0, 118, 177);
    text-decoration: none;
  }
  ${({ isToggled }) =>
    isToggled &&
    `
  background: #edeff0;
  border-color: #8f98a1;
  box-shadow: inset 0 2px 5px -3px #555d66;
  `}
`;

const InputGroup = styled.div`
  flex-basis: 100%;
`;

const AMButton = styled(Button)`
  margin-right: -1px;
  border-radius: 3px 0 0 3px;
`;

const PMButton = styled(Button)`
  margin-left: -1px;
  border-radius: 0 3px 3px 0;
`;

function TimePicker({ onChange, is12Hour, localData, setLocalData }) {
  const onChangeEvent = (prop) => (evt) => {
    setLocalData({
      ...localData,
      [prop]: parseInt(evt.target.value),
    });
  };

  const getMaxHours = () => {
    return is12Hour ? 12 : 23;
  };

  const getMinHours = () => {
    return is12Hour ? 1 : 0;
  };

  const getHours = (value) => {
    const { am } = localData;
    if (!is12Hour) {
      return value;
    }
    return am === 'AM' ? value % 12 : ((value % 12) + 12) % 24;
  };

  const changeDate = (newDate, props = {}) => {
    setLocalData({ ...localData, ...props, date: newDate });
    onChange(newDate.toISOString());
  };

  const updateMinutes = () => {
    const { minutes, date } = localData;
    const value = parseInt(minutes);
    if (isNaN(value) || value < 0 || value > 59) {
      return;
    }
    const newDate = date;
    newDate.setMinutes(minutes);
    changeDate(newDate);
  };

  const updateHours = () => {
    const { hours, date } = localData;
    const value = parseInt(hours);
    if (isNaN(value) || value < getMinHours() || value > getMaxHours()) {
      return;
    }

    const newDate = date;
    newDate.setHours(getHours(hours));
    changeDate(newDate);
  };

  const updateAmPm = (value) => () => {
    const { am, date, hours } = localData;
    if (am === value) {
      return;
    }
    const newDate = date;
    if (value === 'PM') {
      newDate.setHours(((hours % 12) + 12) % 24);
    } else {
      newDate.setHours(hours % 12);
    }
    changeDate(newDate, { am: value });
  };

  return (
    <TimeWrapper>
      <Fieldset>
        <Legend>{__('Time', 'web-stories')}</Legend>
        <InputRow>
          <InputGroup>
            <NumberInput
              aria-label={__('Hours', 'web-stories')}
              type="number"
              step={1}
              min={getMinHours()}
              max={getMaxHours()}
              value={parseInt(localData.hours)}
              onChange={onChangeEvent('hours')}
              onBlur={updateHours}
            />
            <TimeSeparator>{':'}</TimeSeparator>
            <NumberInput
              aria-label={__('Minutes', 'web-stories')}
              type="number"
              min={0}
              max={59}
              value={parseInt(localData.minutes)}
              onChange={onChangeEvent('minutes')}
              onBlur={updateMinutes}
            />
          </InputGroup>
          {is12Hour && (
            <InputGroup>
              <AMButton
                type="button"
                isToggled={localData.am === 'AM'}
                onClick={updateAmPm('AM')}
              >
                {__('AM', 'web-stories')}
              </AMButton>
              <PMButton
                type="button"
                isToggled={localData.am === 'PM'}
                onClick={updateAmPm('PM')}
              >
                {__('PM', 'web-stories')}
              </PMButton>
            </InputGroup>
          )}
        </InputRow>
      </Fieldset>
    </TimeWrapper>
  );
}

TimePicker.propTypes = {
  onChange: PropTypes.func.isRequired,
  is12Hour: PropTypes.bool,
  localData: PropTypes.shape({
    am: PropTypes.string.isRequired,
    hours: PropTypes.number.isRequired,
    minutes: PropTypes.number.isRequired,
    date: PropTypes.instanceOf(Date).isRequired,
  }).isRequired,
  setLocalData: PropTypes.func.isRequired,
};

export default TimePicker;
<commit_msg>Focus on the hours field when opening calendar<commit_after>/*
 * Copyright 2020 Google LLC
 *
 * 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
 *
 *     https://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.
 */

/**
 * External dependencies
 */
import styled, { css } from 'styled-components';
import PropTypes from 'prop-types';

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';
import { useEffect, useRef } from 'react';

const TimeWrapper = styled.div`
  margin-bottom: 1em;
  padding: 0 20px;
`;

const Fieldset = styled.fieldset`
  margin-top: 0.5em;
  position: relative;
`;

const Legend = styled.legend`
  position: absolute;
  top: -999em;
  left: -999em;
`;

const InputRow = styled.div`
  display: flex;
`;

const inputCSS = css`
  min-height: 30px;
  box-shadow: 0 0 0 transparent;
  transition: box-shadow 0.1s linear;
  border-radius: 4px;
  border: 1px solid #7e8993;
  box-sizing: border-box;
  height: 28px;
  vertical-align: middle;
  background-color: #fff;
  color: #32373c;
`;

const NumberInput = styled.input`
  ${inputCSS}
  padding: 0;
  margin-right: 4px;
  text-align: center;
  width: 50%;
  max-width: 50px;
  ::-webkit-inner-spin-button,
  ::-webkit-outer-spin-button {
    margin: 0;
    appearance: none;
  }
`;

const TimeSeparator = styled.span`
  padding: 0 3px 0 0;
  color: #555d66;
`;

const Button = styled.button`
  display: inline-flex;
  text-decoration: none;
  font-size: 13px;
  margin: 0;
  border: 0;
  cursor: pointer;
  transition: box-shadow 0.1s linear;
  padding: 0 10px;
  line-height: 2;
  height: 30px;
  border-radius: 3px;
  white-space: nowrap;
  border-width: 1px;
  border-style: solid;
  color: rgb(0, 117, 175);
  border-color: rgb(0, 117, 175);
  background: #f3f5f6;

  &:focus {
    outline: 2px solid transparent;
    background: #f3f5f6;
    color: rgb(0, 93, 140);
    border-color: rgb(0, 118, 177);
    box-shadow: 0 0 0 1px rgb(0, 118, 177);
    text-decoration: none;
  }
  ${({ isToggled }) =>
    isToggled &&
    `
  background: #edeff0;
  border-color: #8f98a1;
  box-shadow: inset 0 2px 5px -3px #555d66;
  `}
`;

const InputGroup = styled.div`
  flex-basis: 100%;
`;

const AMButton = styled(Button)`
  margin-right: -1px;
  border-radius: 3px 0 0 3px;
`;

const PMButton = styled(Button)`
  margin-left: -1px;
  border-radius: 0 3px 3px 0;
`;

function TimePicker({ onChange, is12Hour, localData, setLocalData }) {
  const onChangeEvent = (prop) => (evt) => {
    setLocalData({
      ...localData,
      [prop]: parseInt(evt.target.value),
    });
  };

  const getMaxHours = () => {
    return is12Hour ? 12 : 23;
  };

  const getMinHours = () => {
    return is12Hour ? 1 : 0;
  };

  const getHours = (value) => {
    const { am } = localData;
    if (!is12Hour) {
      return value;
    }
    return am === 'AM' ? value % 12 : ((value % 12) + 12) % 24;
  };

  const changeDate = (newDate, props = {}) => {
    setLocalData({ ...localData, ...props, date: newDate });
    onChange(newDate.toISOString());
  };

  const updateMinutes = () => {
    const { minutes, date } = localData;
    const value = parseInt(minutes);
    if (isNaN(value) || value < 0 || value > 59) {
      return;
    }
    const newDate = date;
    newDate.setMinutes(minutes);
    changeDate(newDate);
  };

  const updateHours = () => {
    const { hours, date } = localData;
    const value = parseInt(hours);
    if (isNaN(value) || value < getMinHours() || value > getMaxHours()) {
      return;
    }

    const newDate = date;
    newDate.setHours(getHours(hours));
    changeDate(newDate);
  };

  const updateAmPm = (value) => () => {
    const { am, date, hours } = localData;
    if (am === value) {
      return;
    }
    const newDate = date;
    if (value === 'PM') {
      newDate.setHours(((hours % 12) + 12) % 24);
    } else {
      newDate.setHours(hours % 12);
    }
    changeDate(newDate, { am: value });
  };

  const hours = useRef();
  useEffect(() => {
    hours.current.focus();
  }, []);

  return (
    <TimeWrapper>
      <Fieldset>
        <Legend>{__('Time', 'web-stories')}</Legend>
        <InputRow>
          <InputGroup>
            <NumberInput
              ref={hours}
              aria-label={__('Hours', 'web-stories')}
              type="number"
              step={1}
              min={getMinHours()}
              max={getMaxHours()}
              value={parseInt(localData.hours)}
              onChange={onChangeEvent('hours')}
              onBlur={updateHours}
            />
            <TimeSeparator>{':'}</TimeSeparator>
            <NumberInput
              aria-label={__('Minutes', 'web-stories')}
              type="number"
              min={0}
              max={59}
              value={parseInt(localData.minutes)}
              onChange={onChangeEvent('minutes')}
              onBlur={updateMinutes}
            />
          </InputGroup>
          {is12Hour && (
            <InputGroup>
              <AMButton
                type="button"
                isToggled={localData.am === 'AM'}
                onClick={updateAmPm('AM')}
              >
                {__('AM', 'web-stories')}
              </AMButton>
              <PMButton
                type="button"
                isToggled={localData.am === 'PM'}
                onClick={updateAmPm('PM')}
              >
                {__('PM', 'web-stories')}
              </PMButton>
            </InputGroup>
          )}
        </InputRow>
      </Fieldset>
    </TimeWrapper>
  );
}

TimePicker.propTypes = {
  onChange: PropTypes.func.isRequired,
  is12Hour: PropTypes.bool,
  localData: PropTypes.shape({
    am: PropTypes.string.isRequired,
    hours: PropTypes.number.isRequired,
    minutes: PropTypes.number.isRequired,
    date: PropTypes.instanceOf(Date).isRequired,
  }).isRequired,
  setLocalData: PropTypes.func.isRequired,
};

export default TimePicker;
<|endoftext|>


<commit_before>// An example script for asking Tanium a question

/* name - The name of the Saved-Question in Tanium server (mandatory if no 'id' was specified)
For example:
	Computer Name
	User Information
	Adobe Acrobat Versions
	BIOS Information
	CPU Utilization Over 75%
	Installed Applications
	...
*/
// id - The ID of the Saved-Question in Tanium server (mandatory if no 'name' was specified)
// timeout - seconds to wait on each iteration while waiting for the question's result
var taniumArgs = {
						'name': args.name,
						'id': args.id,
						'timeout': args.timeout
			    };

var table = {
    Type: 1,
    ContentsFormat: 'table',
    Contents: []
};

var res = executeCommand('tn-result-info', taniumArgs);
if (res[0].Type !== entryTypes.error) {
    if (!res[0].Contents.result_infos) {
        return res[0].Contents.Envelope.Body.return.command;
    }

    // Need to compare 'mr_passed' and 'estimated_total' values,
    // to confirm that all machines have answered
				var answers = res[0].Contents.result_infos.result_info.mr_passed;
				var expectedAnswers = res[0].Contents.result_infos.result_info.estimated_total;

    // Check the status 10 times, and wait 'timeout' seconds between each iteration
    var iterToWait = 10;
    var sec = 1;
    if (taniumArgs.timeout) {
    				sec = parseInt(taniumArgs.timeout) || 1;
    }
				while (answers !== expectedAnswers && iterToWait-- > 0) {
								wait(sec);
								res = executeCommand('tn-result-info', taniumArgs);
								if (res[0].Type === entryTypes.error) {
												return res[0];
								}
							 answers = res[0].Contents.result_infos.result_info.mr_passed;
        expectedAnswers = res[0].Contents.result_infos.result_info.estimated_total;
				}

    // Get question data (i.e. question result)
    var qDataRes = executeCommand('tn-result-data', taniumArgs);
    if (!qDataRes[0].Contents.result_sets) {
        return qDataRes[0].Contents.Envelope.Body.return.command;
    }

				// Extract the relevant fields from the data
				itemCount = parseInt(qDataRes[0].Contents.result_sets.result_set.item_count);
				if (itemCount === 0) {
								return 'No results';
				}

    var output = "";
    var cs = qDataRes[0].Contents.result_sets.result_set.cs;
    var rs = qDataRes[0].Contents.result_sets.result_set.rs;

				// When a single item is returned, rs.r is a single object. Otherwise, it is an array...
    if (itemCount === 1) {
        var row = {};
    				for (var i=0; i < cs.c.length; i++) {
        				//output += cs.c[i].dn + ': ' + rs.r.c[i].v + '\n';
        				row[cs.c[i].dn] = rs.r.c[i].v;
        }
        table.Contents.push(row);
    } else {
				    for (var item=0; item < itemCount; item++) {
								    var row = {};
								    for (var j=0; j < cs.c.length; j++) {
												    // output += cs.c[j].dn + ': ' + rs.r[item].c[j].v + '\n';
												    row[cs.c[j].dn] = rs.r[item].c[j].v;
								    }
								    table.Contents.push(row);
				    }
				}

    if (table.Contents.length === 0) {
    			return 'No Results';
    }
    return table;
}

return res;
<commit_msg>Fixed passing of empty argument which caused an error inside the command.<commit_after>// An example script for asking Tanium a question

/* name - The name of the Saved-Question in Tanium server (mandatory if no 'id' was specified)
For example:
	Computer Name
	User Information
	Adobe Acrobat Versions
	BIOS Information
	CPU Utilization Over 75%
	Installed Applications
	...
*/
// id - The ID of the Saved-Question in Tanium server (mandatory if no 'name' was specified)
// timeout - seconds to wait on each iteration while waiting for the question's result

var table = {
    Type: 1,
    ContentsFormat: 'table',
    Contents: []
};

if (!args.name && !args.id)
    return { ContentsFormat: formats.text, Type: entryTypes.error, Contents: 'You must provide name or id.' };
var res = executeCommand('tn-result-info', args);
if (res[0].Type !== entryTypes.error) {
    if (!res[0].Contents.result_infos) {
        return res[0].Contents.Envelope.Body.return.command;
    }

    // Need to compare 'mr_passed' and 'estimated_total' values,
    // to confirm that all machines have answered
				var answers = res[0].Contents.result_infos.result_info.mr_passed;
				var expectedAnswers = res[0].Contents.result_infos.result_info.estimated_total;

    // Check the status 10 times, and wait 'timeout' seconds between each iteration
    var iterToWait = 10;
    var sec = 1;
    if (args.timeout) {
    				sec = parseInt(args.timeout) || 1;
    }
				while (answers !== expectedAnswers && iterToWait-- > 0) {
								wait(sec);
								res = executeCommand('tn-result-info', args);
								if (res[0].Type === entryTypes.error) {
												return res[0];
								}
							 answers = res[0].Contents.result_infos.result_info.mr_passed;
        expectedAnswers = res[0].Contents.result_infos.result_info.estimated_total;
				}

    // Get question data (i.e. question result)
    var qDataRes = executeCommand('tn-result-data', args);
    if (!qDataRes[0].Contents.result_sets) {
        return qDataRes[0].Contents.Envelope.Body.return.command;
    }

				// Extract the relevant fields from the data
				itemCount = parseInt(qDataRes[0].Contents.result_sets.result_set.item_count);
				if (itemCount === 0) {
								return 'No results';
				}

    var output = "";
    var cs = qDataRes[0].Contents.result_sets.result_set.cs;
    var rs = qDataRes[0].Contents.result_sets.result_set.rs;

				// When a single item is returned, rs.r is a single object. Otherwise, it is an array...
    if (itemCount === 1) {
        var row = {};
    				for (var i=0; i < cs.c.length; i++) {
        				//output += cs.c[i].dn + ': ' + rs.r.c[i].v + '\n';
        				row[cs.c[i].dn] = formatCell(rs.r.c[i].v);
        }
        table.Contents.push(row);
    } else {
				    for (var item=0; item < itemCount; item++) {
								    var row = {};
								    for (var j=0; j < cs.c.length; j++) {
												    // output += cs.c[j].dn + ': ' + rs.r[item].c[j].v + '\n';
												    row[cs.c[j].dn] = formatCell(rs.r[item].c[j].v);
								    }
								    table.Contents.push(row);
				    }
				}

    if (table.Contents.length === 0) {
    			return 'No Results';
    }
    return table;
}

return res;
<|endoftext|>