<commit_before>'use strict';

var Promise = require('bluebird');
var path = require('path');
var fs = require('fs');
var tildify = require('tildify');
var gulp = require('gulp');
var gutil = require('gulp-util');
var replace = require('gulp-replace');
var rename = require('gulp-rename');
var stringUtils = require('../utils/string');

function validateComponentName (filename) {
  if (filename.indexOf('-') === -1) {
    gutil.log(
      gutil.colors.red('[-Error:] '),
      gutil.colors.cyan(filename),
      gutil.colors.red(' must be a dashize string. ex: my-component')
    );
    gutil.log(
      gutil.colors.red('[-Error:]  Generate task has been canceled')
    );
    process.exit(0);
  }
}

function injectSrcPath (srcPath, type) {
  var injectTemplateGenerator;
  // when `type` is `route` or `component`, will generate its template file
  if (type === 'route' || type === 'component') {
    injectTemplateGenerator = [{
      type:          'template',
      injection:     ( type === 'component' ) ? 'components' : true,
      generatorPath: path.join(__dirname, '..', 'skeletons/generators/template.js')
    }];
    srcPath = srcPath.concat(injectTemplateGenerator);
  }

  // Default, it will generate whatever user inserts the `type`
  srcPath = srcPath.concat([{
    type:          type,
    generatorPath: path.join(__dirname, '..', 'skeletons/generators', type) + '.js'
  }]);
  // return the modified `srcPath` array
  return srcPath;
}

function generatorEngine
(type, srcPath, injection, moduleName, moduleDashedName, fileName, destPath) {
  var ext = (type === 'template') ? '.hbs' : '.js';
  var fullFilePath = destPath + '/' + fileName + ext;

  // if the file has existed, it will abort the task
  // if return true, mean that it is an injection file, which already exist in the system
  // handle the case in the next condition
  var stopGenerateFile = checkFileExisted(fullFilePath, injection, fileName, ext, destPath);
  // check if template is existed or not, not going to kill the process
  // only stop the generator task on this operation
  if (stopGenerateFile) {
    return;
  }

  // Classify the plain module name without its type
  var classifyName = stringUtils.classify(moduleDashedName);

  return gulp.src(srcPath)
    .pipe(replace(/__NAMESPACE__/g, moduleName))
    // __DASHERIZE_NAMESPACE__  mainly used in `-test` generator
    .pipe(replace(/__DASHERIZE_NAMESPACE__/g, moduleDashedName))
    // __CLASSIFY_NAMESPACE__ mainly used in regular generator
    .pipe(replace(/__CLASSIFY_NAMESPACE__/g, classifyName))
    .pipe(rename({
      basename: fileName,
      extname:  ext
    }))
    .on('end', function () {
      gutil.log(
        gutil.colors.green('[-done:] Generate'),
        gutil.colors.cyan(fileName + ext),
        gutil.colors.green('at'),
        gutil.colors.magenta(tildify(destPath))
      );
    })
    .pipe(gulp.dest(destPath));
}

// @describe	generate an model,view,store,controller from base template
function runTasks (generator, options) {
  // check for the options mode, to generate an unit test file or not
  var isGeneratingTest = options.test || false;

  return gulp.task('gen', function () {
    var type = generator.type;
    var name = generator.name;
    var pathName = '';
    var moduleName = '';
    var moduleDashedName = '';
    var i = 0;
    var pathNested; // Boolean
    var fileName; // setup the fileName which used for rename module
    var srcPath = []; // the filePath/srcPath would be used to generate files

    // based on the passing name arguments, to determine it is an nested folder structure
    // or it is a simple file generation. assign a var `fileName` for current file name
    if (name.indexOf('/') > -1) {
      name = name.split('/');
      pathNested = true;
      fileName = name.pop();
    } else {
      pathNested = false;
      fileName = name;
    }

    // handle the error case when arg is `component:foo`
    // component name has to be dash separated string
    // case 1: `em g component:name`         <= simple case
    // case 2: `em g component:nested/name`  <= nested case
    if (type === 'component') {
      validateComponentName(fileName);
    }
    // when type is template, name[0] is component, name of nest path has to be dashized string
    // case 3: `em g template:component/name`  <= nested case in template
    if (type === 'template' && pathNested && name[0] === 'component') {
      validateComponentName(fileName);
    }

    // Setup `pathName`
    // `moduleName` would be used inside replacement of template placeholder
    if (pathNested) {
      // build up the nested path
      for (; i < name.length; i++) {
        // 'component' and 'components' resolve as a 'app/templates/components/'
        if (type === 'template' && name[0] === 'component') {
          name[i] = 'components';
        }
        pathName += '/' + name[i];
        moduleName += name[i] + '-';
      }
      // append fileName to the moduleName string
      moduleName += fileName;
    } else {
      pathName += name;
      moduleName = name;
    }

    // dash separated moduleName used in template replacement
    moduleDashedName += moduleName;
    // Classify the moduleName in format of `MattMaController`
    moduleName = stringUtils.classify(moduleName + '-' + type);

    // ignore the 'store' case, since it is already created
    var typeFolder = path.resolve('client/app', type + 's');

    // if client/app/[type](s) is not existed and it is not a test generator, simply create one
    if (!fs.existsSync(typeFolder) && type.indexOf('test') === -1) {
      fs.mkdirSync(typeFolder);
      gutil.log(
        gutil.colors.gray('[-log:] Created a new folder at '),
        gutil.colors.cyan('~/client/app/' + type + 's')
      );
    }

    // Handle `flag` of `--test` case, and other special case
    // like generate template when the type is route or component, etc
    if (isGeneratingTest) {
      var injectTestFile = [{
        type:          type + '-test',
        injection:     true,
        generatorPath: path.join(__dirname, '..', 'skeletons/generators', type) + '-test.js',
        testGenerator: true
      }];
      // flag `-T` or `--test`, will generate the unit test file
      srcPath = srcPath.concat(injectTestFile);

      srcPath = injectSrcPath(srcPath, type);
    } else {
      if (type === 'route' || type === 'component') {
        srcPath = injectSrcPath(srcPath, type);
      } else {
        // convert the array into string.
        srcPath = path.join(__dirname, '..', 'skeletons/generators', type) + '.js';
      }
    }

    var dirName, finalDirName, finalPath, destPath;

    // if type is test, or route-test or any sorts, it should append `-test` to the filename
    fileName = (type.indexOf('test') > -1) ? fileName + '-test' : fileName;

    // if it is a string, simple call generatorEngine once
    // else it is an object(array), repeat the generatorEngine call
    if (typeof srcPath === 'string') {
      dirName = (type === 'store') ? type : (type.slice(-1) === 's') ? type : type + 's';

      // Figure out the type is testing generator
      if (type.indexOf('test') > -1) {
        // Is it an Unit Test generator or Integration Test generator
        if (type.indexOf('-test') > -1) {
          var typeArray = type.split('-');
          finalDirName = 'tests/unit/' + typeArray[0] + 's';
        } else {
          finalDirName = dirName + '/integration';
        }
      } else {
        finalDirName = dirName;
      }

      finalPath = pathNested ? finalDirName + pathName : finalDirName;

      destPath = (type.indexOf('test') > -1) ?
      path.resolve('client') + '/' + finalPath :
      path.resolve('client/app') + '/' + finalPath;

      generatorEngine(type, srcPath, null, moduleName, moduleDashedName, fileName, destPath);
    } else {
      for (var j = 0, l = srcPath.length; j < l; j++) {
        var _type = srcPath[j].type;
        var testDirName;
        // when original type is 'component'
        // it will create a template file at 'templates/components' folder
        var injection = srcPath[j].injection;
        var finalFileName;

        dirName = (_type === 'store') ? _type : (_type.slice(-1) === 's') ? _type : _type + 's';
        dirName = (injection === 'components') ? dirName + '/' + injection : dirName;
        testDirName = (type === 'store') ? type : (type.slice(-1) === 's') ? type : type + 's';

        finalPath = pathNested ? dirName + pathName : dirName;

        if (isGeneratingTest && srcPath[j].testGenerator) {
          destPath = path.resolve('client/tests/unit') + '/' + testDirName;
          finalFileName = fileName + '-test';
        } else {
          destPath = path.resolve('client/app') + '/' + finalPath;
          finalFileName = fileName;
        }

        generatorEngine(
          _type, srcPath[j].generatorPath, injection, moduleName,
          moduleDashedName, finalFileName, destPath
        );
      }
    }
  });
}

// Check the fullname attribute is correct or not
var VALID_FULL_NAME_REGEXP = /^[^:]+.+:[^:]+$/;

var generate = function (generator, options) {
  // if the folder 'client/app' is not existed
  // can assume that the project may not be created by Ember Rocks
  if (!fs.existsSync('client') && !fs.existsSync('client/app')) {
    gutil.log(
      gutil.colors.red(
        '[-Error:] This project may not be created by \'Ember-Rocks\'\n'
      ),
      gutil.colors.red(
        '[-Error:] `em new [dirName]` does not install the NPM packages dependencies correctly'
      )
    );
    process.exit(1);
  }

  // Error out when user did not provide any argument
  if (!generator || typeof generator !== 'string') {
    gutil.log(gutil.colors.red('[-Error:] Missing type:name argument.'), 'ex: em new route:post');
    gutil.log(gutil.colors.red('[-Error:]'), 'See \'em generate --help\'');
    process.exit(0);
  }

  if (!VALID_FULL_NAME_REGEXP.test(generator)) {
    errorHandler(generator);
  }

  var validTypes = [
    'adapter', 'component', 'controller', 'helper', 'initializer', 'mixin', 'model',
    'route', 'serializer', 'template', 'transform', 'util', 'view',
    'test', 'adapter-test', 'component-test', 'controller-test', 'helper-test',
    'initializer-test', 'mixin-test', 'model-test', 'route-test', 'serializer-test',
    'transform-test', 'util-test', 'view-test'
  ];
  var gen;
  var generatorAndTasks = generator.split(':', 2);
  var type = generatorAndTasks[0];
  var name = generatorAndTasks[1];

  // type could be either route or routes
  type = (type.slice(-1) === 's') ? type.substring(0, type.length - 1) : type;

  // Type must be in the `validTypes` array
  if (validTypes.indexOf(type) > -1) {
    // Name must be a valid string
    if (name.length > 0) {
      gen = {
        type: type,
        name: name
      };
    } else {
      gutil.log(
        gutil.colors.red('[-Error:] '),
        gutil.colors.cyan(name),
        gutil.colors.red(' must be a valid string.')
      );
      gutil.log(gutil.colors.red('[-Error:]'), 'See \'em generate --help\'');
      process.exit(0);
    }
  } else {
    gutil.log(
      gutil.colors.red('[-Error:] '),
      gutil.colors.cyan(type),
      gutil.colors.red(' is not a valid type.')
    );
    gutil.log(
      gutil.colors.bold('[-note:] valid types are'),
      gutil.colors.cyan(validTypes.join(', '))
    );
    process.exit(0);
  }

  runTasks(gen, options);
  // Trigger the generator task
  gulp.start('gen');
};

