<commit_before>'use strict';

if (!process.env.PLEXPY_TOKEN) {
    throw new Error('PLEXPY_TOKEN is required');
}

const Influx = require('influx');
const request = require('request-promise');

const checkInterval = process.env.UPDATE_INTERVAL_MS || 1000 * 30;

const influxClient = new Influx.InfluxDB({
    host: process.env.INFLUX_HOST || 'localhost',
    port: process.env.INFLUX_PORT || 8086,
    protocol: process.env.INFLUX_PROTOCOL || 'http',
    database: process.env.INFLUX_DB || 'plex'
});

const plexPyConfig = {
    token: process.env.PLEXPY_TOKEN || '',
    host: process.env.PLEXPY_HOST || 'localhost',
    protocol: process.env.PLEXPY_PROTOCOL ||'http',
    port: process.env.PLEXPY_PORT || 8181,
    baseUrl: process.env.PLEXPY_BASEURL || ''
};

const plexpyOptions = {
    url: `${plexPyConfig.protocol}://${plexPyConfig.host}:${plexPyConfig.port}/${plexPyConfig.baseUrl}/api/v2?apikey=${plexPyConfig.token}`,
    resolveWithFullResponse: true
};

const STATE_PLAYING = 'playing';
const STREAM_DIRECTPLAY = 'direct play';

let timer;

function log(message) {
    console.log(message);
}

function getPlexPyActivityData() {
    return request(Object.assign(plexpyOptions, {
        qs: { cmd: 'get_activity' }
    }));
}

function getPlexPyLibraryData() {
    return request(Object.assign(plexpyOptions, {
        qs: { cmd: 'get_libraries' }
    }));
}

function getPlexPyUsersData() {
    return request(Object.assign(plexpyOptions, {
        qs: { cmd: 'get_users_table' }
    }));
}

function writeToInflux(seriesName, values, tags) {
    return influxClient.writeMeasurement(seriesName, [{
        fields: values,
        tags: tags
    }]);
}

function groupBy(data, key) {
    let newArr = [], types = {};

    data.forEach(item => {
        if (!(item[key] in types)) {
            types[item[key]] = {type: item[key], data: []};
            newArr.push(types[item[key]]);
        }
        types[item[key]].data.push(item);
    });

    return newArr;
}

function onGetPlexPyActivityData(response) {
    let sessions = JSON.parse(response.body).response.data.sessions;

    if (sessions.length === 0) {
        api.log(`${new Date()}: No sessions to log`);
        return;
    }

    let sessionsByResolution = groupBy(sessions, 'video_resolution');

    sessionsByResolution.forEach(data => {
        let resolutionSessions = data.data;

        let sessionData = {
            total_stream_count: resolutionSessions && resolutionSessions.length || 0,
            total_stream_playing_count: 0,
            transcode_stream_count: 0,
            transcode_stream_playing_count: 0,
            direct_stream_count: 0,
            direct_stream_playing_count: 0
        };

        let tags = {
            resolution: data.type
        };

        resolutionSessions.forEach(session => {
            if (session.state !== STATE_PLAYING) {
                return;
            }

            if (session.transcode_decision === STREAM_DIRECTPLAY) {
                sessionData.direct_stream_count++;
                if (session.state === STATE_PLAYING) {
                    sessionData.direct_stream_playing_count++;
                }
            } else {
                sessionData.transcode_stream_count++;
                if (session.state === STATE_PLAYING) {
                    sessionData.transcode_stream_playing_count++;
                }
            }

            if (session.state === STATE_PLAYING) {
                sessionData.total_stream_playing_count++;
            }
        });

        writeToInflux('sessions', sessionData, tags).then(function(){
            api.log(`${new Date()}: wrote session data to influx`);
        });

    });

}

function onGetPlexPyLibraryData(response) {
    let libraryData = JSON.parse(response.body).response.data;

    libraryData.forEach(library => {
        let value = { count: Number(library.count) };
        let tags = {
            type: library.section_type,
            section: library.section_name
        };

        writeToInflux('library', value, tags).then(function(){
            api.log(`${new Date()}: wrote ${library.section_name} library data to influx`);
        });
    });
}

function onGetPlexPyUsersData(response) {
    let usersData = JSON.parse(response.body).response.data.data;

    usersData.forEach(user => {
        let value = {
            duration: user.duration,
            plays: user.plays
        };
        let tags = { username: user.friendly_name };

        writeToInflux('users', value, tags).then(function(){
            api.log(`${new Date()}: wrote ${user.friendly_name} user data to influx`);
        });
    });
}

function restart() {
    api.log(`${new Date()}: fetching plexpy metrics`);

    // Every {checkInterval} seconds
    timer = setTimeout(start, checkInterval);
}

function start() {
    let getActivityData = api.getPlexPyActivityData().then(onGetPlexPyActivityData);

    let getLibraryData = api.getPlexPyLibraryData().then(onGetPlexPyLibraryData);

    let getUserData = api.getPlexPyUsersData().then(onGetPlexPyUsersData);

    Promise.all([getActivityData, getLibraryData, getUserData]).then(restart, reason => {
        api.log(`${new Date()}: ${reason}`);
    });
}

function stop() {
    api.log(`${new Date()}: stopping plexpy2influx`);

    clearTimeout(timer);
}

let api = { getPlexPyActivityData, getPlexPyLibraryData, getPlexPyUsersData, log, start, stop, writeToInflux };

module.exports = api;
<commit_msg>Add Error Handling and Better Logging<commit_after>'use strict';

if (!process.env.PLEXPY_TOKEN) {
    throw new Error('PLEXPY_TOKEN is required');
}

const Influx = require('influx');
const request = require('request-promise');

const checkInterval = process.env.UPDATE_INTERVAL_MS || 1000 * 30;

const influxClient = new Influx.InfluxDB({
    host: process.env.INFLUX_HOST || 'localhost',
    port: process.env.INFLUX_PORT || 8086,
    protocol: process.env.INFLUX_PROTOCOL || 'http',
    database: process.env.INFLUX_DB || 'plex'
});

const plexPyConfig = {
    token: process.env.PLEXPY_TOKEN || '',
    host: process.env.PLEXPY_HOST || 'localhost',
    protocol: process.env.PLEXPY_PROTOCOL ||'http',
    port: process.env.PLEXPY_PORT || 8181,
    baseUrl: process.env.PLEXPY_BASEURL || ''
};

const plexpyOptions = {
    url: `${plexPyConfig.protocol}://${plexPyConfig.host}:${plexPyConfig.port}/${plexPyConfig.baseUrl}/api/v2?apikey=${plexPyConfig.token}`,
    resolveWithFullResponse: true
};

const STATE_PLAYING = 'playing';
const STREAM_DIRECTPLAY = 'direct play';

let timer;

function log(message) {
    console.log(message);
}

function getPlexPyActivityData() {
    api.log(`${new Date()}: Getting PlexPy Activity Data`);

    return request(Object.assign(plexpyOptions, {
        qs: { cmd: 'get_activity' }
    }));
}

function getPlexPyLibraryData() {
    api.log(`${new Date()}: Getting PlexPy Library Data`);

    return request(Object.assign(plexpyOptions, {
        qs: { cmd: 'get_libraries' }
    }));
}

function getPlexPyUsersData() {
    api.log(`${new Date()}: Getting PlexPy User Data`);

    return request(Object.assign(plexpyOptions, {
        qs: { cmd: 'get_users_table' }
    }));
}

function writeToInflux(seriesName, values, tags) {
    return influxClient.writeMeasurement(seriesName, [{
        fields: values,
        tags: tags
    }]);
}

function groupBy(data, key) {
    let newArr = [], types = {};

    data.forEach(item => {
        if (!(item[key] in types)) {
            types[item[key]] = {type: item[key], data: []};
            newArr.push(types[item[key]]);
        }
        types[item[key]].data.push(item);
    });

    return newArr;
}

function onGetPlexPyActivityData(response) {
    api.log(`${new Date()}: Parsing PlexPy Activity Data`);

    let sessions = JSON.parse(response.body).response.data.sessions;

    if (sessions.length === 0) {
        api.log(`${new Date()}: No sessions to log`);
        return;
    }

    let sessionsByResolution = groupBy(sessions, 'video_resolution');

    sessionsByResolution.forEach(data => {
        let resolutionSessions = data.data;

        let sessionData = {
            total_stream_count: resolutionSessions && resolutionSessions.length || 0,
            total_stream_playing_count: 0,
            transcode_stream_count: 0,
            transcode_stream_playing_count: 0,
            direct_stream_count: 0,
            direct_stream_playing_count: 0
        };

        let tags = {
            resolution: data.type
        };

        resolutionSessions.forEach(session => {
            if (session.state !== STATE_PLAYING) {
                return;
            }

            if (session.transcode_decision === STREAM_DIRECTPLAY) {
                sessionData.direct_stream_count++;
                if (session.state === STATE_PLAYING) {
                    sessionData.direct_stream_playing_count++;
                }
            } else {
                sessionData.transcode_stream_count++;
                if (session.state === STATE_PLAYING) {
                    sessionData.transcode_stream_playing_count++;
                }
            }

            if (session.state === STATE_PLAYING) {
                sessionData.total_stream_playing_count++;
            }
        });

        writeToInflux('sessions', sessionData, tags).then(function(){
            api.log(`${new Date()}: wrote session data to influx`);
        });

    });

}

function onGetPlexPyLibraryData(response) {
    api.log(`${new Date()}: Parsing PlexPy Library Data`);

    let libraryData = JSON.parse(response.body).response.data;

    libraryData.forEach(library => {
        let value = { count: Number(library.count) };
        let tags = {
            type: library.section_type,
            section: library.section_name
        };

        writeToInflux('library', value, tags).then(function(){
            api.log(`${new Date()}: wrote ${library.section_name} library data to influx`);
        });
    });
}

function onGetPlexPyUsersData(response) {
    api.log(`${new Date()}: Parsing PlexPy User Data`);

    let usersData = JSON.parse(response.body).response.data.data;

    usersData.forEach(user => {
        let value = {
            duration: user.duration,
            plays: user.plays
        };
        let tags = { username: user.friendly_name };

        writeToInflux('users', value, tags).then(function(){
            api.log(`${new Date()}: wrote ${user.friendly_name} user data to influx`);
        });
    });
}

function handleError(err) {
    api.log(`${new Date()}: Error`);
    api.log(err);
}

function restart() {
    // Every {checkInterval} seconds
    timer = setTimeout(start, checkInterval);
}

function start() {
    api.log(`${new Date()}: Initialize PlexPy2Influx`);

    let getActivityData = api.getPlexPyActivityData().then(onGetPlexPyActivityData).catch(handleError);

    let getLibraryData = api.getPlexPyLibraryData().then(onGetPlexPyLibraryData).catch(handleError);

    let getUserData = api.getPlexPyUsersData().then(onGetPlexPyUsersData).catch(handleError);

    Promise.all([getActivityData, getLibraryData, getUserData]).then(restart, reason => {
        api.log(`${new Date()}: ${reason}`);
    }).catch(handleError);
}

function stop() {
    api.log(`${new Date()}: stopping plexpy2influx`);

    clearTimeout(timer);
}

let api = { getPlexPyActivityData, getPlexPyLibraryData, getPlexPyUsersData, log, start, stop, writeToInflux };

module.exports = api;
<|endoftext|>


<commit_before>// Copyright 2018-2020, University of Colorado Boulder

/**
 * IOType for a window.Event
 *
 * @author Michael Kauzmann (PhET Interactive Simulations)
 * @author Chris Klusendorf (PhET Interactive Simulations)
 * @author Sam Reid (PhET Interactive Simulations)
 */

import ArrayIO from '../../../tandem/js/types/ArrayIO.js';
import BooleanIO from '../../../tandem/js/types/BooleanIO.js';
import IOType from '../../../tandem/js/types/IOType.js';
import NullableIO from '../../../tandem/js/types/NullableIO.js';
import NumberIO from '../../../tandem/js/types/NumberIO.js';
import StringIO from '../../../tandem/js/types/StringIO.js';
import scenery from '../scenery.js';