module.exports = generate;

function checkFileExisted (fullFilePath, injection, fileName, ext, destPath) {
  if (fs.existsSync(fullFilePath)) {
    if (!!injection) {
      gutil.log(
        gutil.colors.red('[-Warning:] '),
        gutil.colors.cyan(fileName + ext),
        gutil.colors.red('has existed at '),
        gutil.colors.magenta(tildify(destPath))
      );
      // Does not continue to generate file, but won't stop the process
      return true;
    } else {
      gutil.log(
        gutil.colors.red('[-Error:] '),
        gutil.colors.cyan(fileName + ext),
        gutil.colors.red('has existed at '),
        gutil.colors.magenta(tildify(destPath))
      );
      gutil.log(
        gutil.colors.red('[-Error:]  Generate task has been canceled')
      );
      // File is existed in the system, kill the process
      process.exit(0);
    }
  }
}

function errorHandler (fullName) {
  gutil.log(
    gutil.colors.red('[-Error:] Invalid argument, expected: `type:name` got: '),
    gutil.colors.bold(fullName)
  );

  gutil.log(
    '[-Syntax:]',
    gutil.colors.cyan('type:name'), ' ex: em generate route:post'
  );

  gutil.log(
    gutil.colors.red('[-Error:]'),
    'See \'em generate --help\''
  );
  process.exit(0);
}
<commit_msg>move the generate simple template from the runTasks function<commit_after>'use strict';

var Promise = require('bluebird');
var path = require('path');
var fs = require('fs');
var tildify = require('tildify');
var gulp = require('gulp');
var gutil = require('gulp-util');
var replace = require('gulp-replace');
var rename = require('gulp-rename');
var stringUtils = require('../utils/string');

function validateComponentName (filename) {
  if (filename.indexOf('-') === -1) {
    gutil.log(
      gutil.colors.red('[-Error:] '),
      gutil.colors.cyan(filename),
      gutil.colors.red(' must be a dashize string. ex: my-component')
    );
    gutil.log(
      gutil.colors.red('[-Error:]  Generate task has been canceled')
    );
    process.exit(0);
  }
}

function injectSrcPath (srcPath, type) {
  var injectTemplateGenerator;
  // when `type` is `route` or `component`, will generate its template file
  if (type === 'route' || type === 'component') {
    injectTemplateGenerator = [{
      type:          'template',
      injection:     ( type === 'component' ) ? 'components' : true,
      generatorPath: path.join(__dirname, '..', 'skeletons/generators/template.js')
    }];
    srcPath = srcPath.concat(injectTemplateGenerator);
  }

  // Default, it will generate whatever user inserts the `type`
  srcPath = srcPath.concat([{
    type:          type,
    generatorPath: path.join(__dirname, '..', 'skeletons/generators', type) + '.js'
  }]);
  // return the modified `srcPath` array
  return srcPath;
}

function generatorEngine
(type, srcPath, injection, moduleName, moduleDashedName, fileName, destPath) {
  var ext = (type === 'template') ? '.hbs' : '.js';
  var fullFilePath = destPath + '/' + fileName + ext;

  // if the file has existed, it will abort the task
  // if return true, mean that it is an injection file, which already exist in the system
  // handle the case in the next condition
  var stopGenerateFile = checkFileExisted(fullFilePath, injection, fileName, ext, destPath);
  // check if template is existed or not, not going to kill the process
  // only stop the generator task on this operation
  if (stopGenerateFile) {
    return;
  }

  // Classify the plain module name without its type
  var classifyName = stringUtils.classify(moduleDashedName);

  return gulp.src(srcPath)
    .pipe(replace(/__NAMESPACE__/g, moduleName))
    // __DASHERIZE_NAMESPACE__  mainly used in `-test` generator
    .pipe(replace(/__DASHERIZE_NAMESPACE__/g, moduleDashedName))
    // __CLASSIFY_NAMESPACE__ mainly used in regular generator
    .pipe(replace(/__CLASSIFY_NAMESPACE__/g, classifyName))
    .pipe(rename({
      basename: fileName,
      extname:  ext
    }))
    .on('end', function () {
      gutil.log(
        gutil.colors.green('[-done:] Generate'),
        gutil.colors.cyan(fileName + ext),
        gutil.colors.green('at'),
        gutil.colors.magenta(tildify(destPath))
      );
    })
    .pipe(gulp.dest(destPath));
}

// @describe	generate an model,view,store,controller from base template
function runTasks (generator, options) {
  // check for the options mode, to generate an unit test file or not
  var isGeneratingTest = options.test || false;

  return gulp.task('gen', function () {
    var type = generator.type;
    var name = generator.name;
    var pathName = '';
    var moduleName = '';
    var moduleDashedName = '';
    var i = 0;
    var pathNested; // Boolean
    var fileName; // setup the fileName which used for rename module
    var srcPath = []; // the filePath/srcPath would be used to generate files

    // based on the passing name arguments, to determine it is an nested folder structure
    // or it is a simple file generation. assign a var `fileName` for current file name
    if (name.indexOf('/') > -1) {
      name = name.split('/');
      pathNested = true;
      fileName = name.pop();
    } else {
      pathNested = false;
      fileName = name;
    }

    // handle the error case when arg is `component:foo`
    // component name has to be dash separated string
    // case 1: `em g component:name`         <= simple case
    // case 2: `em g component:nested/name`  <= nested case
    if (type === 'component') {
      validateComponentName(fileName);
    }
    // when type is template, name[0] is component, name of nest path has to be dashized string
    // case 3: `em g template:component/name`  <= nested case in template
    if (type === 'template' && pathNested && name[0] === 'component') {
      validateComponentName(fileName);
    }

    // Setup `pathName`
    // `moduleName` would be used inside replacement of template placeholder
    if (pathNested) {
      // build up the nested path
      for (; i < name.length; i++) {
        // 'component' and 'components' resolve as a 'app/templates/components/'
        if (type === 'template' && name[0] === 'component') {
          name[i] = 'components';
        }
        pathName += '/' + name[i];
        moduleName += name[i] + '-';
      }
      // append fileName to the moduleName string
      moduleName += fileName;
    } else {
      pathName += name;
      moduleName = name;
    }

    // dash separated moduleName used in template replacement
    moduleDashedName += moduleName;
    // Classify the moduleName in format of `MattMaController`
    moduleName = stringUtils.classify(moduleName + '-' + type);

    // ignore the 'store' case, since it is already created
    var typeFolder = path.resolve('client/app', type + 's');

    // if client/app/[type](s) is not existed and it is not a test generator, simply create one
    if (!fs.existsSync(typeFolder) && type.indexOf('test') === -1) {
      fs.mkdirSync(typeFolder);
      gutil.log(
        gutil.colors.gray('[-log:] Created a new folder at '),
        gutil.colors.cyan('~/client/app/' + type + 's')
      );
    }

    // Handle `flag` of `--test` case, and other special case
    // like generate template when the type is route or component, etc
    if (isGeneratingTest) {
      var injectTestFile = [{
        type:          type + '-test',
        injection:     true,
        generatorPath: path.join(__dirname, '..', 'skeletons/generators', type) + '-test.js',
        testGenerator: true
      }];
      // flag `-T` or `--test`, will generate the unit test file
      srcPath = srcPath.concat(injectTestFile);

      srcPath = injectSrcPath(srcPath, type);
    } else {
      if (type === 'route' || type === 'component') {
        srcPath = injectSrcPath(srcPath, type);
      } else {
        // convert the array into string.
        srcPath = path.join(__dirname, '..', 'skeletons/generators', type) + '.js';
      }
    }

    var dirName, finalPath, destPath;

    // if type is test, or route-test or any sorts, it should append `-test` to the filename
    fileName = (type.indexOf('test') > -1) ? fileName + '-test' : fileName;

    // if it is a string, simple call generatorEngine once
    // else it is an object(array), repeat the generatorEngine call
    if (typeof srcPath === 'string') {
      generateSimpleFile(type, srcPath, moduleName, moduleDashedName, fileName, pathName, pathNested);
    } else {
      for (var j = 0, l = srcPath.length; j < l; j++) {
        var _type = srcPath[j].type;
        var testDirName;
        // when original type is 'component'
        // it will create a template file at 'templates/components' folder
        var injection = srcPath[j].injection;
        var finalFileName;

        dirName = (_type === 'store') ? _type : (_type.slice(-1) === 's') ? _type : _type + 's';
        dirName = (injection === 'components') ? dirName + '/' + injection : dirName;
        testDirName = (type === 'store') ? type : (type.slice(-1) === 's') ? type : type + 's';

        finalPath = pathNested ? dirName + pathName : dirName;

        if (isGeneratingTest && srcPath[j].testGenerator) {
          destPath = path.resolve('client/tests/unit') + '/' + testDirName;
          finalFileName = fileName + '-test';
        } else {
          destPath = path.resolve('client/app') + '/' + finalPath;
          finalFileName = fileName;
        }

        generatorEngine(
          _type, srcPath[j].generatorPath, injection, moduleName,
          moduleDashedName, finalFileName, destPath
        );
      }
    }
  });
}

function generateSimpleFile(type, srcPath, moduleName, moduleDashedName, fileName, pathName, pathNested) {
  var dirName = (type === 'store') ? type : (type.slice(-1) === 's') ? type : type + 's';
  var finalDirName;
  var finalPath;

  // Figure out the type is testing generator
  if (type.indexOf('test') > -1) {
    // Is it an Unit Test generator or Integration Test generator
    if (type.indexOf('-test') > -1) {
      var typeArray = type.split('-');
      finalDirName = 'tests/unit/' + typeArray[0] + 's';
    } else {
      finalDirName = dirName + '/integration';
    }
  } else {
    finalDirName = dirName;
  }

  finalPath = pathNested ? finalDirName + pathName : finalDirName;

  var destPath = (type.indexOf('test') > -1) ?
  path.resolve('client') + '/' + finalPath :
  path.resolve('client/app') + '/' + finalPath;

  generatorEngine(type, srcPath, null, moduleName, moduleDashedName, fileName, destPath);
}

// Check the fullname attribute is correct or not
var VALID_FULL_NAME_REGEXP = /^[^:]+.+:[^:]+$/;