const EventIO = new IOType( 'EventIO', {
  valueType: window.Event,
  documentation: 'A DOM Event',
  toStateObject: domEvent => scenery.Input.serializeDomEvent( domEvent ),
  fromStateObject: stateObject => scenery.Input.deserializeDomEvent( stateObject ),

  // This should remain the same as Input.domEventPropertiesToSerialize (local var). Each key can be null depending on
  // what Event interface is being serialized (which depends on what DOM Event the instance is).
  stateSchema: EventIO => ( {
    pointerId: NullableIO( NumberIO ),
    pointerType: NullableIO( StringIO ),
    clientX: NullableIO( NumberIO ),
    clientY: NullableIO( NumberIO ),
    ctrlKey: NullableIO( BooleanIO ),
    shiftKey: NullableIO( BooleanIO ),
    altKey: NullableIO( BooleanIO ),
    metaKey: NullableIO( BooleanIO ),
    button: NullableIO( NumberIO ),
    relatedTarget: NullableIO( EventIO ),
    pageX: NullableIO( NumberIO ),
    pageY: NullableIO( NumberIO ),
    which: NullableIO( NumberIO ),
    type: NullableIO( StringIO ),
    target: NullableIO( EventIO ),
    keyCode: NullableIO( NumberIO ),
    key: NullableIO( StringIO ),
    deltaX: NullableIO( NumberIO ),
    deltaY: NullableIO( NumberIO ),
    deltaZ: NullableIO( NumberIO ),
    deltaMode: NullableIO( NumberIO ),
    charCode: NullableIO( NumberIO ),
    changedTouches: NullableIO( ArrayIO( EventIO ) ),
    scale: NullableIO( NumberIO )
  } )
} );

scenery.register( 'EventIO', EventIO );
export default EventIO;<commit_msg>update copyright dates from daily grunt work<commit_after>// Copyright 2018-2021, University of Colorado Boulder

/**
 * IOType for a window.Event
 *
 * @author Michael Kauzmann (PhET Interactive Simulations)
 * @author Chris Klusendorf (PhET Interactive Simulations)
 * @author Sam Reid (PhET Interactive Simulations)
 */

import ArrayIO from '../../../tandem/js/types/ArrayIO.js';
import BooleanIO from '../../../tandem/js/types/BooleanIO.js';
import IOType from '../../../tandem/js/types/IOType.js';
import NullableIO from '../../../tandem/js/types/NullableIO.js';
import NumberIO from '../../../tandem/js/types/NumberIO.js';
import StringIO from '../../../tandem/js/types/StringIO.js';
import scenery from '../scenery.js';

const EventIO = new IOType( 'EventIO', {
  valueType: window.Event,
  documentation: 'A DOM Event',
  toStateObject: domEvent => scenery.Input.serializeDomEvent( domEvent ),
  fromStateObject: stateObject => scenery.Input.deserializeDomEvent( stateObject ),

  // This should remain the same as Input.domEventPropertiesToSerialize (local var). Each key can be null depending on
  // what Event interface is being serialized (which depends on what DOM Event the instance is).
  stateSchema: EventIO => ( {
    pointerId: NullableIO( NumberIO ),
    pointerType: NullableIO( StringIO ),
    clientX: NullableIO( NumberIO ),
    clientY: NullableIO( NumberIO ),
    ctrlKey: NullableIO( BooleanIO ),
    shiftKey: NullableIO( BooleanIO ),
    altKey: NullableIO( BooleanIO ),
    metaKey: NullableIO( BooleanIO ),
    button: NullableIO( NumberIO ),
    relatedTarget: NullableIO( EventIO ),
    pageX: NullableIO( NumberIO ),
    pageY: NullableIO( NumberIO ),
    which: NullableIO( NumberIO ),
    type: NullableIO( StringIO ),
    target: NullableIO( EventIO ),
    keyCode: NullableIO( NumberIO ),
    key: NullableIO( StringIO ),
    deltaX: NullableIO( NumberIO ),
    deltaY: NullableIO( NumberIO ),
    deltaZ: NullableIO( NumberIO ),
    deltaMode: NullableIO( NumberIO ),
    charCode: NullableIO( NumberIO ),
    changedTouches: NullableIO( ArrayIO( EventIO ) ),
    scale: NullableIO( NumberIO )
  } )
} );

scenery.register( 'EventIO', EventIO );
export default EventIO;<|endoftext|>


<commit_before>'use strict';
var yeoman = require('yeoman-generator');
var chalk = require('chalk');
var yosay = require('yosay');
var mkdirp = require('mkdirp');

module.exports = yeoman.generators.Base.extend({
  prompting: function () {
    var done = this.async();
    var questions = 3;
    // Have Yeoman greet the user.
    this.log(yosay(
      'Welcome to the finest ' + chalk.red('generator-jrocket') + ' generator!'
    ));

    var prompts = [
      {
        type: 'string',
        name: 'baseName',
        message: '(1/' + questions + ') What is the base name of your application?',
        default: 'app'
      },
      {
        type: 'string',
        name: 'packageName',
        message: '(2/' + questions + ') What is your default Java package name?',
        default: 'com.myapp'
      },
      {
        type: 'list',
        name: 'testingFramework',
        message: '(3/' + questions + ') Which testing framework would you like to use?',
        choices: [
          {
            value: 'junit',
            name: 'Junit with mockito (tests in src/test/java)'
          },
          {
            value: 'spock',
            name: 'Spock with groovy (tests in src/test/groovy)'
          }
        ],
        default: 0
      }
    ];

    this.prompt(prompts, function (props) {
      this.props = props;
      this.baseName = this.props.baseName;
      this.packageName = this.props.packageName;
      this.testingFramework = this.props.testingFramework;

      done();
    }.bind(this));
  },

  writing: function () {

    // create server
    var serverDir = 'server/';
    this.template(serverDir + 'pom.xml', serverDir + 'pom.xml', this, {});

    var packageFolder = this.packageName.replace(/\./g, '/');
    var srcDir = serverDir + 'src/main/java/';
    var srcDestDir = srcDir + packageFolder + '/';

    this.template(srcDir + 'Application.java', srcDestDir + 'Application.java', this, {});
    this.template(srcDir + 'config/spark/JsonUtil.java', srcDestDir + 'config/spark/JsonUtil.java', this, {});
    this.template(srcDir + 'config/spark/Spark.java', srcDestDir + 'config/spark/Spark.java', this, {});
    this.template(srcDir + 'config/spark/SparkConfiguration.java', srcDestDir + 'config/spark/SparkConfiguration.java', this, {});
    this.template(srcDir + 'rest/HelloSpark.java', srcDestDir + 'rest/HelloSpark.java', this, {});

    var resourcesDir = serverDir + 'src/main/resources/';
    this.template(resourcesDir + 'application.properties', resourcesDir + 'application.properties', this, {});
    this.template(resourcesDir + 'logback.xml', resourcesDir + 'logback.xml', this, {});

    var resourcesTestDir = serverDir + 'src/test/resources/';
    this.template(resourcesTestDir + 'application.properties', resourcesTestDir + 'application.properties', this, {});
    if (this.testingFramework == 'spock') {
      var testDir = 'src/test/groovy/';
      var testSrcDir = serverDir + testDir;
      var testDestDir = testSrcDir + packageFolder + '/';
      this.template(testSrcDir + 'ApplicationSpec.groovy', testDestDir + 'ApplicationSpec.groovy', this, {});
    } else {
      var testDir = 'src/test/java/';
      var testSrcDir = serverDir + testDir;
      var testDestDir = testSrcDir + packageFolder + '/';
      this.template(testSrcDir + 'ApplicationTest.java', testDestDir + 'ApplicationTest.java', this, {});
    }

    // create client
    var clientDir = 'client/';
    this.template(clientDir + 'gulpfile.js', clientDir + 'gulpfile.js', this, {});
    this.template(clientDir + 'karma.conf.js', clientDir + 'karma.conf.js', this, {});
    this.template(clientDir + 'package.json', clientDir + 'package.json', this, {});
    this.template(clientDir + 'test-main.js', clientDir + 'test-main.js', this, {});
    this.template(clientDir + 'tsconfig.json', clientDir + 'tsconfig.json', this, {});
    this.template(clientDir + 'tsd.json', clientDir + 'tsd.json', this, {});

    var clientSrcDir = 'client/src/';
    this.template(clientSrcDir + 'index.html', clientSrcDir + 'index.html', this, {});
    this.template(clientSrcDir + 'bootstrap.ts', clientSrcDir + 'bootstrap.ts', this, {});

    var clientComponentsSrcDir = clientSrcDir + 'components/';
    this.template(clientComponentsSrcDir + 'app/app.component.ts', clientComponentsSrcDir + 'app/app.component.ts', this, {});
    this.template(clientComponentsSrcDir + 'app/app.component.spec.ts', clientComponentsSrcDir + 'app/app.component.spec.ts', this, {});

    var clientServicesSrcDir = clientSrcDir + 'services/';
    this.template(clientServicesSrcDir + 'hello-world.service.ts', clientServicesSrcDir + 'hello-world.service.ts', this, {});

    var clientToolsDir = 'client/tools/';
    var clientToolsGulpTasksSrcDir = clientToolsDir + 'gulp-tasks/';
    this.template(clientToolsGulpTasksSrcDir + 'clean.js', clientToolsGulpTasksSrcDir + 'clean.js', this, {});
    this.template(clientToolsGulpTasksSrcDir + 'css.js', clientToolsGulpTasksSrcDir + 'css.js', this, {});
    this.template(clientToolsGulpTasksSrcDir + 'html.js', clientToolsGulpTasksSrcDir + 'html.js', this, {});
    this.template(clientToolsGulpTasksSrcDir + 'lib.js', clientToolsGulpTasksSrcDir + 'lib.js', this, {});
    this.template(clientToolsGulpTasksSrcDir + 'serve.js', clientToolsGulpTasksSrcDir + 'serve.js', this, {});
    this.template(clientToolsGulpTasksSrcDir + 'test.js', clientToolsGulpTasksSrcDir + 'test.js', this, {});
    this.template(clientToolsGulpTasksSrcDir + 'typescript.js', clientToolsGulpTasksSrcDir + 'typescript.js', this, {});

    var clientToolsTypingsSrcDir = clientToolsDir + 'typings/';
    this.template(clientToolsTypingsSrcDir + 'tsd.d.ts', clientToolsTypingsSrcDir + 'tsd.d.ts', this, {});

    this.config.set('baseName', this.baseName);
    this.config.set('packageName', this.packageName);
  },

  install: function () {
    //this.installDependencies();
  }
});
<commit_msg>[client] tests are still not supported<commit_after>'use strict';
var yeoman = require('yeoman-generator');
var chalk = require('chalk');
var yosay = require('yosay');
var mkdirp = require('mkdirp');