var generate = function (generator, options) {
  // if the folder 'client/app' is not existed
  // can assume that the project may not be created by Ember Rocks
  if (!fs.existsSync('client') && !fs.existsSync('client/app')) {
    gutil.log(
      gutil.colors.red(
        '[-Error:] This project may not be created by \'Ember-Rocks\'\n'
      ),
      gutil.colors.red(
        '[-Error:] `em new [dirName]` does not install the NPM packages dependencies correctly'
      )
    );
    process.exit(1);
  }

  // Error out when user did not provide any argument
  if (!generator || typeof generator !== 'string') {
    gutil.log(gutil.colors.red('[-Error:] Missing type:name argument.'), 'ex: em new route:post');
    gutil.log(gutil.colors.red('[-Error:]'), 'See \'em generate --help\'');
    process.exit(0);
  }

  if (!VALID_FULL_NAME_REGEXP.test(generator)) {
    errorHandler(generator);
  }

  var validTypes = [
    'adapter', 'component', 'controller', 'helper', 'initializer', 'mixin', 'model',
    'route', 'serializer', 'template', 'transform', 'util', 'view',
    'test', 'adapter-test', 'component-test', 'controller-test', 'helper-test',
    'initializer-test', 'mixin-test', 'model-test', 'route-test', 'serializer-test',
    'transform-test', 'util-test', 'view-test'
  ];
  var gen;
  var generatorAndTasks = generator.split(':', 2);
  var type = generatorAndTasks[0];
  var name = generatorAndTasks[1];

  // type could be either route or routes
  type = (type.slice(-1) === 's') ? type.substring(0, type.length - 1) : type;

  // Type must be in the `validTypes` array
  if (validTypes.indexOf(type) > -1) {
    // Name must be a valid string
    if (name.length > 0) {
      gen = {
        type: type,
        name: name
      };
    } else {
      gutil.log(
        gutil.colors.red('[-Error:] '),
        gutil.colors.cyan(name),
        gutil.colors.red(' must be a valid string.')
      );
      gutil.log(gutil.colors.red('[-Error:]'), 'See \'em generate --help\'');
      process.exit(0);
    }
  } else {
    gutil.log(
      gutil.colors.red('[-Error:] '),
      gutil.colors.cyan(type),
      gutil.colors.red(' is not a valid type.')
    );
    gutil.log(
      gutil.colors.bold('[-note:] valid types are'),
      gutil.colors.cyan(validTypes.join(', '))
    );
    process.exit(0);
  }

  runTasks(gen, options);
  // Trigger the generator task
  gulp.start('gen');
};

module.exports = generate;

function checkFileExisted (fullFilePath, injection, fileName, ext, destPath) {
  if (fs.existsSync(fullFilePath)) {
    if (!!injection) {
      gutil.log(
        gutil.colors.red('[-Warning:] '),
        gutil.colors.cyan(fileName + ext),
        gutil.colors.red('has existed at '),
        gutil.colors.magenta(tildify(destPath))
      );
      // Does not continue to generate file, but won't stop the process
      return true;
    } else {
      gutil.log(
        gutil.colors.red('[-Error:] '),
        gutil.colors.cyan(fileName + ext),
        gutil.colors.red('has existed at '),
        gutil.colors.magenta(tildify(destPath))
      );
      gutil.log(
        gutil.colors.red('[-Error:]  Generate task has been canceled')
      );
      // File is existed in the system, kill the process
      process.exit(0);
    }
  }
}

function errorHandler (fullName) {
  gutil.log(
    gutil.colors.red('[-Error:] Invalid argument, expected: `type:name` got: '),
    gutil.colors.bold(fullName)
  );

  gutil.log(
    '[-Syntax:]',
    gutil.colors.cyan('type:name'), ' ex: em generate route:post'
  );

  gutil.log(
    gutil.colors.red('[-Error:]'),
    'See \'em generate --help\''
  );
  process.exit(0);
}
<|endoftext|>


<commit_before>/* eslint-disable indent */
require('babel-polyfill');
require('regenerator-runtime');

import frun from 'first-run';

import chalk from 'chalk';
import ms from 'ms';
import * as TableUtility from '../extra/table-utility';
import Table from 'cli-table';

import { prompt as ask } from 'inquirer';
import { config } from '../extra/config';
import { clearSettings, errorHandler, highlightJSON, printBlock, pathFixer } from '../extra/utils';

export default async function settings([action, target, value]) {
	const questions = [];

	if (action) action = action.toString().toLowerCase();
	if (target) target = target.toString().toLowerCase();

	const _directory = generateQuestion('_directory', 'Default download path:', {
		default: config.get('directory'),
		filter: (input) => pathFixer(input),
	});

	const _askForLike = generateQuestion('_askForLike', 'Prompt to like the downloaded photo after download?', {
		type: 'confirm',
		default: config.get('askForLike'),
	});

	const _askForReport = generateQuestion('_askForReport', 'Prompt to report errors?', {
		type: 'confirm',
		default: config.get('shouldReportErrors'),
	});

	const _askForAutoReport = generateQuestion('_askForAutoReport', 'Auto report errors?', {
		type: 'confirm',
		default: config.get('shouldReportErrorsAutomatically'),
		when: (a) => a._askForReport === false,
	});

	const _askForCollection = generateQuestion(
		'_askForCollection',
		'Prompt to add the downloaded photo to a collection?',
		{
			type: 'confirm',
			prefix: chalk`{red {bold [BETA]}}`,
			default: config.get('askForCollection'),
		},
	);

	const _userFolder = generateQuestion('_userFolder', 'Do you want store photos by username?', {
		default: config.get('userFolder'),
		type: 'confirm',
	});

	const _confirmWallpaper = generateQuestion('_confirmWallpaper', 'Do you want to confirm each wallpaper?', {
		default: false,
		type: 'confirm',
	});

	const _updateInterval = generateQuestion('_updateInterval', 'Set the "pic of the day" cache expiration', {
		default: ms(1000 * 60 * 60 * 3),
	});

	switch (action) {
		case 'help':
		case 'how':
		case 'h':
			const commands = TableUtility.mapTableContent([
				[chalk`get`, 'null', 'get all settings'.toUpperCase()],
				[chalk`clear`, 'reset|restore', 'reset settings to default values'.toUpperCase()][
					(chalk`set {gray <settings_key>}`, 'null', 'opens menu for specific setting'.toUpperCase())
				],
				['help', 'how', 'SHOWS THIS MESSAGE'],
			]);

			const table = new Table(TableUtility.helpTableConfiguration);
			table.push(...commands);

			printBlock(chalk`{yellow ~ {bold ALIASES HELP} ~}`, '', table.toString());
			break;
		case 'get':
			if (target && target.toLowerCase() == 'picoftheday') {
				target = 'pic-of-the-day';
			}

			const user = config.get('user');

			const settings = config.get(); //target ? config.get(target) : config.get();

			if (settings['pic-of-the-day'] && settings['pic-of-the-day'].date) {
				if (settings['pic-of-the-day'].date.delay) {
					settings['pic-of-the-day'].date.delay = ms(settings['pic-of-the-day'].date.delay);
				}
			}

			settings.picOfTheDay = settings['pic-of-the-day'];
			settings.settingsPath = config.path;

			delete settings['error'];
			delete settings['keys'];
			delete settings['user'];
			delete settings['pic-of-the-day'];

			if (!settings || (target && !settings[target])) {
				return printBlock(chalk`Settings key: "{cyan ${target}}" {red {bold NOT} available}.`);
			}

			if (user && user.token) {
				settings['OAuth Token'] = user.token;
			}

			if (settings[target]) {
				let o = {};

				o[target] = settings[target];

				return printBlock(chalk`{bold {bgYellow {black SETTINGS}}}\n`, highlightJSON(o));
			}

			printBlock(chalk`{bold {bgYellow {black SETTINGS}}}\n`, highlightJSON(settings));
			break;
		case 'clear':
		case 'reset':
		case 'restore':
			ask([
				generateQuestion('confirm', chalk`Are you sure? This action is {underline NOT reversable}!`, {
					type: 'confirm',
					default: false,
				}),
			])
				.then(async ({ confirm }) => {
					if (confirm) {
						frun.clear();

						await clearSettings();

						printBlock(chalk`{yellow Settings Restored!}`);
					} else {
						printBlock(chalk`{red {bold Operation aborted!}}`);
					}
				})
				.catch((error) => {
					errorHandler(error);
				});
			break;

		case 'set':
		default:
			switch (target) {
				case 'report':
				case 'errors':
				case 'error':
					questions.push(_askForReport, _askForAutoReport);
					break;
				case 'directory':
				case 'dir':
					questions.push(_directory);
					break;
				case 'user':
				case 'user-folder':
				case 'userFolder':
				case 'groups':
					questions.push(_userFolder);
					break;
				case 'like':
				case 'askforlike':
					questions.push(_askForLike);
					break;
				case 'collection':
				case 'askforcollection':
					questions.push(_askForCollection);
					break;
				case 'confirm':
					questions.push(_confirmWallpaper);
					break;
				case 'prompt':
				case 'prompts':
					questions.push(_askForCollection, _askForLike);
					break;
				case 'update':
				case 'interval':
				case 'pic-of-the-day':
					questions.push(_updateInterval);
					break;
				default:
					questions.push(
						_userFolder,
						_askForReport,
						_askForAutoReport,
						_directory,
						_confirmWallpaper,
						_askForCollection,
						_askForLike,
						_updateInterval,
					);
					break;
			}

			const {
				_confirmWallpaper: confirmWallpaper,
				_userFolder: folder,
				_directory: dir,
				_askForCollection: collection,
				_askForLike: like,
				_updateInterval: picUpdateInterval,
				_askForAutoReport: shouldAutoReportErrors,
				_askForReport: shouldReportErrors,
			} = await ask(questions);

			let validSetting = false;

			if (confirmWallpaper !== undefined) {
				config.set('confirm-wallpaper', confirmWallpaper);
				validSetting = true;
			}

			if (shouldAutoReportErrors !== undefined) {
				config.set('shouldReportErrorsAutomatically', shouldAutoReportErrors);
				validSetting = true;
			}

			if (shouldReportErrors !== undefined) {
				config.set('shouldReportErrors', shouldReportErrors);
				validSetting = true;
			}

			if (picUpdateInterval !== undefined) {
				config.set(
					'pic-of-the-day',
					Object.assign({}, config.get('pic-of-the-day'), { date: { delay: picUpdateInterval } }),
				);
				validSetting = true;
			}

			if (folder !== undefined) {
				config.set('userFolder', folder);
				validSetting = true;
			}

			if (dir !== undefined) {
				config.set('directory', dir);
				validSetting = true;
			}

			if (collection !== undefined) {
				config.set('askForCollection', collection);
				validSetting = true;
			}

			if (like !== undefined) {
				config.set('askForLike', collection);
				validSetting = true;
			}

			if (!validSetting) {
				printBlock(
					chalk`{bold {red OOPS!}}`,
					chalk`It seems that there were a {red problem} with your {cyan settings}...`,
					'',
					'{green Please try again} or {yellow report the issue} {dim (--report)}',
				);
				break;
			}

			printBlock(
				chalk`{bold Settings saved!}`,
				'Run:',
				'',
				chalk`{dim $ splash} {green settings {bold get}}`,
				'',
				'To view them.',
			);
			break;
	}
}

function generateQuestion(name, message, options = {}) {
	const fieldRequired = (input) => {
		if (input.length) return true;
		return 'Error: that field is required!';
	};

	options.validate = options.validate || fieldRequired;

	return {
		name,
		message,
		prefix: chalk.green('#'),
		...options,
	};
}
<commit_msg>Fixes #66<commit_after>/* eslint-disable indent */
require('babel-polyfill');
require('regenerator-runtime');

import frun from 'first-run';

import chalk from 'chalk';
import ms from 'ms';
import * as TableUtility from '../extra/table-utility';
import Table from 'cli-table';

import { prompt as ask } from 'inquirer';
import { config } from '../extra/config';
import { clearSettings, errorHandler, highlightJSON, printBlock, pathFixer } from '../extra/utils';

export default async function settings([action, target, value]) {
	const questions = [];

	if (action) action = action.toString().toLowerCase();
	if (target) target = target.toString().toLowerCase();

	const _directory = generateQuestion('_directory', 'Default download path:', {
		default: config.get('directory'),
		filter: (input) => pathFixer(input),
	});

	const _askForLike = generateQuestion('_askForLike', 'Prompt to like the downloaded photo after download?', {
		type: 'confirm',
		default: config.get('askForLike'),
	});

	const _askForReport = generateQuestion('_askForReport', 'Prompt to report errors?', {
		type: 'confirm',
		default: config.get('shouldReportErrors'),
	});

	const _askForAutoReport = generateQuestion('_askForAutoReport', 'Auto report errors?', {
		type: 'confirm',
		default: config.get('shouldReportErrorsAutomatically'),
		when: (a) => a._askForReport === false,
	});

	const _askForCollection = generateQuestion(
		'_askForCollection',
		'Prompt to add the downloaded photo to a collection?',
		{
			type: 'confirm',
			prefix: chalk`{red {bold [BETA]}}`,
			default: config.get('askForCollection'),
		},
	);

	const _userFolder = generateQuestion('_userFolder', 'Do you want store photos by username?', {
		default: config.get('userFolder'),
		type: 'confirm',
	});

	const _confirmWallpaper = generateQuestion('_confirmWallpaper', 'Do you want to confirm each wallpaper?', {
		default: false,
		type: 'confirm',
	});

	const _updateInterval = generateQuestion('_updateInterval', 'Set the "pic of the day" cache expiration', {
		default: ms(1000 * 60 * 60 * 3),
	});

	switch (action) {
		case 'help':
		case 'how':
		case 'h':
			const commands = TableUtility.mapTableContent([
				[chalk`get`, 'null', 'get all settings'.toUpperCase()],
				[chalk`clear`, 'reset|restore', 'reset settings to default values'.toUpperCase()][
					(chalk`set {gray <settings_key>}`, 'null', 'opens menu for specific setting'.toUpperCase())
				],
				['help', 'how', 'SHOWS THIS MESSAGE'],
			]);

			const table = new Table(TableUtility.helpTableConfiguration);
			table.push(...commands);

			printBlock(chalk`{yellow ~ {bold ALIASES HELP} ~}`, '', table.toString());
			break;
		case 'get':
			if (target && target.toLowerCase() == 'picoftheday') {
				target = 'pic-of-the-day';
			}

			const user = config.get('user');

			const settings = config.get(); //target ? config.get(target) : config.get();

			if (settings['pic-of-the-day'] && settings['pic-of-the-day'].date) {
				if (settings['pic-of-the-day'].date.delay) {
					settings['pic-of-the-day'].date.delay = ms(settings['pic-of-the-day'].date.delay);
				}
			}

			settings.picOfTheDay = settings['pic-of-the-day'];
			settings.settingsPath = config.path;

			delete settings['error'];
			delete settings['keys'];
			delete settings['user'];
			delete settings['pic-of-the-day'];

			if (!settings || (target && !settings[target])) {
				return printBlock(chalk`Settings key: "{cyan ${target}}" {red {bold NOT} available}.`);
			}

			if (user && user.token) {
				settings['OAuth Token'] = user.token;
			}

			if (settings[target]) {
				let o = {};

				o[target] = settings[target];

				return printBlock(chalk`{bold {bgYellow {black SETTINGS}}}\n`, highlightJSON(o));
			}

			printBlock(chalk`{bold {bgYellow {black SETTINGS}}}\n`, highlightJSON(settings));
			break;
		case 'clear':
		case 'reset':
		case 'restore':
			ask([
				generateQuestion('confirm', chalk`Are you sure? This action is {underline NOT reversable}!`, {
					type: 'confirm',
					default: false,
				}),
			])
				.then(async ({ confirm }) => {
					if (confirm) {
						frun.clear();

						await clearSettings();

						printBlock(chalk`{yellow Settings Restored!}`);
					} else {
						printBlock(chalk`{red {bold Operation aborted!}}`);
					}
				})
				.catch((error) => {
					errorHandler(error);
				});
			break;

		case 'set':
		default:
			switch (target) {
				case 'report':
				case 'errors':
				case 'error':
					questions.push(_askForReport, _askForAutoReport);
					break;
				case 'directory':
				case 'dir':
					questions.push(_directory);
					break;
				case 'user':
				case 'user-folder':
				case 'userFolder':
				case 'groups':
					questions.push(_userFolder);
					break;
				case 'like':
				case 'askforlike':
					questions.push(_askForLike);
					break;
				case 'collection':
				case 'askforcollection':
					questions.push(_askForCollection);
					break;
				case 'confirm':
					questions.push(_confirmWallpaper);
					break;
				case 'prompt':
				case 'prompts':
					questions.push(_askForCollection, _askForLike);
					break;
				case 'update':
				case 'interval':
				case 'pic-of-the-day':
					questions.push(_updateInterval);
					break;
				default:
					questions.push(
						_userFolder,
						_askForReport,
						_askForAutoReport,
						_directory,
						_confirmWallpaper,
						_askForCollection,
						_askForLike,
						_updateInterval,
					);
					break;
			}

			const {
				_confirmWallpaper: confirmWallpaper,
				_userFolder: folder,
				_directory: dir,
				_askForCollection: collection,
				_askForLike: like,
				_updateInterval: picUpdateInterval,
				_askForAutoReport: shouldAutoReportErrors,
				_askForReport: shouldReportErrors,
			} = await ask(questions);

			let validSetting = false;

			if (confirmWallpaper !== undefined) {
				config.set('confirm-wallpaper', confirmWallpaper);
				validSetting = true;
			}

			if (shouldAutoReportErrors !== undefined) {
				config.set('shouldReportErrorsAutomatically', shouldAutoReportErrors);
				validSetting = true;
			}

			if (shouldReportErrors !== undefined) {
				config.set('shouldReportErrors', shouldReportErrors);
				validSetting = true;
			}

			if (picUpdateInterval !== undefined) {
				config.set(
					'pic-of-the-day',
					Object.assign({}, config.get('pic-of-the-day'), { date: { delay: picUpdateInterval } }),
				);
				validSetting = true;
			}

			if (folder !== undefined) {
				config.set('userFolder', folder);
				validSetting = true;
			}

			if (dir !== undefined) {
				config.set('directory', dir);
				validSetting = true;
			}

			if (collection !== undefined) {
				config.set('askForCollection', collection);
				validSetting = true;
			}

			if (like !== undefined) {
				config.set('askForLike', like);
				validSetting = true;
			}

			if (!validSetting) {
				printBlock(
					chalk`{bold {red OOPS!}}`,
					chalk`It seems that there were a {red problem} with your {cyan settings}...`,
					'',
					'{green Please try again} or {yellow report the issue} {dim (--report)}',
				);
				break;
			}

			printBlock(
				chalk`{bold Settings saved!}`,
				'Run:',
				'',
				chalk`{dim $ splash} {green settings {bold get}}`,
				'',
				'To view them.',
			);
			break;
	}
}

function generateQuestion(name, message, options = {}) {
	const fieldRequired = (input) => {
		if (input.length) return true;
		return 'Error: that field is required!';
	};

	options.validate = options.validate || fieldRequired;

	return {
		name,
		message,
		prefix: chalk.green('#'),
		...options,
	};
}
<|endoftext|>


<commit_before>var send = function(){
    var addr = $("#addr option:selected").val();
    var cmd = $("#cmd option:selected").val();
    var del = $('#del').val();
    var bri = $('#bri').val();
    var rgb = $('#rgb').val();
    var tout = $('#tout').val();

    R = hexToR(rgb);
    G = hexToG(rgb);
    B = hexToB(rgb);

    rgb = R+','+G+','+B;
    run(addr,cmd,del,bri,rgb,tout);
}

var run = function(addr, cmd, del, bri, rgb, tout) {
    var getCmd = "../lights/lights_cmd.php?cmd=" + cmd + "&del=" + del + "&bri="
            + bri + "&rgb=" + rgb + "&tout=" + tout+ '&addr="' + addr+'"';
    console.log('sending command');
    $.get(getCmd, function(d){
        console.log(d);
    });
}

var pTimeout = 0;

var party = function(){
   var bri = '30'
   run('00 00 00 00 00 00 FF FF','P','50',bri,'255,100,0','0');

   $.get('../sounds/sound_cmd.php?name=eyemix.mp3');

   clearTimeout(pTimeout);
   pTimeout = setTimeout(function(){
        run('00 00 00 00 00 00 FF FF','G','800',bri,'128,0,128','0');

        pTimeout = setTimeout(function(){
            run('00 00 00 00 00 00 FF FF','D','40',bri,'255,100,0','0');
        },15000);
   },15000);
}

var stop = function(){
    clearTimeout(pTimeout);
   $.get('../sounds/stop_cmd.php');
   run('00 00 00 00 00 00 FF FF','O','50','0','255,100,0','1');
}

function hexToR(h) {return parseInt((cutHex(h)).substring(0,2),16)}
function hexToG(h) {return parseInt((cutHex(h)).substring(2,4),16)}
function hexToB(h) {return parseInt((cutHex(h)).substring(4,6),16)}
function cutHex(h) {return (h.charAt(0)=="#") ? h.substring(1,7):h}<commit_msg>fixing bugs<commit_after>var send = function(){
    var addr = $("#addr option:selected").val();
    var cmd = $("#cmd option:selected").val();
    var del = $('#del').val();
    var bri = $('#bri').val();
    var rgb = $('#rgb').val();
    var tout = $('#tout').val();

    R = hexToR(rgb);
    G = hexToG(rgb);
    B = hexToB(rgb);

    rgb = R+','+G+','+B;
    run(addr,cmd,del,bri,rgb,tout);
}