module.exports = yeoman.generators.Base.extend({
  prompting: function () {
    var done = this.async();
    var questions = 3;
    // Have Yeoman greet the user.
    this.log(yosay(
      'Welcome to the finest ' + chalk.red('generator-jrocket') + ' generator!'
    ));

    var prompts = [
      {
        type: 'string',
        name: 'baseName',
        message: '(1/' + questions + ') What is the base name of your application?',
        default: 'app'
      },
      {
        type: 'string',
        name: 'packageName',
        message: '(2/' + questions + ') What is your default Java package name?',
        default: 'com.myapp'
      },
      {
        type: 'list',
        name: 'testingFramework',
        message: '(3/' + questions + ') Which testing framework would you like to use?',
        choices: [
          {
            value: 'junit',
            name: 'Junit with mockito (tests in src/test/java)'
          },
          {
            value: 'spock',
            name: 'Spock with groovy (tests in src/test/groovy)'
          }
        ],
        default: 0
      }
    ];

    this.prompt(prompts, function (props) {
      this.props = props;
      this.baseName = this.props.baseName;
      this.packageName = this.props.packageName;
      this.testingFramework = this.props.testingFramework;

      done();
    }.bind(this));
  },

  writing: function () {

    // create server
    var serverDir = 'server/';
    this.template(serverDir + 'pom.xml', serverDir + 'pom.xml', this, {});

    var packageFolder = this.packageName.replace(/\./g, '/');
    var srcDir = serverDir + 'src/main/java/';
    var srcDestDir = srcDir + packageFolder + '/';

    this.template(srcDir + 'Application.java', srcDestDir + 'Application.java', this, {});
    this.template(srcDir + 'config/spark/JsonUtil.java', srcDestDir + 'config/spark/JsonUtil.java', this, {});
    this.template(srcDir + 'config/spark/Spark.java', srcDestDir + 'config/spark/Spark.java', this, {});
    this.template(srcDir + 'config/spark/SparkConfiguration.java', srcDestDir + 'config/spark/SparkConfiguration.java', this, {});
    this.template(srcDir + 'rest/HelloSpark.java', srcDestDir + 'rest/HelloSpark.java', this, {});

    var resourcesDir = serverDir + 'src/main/resources/';
    this.template(resourcesDir + 'application.properties', resourcesDir + 'application.properties', this, {});
    this.template(resourcesDir + 'logback.xml', resourcesDir + 'logback.xml', this, {});

    var resourcesTestDir = serverDir + 'src/test/resources/';
    this.template(resourcesTestDir + 'application.properties', resourcesTestDir + 'application.properties', this, {});
    if (this.testingFramework == 'spock') {
      var testDir = 'src/test/groovy/';
      var testSrcDir = serverDir + testDir;
      var testDestDir = testSrcDir + packageFolder + '/';
      this.template(testSrcDir + 'ApplicationSpec.groovy', testDestDir + 'ApplicationSpec.groovy', this, {});
    } else {
      var testDir = 'src/test/java/';
      var testSrcDir = serverDir + testDir;
      var testDestDir = testSrcDir + packageFolder + '/';
      this.template(testSrcDir + 'ApplicationTest.java', testDestDir + 'ApplicationTest.java', this, {});
    }

    // create client
    var clientDir = 'client/';
    this.template(clientDir + 'gulpfile.js', clientDir + 'gulpfile.js', this, {});
    this.template(clientDir + 'karma.conf.js', clientDir + 'karma.conf.js', this, {});
    this.template(clientDir + 'package.json', clientDir + 'package.json', this, {});
    this.template(clientDir + 'test-main.js', clientDir + 'test-main.js', this, {});
    this.template(clientDir + 'tsconfig.json', clientDir + 'tsconfig.json', this, {});
    this.template(clientDir + 'tsd.json', clientDir + 'tsd.json', this, {});

    var clientSrcDir = 'client/src/';
    this.template(clientSrcDir + 'index.html', clientSrcDir + 'index.html', this, {});
    this.template(clientSrcDir + 'bootstrap.ts', clientSrcDir + 'bootstrap.ts', this, {});

    var clientComponentsSrcDir = clientSrcDir + 'components/';
    this.template(clientComponentsSrcDir + 'app/app.component.ts', clientComponentsSrcDir + 'app/app.component.ts', this, {});
    //this.template(clientComponentsSrcDir + 'app/app.component.spec.ts', clientComponentsSrcDir + 'app/app.component.spec.ts', this, {});

    var clientServicesSrcDir = clientSrcDir + 'services/';
    this.template(clientServicesSrcDir + 'hello-world.service.ts', clientServicesSrcDir + 'hello-world.service.ts', this, {});

    var clientToolsDir = 'client/tools/';
    var clientToolsGulpTasksSrcDir = clientToolsDir + 'gulp-tasks/';
    this.template(clientToolsGulpTasksSrcDir + 'clean.js', clientToolsGulpTasksSrcDir + 'clean.js', this, {});
    this.template(clientToolsGulpTasksSrcDir + 'css.js', clientToolsGulpTasksSrcDir + 'css.js', this, {});
    this.template(clientToolsGulpTasksSrcDir + 'html.js', clientToolsGulpTasksSrcDir + 'html.js', this, {});
    this.template(clientToolsGulpTasksSrcDir + 'lib.js', clientToolsGulpTasksSrcDir + 'lib.js', this, {});
    this.template(clientToolsGulpTasksSrcDir + 'serve.js', clientToolsGulpTasksSrcDir + 'serve.js', this, {});
    this.template(clientToolsGulpTasksSrcDir + 'test.js', clientToolsGulpTasksSrcDir + 'test.js', this, {});
    this.template(clientToolsGulpTasksSrcDir + 'typescript.js', clientToolsGulpTasksSrcDir + 'typescript.js', this, {});

    var clientToolsTypingsSrcDir = clientToolsDir + 'typings/';
    this.template(clientToolsTypingsSrcDir + 'tsd.d.ts', clientToolsTypingsSrcDir + 'tsd.d.ts', this, {});

    this.config.set('baseName', this.baseName);
    this.config.set('packageName', this.packageName);
  },

  install: function () {
    //this.installDependencies();
  }
});
<|endoftext|>


<commit_before>'use strict';

const Generator = require('yeoman-generator');
const chalk = require('chalk');
const yosay = require('yosay');
const npmWhoami = require('npm-whoami');
const path = require('path');
const file = require('file');
const _ = require('lodash');
const jsonEscape = require('../../utils/').jsonEscape;

let config;

module.exports = Generator.extend({
  initializing: function() {
    this.pkg = require('../../package.json');
    this.dirname = path.basename(this.destinationRoot());
  },

  prompting: function() {
    this.log(yosay(
      'Welcome to the ' + chalk.red('Hapi API Generator') + ' generator!'
    ));

    this.username = '';
    try {
      this.username = npmWhoami.sync();
    } catch(e) {
      console.warn('Error getting npm user name: run `npm login`');
    }

    const gitName = this.user.git.name();
    const gitEmail = this.user.git.email();
    let defaultAuthor = gitName ? gitName : '';
    if (gitEmail) {
      defaultAuthor += ` <${gitEmail}>`;
    }

    const prompts = [
      {
        type: 'input',
        name: 'user',
        message: 'What is the username/organization for this project?',
        default: this.username,
        store: true
      },
      {
        type: 'input',
        name: 'repo',
        message: 'What is the repository/project name?',
        default: this.dirname
      },
      {
        type: 'input',
        name: 'description',
        message: 'What is a description for this project?',
        default: 'My awesome API'
      },
      {
        type: 'input',
        name: 'author',
        message: 'Who is the author of this project?',
        default: defaultAuthor,
        store: true
      },
      {
        type: 'input',
        name: 'apiPrefix',
        message: 'How do you want to prefix your API endpoint? (Type \'/\' for no prefix)',
        default: '/api/v1'
      },
      {
        type: 'input',
        name: 'dbName',
        message: 'How do you want to call the database for this project?',
        default: 'my-api'
      }
    ];

    return this.prompt(prompts).then((props) => {
      let apiPrefix = jsonEscape(props.apiPrefix);
      apiPrefix = apiPrefix === '/' ? '' : apiPrefix;

      const repo = jsonEscape(props.repo);

      config = {
        user: jsonEscape(props.user),
        repo: repo,
        kebabRepoName: _.kebabCase(repo),
        description: jsonEscape(props.description),
        author: jsonEscape(props.author),
        projectName: _.camelCase(jsonEscape(props.repo)),
        dbName: jsonEscape(props.dbName),
        dbConnectionName: _.camelCase(props.dbName),
        apiPrefix: apiPrefix
      };
    });
  },

  writing: {
    app: function() {
      const src = this.sourceRoot();
      file.walkSync(src, (dirPath, dirs, files) => {
        const relativeDir = path.relative(src, dirPath);
        files.forEach((filename) => {
          this.fs.copyTpl(
            this.templatePath(relativeDir, filename),
            this.destinationPath(relativeDir, filename),
            config
          );
        });
      });
    }
  },

  install: function() {
    this.installDependencies({
      bower: false,
      npm: true,
      skipInstall: this.options['skip-install']
    });
  }
});
<commit_msg>Init git repository before install<commit_after>'use strict';

const Generator = require('yeoman-generator');
const chalk = require('chalk');
const yosay = require('yosay');
const npmWhoami = require('npm-whoami');
const path = require('path');
const file = require('file');
const _ = require('lodash');
const jsonEscape = require('../../utils/').jsonEscape;

let config;

module.exports = Generator.extend({
  initializing: function() {
    this.pkg = require('../../package.json');
    this.dirname = path.basename(this.destinationRoot());
  },

  prompting: function() {
    this.log(yosay(
      'Welcome to the ' + chalk.red('Hapi API Generator') + ' generator!'
    ));

    this.username = '';
    try {
      this.username = npmWhoami.sync();
    } catch(e) {
      console.warn('Error getting npm user name: run `npm login`');
    }

    const gitName = this.user.git.name();
    const gitEmail = this.user.git.email();
    let defaultAuthor = gitName ? gitName : '';
    if (gitEmail) {
      defaultAuthor += ` <${gitEmail}>`;
    }

    const prompts = [
      {
        type: 'input',
        name: 'user',
        message: 'What is the username/organization for this project?',
        default: this.username,
        store: true
      },
      {
        type: 'input',
        name: 'repo',
        message: 'What is the repository/project name?',
        default: this.dirname
      },
      {
        type: 'input',
        name: 'description',
        message: 'What is a description for this project?',
        default: 'My awesome API'
      },
      {
        type: 'input',
        name: 'author',
        message: 'Who is the author of this project?',
        default: defaultAuthor,
        store: true
      },
      {
        type: 'input',
        name: 'apiPrefix',
        message: 'How do you want to prefix your API endpoint? (Type \'/\' for no prefix)',
        default: '/api/v1'
      },
      {
        type: 'input',
        name: 'dbName',
        message: 'How do you want to call the database for this project?',
        default: 'my-api'
      }
    ];

    return this.prompt(prompts).then((props) => {
      let apiPrefix = jsonEscape(props.apiPrefix);
      apiPrefix = apiPrefix === '/' ? '' : apiPrefix;

      const repo = jsonEscape(props.repo);

      config = {
        user: jsonEscape(props.user),
        repo: repo,
        kebabRepoName: _.kebabCase(repo),
        description: jsonEscape(props.description),
        author: jsonEscape(props.author),
        projectName: _.camelCase(jsonEscape(props.repo)),
        dbName: jsonEscape(props.dbName),
        dbConnectionName: _.camelCase(props.dbName),
        apiPrefix: apiPrefix
      };
    });
  },

  writing: {
    app: function() {
      const src = this.sourceRoot();
      file.walkSync(src, (dirPath, dirs, files) => {
        const relativeDir = path.relative(src, dirPath);
        files.forEach((filename) => {
          this.fs.copyTpl(
            this.templatePath(relativeDir, filename),
            this.destinationPath(relativeDir, filename),
            config
          );
        });
      });
    }
  },

  install: function() {
    this.spawnCommandSync('git', ['init', '-q']);
    this.log(`\n\n\nInitialized empty Git repository in ${this.destinationRoot()}`);
    this.installDependencies({
      bower: false,
      npm: true,
      skipInstall: this.options['skip-install']
    });
  }
});
<|endoftext|>


<commit_before><commit_msg>[PORTTISK-1241] users published layers listing removed for now<commit_after><|endoftext|>


<commit_before>'use strict';
var yeoman = require('yeoman-generator');
var chalk = require('chalk');
var yosay = require('yosay');

const tplCopy = function (name, to, props) {
  this.fs.copyTpl(
    this.templatePath(name),
    this.destinationPath(to || name),
    (props || this.props)
  );
};

const fileListCopy = function (files, dest) {
  const cpy = tplCopy.bind(this);
  files.forEach(filename => {
    cpy(filename, dest, this.props);
  });
};

const availableFeatures = [
  'redux'
];