var run = function(addr, cmd, del, bri, rgb, tout) {
    var getCmd = "../lights/lights_cmd.php?cmd=" + cmd + "&del=" + del + "&bri="
            + bri + "&rgb=" + rgb + "&tout=" + tout+ '&addr="' + addr+'"';
    console.log('sending command');
    $.get(getCmd, function(d){
        console.log(d);
    });
}

var pTimeout = 0;

var party = function(){
   var bri = '30'
   run('00 00 00 00 00 00 FF FF','P','50',bri,'255,100,0','0');

   $.get('../sounds/sound_cmd.php?name=eyemix.mp3');

   clearTimeout(pTimeout);
   pTimeout = setTimeout(function(){
        run('00 00 00 00 00 00 FF FF','G','800',bri,'128,0,128','0');

        pTimeout = setTimeout(function(){
            run('00 00 00 00 00 00 FF FF','D','40',bri,'255,100,0','0');

            pTimeout = setTimeout(function(){
                run('00 00 00 00 00 00 FF FF','G','800',bri,'5,200,23','0');
                pTimeout = setTimeout(function(){
                      run('00 00 00 00 00 00 FF FF','D','40',bri,'255,100,0','0');
                },5000);
            },15000);
        },15000);

   },15000);
}

var stop = function(){
    clearTimeout(pTimeout);
   $.get('../sounds/stop_cmd.php');
   run('00 00 00 00 00 00 FF FF','O','50','0','255,100,0','1');
}

function hexToR(h) {return parseInt((cutHex(h)).substring(0,2),16)}
function hexToG(h) {return parseInt((cutHex(h)).substring(2,4),16)}
function hexToB(h) {return parseInt((cutHex(h)).substring(4,6),16)}
function cutHex(h) {return (h.charAt(0)=="#") ? h.substring(1,7):h}<|endoftext|>


<commit_before>var layerGroup = new L.FeatureGroup();

$(document).ready(function () {
    var map = L.map('map').setView([48.76375572, 31.62963867], 6);

    L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
        attribution: '© OpenStreetMap contributors'
    }).addTo(map);

    var points = $("#map").data();

    for (var point in points.items) {
        if (points.items.hasOwnProperty(point)) {
            L.marker([points.items[point].latitude, points.items[point].longitude]).addTo(map);
        }
    }

    function formatDate(dateObject) {
        var d = new Date(dateObject);
        var day = d.getDate();
        var month = d.getMonth() + 1;
        var year = d.getFullYear();

        if (day < 10) {
            day = "0" + day;
        }
        if (month < 10) {
            month = "0" + month;
        }
        var dateTime = day + "." + month + "." + year;

        return dateTime;
    }

    /* Clear page from all items and markers on map */
    function clearPage() {
        layerGroup.clearLayers();
        $('#items').empty();
    }
    var categories;
    var categoriesId = [];
    var checkedCategory = false;
    $.ajax({
        url: Routing.generate('get_categories', true),
        type: 'get',
        dataType: 'JSON',
        success: function (data) {
            categories = new Object(data);
            $.ajax({
                url: Routing.generate('show_lost_points'),
                type: 'get',
                dataType: 'JSON',
                success: function (data) {
                    console.log(Routing.generate('show_lost_points'));
                    var layer = null;
                    var center = null;
                    $('.btn-group').on('change', function() {
                        categoriesId = [];
                        clearPage();
                        checkedCategory = false;
                        $('.btn-group input:checked').each(function(id, label) {
                            categoriesId.push($(label).data('categoryId'));
                            clearPage();
                            for (var i = 0; i < data.length; i++) {
                                if ((categoriesId.indexOf(data[i].categoryId)) >= 0) {
                                    checkedCategory = true;
                                    var cat = categories[data[i].categoryId];
                                    var options = {color: "#000000", weight: 2};
                                    var area;
                                    switch (data[i].areaType) {
                                        case 'polygon':
                                            area = JSON.parse(data[i].area);
                                            var polygon = [];
                                            var summLat = 0, summLng = 0;

                                            for (var j = 0; j < area.length; j++) {
                                                polygon.push([area[j].latitude, area[j].longitude]);
                                                summLat += parseInt(area[j].latitude);
                                                summLng += parseInt(area[j].longitude);
                                            }

                                            layer = L.polygon(polygon, options);
                                            center = [summLat / area.length, summLng / area.length];
                                            map.setView(center, 6);
                                            break;
                                        case 'rectangle':
                                            area = JSON.parse(data[i].area);
                                            var bounds = [[area[0].latitude, area[0].longitude], [area[2].latitude, area[2].longitude]];

                                            layer = L.rectangle(bounds, options);
                                            center = [area[0].latitude, area[0].longitude];
                                            map.setView([area[0].latitude, area[0].longitude], 6);
                                            break;
                                        case 'circle':
                                            area = JSON.parse(data[i].area);

                                            layer = L.circle([area[0].latlng.lat, area[0].latlng.lng], area[0].radius, options);
                                            center = [area[0].latlng.lat, area[0].latlng.lng];
                                            map.setView([area[0].latlng.lat, area[0].latlng.lng], 6);
                                            break;
                                        case 'marker':
                                            if (cat['imageName'] !== null) {
                                                var icon = L.icon({
                                                    iconUrl: cat['imageName'], iconSize: [32, 32]
                                                });
                                                layer = L.marker([data[i].latitude, data[i].longitude], {icon: icon});
                                            } else {
                                                layer = L.marker([data[i].latitude, data[i].longitude]);
                                            }

                                            center = [data[i].latitude, data[i].longitude];
                                            map.setView([data[i].latitude, data[i].longitude], 6);
                                            break;
                                    }

                                    $('#items').append('
' + data[i].title + '
');

                                    var popupText = "

"
                                        + cat.title
                                        + "

"
                                        + "
"
                                        + data[i].title
                                        + "

"
                                        + "
Added: "
                                        + formatDate(data[i].date.date)
                                        + "

";

                                    layer.bindPopup(popupText);
                                    layerGroup.addLayer(layer).addTo(map);
                                }
                            }
                        });

                    });
                }
            });
        }
    });

    map.addLayer(layerGroup);
});
<commit_msg>Fix fails<commit_after>var layerGroup = new L.FeatureGroup();

$(document).ready(function () {
    var map = L.map('map').setView([48.76375572, 31.62963867], 6);

    L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
        attribution: '© OpenStreetMap contributors'
    }).addTo(map);

    var points = $("#map").data();

    for (var point in points.items) {
        if (points.items.hasOwnProperty(point)) {
            L.marker([points.items[point].latitude, points.items[point].longitude]).addTo(map);
        }
    }

    function formatDate(dateObject) {
        var d = new Date(dateObject);
        var day = d.getDate();
        var month = d.getMonth() + 1;
        var year = d.getFullYear();

        if (day < 10) {
            day = "0" + day;
        }
        if (month < 10) {
            month = "0" + month;
        }
        var dateTime = day + "." + month + "." + year;

        return dateTime;
    }

    /* Clear page from all items and markers on map */
    function clearPage() {
        layerGroup.clearLayers();
        $('#items').empty();
    }
    var categories;
    var categoriesId = [];
    var checkedCategory = false;
    $.ajax({
        url: Routing.generate('get_categories'),
        type: 'get',
        dataType: 'JSON',
        success: function (data) {
            categories = new Object(data);
            $.ajax({
                url: Routing.generate('show_lost_points'),
                type: 'get',
                dataType: 'JSON',
                success: function (data) {
                    var layer = null;
                    var center = null;
                    $('.btn-group').on('change', function() {
                        categoriesId = [];
                        clearPage();
                        checkedCategory = false;
                        $('.btn-group input:checked').each(function(id, label) {
                            categoriesId.push($(label).data('categoryId'));
                            clearPage();
                            for (var i = 0; i < data.length; i++) {
                                if ((categoriesId.indexOf(data[i].categoryId)) >= 0) {
                                    checkedCategory = true;
                                    var cat = categories[data[i].categoryId];
                                    var options = {color: "#000000", weight: 2};
                                    var area;
                                    switch (data[i].areaType) {
                                        case 'polygon':
                                            area = JSON.parse(data[i].area);
                                            var polygon = [];
                                            var summLat = 0, summLng = 0;

                                            for (var j = 0; j < area.length; j++) {
                                                polygon.push([area[j].latitude, area[j].longitude]);
                                                summLat += parseInt(area[j].latitude);
                                                summLng += parseInt(area[j].longitude);
                                            }

                                            layer = L.polygon(polygon, options);
                                            center = [summLat / area.length, summLng / area.length];
                                            map.setView(center, 6);
                                            break;
                                        case 'rectangle':
                                            area = JSON.parse(data[i].area);
                                            var bounds = [[area[0].latitude, area[0].longitude], [area[2].latitude, area[2].longitude]];

                                            layer = L.rectangle(bounds, options);
                                            center = [area[0].latitude, area[0].longitude];
                                            map.setView([area[0].latitude, area[0].longitude], 6);
                                            break;
                                        case 'circle':
                                            area = JSON.parse(data[i].area);

                                            layer = L.circle([area[0].latlng.lat, area[0].latlng.lng], area[0].radius, options);
                                            center = [area[0].latlng.lat, area[0].latlng.lng];
                                            map.setView([area[0].latlng.lat, area[0].latlng.lng], 6);
                                            break;
                                        case 'marker':
                                            if (cat['imageName'] !== null) {
                                                var icon = L.icon({
                                                    iconUrl: cat['imageName'], iconSize: [32, 32]
                                                });
                                                layer = L.marker([data[i].latitude, data[i].longitude], {icon: icon});
                                            } else {
                                                layer = L.marker([data[i].latitude, data[i].longitude]);
                                            }

                                            center = [data[i].latitude, data[i].longitude];
                                            map.setView([data[i].latitude, data[i].longitude], 6);
                                            break;
                                    }

                                    $('#items').append('
' + data[i].title + '
');

                                    var popupText = "

"
                                        + cat.title
                                        + "

"
                                        + "
"
                                        + data[i].title
                                        + "

"
                                        + "
Added: "
                                        + formatDate(data[i].date.date)
                                        + "

";

                                    layer.bindPopup(popupText);
                                    layerGroup.addLayer(layer).addTo(map);
                                }
                            }
                        });

                    });
                }
            });
        }
    });

    map.addLayer(layerGroup);
});
<|endoftext|>