module.exports = yeoman.Base.extend({
  prompting: function () {
    // Have Yeoman greet the user.
    this.log(yosay(
      'Welcome to the gnarly ' + chalk.red('generator-react-gen') + ' generator!'
    ));

    var prompts = [{
      type: 'input',
      name: 'title',
      message: 'App name',
      default: this.appname
    }, {
      type: 'input',
      name: 'authorName',
      message: 'Author name',
      default: 'Ari Lerner'
    }, {
      type: 'input',
      name: 'authorEmail',
      message: 'Author email',
      default: 'ari@fullstack.io'
    }];

    // feature options
    availableFeatures.forEach(feature => this.option(feature));

    return this.prompt(prompts)
    .then(function (props) {
      // To access props later use this.props.someAnswer;
      this.props = props;

      this.features = [];
      availableFeatures.forEach(feature => {
        if (this.options[feature]) {
          this.features.push(feature);
        }
      });
    }.bind(this));
  },

  writing: function () {
    // root files
    var copyFiles = fileListCopy.bind(this);
    var baseFiles = ['package.json',
      'webpack.config.js',
      'karma.conf.js',
      '.babelrc',
      'src/'
    ];
    var dependencies = [
      'react', 'react-dom', 'classnames', 'font-awesome',
      'react-router', 'react-router-redux'
    ];
    var devDependencies = [
      'autoprefixer',
      'babel-core',
      'babel-loader',
      'babel-plugin-transform-es2015-modules-umd',
      'babel-polyfill',
      'babel-preset-es2015',
      'babel-preset-react',
      'babel-preset-react-hmre',
      'babel-preset-stage-0',
      'babel-register',
      'chai',
      'chai-enzyme',
      'cross-env',
      'css-loader',
      'cssnano',
      'dotenv',
      'enzyme',
      'expect',
      'file-loader',
      'hjs-webpack',
      'jasmine-core',
      'json-loader',
      'karma',
      'karma-chai',
      'karma-jasmine',
      'karma-mocha',
      'karma-phantomjs-launcher',
      'karma-sourcemap-loader',
      'karma-spec-reporter',
      'karma-webpack',
      'mocha',
      'phantomjs-polyfill',
      'phantomjs-prebuilt',
      'postcss-loader',
      'precss',
      'react-addons-test-utils',
      'sinon',
      'style-loader',
      'url-loader',
      'webpack'
    ];

    var featureFiles = {
      redux: {
        'src/': {
          dependencies: ['react-redux',
            'redux-module-builder', 'redux-thunk'],
          devDependencies: ['redux-devtools',
          'redux-devtools-log-monitor', 'redux-devtools-dock-monitor'],
          files: ['features/redux/']
        }
      }
    };

    copyFiles(baseFiles);
    const cp = tplCopy.bind(this);
    cp("env", ".env", this.props);

    this.features.forEach(featureKey => {
      this.log(`======> Enabling ` + chalk.blue(featureKey));
      const feat = featureFiles[featureKey];
      Object.keys(feat)
      .forEach(key => {
        const dest = key;
        const feature = feat[key];
        const files = feature.files;
        copyFiles(files, dest);

        if (feature.dependencies) {
          dependencies = dependencies.concat(feature.dependencies);
        }
        if (feature.devDependencies) {
          devDependencies =
            devDependencies.concat(feature.devDependencies);
        }
      });
    });

    this.npmInstall(dependencies, {save: true});
    this.npmInstall(devDependencies, {saveDev: true});
  },

  install: function () {
    this.installDependencies();
  }
});
<commit_msg>add tests.webpack.js<commit_after>'use strict';
var yeoman = require('yeoman-generator');
var chalk = require('chalk');
var yosay = require('yosay');

const tplCopy = function (name, to, props) {
  this.fs.copyTpl(
    this.templatePath(name),
    this.destinationPath(to || name),
    (props || this.props)
  );
};

const fileListCopy = function (files, dest) {
  const cpy = tplCopy.bind(this);
  files.forEach(filename => {
    cpy(filename, dest, this.props);
  });
};

const availableFeatures = [
  'redux'
];

module.exports = yeoman.Base.extend({
  prompting: function () {
    // Have Yeoman greet the user.
    this.log(yosay(
      'Welcome to the gnarly ' + chalk.red('generator-react-gen') + ' generator!'
    ));

    var prompts = [{
      type: 'input',
      name: 'title',
      message: 'App name',
      default: this.appname
    }, {
      type: 'input',
      name: 'authorName',
      message: 'Author name',
      default: 'Ari Lerner'
    }, {
      type: 'input',
      name: 'authorEmail',
      message: 'Author email',
      default: 'ari@fullstack.io'
    }];

    // feature options
    availableFeatures.forEach(feature => this.option(feature));

    return this.prompt(prompts)
    .then(function (props) {
      // To access props later use this.props.someAnswer;
      this.props = props;

      this.features = [];
      availableFeatures.forEach(feature => {
        if (this.options[feature]) {
          this.features.push(feature);
        }
      });
    }.bind(this));
  },

  writing: function () {
    // root files
    var copyFiles = fileListCopy.bind(this);
    var baseFiles = ['package.json',
      'tests.webpack.js',
      'webpack.config.js',
      'karma.conf.js',
      '.babelrc',
      'src/'
    ];
    var dependencies = [
      'react', 'react-dom', 'classnames', 'font-awesome',
      'react-router', 'react-router-redux'
    ];
    var devDependencies = [
      'autoprefixer',
      'babel-core',
      'babel-loader',
      'babel-plugin-transform-es2015-modules-umd',
      'babel-polyfill',
      'babel-preset-es2015',
      'babel-preset-react',
      'babel-preset-react-hmre',
      'babel-preset-stage-0',
      'babel-register',
      'chai',
      'chai-enzyme',
      'cross-env',
      'css-loader',
      'cssnano',
      'dotenv',
      'enzyme',
      'expect',
      'file-loader',
      'hjs-webpack',
      'jasmine-core',
      'json-loader',
      'karma',
      'karma-chai',
      'karma-jasmine',
      'karma-mocha',
      'karma-phantomjs-launcher',
      'karma-sourcemap-loader',
      'karma-spec-reporter',
      'karma-webpack',
      'mocha',
      'phantomjs-polyfill',
      'phantomjs-prebuilt',
      'postcss-loader',
      'precss',
      'react-addons-test-utils',
      'sinon',
      'style-loader',
      'url-loader',
      'webpack'
    ];

    var featureFiles = {
      redux: {
        'src/': {
          dependencies: ['react-redux',
            'redux-module-builder', 'redux-thunk'],
          devDependencies: ['redux-devtools',
          'redux-devtools-log-monitor', 'redux-devtools-dock-monitor'],
          files: ['features/redux/']
        }
      }
    };

    copyFiles(baseFiles);
    const cp = tplCopy.bind(this);
    cp("env", ".env", this.props);

    this.features.forEach(featureKey => {
      this.log(`======> Enabling ` + chalk.blue(featureKey));
      const feat = featureFiles[featureKey];
      Object.keys(feat)
      .forEach(key => {
        const dest = key;
        const feature = feat[key];
        const files = feature.files;
        copyFiles(files, dest);

        if (feature.dependencies) {
          dependencies = dependencies.concat(feature.dependencies);
        }
        if (feature.devDependencies) {
          devDependencies =
            devDependencies.concat(feature.devDependencies);
        }
      });
    });

    this.npmInstall(dependencies, {save: true});
    this.npmInstall(devDependencies, {saveDev: true});
  },

  install: function () {
    this.installDependencies();
  }
});
<|endoftext|>


<commit_before>'use strict';

/**
 * Drizzle Project Yeoman Generator
 *
 * @example yo drizzle
 * @example yo drizzle --full
 * @example yo drizzle --help
 */

const chalk = require('chalk');
const inquirer = require('inquirer');
const yeoman = require('yeoman-generator');
const utils = require('./utils');

const PackageType = {
  POSTCSS: 'PostCSS',
  JS: 'JavaScript'
};

const INTRO = `
${chalk.bold.underline('Welcome to your new Drizzle project.')}
${chalk.dim('Beginning setup phase...')}
`;

const OUTRO = `
${chalk.dim('Setup phase completed.')}
`;

// Command options (e.g. you drizzle --full)
const standardOptions = new Map([
  ['full', {
    desc: 'Present the full list of prompts.',
    type: Boolean,
    default: false
  }]
]);

// Optional things to install
const dependencies = new Map([
  ['gsap', PackageType.JS],
  ['jquery', PackageType.JS],
  ['lodash', PackageType.JS],
  ['moment', PackageType.JS],
  ['ramda', PackageType.JS],
  ['postcss-easings', PackageType.POSTCSS],
  ['postcss-mixins', PackageType.POSTCSS],
  ['css-modularscale', PackageType.POSTCSS]
]);

// Separator for list/checkbox prompts.
const separator = label =>
  new inquirer.Separator(`--- ${label} ---`);

// Always presented
const standardPrompts = [
  {
    name: 'title',
    type: 'input',
    message: 'Title',
    default: 'Untitled Drizzle Project'
  },
  {
    name: 'description',
    type: 'input',
    message: 'Description',
    default: 'A description of my project.'
  }
];

// Presented when the --full option is used
const extraPrompts = [
  {
    name: 'dependencies',
    type: 'checkbox',
    message: 'Include optional packages?',
    choices () {
      const depGroups = utils.groupByVal(Array.from(dependencies));
      const choices = [];

      Object.keys(depGroups).forEach(key => {
        choices.push(separator(key));
        choices.push.apply(choices, depGroups[key].map(utils.pairKey));
      });

      return choices;
    }
  },
  {
    name: 'serviceWorker',
    type: 'confirm',
    message: `Include a ${chalk.underline('service-worker.js')} script?`,
    default: false
  }
];

module.exports = class extends yeoman.Base {
  /**
   * Define options and arguments.
   * Set the default properties (for optional prompts).
   */
  constructor (args, options) {
    super(args, options);

    // Setup options
    standardOptions.forEach((val, key) =>
      this.option(key, val)
    );

    // Setup default props
    this.props = {
      dependencies: [],
      slug: utils.toSlug(this.appname)
    };

    this.log(INTRO);
  }

  /**
   * Show the intro message.
   * Present the prompts.
   * Assign thier answers as properties.
   */
  prompting () {
    const done = this.async();
    const prompts = this.options.full ?
      standardPrompts.concat(extraPrompts) : standardPrompts;

    this.prompt(prompts, props => {
      // Assign input props (must be done first)
      Object.assign(this.props, props);

      done();
    });
  }

  /**
   * Copy Drizzle folder contents to destination.
   * Copy .github files to destination (TODO: move these to Drizzle)
   * Render README.md template to destination.
   */
  writing () {
    const dest = this.destinationPath();
    const templates = this.templatePath();

    this.fs.copy(`${templates}/drizzle/**/*`, dest, {
      globOptions: {
        dot: true,
        ignore: [
          '**/.git',
          '**/.travis.yml',
          '**/LICENSE',
          '**/README.md'
        ]
      }
    });

    this.fs.copy(
      `${templates}/.github`, `${dest}/.github`
    );

    this.fs.copyTpl(
      `${templates}/README.md`,
      `${dest}/README.md`,
      this.props
    );
  }

  /**
   * Extend the Drizzle package.json with prompt values.
   * Install dependencies selected via prompt.
   */
  install () {
    if (this.options.full && this.props.dependencies.length) {
      this.npmInstall(this.props.dependencies, {
        saveDev: true
      });
    }
  }

  /**
   * Signal the end.
   */
  end () {
    this.log(OUTRO);
  }
};
<commit_msg>Simplify install logic<commit_after>'use strict';

/**
 * Drizzle Project Yeoman Generator
 *
 * @example yo drizzle
 * @example yo drizzle --full
 * @example yo drizzle --help
 */

const chalk = require('chalk');
const inquirer = require('inquirer');
const yeoman = require('yeoman-generator');
const utils = require('./utils');

const PackageType = {
  POSTCSS: 'PostCSS',
  JS: 'JavaScript'
};

const INTRO = `
${chalk.bold.underline('Welcome to your new Drizzle project.')}
${chalk.dim('Beginning setup phase...')}
`;

const OUTRO = `
${chalk.dim('Setup phase completed.')}
`;

// Command options (e.g. you drizzle --full)
const standardOptions = new Map([
  ['full', {
    desc: 'Present the full list of prompts.',
    type: Boolean,
    default: false
  }]
]);

// Optional things to install
const dependencies = new Map([
  ['gsap', PackageType.JS],
  ['jquery', PackageType.JS],
  ['lodash', PackageType.JS],
  ['moment', PackageType.JS],
  ['ramda', PackageType.JS],
  ['postcss-easings', PackageType.POSTCSS],
  ['postcss-mixins', PackageType.POSTCSS],
  ['css-modularscale', PackageType.POSTCSS]
]);

// Separator for list/checkbox prompts.
const separator = label =>
  new inquirer.Separator(`--- ${label} ---`);