<commit_before>'use strict';
var gulp = require('gulp');
var gutil = require('gulp-util');
var fs = require('fs');
var del = require('del');
var uglify = require('gulp-uglify');
var gulpif = require('gulp-if');
var exec = require('child_process').exec;
var runSequence = require('run-sequence')
var notify = require('gulp-notify');
var buffer = require('vinyl-buffer');
var gulpwatch = require('gulp-watch');
var argv = require('yargs').argv;
// sass
var sass = require('gulp-sass');
var postcss = require('gulp-postcss');
var postcssFlexbugFixes = require('postcss-flexbugs-fixes');
var autoprefixer = require('autoprefixer');
var sourcemaps = require('gulp-sourcemaps');
// BrowserSync
var browserSync = require('browser-sync');
// js
var watchify = require('watchify');
var browserify = require('browserify');
var source = require('vinyl-source-stream');
// linting
var jshint = require('gulp-jshint');
var stylish = require('jshint-stylish');
// Scratch image rendering
var scratchblocks = require('scratchblocks');
var rename = require("gulp-rename");
var through = require('through2');
var PluginError = require('gulp-util').PluginError;

// gulp build --production
var production = !!argv.production;
// determine if we're doing a build
// and if so, bypass the livereload
var build = argv._.length ? argv._[0] === 'build' : false;
var watch = argv._.length ? argv._[0] === 'watch' : true;

// ----------------------------
// Error notification methods
// ----------------------------
var beep = function() {
  var os = require('os');
  var file = 'gulp/error.wav';
  if (os.platform() === 'linux') {
    // linux
    exec("aplay " + file);
  } else {
    // mac
    console.log("afplay " + file);
    exec("afplay " + file);
  }
};
var handleError = function(task) {
  return function(err) {
    beep();

      notify.onError({
        message: task + ' failed, check the logs..',
        sound: false
      })(err);

    gutil.log(gutil.colors.bgRed(task + ' error:'), gutil.colors.red(err));
  };
};
var scratchSVG = function() {
  var PLUGIN_NAME = 'scratchSVG';
  return through.obj(function(file, encoding, callback) {
    if (file.isNull()) {
        // nothing to do
        return callback(null, file);
    }

    if (file.isStream()) {
        // file.contents is a Stream - https://nodejs.org/api/stream.html
        this.emit('error', new PluginError(PLUGIN_NAME, 'Streams not supported!'));
    } else if (file.isBuffer()) {
        // file.contents is a Buffer - https://nodejs.org/api/buffer.html
        var doc = scratchblocks.parse(file.contents.toString())
        doc.render(svg => {
          var string = doc.exportSVGString();
          // Remove invalid xmlns attribute due to issue https://github.com/scratchblocks/scratchblocks/issues/219
          string = string.replace(
            '<use xmlns="http://www.w3.org/1999/xlink" href="#greenFlag"',
            '<use href="#greenFlag"'
          );
          file.contents = new Buffer(string);
        })
        return callback(null, file);
    }
  });
};
// --------------------------
// CUSTOM TASK METHODS
// --------------------------
var tasks = {
  // --------------------------
  // Delete build folder
  // --------------------------
  clean: function() {
    return del(['build/']);
  },
  // --------------------------
  // Copy static images
  // --------------------------
  images: function() {
    return gulp.src('static/img/**/*')
      .pipe(gulp.dest('build/img'));
  },
  // --------------------------
  // CSS
  // --------------------------
  css: function() {
    return gulp.src('static/css/**/*.css')
      .pipe(gulp.dest('build/css'));
  },
  // --------------------------
  // JS
  // --------------------------
  js: function() {
    return gulp.src('static/js/**/*.js')
      .pipe(gulp.dest('build/js'));
  },
  // --------------------------
  // Scratch
  // --------------------------
  scratch: function() {
    return gulp.src('temp/scratch-blocks-*.txt')
      .pipe(scratchSVG())
      .pipe(rename(function (path) {
        path.extname = ".svg"
      }))
      // give it a file and save
      .pipe(gulp.dest('build/img'));
  },
  // --------------------------
  // SASS (libsass)
  // --------------------------
  sass: function() {
    return gulp.src('static/scss/*.scss')
      // sourcemaps + sass + error handling
      .pipe(gulpif(!production, sourcemaps.init()))
      .pipe(sass({
        sourceComments: !production,
        outputStyle: production ? 'compressed' : 'nested'
      }))
      .on('error', handleError('SASS'))
      // generate .maps
      .pipe(gulpif(!production, sourcemaps.write({
        'includeContent': false,
        'sourceRoot': '.'
      })))
      // autoprefixer
      .pipe(gulpif(!production, sourcemaps.init({
        'loadMaps': true
      })))
      .pipe(postcss([autoprefixer({browsers: ['last 2 versions']}), postcssFlexbugFixes]))
      // we don't serve the source files
      // so include scss content inside the sourcemaps
      .pipe(sourcemaps.write({
        'includeContent': true
      }))
      // write sourcemaps to a specific directory
      // give it a file and save
      .pipe(gulp.dest('build/css'));
  },

  // --------------------------
  // linting
  // --------------------------
  lintjs: function() {
    return gulp.src([
        'gulpfile.js',
        'static/js/index.js',
        'static/js/**/*.js'
      ]).pipe(jshint())
      .pipe(jshint.reporter(stylish))
      .on('error', function() {
        beep();
      });
  },
};

gulp.task('browser-sync', function() {
    browserSync.init({
        proxy: "localhost:8000",
        port: process.env.PORT || 3000
    });
});

gulp.task('reload-sass', ['sass'], function(){
  browserSync.reload();
});
gulp.task('reload-scratch', ['scratch'], function(){
  browserSync.reload();
});
gulp.task('reload-js', ['js'], function(){
  browserSync.reload();
});
gulp.task('reload-css', ['css'], function(){
  browserSync.reload();
});
gulp.task('reload-templates', [], function(){
  browserSync.reload();
});

// // --------------------------
// // CUSTOMS TASKS
// // --------------------------
gulp.task('clean', tasks.clean);
// // for production we require the clean method on every individual task
var req = [];
// // individual tasks
gulp.task('images', req, tasks.images);
gulp.task('js', req, tasks.js);
gulp.task('css', req, tasks.css);
gulp.task('sass', req, tasks.sass);
gulp.task('scratch', req, tasks.scratch);
gulp.task('lint:js', tasks.lintjs);
gulp.task('optimize', tasks.optimize);
gulp.task('test', tasks.test);

// --------------------------
// DEV/WATCH TASK
// --------------------------
gulp.task('watch', ['scratch', 'images', 'css', 'js', 'sass', 'browser-sync'], function() {
  // --------------------------
  // watch:scratch
  // --------------------------
  gulpwatch('temp/scratch-blocks-*.txt', function() {
      gulp.start('reload-scratch');
  });
  // --------------------------
  // watch:sass
  // --------------------------
  gulp.watch('static/scss/**/*.scss', ['reload-sass']);

  // --------------------------
  // watch:js
  // --------------------------
  gulp.watch('static/js/**/*.js', ['lint:js', 'reload-js']);

  // --------------------------
  // watch:css
  // --------------------------
  gulp.watch('static/css/**/*.css', ['reload-css']);

  // --------------------------
  // watch:templates
  // --------------------------
  gulp.watch('templates/**/*.html', ['reload-templates']);

  gutil.log(gutil.colors.bgGreen('Watching for changes...'));
});

// build task
gulp.task('build', function(callback) {
  runSequence('clean', ['images', 'css', 'js', 'sass', 'scratch'], callback);
});

gulp.task('default', ['watch']);

// gulp (watch) : for development and livereload
// gulp build : for a one off development build
// gulp build --production : for a minified production build
<commit_msg>Rerun image task and reload browser when image folder changes<commit_after>'use strict';
var gulp = require('gulp');
var gutil = require('gulp-util');
var fs = require('fs');
var del = require('del');
var uglify = require('gulp-uglify');
var gulpif = require('gulp-if');
var exec = require('child_process').exec;
var runSequence = require('run-sequence')
var notify = require('gulp-notify');
var buffer = require('vinyl-buffer');
var gulpwatch = require('gulp-watch');
var argv = require('yargs').argv;
// sass
var sass = require('gulp-sass');
var postcss = require('gulp-postcss');
var postcssFlexbugFixes = require('postcss-flexbugs-fixes');
var autoprefixer = require('autoprefixer');
var sourcemaps = require('gulp-sourcemaps');
// BrowserSync
var browserSync = require('browser-sync');
// js
var watchify = require('watchify');
var browserify = require('browserify');
var source = require('vinyl-source-stream');
// linting
var jshint = require('gulp-jshint');
var stylish = require('jshint-stylish');
// Scratch image rendering
var scratchblocks = require('scratchblocks');
var rename = require("gulp-rename");
var through = require('through2');
var PluginError = require('gulp-util').PluginError;

// gulp build --production
var production = !!argv.production;
// determine if we're doing a build
// and if so, bypass the livereload
var build = argv._.length ? argv._[0] === 'build' : false;
var watch = argv._.length ? argv._[0] === 'watch' : true;