// Always presented
const standardPrompts = [
  {
    name: 'title',
    type: 'input',
    message: 'Title',
    default: 'Untitled Drizzle Project'
  },
  {
    name: 'description',
    type: 'input',
    message: 'Description',
    default: 'A description of my project.'
  }
];

// Presented when the --full option is used
const extraPrompts = [
  {
    name: 'dependencies',
    type: 'checkbox',
    message: 'Include optional packages?',
    choices () {
      const depGroups = utils.groupByVal(Array.from(dependencies));
      const choices = [];

      Object.keys(depGroups).forEach(key => {
        choices.push(separator(key));
        choices.push.apply(choices, depGroups[key].map(utils.pairKey));
      });

      return choices;
    }
  },
  {
    name: 'serviceWorker',
    type: 'confirm',
    message: `Include a ${chalk.underline('service-worker.js')} script?`,
    default: false
  }
];

module.exports = class extends yeoman.Base {
  /**
   * Define options and arguments.
   * Set the default properties (for optional prompts).
   */
  constructor (args, options) {
    super(args, options);

    // Setup options
    standardOptions.forEach((val, key) =>
      this.option(key, val)
    );

    // Setup default props
    this.props = {
      dependencies: [],
      slug: utils.toSlug(this.appname)
    };

    this.log(INTRO);
  }

  /**
   * Show the intro message.
   * Present the prompts.
   * Assign thier answers as properties.
   */
  prompting () {
    const done = this.async();
    const prompts = this.options.full ?
      standardPrompts.concat(extraPrompts) : standardPrompts;

    this.prompt(prompts, props => {
      // Assign input props (must be done first)
      Object.assign(this.props, props);

      done();
    });
  }

  /**
   * Copy Drizzle folder contents to destination.
   * Copy .github files to destination (TODO: move these to Drizzle)
   * Render README.md template to destination.
   */
  writing () {
    const dest = this.destinationPath();
    const templates = this.templatePath();

    this.fs.copy(`${templates}/drizzle/**/*`, dest, {
      globOptions: {
        dot: true,
        ignore: [
          '**/.git',
          '**/.travis.yml',
          '**/LICENSE',
          '**/README.md'
        ]
      }
    });

    this.fs.copy(
      `${templates}/.github`, `${dest}/.github`
    );

    this.fs.copyTpl(
      `${templates}/README.md`,
      `${dest}/README.md`,
      this.props
    );
  }

  /**
   * Extend the Drizzle package.json with prompt values.
   * Install dependencies selected via prompt.
   */
  install () {
    const deps = this.props.dependencies;
    if (deps.length) {
      this.npmInstall(deps, {saveDev: true});
    }
  }

  /**
   * Signal the end.
   */
  end () {
    this.log(OUTRO);
  }
};
<|endoftext|>


<commit_before>'use strict';
var yeoman = require('yeoman-generator');
var chalk = require('chalk');
var yosay = require('yosay');

module.exports = yeoman.generators.Base.extend({
   _getPrompts: function () {
    var prompts = [{
      type: 'input',
      name: 'humanName',
      message: 'What should I call your subtheme?',
      default: 'An awesome theme powered by Backdrop and Yeoman!'
     }, {
      type: 'input',
      name: 'name',
      message: 'What is the machine name of your subtheme?',
      default: this.appname,
      validate: appNameValidation,
      filter: function (input) {
        return input.toLowerCase().replace(/[^a-z0-9]+/, '_').substr(0, 32);
      }
    }, {
      type: 'input',
      name: 'description',
      message: 'Subtheme description:',
      default: 'An aweseome theme powered by Backdrop CMS and Yeoman!'
    }, {
      type: 'input',
      name: 'userName',
      message: 'Your Full name:',
      default: this.user.name
    }, {
      type: 'input',
      name: 'userEmail',
      message: 'Your Email:',
      default: this.user.email
    }, {
      type: 'input',
      name: 'repo',
      message: 'Repository URL:'
    },
      return prompts;
    }];

 },
  _saveProps: function (props, callback) {
    this.humanName = props.humanName;
    this.appname = props.name;
    this.description = props.description;
    this.repo = props.repo;
    this.userName = props.userName;
    this.userEmail = props.userEmail;
    callback();
  },
  _createProjectFileSystem: function () {
    var destRoot = this.destinationRoot(),
        sourceRoot = this.sourceRoot(),
        appDir = destRoot + '/app',
        templateContext = {
          appname = this.appname,
          humanName = this.humanName,
          description = this.description,
          userName = this.userName,
          userEmail = this.userEmail,
          repo = this.repo,
        };
  },
   initializing: function () {
    this.pkg = require('../../package.json');

   prompting: function () {
    var done = this.async();
    // Have Yeoman greet the user.
    this.log(yosay(
      'Welcome to the amazing ' + chalk.green('Backdroptheme') + ' generator!'
    ));

    this.prompt(this_getPrompts, function (props) {
      this._saveProps(props, done);
    }.bind(this));
  },

  writing: {
    app: function () {
      this.fs.copyTpl (
        this.templatePath('_package.json', templateContext),
        this.destinationPath('package.json')
      );
      this.fs.copyTpl(
        this.templatePath('_bower.json', templateContext),
        this.destinationPath('bower.json')
      );
    },

    projectfiles: function () {
      this.fs.copy(
        this.templatePath('editorconfig'),
        this.destinationPath('.editorconfig')
      );
      this.fs.copy(
        this.templatePath('jshintrc'),
        this.destinationPath('.jshintrc')
      );
    }
  },

  install: function () {
    this.installDependencies();
  }
});
<commit_msg>add methods<commit_after>'use strict';
var yeoman = require('yeoman-generator');
var chalk = require('chalk');
var yosay = require('yosay');

module.exports = yeoman.generators.Base.extend({
   _getPrompts: function () {
    var prompts = [{
      type: 'input',
      name: 'humanName',
      message: 'What should I call your subtheme?',
      default: 'An awesome theme powered by Backdrop and Yeoman!'
     }, {
      type: 'input',
      name: 'name',
      message: 'What is the machine name of your subtheme?',
      default: this.appname,
      validate: appNameValidation,
      filter: function (input) {
        return input.toLowerCase().replace(/[^a-z0-9]+/, '_').substr(0, 32);
      }
    }, {
      type: 'input',
      name: 'description',
      message: 'Subtheme description:',
      default: 'An aweseome theme powered by Backdrop CMS and Yeoman!'
    }, {
      type: 'input',
      name: 'userName',
      message: 'Your Full name:',
      default: this.user.name
    }, {
      type: 'input',
      name: 'userEmail',
      message: 'Your Email:',
      default: this.user.email
    }, {
      type: 'input',
      name: 'repo',
      message: 'Repository URL:'
    },
      return prompts;
    }];

 },
  _saveProps: function (props, callback) {
    this.humanName = props.humanName;
    this.appname = props.name;
    this.description = props.description;
    this.repo = props.repo;
    this.userName = props.userName;
    this.userEmail = props.userEmail;
    callback();
  },
  _createProjectFileSystem: function () {
    var destRoot = this.destinationRoot(),
        sourceRoot = this.sourceRoot(),
        appDir = destRoot + '/app',
        templateContext = {
          appname = this.appname,
          humanName = this.humanName,
          description = this.description,
          userName = this.userName,
          userEmail = this.userEmail,
          repo = this.repo,
        };
  },
   initializing: function () {
    this.pkg = require('../../package.json');

   prompting: function () {
    var done = this.async();
    // Have Yeoman greet the user.
    this.log(yosay(
      'Welcome to the amazing ' + chalk.green('Backdroptheme') + ' generator!'
    ));

    this.prompt(this_getPrompts, function (props) {
      this._saveProps(props, done);
    }.bind(this));
  },

  writing: {
    app: function () {
      var destRoot = this.destinationRoot(),
        sourceRoot = this.sourceRoot(),
        appDir = destRoot + '/app',
        templateContext = {
          appname = this.appname,
          humanName = this.humanName,
          description = this.description,
          userName = this.userName,
          userEmail = this.userEmail,
          repo = this.repo,
        }; {
      this.fs.copyTpl (
        this.templatePath('_package.json'),
        this.destinationPath('package.json' templateContext);
      );
      this.fs.copyTpl(
        this.templatePath('_bower.json'),
        this.destinationPath('bower.json' templateContext);
      );
    },

    projectfiles: function () {
      this.fs.copy(
        this.templatePath('editorconfig'),
        this.destinationPath('.editorconfig')
      );
      this.fs.copy(
        this.templatePath('jshintrc'),
        this.destinationPath('.jshintrc')
      );
    }
  },

  install: function () {
    this.installDependencies();
  }
});
<|endoftext|>


<commit_before>const SCREEN_WIDTH = window.innerWidth;
const SCREEN_HEIGHT = window.innerHeight;
const VIEW_ANGLE = 45;
const ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT;
const NEAR = 1;
const FAR = 10000;

let scene;
let camera;
let renderer;
let sunGeometry;
let earthGeometry;
let sunMaterial;
let earthMaterial;
let sun;
let earth;
let controls;
let ambientLight;

const origin = new THREE.Vector3(0, 0, 0);

function init() {
  scene = new THREE.Scene();

  camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
  camera.position.set(300, 300, 300);
  camera.lookAt(origin);

  sunGeometry = new THREE.SphereBufferGeometry(100, 32, 32);
  earthGeometry = new THREE.SphereBufferGeometry(25, 16, 16);
  sunMaterial = new THREE.MeshLambertMaterial();
  earthMaterial = new THREE.MeshLambertMaterial();

  sun = new THREE.Mesh(sunGeometry, sunMaterial);
  scene.add(sun);

  earth = new THREE.Mesh(earthGeometry, earthMaterial);
  scene.add(earth);

  ambientLight = new THREE.AmbientLight(0xffffff);
  scene.add(ambientLight);

  renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setSize(window.innerWidth, window.innerHeight);

  controls = new THREE.OrbitControls(camera, renderer.domElement);

  THREEx.WindowResize(renderer, camera);

  document.body.appendChild(renderer.domElement);

  const loader = new THREE.TextureLoader();

  // load a resource
  loader.load(
    // resource URL
    '../../assets/textures/planets/earth.jpg',
    // Function when resource is loaded
    (texture) => {
      console.log(texture);
      earthMaterial.map = texture;
      earthMaterial.needsUpdate = true;
    },
  );

  // load a resource
  loader.load(
    // resource URL
    '../../assets/textures/planets/sun.jpg',
    // Function when resource is loaded
    (texture) => {
      console.log(texture);
      sunMaterial.map = texture;
      sunMaterial.needsUpdate = true;
    },
  );
}

let angle = 0;

function update() {
  const y = Math.sin(angle) * 300;
  const y2 = Math.cos(angle) * 300;

  angle += 0.01;
  sun.position.set(0, 0, 0);

  angle += 0.01;
  earth.position.set(-y, 0, y2);

  controls.update();
}

function render() {
  renderer.render(scene, camera);
}

function tick() {
  update();
  render();
  requestAnimationFrame(tick);
}

init();
tick();
<commit_msg>Revert "Revert "test""<commit_after>const SCREEN_WIDTH = window.innerWidth;
const SCREEN_HEIGHT = window.innerHeight;
const VIEW_ANGLE = 45;
const ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT;
const NEAR = 1;
const FAR = 10000;

let scene;
let camera;
let renderer;
let sunGeometry;
let earthGeometry;
let sunMaterial;
let earthMaterial;
let sun;
let earth;
let controls;
let ambientLight;

const origin = new THREE.Vector3(0, 0, 0);

function init() {
  scene = new THREE.Scene();
// yeet
  camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
  camera.position.set(300, 300, 300);
  camera.lookAt(origin);

  sunGeometry = new THREE.SphereBufferGeometry(100, 32, 32);
  earthGeometry = new THREE.SphereBufferGeometry(25, 16, 16);
  sunMaterial = new THREE.MeshLambertMaterial();
  earthMaterial = new THREE.MeshLambertMaterial();

  sun = new THREE.Mesh(sunGeometry, sunMaterial);
  scene.add(sun);

  earth = new THREE.Mesh(earthGeometry, earthMaterial);
  scene.add(earth);

  ambientLight = new THREE.AmbientLight(0xffffff);
  scene.add(ambientLight);

  renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setSize(window.innerWidth, window.innerHeight);

  controls = new THREE.OrbitControls(camera, renderer.domElement);

  THREEx.WindowResize(renderer, camera);

  document.body.appendChild(renderer.domElement);

  const loader = new THREE.TextureLoader();

  // load a resource
  loader.load(
    // resource URL
    '../../assets/textures/planets/earth.jpg',
    // Function when resource is loaded
    (texture) => {
      console.log(texture);
      earthMaterial.map = texture;
      earthMaterial.needsUpdate = true;
    },
  );

  // load a resource
  loader.load(
    // resource URL
    '../../assets/textures/planets/sun.jpg',
    // Function when resource is loaded
    (texture) => {
      console.log(texture);
      sunMaterial.map = texture;
      sunMaterial.needsUpdate = true;
    },
  );
}

let angle = 0;

function update() {
  const y = Math.sin(angle) * 300;
  const y2 = Math.cos(angle) * 300;

  angle += 0.01;
  sun.position.set(0, 0, 0);

  angle += 0.01;
  earth.position.set(-y, 0, y2);

  controls.update();
}

function render() {
  renderer.render(scene, camera);
}

function tick() {
  update();
  render();
  requestAnimationFrame(tick);
}

init();
tick();
<|endoftext|>


<commit_before><commit_msg>DIG-12: rm'd upload task<commit_after><|endoftext|>


<commit_before>
// here is where we actually enter characters into the
// text.
//
// A relatively small part of what a text editor actually does.

module.exports = function (doc, keys, cursor) {
  keys.on('keypress', function (ch, key) {

    console.error(key)

    if(key.shift && key.name.length === 1)
      key.name = key.name.toUpperCase()

    if     (key.name == 'delete') {
      if(doc.marks) doc.clearMarked()
      else if(key.ctrl) doc.mark().next().mark().clearMarked()
      else          doc.delete(1)
    }
    else if(key.name == 'backspace') {
      if(doc.marks) doc.clearMarked()
      else if(key.ctrl) doc.mark().prev().mark().clearMarked()
      else          doc.delete(-1)
    }
    else if(key.name == 'tab')       doc.write('  ')
    else if(key.name == 'enter')     doc.clearMarked().newline()
    else if(' ' <= ch && ch <= '~')  doc.clearMarked().write(ch)
  })
}
<commit_msg>make Ctrl-backspace work<commit_after>
// here is where we actually enter characters into the
// text.
//
// A relatively small part of what a text editor actually does.

module.exports = function (doc, keys, cursor) {
  keys.on('keypress', function (ch, key) {

    console.error(key)

    if(key.shift && key.name.length === 1)
      key.name = key.name.toUpperCase()

    if     (key.name == 'delete') {
      if(doc.marks) doc.clearMarked()
      else if(key.ctrl) doc.mark().next().mark().clearMarked()
      else          doc.delete(1)
    }
    else if(key.name == 'backspace') {
      if(doc.marks) doc.clearMarked()
      //quirk in keypress... TODO should make fix.
      else if(key.ctrl || key.sequence == '\b') doc.mark().prev().mark().clearMarked()
      else          doc.delete(-1)
    }
    else if(key.name == 'tab')       doc.write('  ')
    else if(key.name == 'enter')     doc.clearMarked().newline()
    else if(' ' <= ch && ch <= '~')  doc.clearMarked().write(ch)
  })
}
<|endoftext|>


<commit_before>'use strict';
var yeoman = require('yeoman-generator');
var chalk = require('chalk');
var yosay = require('yosay');

module.exports = yeoman.generators.Base.extend({
  prompting: function() {
    var done = this.async();

    var prompts = [{
      type: 'input',
      name: 'import',
      message: 'What is the import path of your project?',
      default: 'github.com/yourname/pkgname'
    }];

    this.prompt(prompts, function(props){
      this.props = props; // To access props later use this.props.import;

      var destdir = process.env.GOPATH + "/src/" + props.import; // src under GOPATH
      if(!process.env.GOPATH.trim()) {
        destdir = this.destinationPath("src/" + props.import); // src under current directory
      }
      this.destdir = destdir;

      done();
    }.bind(this));
  },

  writing: {
    lib: function() {

      var pkgname = this.props.import.split('/').reverse()[0];

      this.fs.copyTpl(
        this.templatePath('_main.go'),
        this.destdir+'/cmd/command/main.go',
        { projectImport: this.props.import,
          packageName: pkgname}
      );

      this.fs.copyTpl(
        this.templatePath('_lib.go'),
        this.destdir+'/lib.go',
        { packageName: pkgname}
      );

      this.fs.copyTpl(
        this.templatePath('_lib_test.go'),
        this.destdir+'/lib_test.go',
        { packageName: pkgname}
      );

      this.fs.copy(
        this.templatePath('.gitignore'),
        this.destdir+'/.gitignore'
      );

    },

    workspace: function() {
      var gitinit = this.spawnCommand('git', ['init', this.destdir]);
    }
  }

});
<commit_msg>Handling of gb argument to subgenerator goweb:lib<commit_after>'use strict';
var yeoman = require('yeoman-generator');
var chalk = require('chalk');
var yosay = require('yosay');

module.exports = yeoman.generators.Base.extend({
  prompting: function() {

    var done = this.async();

    var prompts = [{
      type: 'input',
      name: 'import',
      message: 'What is the import path of your project?',
      default: 'github.com/yourname/pkgname'
    }];

    this.prompt(prompts, function(props){
      this.props = props; // To access props later use this.props.import;

      var destdir = process.env.GOPATH + "/src/" + props.import; // src under GOPATH
      if(!process.env.GOPATH.trim()) {
        destdir = this.destinationPath("src/" + props.import); // src under current directory
      }

      // handle explicit gb project
      if (process.argv[3] == 'gb') {
        destdir = this.destinationPath("src/" + props.import); // src under current directory
      }

      this.destdir = destdir;

      done();
    }.bind(this));
  },

  writing: {
    lib: function() {

      var pkgname = this.props.import.split('/').reverse()[0];

      this.fs.copyTpl(
        this.templatePath('_main.go'),
        this.destdir+'/cmd/command/main.go',
        { projectImport: this.props.import,
          packageName: pkgname}
      );

      this.fs.copyTpl(
        this.templatePath('_lib.go'),
        this.destdir+'/lib.go',
        { packageName: pkgname}
      );

      this.fs.copyTpl(
        this.templatePath('_lib_test.go'),
        this.destdir+'/lib_test.go',
        { packageName: pkgname}
      );

      this.fs.copy(
        this.templatePath('.gitignore'),
        this.destdir+'/.gitignore'
      );

    },

    workspace: function() {
      var gitinit = this.spawnCommand('git', ['init', this.destdir]);
    }
  }

});
<|endoftext|>


<commit_before>'use strict';

module.exports = {
  app: {
    title: 'MEAN.JS',
    description: 'Full-Stack JavaScript with MongoDB, Express, AngularJS, and Node.js',
    keywords: 'mongodb, express, angularjs, node.js, mongoose, passport',
    googleAnalyticsTrackingID: process.env.GOOGLE_ANALYTICS_TRACKING_ID || 'GOOGLE_ANALYTICS_TRACKING_ID'
  },
  port: process.env.PORT || 3000,
  templateEngine: 'swig',
  // Session Cookie settings
  sessionCookie: {
    // session expiration is set by default to 24 hours
    maxAge: 24 * (60 * 60 * 1000),
    // httpOnly flag makes sure the cookie is only accessed
    // through the HTTP protocol and not JS/browser
    httpOnly: true,
    // secure cookie should be turned to true to provide additional
    // layer of security so that the cookie is set only when working
    // in HTTPS mode.
    secure: false
  },
  // sessionSecret should be changed for security measures and concerns
  sessionSecret: process.env.SESSION_SECRET || 'MEAN',
  // sessionKey is set to the generic sessionId key used by PHP applications
  // for obsecurity reasons
  sessionKey: 'sessionId',
  sessionCollection: 'sessions',
  logo: 'modules/core/client/img/brand/logo.png',
  favicon: 'modules/core/client/img/brand/favicon.ico',
  uploads: {
    profileUpload: {
      dest: './modules/users/client/img/profile/uploads/', // Profile upload destination path
      limits: {
        fileSize: 1*1024*1024 // Max file size in bytes (1 MB)
      }
    }
  }
};
<commit_msg>update app title<commit_after>'use strict';

module.exports = {
  app: {
    title: 'Stipendify',
    description: 'Full-Stack JavaScript with MongoDB, Express, AngularJS, and Node.js',
    keywords: 'mongodb, express, angularjs, node.js, mongoose, passport',
    googleAnalyticsTrackingID: process.env.GOOGLE_ANALYTICS_TRACKING_ID || 'GOOGLE_ANALYTICS_TRACKING_ID'
  },
  port: process.env.PORT || 3000,
  templateEngine: 'swig',
  // Session Cookie settings
  sessionCookie: {
    // session expiration is set by default to 24 hours
    maxAge: 24 * (60 * 60 * 1000),
    // httpOnly flag makes sure the cookie is only accessed
    // through the HTTP protocol and not JS/browser
    httpOnly: true,
    // secure cookie should be turned to true to provide additional
    // layer of security so that the cookie is set only when working
    // in HTTPS mode.
    secure: false
  },
  // sessionSecret should be changed for security measures and concerns
  sessionSecret: process.env.SESSION_SECRET || 'MEAN',
  // sessionKey is set to the generic sessionId key used by PHP applications
  // for obsecurity reasons
  sessionKey: 'sessionId',
  sessionCollection: 'sessions',
  logo: 'modules/core/client/img/brand/logo.png',
  favicon: 'modules/core/client/img/brand/favicon.ico',
  uploads: {
    profileUpload: {
      dest: './modules/users/client/img/profile/uploads/', // Profile upload destination path
      limits: {
        fileSize: 1*1024*1024 // Max file size in bytes (1 MB)
      }
    }
  }
};
<|endoftext|>


<commit_before>// karma - reward good and penalize bad mail senders

var ipaddr = require('ipaddr.js');
var redis = require('redis');
var db;

exports.register = function () {
    var plugin = this;

    this.register_hook('init_master',  'karma_onInit');
    this.register_hook('init_child',   'karma_onInit');
    this.register_hook('deny',         'karma_onDeny');
    this.register_hook('lookup_rdns',  'karma_onConnect');
    this.register_hook('mail',         'karma_onMailFrom');
    this.register_hook('rcpt',         'karma_onRcptTo');
    this.register_hook('data',         'karma_onData');
    this.register_hook('data_post',    'karma_onDataPost');
    this.register_hook('disconnect',   'karma_onDisconnect');
};

exports.karma_onInit = function (next, server) {
    initRedisConnection(this);
    return next();
};

function initRedisConnection(self) {
    if (db && db.ping()) return;   // connection is good

    var config     = self.config.get('karma.ini');
    var redis_ip  = '127.0.0.1';
    var redis_port = '6379';
    if (config.redis) {
        redis_ip = config.redis.server_ip || '127.0.0.1';
        redis_port = config.redis.server_port || '6379';
    };

    db = redis.createClient(redis_port, redis_ip);
    db.on('error', function (error) {
        self.logerror('Redis error: ' + error.message);
        db.end();
        db = null;
    });
};

exports.karma_onConnect = function (next, connection) {
    var plugin = this;
    var config = this.config.get('karma.ini');

    initRedisConnection(this);
    initConnectionNote(connection, config);

    var r_ip = connection.remote_ip;
    var dbkey = 'karma|' + r_ip;
    var expire = (config.main.expire_days || 60) * 86400; // convert to days

    function initRemoteIP () {
        db.multi()
            .hmset(dbkey, {'penalty_start_ts': 0, 'bad': 0, 'good': 0, 'connections': 1})
            .expire(dbkey, expire)
            .exec();
        connection.logdebug(plugin,"first connect");
    };

    db.multi()
        .get('concurrent|' + r_ip)
        .hgetall(dbkey)
        .exec(function redisResults (err,replies) {
            if (err) {
                connection.logdebug(plugin,"err: " + err);
                return next();
            };

            if (replies[1] === null) { initRemoteIP(); return next(); };

            db.hincrby(dbkey, 'connections', 1); // increment total connections
            db.expire(dbkey, expire);            // extend expiration date

            var dbr = replies[1]; // 2nd element of DB reply is our karma object
            var history = (dbr.good || 0) - (dbr.bad || 0);
            connection.notes.karma.history = history;

            var summary = dbr.bad + " bad, " + dbr.good + " good, "
                         + dbr.connections + " connects, " + history + " history";

            var too_many = checkConcurrency(plugin, 'concurrent|' + r_ip, replies[0], history);
            if (too_many) {
                connection.loginfo(plugin, too_many + ", (" + summary + ")");
                var delay = config.concurrency.disconnect_delay || 10;
                setTimeout(function () {
                    return next(DENYSOFTDISCONNECT, too_many);
                }, delay * 1000);
            };

            if (dbr.penalty_start_ts === '0') {
                connection.loginfo(plugin, "no penalty, " + karmaSummary(connection));
                return next();
            }

            var days_old = (Date.now() - Date.parse(dbr.penalty_start_ts)) / 86.4;
            var penalty_days = config.main.penalty_days;
            if (days_old >= penalty_days) {
                connection.loginfo(plugin, "penalty expired, " + karmaSummary(connection));
                return next();
            }

            var left = +(penalty_days - days_old).toFixed(2);
            var mess = "Bad karma, you can try again in " + left + " more days.";

            return next(DENY, mess);
        });

    checkAwards(config, connection, plugin);
};

exports.karma_onDeny = function (next, connection, params) {
    /* params
    ** [0] = plugin return value (constants.deny or constants.denysoft)
    ** [1] = plugin return message
    */

    var pi_name     = params[2];
    var pi_function = params[3];
    var pi_params   = params[4];
    var pi_hook     = params[5];

    var plugin = this;
    var transaction = connection.transaction;

    var config = this.config.get('karma.ini');
    initConnectionNote(connection, config);

    // CONSIDER: decrement karma two points for a 5XX deny?
    connection.notes.karma.connection--;
    connection.notes.karma.penalties.push(pi_name);

    connection.loginfo(plugin, 'deny, ' + karmaSummary(connection));

    checkAwards(config, connection, plugin);
    return next();
};

exports.karma_onMailFrom = function (next, connection, params) {
    var plugin = this;
    var config = this.config.get('karma.ini');

    checkSpammyTLD(params[0], config, connection, plugin);
    checkSyntaxMailFrom(connection, plugin);

    checkAwards(config, connection, plugin);
    connection.loginfo(plugin, karmaSummary(connection));
    return next();
};

exports.karma_onRcptTo = function (next, connection, params) {
    var plugin = this;
    var rcpt = params[0];
    var config = this.config.get('karma.ini');

    checkSyntaxRcptTo(connection, plugin);
    var too_many = checkMaxRecipients(connection, plugin, config);
    if (too_many) return next(DENYSOFT, too_many);

    checkAwards(config, connection, plugin);
    connection.loginfo(plugin, karmaSummary(connection));
    return next();
};

exports.karma_onData = function (next, connection) {
// cut off bad senders at DATA to prevent transferring the message
    var config = this.config.get('karma.ini');
    var negative_limit = config.thresholds.negative || -5;
    var karma = connection.notes.karma * 1;

    if (karma.connection <= negative_limit) {
        return next(DENY, "very bad karma score: " + karma);
    }

    checkAwards(config, connection, this);
    return next();
}

exports.karma_onDataPost = function (next, connection) {
    connection.transaction.add_header('X-Haraka-Karma',
        karmaSummary(connection)
    );
    var config = this.config.get('karma.ini');
    checkAwards(config, connection, this);
    return next();
}

exports.karma_onDisconnect = function (next, connection) {
    var plugin = this;
    var config = this.config.get('karma.ini');

    initRedisConnection(this);
    if (config.concurrency) db.incrby('concurrent|' + connection.remote_ip, -1);

    var k = connection.notes.karma;
    if (!k) { connection.logerror(plugin, "karma note missing!"); return next(); };

    if (!k.connection) {
        connection.loginfo(plugin, "neutral: " + karmaSummary(connection));
        return next();
    };

    var key = 'karma|' + connection.remote_ip;
    var history = k.history;

    if (config.threshold) {
        var pos_lim = config.thresholds.positive || 2;

        if (k.connection > pos_lim) {
            db.hincrby(key, 'good', 1);
            connection.loginfo(plugin, "positive: " + karmaSummary(connection));
            return next();
        };

        var bad_limit = config.thresholds.negative || -3;
        if (k.connection < bad_limit) {
            db.hincrby(key, 'bad', 1);
            history--;

            if (history <= config.thresholds.history_negative) {
                if (history < -5) {
                    db.hset(key, 'penalty_start_ts', addDays(Date(), history * -1));
                    connection.loginfo(plugin, "penalty box bonus!: " + karmaSummary(connection));
                }
                else {
                    db.hset(key, 'penalty_start_ts', Date());
                    connection.loginfo(plugin, "penalty box: " + karmaSummary(connection));
                }
                return next();
            }
        }
    };
    checkAwards(config, connection, plugin);
    connection.loginfo(plugin, "no action, " + karmaSummary(connection));
    return next();
};

function karmaSummary(c) {
    var k = c.notes.karma;
    return '('
        + 'conn:' + k.connection
        + ', hist: ' + k.history
        + (k.penalties.length ? ', penalties: '+ k.penalties : '')
        + (k.awards.length    ? ', awards: '   + k.awards    : '')
        + ')';
}

function addDays(date, days) {
    var result = new Date(date);
    result.setDate(date.getDate() + days);
    return result;
}

function checkAwards (config, connection, plugin) {
    if (!connection.notes.karma) return;
    if (!connection.notes.karma.todo) return;
    if (!plugin) plugin = connection;
    var awards = config.awards;

    Object.keys(connection.notes.karma.todo).forEach(function(key) {
        var e = key.split('@').slice(0,2);
        var suffix = e[0];
        var wants = e[1];

        // assemble the object path using the note name
        var note = assembleNoteObj(connection, suffix);
        if (note == null || note === false) {
            // connection.logdebug(plugin, "no connection note: " + key);
            if (!connection.transaction) return;
            note = assembleNoteObj(connection.transaction, suffix);
            if (note == null || note === false) {
                // connection.logdebug(plugin, "no transaction note: " + key);
                return;
            }
        };

        if (wants && note && (!note.toString().match(new RegExp(wants, 'i')))) {
            // connection.logdebug(plugin, "key " + suffix + " wants: " + wants + " but saw: " + note);
            return;
        };

        var karma_to_apply = connection.notes.karma.todo[key];
        if (!karma_to_apply) return;
        if (Number(karma_to_apply) === 'NaN') return;  // garbage in config

        connection.notes.karma.connection += karma_to_apply * 1;
        connection.loginfo(plugin, "applied " + key + " karma: " + karma_to_apply);
        delete connection.notes.karma.todo[key];

        var trimmed = key.substring(0,5) === 'notes' ? key.substring(6) : key;
        if (karma_to_apply > 0) { connection.notes.karma.awards.push(trimmed); };
        if (karma_to_apply < 0) { connection.notes.karma.penalties.push(trimmed); };
    });
}

function checkConcurrency(plugin, con_key, val, history) {
    var config = plugin.config.get('karma.ini');

    if (!config.concurrency) return;

    var count = val || 0;    // add this connection
    count++;
    db.incr(con_key);        // increment Redis, (creates if needed)
    db.expire(con_key, 4 * 60);     // expire after 4 min

    var reject=0;
    if (history <  0 && count > config.concurrency.bad) reject++;
    if (history >  0 && count > config.concurrency.good)    reject++;
    if (history == 0 && count > config.concurrency.neutral) reject++;
    if (reject) return "too many connections for you: " + count;
    return;
};

function checkMaxRecipients(connection, plugin, config) {
    if (!config.recipients) return;     // disabled in config file
    var c = connection.rcpt_count;
    var count = c.accept + c.tempfail + c.reject + 1;
    if (count <= 1) return;           // everybody is allowed one

    connection.logdebug(plugin, "recipient count: " + count );

    var desc = history > 3 ? 'good' : history >= 0 ? 'neutral' : 'bad';

    var cr = config.recipients;

    // the deeds of their past shall not go unnoticed!
    var history = connection.notes.karma.history;
    if (history > 3 && count <= cr.good) return;
    if (history > -1 && count <= cr.neutral) return;

    // this is *more* strict than history, b/c they have fewer opportunity
    // to score positive karma this early in the connection. senders with
    // good history will rarely see these limits.
    var karma = connection.notes.karma.connection;
    if (karma >  3 && count <= cr.good) return;
    if (karma >= 0 && count <= cr.neutral) return;

    return 'too many recipients (' + count + ') for ' + desc + ' karma';
}

function checkSpammyTLD(mail_from, config, connection, plugin) {
    if (!config.spammy_tlds) return;
    if (mail_from.isNull()) return;    // null sender (bounce)

    var from_tld = mail_from.host.split('.').pop();
    // connection.logdebug(plugin, "from_tld: " + from_tld);

    var tld_penalty = (config.spammy_tlds[from_tld] || 0) * 1; // force numeric
    if (tld_penalty === 0) return;

    connection.loginfo(plugin, "spammy TLD: " + tld_penalty);
    connection.notes.karma.connection += tld_penalty;
    connection.notes.karma.penalties.push('spammy.TLD');
};

function checkSyntaxMailFrom(connection, plugin) {
    var full_from = connection.current_line;
    // connection.logdebug(plugin, "mail_from: " + full_from);

// look for an illegal (RFC 5321,2821,821) space in envelope from
    if (full_from.toUpperCase().substring(0,11) === 'MAIL FROM:<') return;

    connection.loginfo(plugin, "illegal envelope address format: " + full_from );
    connection.notes.karma.connection--;
    connection.notes.karma.penalties.push('rfc5321.MailFrom');
};

function checkSyntaxRcptTo(connection, plugin) {
    // check for an illegal RFC (2)821 space in envelope recipient
    var full_rcpt = connection.current_line;
    if (full_rcpt.toUpperCase().substring(0,9) === 'RCPT TO:<') return;

    connection.loginfo(plugin, "illegal envelope address format: " + full_rcpt );
    connection.notes.karma.connection--;
    connection.notes.karma.penalties.push('rfc5321.RcptTo');
};

function initConnectionNote(connection, config) {
    if (connection.notes.karma) return; // init once per connection
    connection.notes.karma = {
        connection: 0,
        history: 0,
        awards: [],
        penalties: [ ],
        todo: {},
    };

    // todo is a list of connection/transaction notes to 'watch' for.
    // When discovered, award their karma points to the connection
    // and remove them from todo.
    var awards = config.awards;
    if (!awards) return;
    Object.keys(awards).forEach(function(key) {
        connection.notes.karma.todo[key] = awards[key];
    });
};

function assembleNoteObj(prefix, key) {
    var note = prefix;
    var parts = key.split('.');
    while(parts.length > 0) {
        note = note[parts.shift()];
        if (note == null) break;
    }
    return note;
};
<commit_msg>karma: shed some camelCase<commit_after>// karma - reward good and penalize bad mail senders

var ipaddr = require('ipaddr.js');
var redis = require('redis');
var db;

exports.register = function () {
    var plugin = this;

    this.register_hook('init_master',  'karma_onInit');
    this.register_hook('init_child',   'karma_onInit');
    this.register_hook('deny',         'karma_onDeny');
    this.register_hook('lookup_rdns',  'karma_onConnect');
    this.register_hook('mail',         'karma_onMailFrom');
    this.register_hook('rcpt',         'karma_onRcptTo');
    this.register_hook('data',         'karma_onData');
    this.register_hook('data_post',    'karma_onDataPost');
    this.register_hook('disconnect',   'karma_onDisconnect');
};

exports.karma_onInit = function (next, server) {
    init_redis_connection(this);
    return next();
};

function init_redis_connection(self) {
    if (db && db.ping()) return;   // connection is good

    var config     = self.config.get('karma.ini');
    var redis_ip  = '127.0.0.1';
    var redis_port = '6379';
    if (config.redis) {
        redis_ip = config.redis.server_ip || '127.0.0.1';
        redis_port = config.redis.server_port || '6379';
    };

    db = redis.createClient(redis_port, redis_ip);
    db.on('error', function (error) {
        self.logerror('Redis error: ' + error.message);
        db.end();
        db = null;
    });
};

exports.karma_onConnect = function (next, connection) {
    var plugin = this;
    var config = this.config.get('karma.ini');

    init_redis_connection(this);
    init_connection_note(connection, config);

    var r_ip = connection.remote_ip;
    var dbkey = 'karma|' + r_ip;
    var expire = (config.main.expire_days || 60) * 86400; // convert to days

    function initRemoteIP () {
        db.multi()
            .hmset(dbkey, {'penalty_start_ts': 0, 'bad': 0, 'good': 0, 'connections': 1})
            .expire(dbkey, expire)
            .exec();
        connection.logdebug(plugin,"first connect");
    };

    db.multi()
        .get('concurrent|' + r_ip)
        .hgetall(dbkey)
        .exec(function redisResults (err,replies) {
            if (err) {
                connection.logdebug(plugin,"err: " + err);
                return next();
            };

            if (replies[1] === null) { initRemoteIP(); return next(); };

            db.hincrby(dbkey, 'connections', 1); // increment total connections
            db.expire(dbkey, expire);            // extend expiration date

            var dbr = replies[1]; // 2nd element of DB reply is our karma object
            var history = (dbr.good || 0) - (dbr.bad || 0);
            connection.notes.karma.history = history;

            var summary = dbr.bad + " bad, " + dbr.good + " good, "
                         + dbr.connections + " connects, " + history + " history";

            var too_many = check_concurrency(plugin, 'concurrent|' + r_ip, replies[0], history);
            if (too_many) {
                connection.loginfo(plugin, too_many + ", (" + summary + ")");
                var delay = config.concurrency.disconnect_delay || 10;
                setTimeout(function () {
                    return next(DENYSOFTDISCONNECT, too_many);
                }, delay * 1000);
            };

            if (dbr.penalty_start_ts === '0') {
                connection.loginfo(plugin, "no penalty, " + karma_summary(connection));
                return next();
            }

            var days_old = (Date.now() - Date.parse(dbr.penalty_start_ts)) / 86.4;
            var penalty_days = config.main.penalty_days;
            if (days_old >= penalty_days) {
                connection.loginfo(plugin, "penalty expired, " + karma_summary(connection));
                return next();
            }

            var left = +(penalty_days - days_old).toFixed(2);
            var mess = "Bad karma, you can try again in " + left + " more days.";

            return next(DENY, mess);
        });

    check_awards(config, connection, plugin);
};

exports.karma_onDeny = function (next, connection, params) {
    /* params
    ** [0] = plugin return value (constants.deny or constants.denysoft)
    ** [1] = plugin return message
    */

    var pi_name     = params[2];
    var pi_function = params[3];
    var pi_params   = params[4];
    var pi_hook     = params[5];

    var plugin = this;
    var transaction = connection.transaction;

    var config = this.config.get('karma.ini');
    init_connection_note(connection, config);

    // CONSIDER: decrement karma two points for a 5XX deny?
    connection.notes.karma.connection--;
    connection.notes.karma.penalties.push(pi_name);

    connection.loginfo(plugin, 'deny, ' + karma_summary(connection));

    check_awards(config, connection, plugin);
    return next();
};

exports.karma_onMailFrom = function (next, connection, params) {
    var plugin = this;
    var config = this.config.get('karma.ini');

    check_spammy_tld(params[0], config, connection, plugin);
    check_syntax_mailfrom(connection, plugin);

    check_awards(config, connection, plugin);
    connection.loginfo(plugin, karma_summary(connection));
    return next();
};

exports.karma_onRcptTo = function (next, connection, params) {
    var plugin = this;
    var rcpt = params[0];
    var config = this.config.get('karma.ini');

    check_syntax_RcptTo(connection, plugin);
    var too_many = max_recipients(connection, plugin, config);
    if (too_many) return next(DENYSOFT, too_many);

    check_awards(config, connection, plugin);
    connection.loginfo(plugin, karma_summary(connection));
    return next();
};

exports.karma_onData = function (next, connection) {
// cut off bad senders at DATA to prevent transferring the message
    var config = this.config.get('karma.ini');
    var negative_limit = config.thresholds.negative || -5;
    var karma = connection.notes.karma * 1;

    if (karma.connection <= negative_limit) {
        return next(DENY, "very bad karma score: " + karma);
    }

    check_awards(config, connection, this);
    return next();
}

exports.karma_onDataPost = function (next, connection) {
    connection.transaction.add_header('X-Haraka-Karma',
        karma_summary(connection)
    );
    var config = this.config.get('karma.ini');
    check_awards(config, connection, this);
    return next();
}

exports.karma_onDisconnect = function (next, connection) {
    var plugin = this;
    var config = this.config.get('karma.ini');

    init_redis_connection(this);
    if (config.concurrency) db.incrby('concurrent|' + connection.remote_ip, -1);

    var k = connection.notes.karma;
    if (!k) { connection.logerror(plugin, "karma note missing!"); return next(); };

    if (!k.connection) {
        connection.loginfo(plugin, "neutral: " + karma_summary(connection));
        return next();
    };

    var key = 'karma|' + connection.remote_ip;
    var history = k.history;

    if (config.threshold) {
        var pos_lim = config.thresholds.positive || 2;

        if (k.connection > pos_lim) {
            db.hincrby(key, 'good', 1);
            connection.loginfo(plugin, "positive: " + karma_summary(connection));
            return next();
        };

        var bad_limit = config.thresholds.negative || -3;
        if (k.connection < bad_limit) {
            db.hincrby(key, 'bad', 1);
            history--;

            if (history <= config.thresholds.history_negative) {
                if (history < -5) {
                    db.hset(key, 'penalty_start_ts', add_days(Date(), history * -1));
                    connection.loginfo(plugin, "penalty box bonus!: " + karma_summary(connection));
                }
                else {
                    db.hset(key, 'penalty_start_ts', Date());
                    connection.loginfo(plugin, "penalty box: " + karma_summary(connection));
                }
                return next();
            }
        }
    };
    check_awards(config, connection, plugin);
    connection.loginfo(plugin, "no action, " + karma_summary(connection));
    return next();
};

function karma_summary(c) {
    var k = c.notes.karma;
    return '('
        + 'conn:' + k.connection
        + ', hist: ' + k.history
        + (k.penalties.length ? ', penalties: '+ k.penalties : '')
        + (k.awards.length    ? ', awards: '   + k.awards    : '')
        + ')';
}

function add_days(date, days) {
    var result = new Date(date);
    result.setDate(date.getDate() + days);
    return result;
}

function check_awards (config, connection, plugin) {
    if (!connection.notes.karma) return;
    if (!connection.notes.karma.todo) return;
    if (!plugin) plugin = connection;
    var awards = config.awards;

    Object.keys(connection.notes.karma.todo).forEach(function(key) {
        var e = key.split('@').slice(0,2);
        var suffix = e[0];
        var wants = e[1];

        // assemble the object path using the note name
        var note = assemble_note_obj(connection, suffix);
        if (note == null || note === false) {
            // connection.logdebug(plugin, "no connection note: " + key);
            if (!connection.transaction) return;
            note = assemble_note_obj(connection.transaction, suffix);
            if (note == null || note === false) {
                // connection.logdebug(plugin, "no transaction note: " + key);
                return;
            }
        };

        if (wants && note && (!note.toString().match(new RegExp(wants, 'i')))) {
            // connection.logdebug(plugin, "key " + suffix + " wants: " + wants + " but saw: " + note);
            return;
        };

        var karma_to_apply = connection.notes.karma.todo[key];
        if (!karma_to_apply) return;
        if (Number(karma_to_apply) === 'NaN') return;  // garbage in config

        connection.notes.karma.connection += karma_to_apply * 1;
        connection.loginfo(plugin, "applied " + key + " karma: " + karma_to_apply);
        delete connection.notes.karma.todo[key];

        var trimmed = key.substring(0,5) === 'notes' ? key.substring(6) : key;
        if (karma_to_apply > 0) { connection.notes.karma.awards.push(trimmed); };
        if (karma_to_apply < 0) { connection.notes.karma.penalties.push(trimmed); };
    });
}

function check_concurrency(plugin, con_key, val, history) {
    var config = plugin.config.get('karma.ini');

    if (!config.concurrency) return;

    var count = val || 0;    // add this connection
    count++;
    db.incr(con_key);        // increment Redis, (creates if needed)
    db.expire(con_key, 4 * 60);     // expire after 4 min

    var reject=0;
    if (history <  0 && count > config.concurrency.bad) reject++;
    if (history >  0 && count > config.concurrency.good)    reject++;
    if (history == 0 && count > config.concurrency.neutral) reject++;
    if (reject) return "too many connections for you: " + count;
    return;
};

function max_recipients(connection, plugin, config) {
    if (!config.recipients) return;     // disabled in config file
    var c = connection.rcpt_count;
    var count = c.accept + c.tempfail + c.reject + 1;
    if (count <= 1) return;           // everybody is allowed one

    connection.logdebug(plugin, "recipient count: " + count );

    var desc = history > 3 ? 'good' : history >= 0 ? 'neutral' : 'bad';

    var cr = config.recipients;

    // the deeds of their past shall not go unnoticed!
    var history = connection.notes.karma.history;
    if (history > 3 && count <= cr.good) return;
    if (history > -1 && count <= cr.neutral) return;

    // this is *more* strict than history, b/c they have fewer opportunity
    // to score positive karma this early in the connection. senders with
    // good history will rarely see these limits.
    var karma = connection.notes.karma.connection;
    if (karma >  3 && count <= cr.good) return;
    if (karma >= 0 && count <= cr.neutral) return;

    return 'too many recipients (' + count + ') for ' + desc + ' karma';
}

function check_spammy_tld(mail_from, config, connection, plugin) {
    if (!config.spammy_tlds) return;
    if (mail_from.isNull()) return;    // null sender (bounce)

    var from_tld = mail_from.host.split('.').pop();
    // connection.logdebug(plugin, "from_tld: " + from_tld);

    var tld_penalty = (config.spammy_tlds[from_tld] || 0) * 1; // force numeric
    if (tld_penalty === 0) return;

    connection.loginfo(plugin, "spammy TLD: " + tld_penalty);
    connection.notes.karma.connection += tld_penalty;
    connection.notes.karma.penalties.push('spammy.TLD');
};

function check_syntax_mailfrom(connection, plugin) {
    var full_from = connection.current_line;
    // connection.logdebug(plugin, "mail_from: " + full_from);

// look for an illegal (RFC 5321,2821,821) space in envelope from
    if (full_from.toUpperCase().substring(0,11) === 'MAIL FROM:<') return;

    connection.loginfo(plugin, "illegal envelope address format: " + full_from );
    connection.notes.karma.connection--;
    connection.notes.karma.penalties.push('rfc5321.MailFrom');
};

function check_syntax_RcptTo(connection, plugin) {
    // check for an illegal RFC (2)821 space in envelope recipient
    var full_rcpt = connection.current_line;
    if (full_rcpt.toUpperCase().substring(0,9) === 'RCPT TO:<') return;

    connection.loginfo(plugin, "illegal envelope address format: " + full_rcpt );
    connection.notes.karma.connection--;
    connection.notes.karma.penalties.push('rfc5321.RcptTo');
};

function init_connection_note(connection, config) {
    if (connection.notes.karma) return; // init once per connection
    connection.notes.karma = {
        connection: 0,
        history: 0,
        awards: [],
        penalties: [ ],
        todo: {},
    };

    // todo is a list of connection/transaction notes to 'watch' for.
    // When discovered, award their karma points to the connection
    // and remove them from todo.
    var awards = config.awards;
    if (!awards) return;
    Object.keys(awards).forEach(function(key) {
        connection.notes.karma.todo[key] = awards[key];
    });
};

function assemble_note_obj(prefix, key) {
    var note = prefix;
    var parts = key.split('.');
    while(parts.length > 0) {
        note = note[parts.shift()];
        if (note == null) break;
    }
    return note;
};
<|endoftext|>


<commit_before><commit_msg>Fix headers bug<commit_after><|endoftext|>