// ----------------------------
// Error notification methods
// ----------------------------
var beep = function() {
  var os = require('os');
  var file = 'gulp/error.wav';
  if (os.platform() === 'linux') {
    // linux
    exec("aplay " + file);
  } else {
    // mac
    console.log("afplay " + file);
    exec("afplay " + file);
  }
};
var handleError = function(task) {
  return function(err) {
    beep();

      notify.onError({
        message: task + ' failed, check the logs..',
        sound: false
      })(err);

    gutil.log(gutil.colors.bgRed(task + ' error:'), gutil.colors.red(err));
  };
};
var scratchSVG = function() {
  var PLUGIN_NAME = 'scratchSVG';
  return through.obj(function(file, encoding, callback) {
    if (file.isNull()) {
        // nothing to do
        return callback(null, file);
    }

    if (file.isStream()) {
        // file.contents is a Stream - https://nodejs.org/api/stream.html
        this.emit('error', new PluginError(PLUGIN_NAME, 'Streams not supported!'));
    } else if (file.isBuffer()) {
        // file.contents is a Buffer - https://nodejs.org/api/buffer.html
        var doc = scratchblocks.parse(file.contents.toString())
        doc.render(svg => {
          var string = doc.exportSVGString();
          // Remove invalid xmlns attribute due to issue https://github.com/scratchblocks/scratchblocks/issues/219
          string = string.replace(
            '<use xmlns="http://www.w3.org/1999/xlink" href="#greenFlag"',
            '<use href="#greenFlag"'
          );
          file.contents = new Buffer(string);
        })
        return callback(null, file);
    }
  });
};
// --------------------------
// CUSTOM TASK METHODS
// --------------------------
var tasks = {
  // --------------------------
  // Delete build folder
  // --------------------------
  clean: function() {
    return del(['build/']);
  },
  // --------------------------
  // Copy static images
  // --------------------------
  images: function() {
    return gulp.src('static/img/**/*')
      .pipe(gulp.dest('build/img'));
  },
  // --------------------------
  // CSS
  // --------------------------
  css: function() {
    return gulp.src('static/css/**/*.css')
      .pipe(gulp.dest('build/css'));
  },
  // --------------------------
  // JS
  // --------------------------
  js: function() {
    return gulp.src('static/js/**/*.js')
      .pipe(gulp.dest('build/js'));
  },
  // --------------------------
  // Scratch
  // --------------------------
  scratch: function() {
    return gulp.src('temp/scratch-blocks-*.txt')
      .pipe(scratchSVG())
      .pipe(rename(function (path) {
        path.extname = ".svg"
      }))
      // give it a file and save
      .pipe(gulp.dest('build/img'));
  },
  // --------------------------
  // SASS (libsass)
  // --------------------------
  sass: function() {
    return gulp.src('static/scss/*.scss')
      // sourcemaps + sass + error handling
      .pipe(gulpif(!production, sourcemaps.init()))
      .pipe(sass({
        sourceComments: !production,
        outputStyle: production ? 'compressed' : 'nested'
      }))
      .on('error', handleError('SASS'))
      // generate .maps
      .pipe(gulpif(!production, sourcemaps.write({
        'includeContent': false,
        'sourceRoot': '.'
      })))
      // autoprefixer
      .pipe(gulpif(!production, sourcemaps.init({
        'loadMaps': true
      })))
      .pipe(postcss([autoprefixer({browsers: ['last 2 versions']}), postcssFlexbugFixes]))
      // we don't serve the source files
      // so include scss content inside the sourcemaps
      .pipe(sourcemaps.write({
        'includeContent': true
      }))
      // write sourcemaps to a specific directory
      // give it a file and save
      .pipe(gulp.dest('build/css'));
  },

  // --------------------------
  // linting
  // --------------------------
  lintjs: function() {
    return gulp.src([
        'gulpfile.js',
        'static/js/index.js',
        'static/js/**/*.js'
      ]).pipe(jshint())
      .pipe(jshint.reporter(stylish))
      .on('error', function() {
        beep();
      });
  },
};

gulp.task('browser-sync', function() {
    browserSync.init({
        proxy: "localhost:8000",
        port: process.env.PORT || 3000
    });
});

gulp.task('reload-sass', ['sass'], function(){
  browserSync.reload();
});
gulp.task('reload-scratch', ['scratch'], function(){
  browserSync.reload();
});
gulp.task('reload-images', ['images'], function(){
  browserSync.reload();
});
gulp.task('reload-js', ['js'], function(){
  browserSync.reload();
});
gulp.task('reload-css', ['css'], function(){
  browserSync.reload();
});
gulp.task('reload-templates', [], function(){
  browserSync.reload();
});

// // --------------------------
// // CUSTOMS TASKS
// // --------------------------
gulp.task('clean', tasks.clean);
// // for production we require the clean method on every individual task
var req = [];
// // individual tasks
gulp.task('images', req, tasks.images);
gulp.task('js', req, tasks.js);
gulp.task('css', req, tasks.css);
gulp.task('sass', req, tasks.sass);
gulp.task('scratch', req, tasks.scratch);
gulp.task('lint:js', tasks.lintjs);
gulp.task('optimize', tasks.optimize);
gulp.task('test', tasks.test);

// --------------------------
// DEV/WATCH TASK
// --------------------------
gulp.task('watch', ['scratch', 'images', 'css', 'js', 'sass', 'browser-sync'], function() {
  // --------------------------
  // watch:scratch
  // --------------------------
  gulpwatch('temp/scratch-blocks-*.txt', function() {
      gulp.start('reload-scratch');
  });
  // --------------------------
  // watch:images
  // --------------------------
  gulpwatch('static/img/**/*', function() {
      gulp.start('reload-images');
  });
  // --------------------------
  // watch:sass
  // --------------------------
  gulp.watch('static/scss/**/*.scss', ['reload-sass']);

  // --------------------------
  // watch:js
  // --------------------------
  gulp.watch('static/js/**/*.js', ['lint:js', 'reload-js']);

  // --------------------------
  // watch:css
  // --------------------------
  gulp.watch('static/css/**/*.css', ['reload-css']);

  // --------------------------
  // watch:templates
  // --------------------------
  gulp.watch('templates/**/*.html', ['reload-templates']);

  gutil.log(gutil.colors.bgGreen('Watching for changes...'));
});

// build task
gulp.task('build', function(callback) {
  runSequence('clean', ['images', 'css', 'js', 'sass', 'scratch'], callback);
});

gulp.task('default', ['watch']);

// gulp (watch) : for development and livereload
// gulp build : for a one off development build
// gulp build --production : for a minified production build
<|endoftext|>


<commit_before>/*jslint node: true, indent: 4 */
'use strict';
var async = require('async');
var discourse,
    conf,
    delay,
    currentBingeCap = 0,
    bingeIgnoreList = [];

 /**
 * Brief description of this module for Help Docs
 */
exports.description = 'Issue Likes to all posts in a thread';

/**
 * Default Configuration settings for this sock_module
 * @type {Object}
 */
exports.configuration = {
    /**
     * Whether this module should be enabled
     * @type {Boolean}
     */
    enabled: false,
    /**
     * Whether this should... something involving following. Imprint on mother ducks?
     * @type {Boolean}
     */
    follow: false,
    /**
     * Whether this module should binge-like to catch up on things you didn't like while it was down
     * @type {Boolean}
     */
    binge: false,
    /**
     * The hour at which to binge-like
     * @type {Number}
     */
    bingeHour: 23,
    /**
     *  The minute at which to binge-like
     * @type {Number}
     */
    bingeMinute: 30,
    /**
     * Maximum amout of posts to like while binging
     * @type {Number}
     */
    bingeCap: 10000,
    /**
     * The topic to auto-like. Defaults to /t/1000
     * @type {Number}
     */
    topic: 1000,
    /**
     * How long to delay before liking in cyborg mode.
     * @type {[type]}
     */
    cyborgDelay: 30 * 1000
};

 /**
 * The name of this sock_module
 */
exports.name = 'AutoLikes';

  /**
 * If defined by a sock_module it is the priority
 * of the module with respect to other modules.
 *
 * sock_modules **should not** define modules with negative permissions.
 * Default value is 50 with lower numbers being higher priority.
 */
exports.priority = 0;

/**
 * The version of this sock_module
 */
exports.version = '1.14.0';

/**
 * Replaces variables in formatting strings, kind of like printf
 * @param  {String} str - The string to format
 * @param  {Array} dict - The variables to format into the string
 * @return {String} the message after replacement
 */
function format(str, dict) {
    for (var name in dict) {
        str = str.replace(new RegExp('%' + name + '%', 'g'), dict[name]);
    }
    return str;
}

/**
 * Wrapper that standardizes parameters for innerBinge. Will binge on either one topic or many.
 * @param  {Function} callback - The callback to call when done binging
 */
function binge(callback) {
    if (typeof conf.topic === 'number') {
        innerBinge(conf.topic, callback);
    } else {
        async.each(conf.topic, function (topic, next) {
            return innerBinge(topic, next);
        }, callback);
    }
}

/**
 * Perform a binge-liking.
 * @param  {Number} topic - The topic number to binge-like on
 * @param  {Function} callback - the callback to call when done binging
 */
function innerBinge(topic, callback) {
    var msg = 'Liking /t/%TOPIC%/%POST% by @%USER%';
    discourse.getAllPosts(topic, function (err, posts, next) {
        if (err || currentBingeCap <= 0) {
            return next(true);
        }
        var likeables = posts.filter(function (x) {
            var action = x.actions_summary.filter(function (y) {
                return y.id === 2;
            });
            return action && action[0].can_act;
        });
        likeables = likeables.slice(0, currentBingeCap);
        async.each(likeables, function (post, flow) {
            if (bingeIgnoreList.indexOf(post.username) >= 0) {
                flow();
            } else {
                discourse.log(format(msg, {
                    'TOPIC': post.topic_id,
                    'POST': post.post_number,
                    'USER': post.username
                }));
                discourse.postAction('like', post.id, function (err2, resp) {
                    flow(err2 || resp.statusCode === 429);
                });
                currentBingeCap--;
            }
        }, next);
    }, function () {
        callback();
    });
}

/**
 * Schedule new binges according to configuration
 */
function scheduleBinges() {
    async.forever(function (cb) {
        var now = new Date(),
            utc = new Date(),
            hours,
            minutes;
        utc.setUTCHours(conf.bingeHour);
        utc.setUTCMinutes(conf.bingeMinute);
        utc.setUTCSeconds(0);
        utc.setMilliseconds(0);
        now = now.getTime();
        utc = utc.getTime();
        if (now > utc) {
            // add a day if scheduling after 23:40 UTC
            utc += 24 * 60 * 60 * 1000;
        }
        minutes = Math.ceil(((utc - now) / 1000) / 60);
        hours = Math.floor(minutes / 60);
        minutes = minutes % 60;
        discourse.log('Like Binge scheduled for ' + hours + 'h' +
            minutes + 'm from now');
        setTimeout(function () {
            currentBingeCap = conf.bingeCap;
            binge(cb);
        }, utc - now);
    });
}

/**
 * Handler for when a message is received. If it is a new post creation message in the correct thread,
 * the module will like it.
 * @param  {Object} message - The message that was received
 * @param  {Object} post - The post information for that message
 * @param  {Function} callback - The callback to call when done
 */
exports.onMessage = function onMessage(message, post, callback) {
    if (message.data && message.data.type === 'created') {
        if (post) {
            discourse.log('Liking Post /t/' + post.topic_id +
                '/' + post.post_number + ' by @' + post.username);
        } else {
            discourse.log('Liking Post #' + message.data.id);
        }
        setTimeout(function () {
            discourse.postAction('like', message.data.id, callback);
        }, Math.floor(Math.random() * 5 * 1000) + delay);
    } else {
        callback();
    }
};

/**
 * Register listeners that do the following if we are in follow mode
 * @param  {Function} callback - the callback to call when complete
 */
exports.registerListeners = function registerListeners(callback) {
    if (conf.enabled && conf.follow) {
        if (typeof conf.topic === 'number') {
            callback(null, ['/topic/' + conf.topic]);
        } else {
            callback(null, conf.topic.map(function (v) {
                return '/topic/' + v;
            }));
        }
    } else {
        callback();
    }
};

/**
* Bootstrap the module
* @param  {string} browser - discourse.
* @param  {object} config - The configuration to use
*/
exports.begin = function begin(browser, config) {
    conf = config.modules[exports.name];
    discourse = browser;
    delay = conf.cyborg ? conf.cyborgDelay : 1;
    if (conf.enabled && conf.binge) {
        bingeIgnoreList = config.admin.ignore;
        scheduleBinges();
    }
};
 <commit_msg>forgot to add module declaration for autoliker<commit_after>/*jslint node: true, indent: 4 */
'use strict';
var async = require('async');
var discourse,
    conf,
    delay,
    currentBingeCap = 0,
    bingeIgnoreList = [];

/**
 * Likes module. The  autoliker
 * @module likes
 */

 /**
 * Brief description of this module for Help Docs
 */
exports.description = 'Issue Likes to all posts in a thread';

/**
 * Default Configuration settings for this sock_module
 * @type {Object}
 */
exports.configuration = {
    /**
     * Whether this module should be enabled
     * @type {Boolean}
     */
    enabled: false,
    /**
     * Whether this should... something involving following. Imprint on mother ducks?
     * @type {Boolean}
     */
    follow: false,
    /**
     * Whether this module should binge-like to catch up on things you didn't like while it was down
     * @type {Boolean}
     */
    binge: false,
    /**
     * The hour at which to binge-like
     * @type {Number}
     */
    bingeHour: 23,
    /**
     *  The minute at which to binge-like
     * @type {Number}
     */
    bingeMinute: 30,
    /**
     * Maximum amout of posts to like while binging
     * @type {Number}
     */
    bingeCap: 10000,
    /**
     * The topic to auto-like. Defaults to /t/1000
     * @type {Number}
     */
    topic: 1000,
    /**
     * How long to delay before liking in cyborg mode.
     * @type {[type]}
     */
    cyborgDelay: 30 * 1000
};

 /**
 * The name of this sock_module
 */
exports.name = 'AutoLikes';

  /**
 * If defined by a sock_module it is the priority
 * of the module with respect to other modules.
 *
 * sock_modules **should not** define modules with negative permissions.
 * Default value is 50 with lower numbers being higher priority.
 */
exports.priority = 0;

/**
 * The version of this sock_module
 */
exports.version = '1.14.0';

/**
 * Replaces variables in formatting strings, kind of like printf
 * @param  {String} str - The string to format
 * @param  {Array} dict - The variables to format into the string
 * @return {String} the message after replacement
 */
function format(str, dict) {
    for (var name in dict) {
        str = str.replace(new RegExp('%' + name + '%', 'g'), dict[name]);
    }
    return str;
}

/**
 * Wrapper that standardizes parameters for innerBinge. Will binge on either one topic or many.
 * @param  {Function} callback - The callback to call when done binging
 */
function binge(callback) {
    if (typeof conf.topic === 'number') {
        innerBinge(conf.topic, callback);
    } else {
        async.each(conf.topic, function (topic, next) {
            return innerBinge(topic, next);
        }, callback);
    }
}

/**
 * Perform a binge-liking.
 * @param  {Number} topic - The topic number to binge-like on
 * @param  {Function} callback - the callback to call when done binging
 */
function innerBinge(topic, callback) {
    var msg = 'Liking /t/%TOPIC%/%POST% by @%USER%';
    discourse.getAllPosts(topic, function (err, posts, next) {
        if (err || currentBingeCap <= 0) {
            return next(true);
        }
        var likeables = posts.filter(function (x) {
            var action = x.actions_summary.filter(function (y) {
                return y.id === 2;
            });
            return action && action[0].can_act;
        });
        likeables = likeables.slice(0, currentBingeCap);
        async.each(likeables, function (post, flow) {
            if (bingeIgnoreList.indexOf(post.username) >= 0) {
                flow();
            } else {
                discourse.log(format(msg, {
                    'TOPIC': post.topic_id,
                    'POST': post.post_number,
                    'USER': post.username
                }));
                discourse.postAction('like', post.id, function (err2, resp) {
                    flow(err2 || resp.statusCode === 429);
                });
                currentBingeCap--;
            }
        }, next);
    }, function () {
        callback();
    });
}

/**
 * Schedule new binges according to configuration
 */
function scheduleBinges() {
    async.forever(function (cb) {
        var now = new Date(),
            utc = new Date(),
            hours,
            minutes;
        utc.setUTCHours(conf.bingeHour);
        utc.setUTCMinutes(conf.bingeMinute);
        utc.setUTCSeconds(0);
        utc.setMilliseconds(0);
        now = now.getTime();
        utc = utc.getTime();
        if (now > utc) {
            // add a day if scheduling after 23:40 UTC
            utc += 24 * 60 * 60 * 1000;
        }
        minutes = Math.ceil(((utc - now) / 1000) / 60);
        hours = Math.floor(minutes / 60);
        minutes = minutes % 60;
        discourse.log('Like Binge scheduled for ' + hours + 'h' +
            minutes + 'm from now');
        setTimeout(function () {
            currentBingeCap = conf.bingeCap;
            binge(cb);
        }, utc - now);
    });
}

/**
 * Handler for when a message is received. If it is a new post creation message in the correct thread,
 * the module will like it.
 * @param  {Object} message - The message that was received
 * @param  {Object} post - The post information for that message
 * @param  {Function} callback - The callback to call when done
 */
exports.onMessage = function onMessage(message, post, callback) {
    if (message.data && message.data.type === 'created') {
        if (post) {
            discourse.log('Liking Post /t/' + post.topic_id +
                '/' + post.post_number + ' by @' + post.username);
        } else {
            discourse.log('Liking Post #' + message.data.id);
        }
        setTimeout(function () {
            discourse.postAction('like', message.data.id, callback);
        }, Math.floor(Math.random() * 5 * 1000) + delay);
    } else {
        callback();
    }
};

/**
 * Register listeners that do the following if we are in follow mode
 * @param  {Function} callback - the callback to call when complete
 */
exports.registerListeners = function registerListeners(callback) {
    if (conf.enabled && conf.follow) {
        if (typeof conf.topic === 'number') {
            callback(null, ['/topic/' + conf.topic]);
        } else {
            callback(null, conf.topic.map(function (v) {
                return '/topic/' + v;
            }));
        }
    } else {
        callback();
    }
};

/**
* Bootstrap the module
* @param  {string} browser - discourse.
* @param  {object} config - The configuration to use
*/
exports.begin = function begin(browser, config) {
    conf = config.modules[exports.name];
    discourse = browser;
    delay = conf.cyborg ? conf.cyborgDelay : 1;
    if (conf.enabled && conf.binge) {
        bingeIgnoreList = config.admin.ignore;
        scheduleBinges();
    }
};
 <|endoftext|>


<commit_before>import React, {PureComponent} from 'react'
import {connect} from 'react-redux'
import CSSModules from 'react-css-modules'
import DocumentTitle from 'react-document-title'
import PropTypes from 'prop-types'
import {Action} from 'wukong-client'

import ChannelTitle from './channel-title'
import MemberList from './member-list'
import NowPlaying from './now-playing'
import LyricsMarquee from './lyrics-marquee'
import ActionPanel from './action-panel'
import OmniPanel from './omni-panel'
import SongList from './song-list'
import PlayerAudio from './player-audio'
import PlayerPreload from './player-preload'
import PlayerExternal from './player-external'
import style from './channel.css'

function mapStateToProps(state, props) {
  return {
    channel: props.match.params.channel
  }
}

function mapDispatchToProps(dispatch) {
  return {
    dispatchChannel(channel) {
      dispatch(Action.Channel.name.create(channel))
    }
  }
}

@connect(mapStateToProps, mapDispatchToProps)
@CSSModules(style)
export default class Channel extends PureComponent {
  static propTypes = {
    channel: PropTypes.string,
    dispatchChannel: PropTypes.func
  }

  updateChannel() {
    this.props.dispatchChannel(this.props.channel)
  }

  componentDidMount() {
    this.updateChannel()
  }

  componentDidUpdate(prevProps, prevState) {
    if (this.props.channel != prevProps.channel) {
      this.updateChannel()
    }
  }

  render() {
    const {channel} = this.props
    const hasExternalAPI = !!window.webkit
    return (
      <DocumentTitle title={`Wukong#${channel}`}>

            <ChannelTitle/>

            <MemberList/>

            <NowPlaying/>
            <LyricsMarquee/>
            <ActionPanel/>

            <OmniPanel/>
            <SongList/>

          {hasExternalAPI || <PlayerAudio/>}
          {hasExternalAPI || <PlayerPreload/>}
          {hasExternalAPI && <PlayerExternal/>}

      </DocumentTitle>
    )
  }
}
<commit_msg>fix in wkwebview<commit_after>import React, {PureComponent} from 'react'
import {connect} from 'react-redux'
import CSSModules from 'react-css-modules'
import DocumentTitle from 'react-document-title'
import PropTypes from 'prop-types'
import {Action} from 'wukong-client'

import ChannelTitle from './channel-title'
import MemberList from './member-list'
import NowPlaying from './now-playing'
import LyricsMarquee from './lyrics-marquee'
import ActionPanel from './action-panel'
import OmniPanel from './omni-panel'
import SongList from './song-list'
import PlayerAudio from './player-audio'
import PlayerPreload from './player-preload'
import PlayerExternal from './player-external'
import style from './channel.css'

function mapStateToProps(state, props) {
  return {
    channel: props.match.params.channel
  }
}

function mapDispatchToProps(dispatch) {
  return {
    dispatchChannel(channel) {
      dispatch(Action.Channel.name.create(channel))
    }
  }
}

@connect(mapStateToProps, mapDispatchToProps)
@CSSModules(style)
export default class Channel extends PureComponent {
  static propTypes = {
    channel: PropTypes.string,
    dispatchChannel: PropTypes.func
  }

  updateChannel() {
    this.props.dispatchChannel(this.props.channel)
  }

  componentDidMount() {
    this.updateChannel()
  }

  componentDidUpdate(prevProps, prevState) {
    if (this.props.channel != prevProps.channel) {
      this.updateChannel()
    }
  }

  render() {
    const {channel} = this.props
    const hasExternalAPI = !!(
      window.webkit &&
      window.webkit.messageHandlers &&
      window.webkit.messageHandlers.wukong
    )
    return (
      <DocumentTitle title={`Wukong#${channel}`}>

            <ChannelTitle/>

            <MemberList/>

            <NowPlaying/>
            <LyricsMarquee/>
            <ActionPanel/>

            <OmniPanel/>
            <SongList/>

          {hasExternalAPI || <PlayerAudio/>}
          {hasExternalAPI || <PlayerPreload/>}
          {hasExternalAPI && <PlayerExternal/>}

      </DocumentTitle>
    )
  }
}
<|endoftext|>