<commit_before>const parse = require('co-busboy');
const sendfile = require('koa-sendfile');
const path = require('path');
const Promise = require('bluebird');
const fs = Promise.promisifyAll(require('fs-extra'));
const config = require('config');
const gm = require('gm');
const logger = require('./logger');
const util = require('./util');

Promise.promisifyAll(Object.getPrototypeOf(gm()));

function getFilePath(param) {
  const result = /(\d+)(.*)/.exec(param);
  if (!result) {
    return null;
  }

  const bookmarkIndex = parseInt(result[1], 10);
  const bookmark = config.bookmarks[bookmarkIndex];
  if (!bookmark) {
    return null;
  }

  let subdir = result[2];
  if (subdir.length > 0) {
    if (subdir[0] !== '/') {
      return null;
    }

    subdir = subdir.substr(1);
  }

  const realpath = path.normalize(path.resolve(bookmark.dir, subdir));
  if (!realpath.startsWith(bookmark.dir)) {
    return null;
  }

  return realpath;
}

function getImageInfo(filepath) {
  const info = {};
  return new Promise((resolve, reject) => {
    const img = gm(filepath);
    img.size((err, value) => {
      if (err) {
        reject(err);
        return;
      }

      info.size = value;
      img.orientation((err2, value2) => {
        if (err2) {
          reject(err2);
          return;
        }

        info.orientation = value2;
        resolve(info);
      });
    });
  });
}

const funcs = {
  *bookmarks() {
    const bookmarks = config.get('bookmarks');
    this.body = JSON.stringify(bookmarks.map(b => b.name));
  },

  *dir(param) {
    const dir = getFilePath(param);
    if (!dir) {
      this.body = 'invalid location';
      return;
    }

    let files = yield fs.readdirAsync(dir);
    files = files.map(file => {
      const stats = fs.lstatSync(path.resolve(dir, file));
      return {
        name: file,
        isDirectory: stats.isDirectory(),
        size: stats.size,
        mtime: stats.mtime.getTime(),
      };
    });
    this.body = files;
  },

  *imageInfo(param) {
    const filepath = getFilePath(param);
    if (!filepath) {
      this.body = 'invalid location';
      return;
    }

    this.body = yield getImageInfo(filepath);
  },

  *download(param) {
    const filepath = getFilePath(param);
    if (!filepath) {
      this.body = 'invalid location';
      return;
    }

    yield sendfile(this, filepath);
    if (!this.status) {
      this.throw(404);
    }
  },

  *image(param) {
    const filepath = getFilePath(param);
    if (!filepath) {
      this.body = 'invalid location';
      return;
    }

    if (!config.cacheDir) {
      yield sendfile(this, filepath);
      return;
    }

    const type = this.query.type;
    if (type !== 'sq100' && type !== 'max800') {
      this.body = 'invalid type';
      return;
    }

    const cacheFilepath = util.getImageCacheFilepath(filepath, type);
    yield util.createImageCache(type, filepath, cacheFilepath);

    yield sendfile(this, cacheFilepath);
    if (!this.status) {
      this.throw(404);
    }
  },

  *upload(param) {
    const dir = getFilePath(param);
    if (!dir) {
      this.body = 'invalid location';
      return;
    }

    const parts = parse(this);
    let part = yield parts;
    while (part) {
      const filename = path.resolve(dir, part.filename);
      const readStream = part;
      const writeStream = fs.createWriteStream(filename);
      yield new Promise((resolve, reject) => {
        readStream.on('error', reject);
        writeStream.on('error', reject);
        writeStream.on('finish', resolve);
        readStream.pipe(writeStream);
      });

      part = yield parts;
    }

    this.status = 200;
  },

  *createFolder(param) {
    const dir = getFilePath(param);
    if (!dir) {
      this.body = 'invalid location';
      return;
    }

    const folderName = this.request.body.name;

    const folderFilepath = path.resolve(dir, folderName);
    yield fs.mkdirAsync(folderFilepath);

    this.body = '{}';
  },

  *delete(param) {
    const dir = getFilePath(param);
    if (!dir) {
      this.body = 'invalid location';
      return;
    }

    const files = this.request.body;

    if (!config.trashDir) {
      for (const file of files) {
        yield fs.unlinkAsync(path.resolve(dir, file));
      }
      this.body = '{}';
      return;
    }

    for (const file of files) {
      const sourceFilepath = path.resolve(dir, file);
      const trashFilename = `${Date.now()}_${file}`;
      const trashFilepath = path.resolve(config.trashDir, trashFilename);
      yield fs.moveAsync(sourceFilepath, trashFilepath);
    }
    this.body = '{}';
  },
};

function init(app) {
  app.use(function* apiHandler(next) {
    const reqPath = decodeURIComponent(this.path);
    const result = /^\/api\/(\w+)\/?(.*)/.exec(reqPath);
    if (!result) {
      yield next;
      return;
    }

    const apiName = result[1];
    const param = result[2];
    if (!funcs[apiName]) {
      logger.warn(`Invalid api: ${apiName}`);
      return;
    }

    try {
      yield* funcs[apiName].call(this, param);
    } catch (err) {
      logger.warn(`Failed to handle api: ${apiName}`, err, err.stack);
      this.status = 500;
    }
  });
}

module.exports = init;
<commit_msg>Add azure storage support<commit_after>const parse = require('co-busboy');
const sendfile = require('koa-sendfile');
const path = require('path');
const Promise = require('bluebird');
const fs = Promise.promisifyAll(require('fs-extra'));
const azure = require('azure-storage');
const config = require('config');
const gm = require('gm');
const logger = require('./logger');
const util = require('./util');

Promise.promisifyAll(Object.getPrototypeOf(gm()));
const blobService = azure.createBlobService();
let containers = [];

function getFilePath(param) {
  logger.info("param: " + param);

  const result = /(\d+)(.*)/.exec(param);
  logger.info(result);
  if (!result) {
    return null;
  }

  const containerIndex = parseInt(result[1], 10);
  const container = containers[containerIndex];
  logger.info("container: " + container.name);
  if (!container) {
    return null;
  }

  let subdir = result[2];
  if (subdir.length > 0) {
    if (subdir[0] !== '/') {
      return null;
    }

    subdir = subdir.substr(1);
  }
  return container.name;
}

function getImageInfo(filepath) {
  const info = {};
  return new Promise((resolve, reject) => {
    const img = gm(filepath);
    img.size((err, value) => {
      if (err) {
        reject(err);
        return;
      }

      info.size = value;
      img.orientation((err2, value2) => {
        if (err2) {
          reject(err2);
          return;
        }

        info.orientation = value2;
        resolve(info);
      });
    });
  });
}
let blobs = [];

function aggregateContainers(err, result, cb) {
  if (err) {
      cb(err);
  } else {
      containers = containers.concat(result.entries);
      if (result.continuationToken !== null) {
          blobService
              .listContainersSegmented(result.continuationToken, aggregateContainers);
      } else {
          cb(null, containers);
      }
  }
}

function getContainersAsync() {
  logger.info('getContainers');
  containers = [];
  return new Promise(function(resolve, reject) {
    blobService.listContainersSegmented(null, function(err, result) {
      aggregateContainers(err, result, function(err, containers) {
        if (err) {
          logger.warn(err);
          reject(err);
        } else {
          resolve(containers);
        }
      });
    });
  });
}

function aggregateBlobs(containerName, err, result, cb) {
  if (err) {
      cb(err);
  } else {
      blobs = blobs.concat(result.entries);
      if (result.continuationToken !== null) {
          blobService
              .listBlobsSegmented(containerName, result.continuationToken, aggregateBlobs);
      } else {
        logger.info(containerName + ": " + blobs.length);
        cb(null, blobs);
      }
  }
}

function getBlobsAsync(containerName) {
  logger.info('getBlobs');
  blobs = [];
  return new Promise(function(resolve, reject) {
    blobService.listBlobsSegmented(containerName, null, function(err, result) {
      aggregateBlobs(containerName, err, result, function(err, blobs) {
        if (err) {
          logger.warn(err);
          reject(err);
        } else {
          logger.info(containerName + " resolve: " + blobs.length);
          resolve(blobs);
        }
      });
    });
  });
}

const funcs = {
  *bookmarks() {
    const bookmarks = config.get('bookmarks');
    this.body = JSON.stringify(bookmarks.map(b => b.name));
  },

  *containers() {
    containers = yield getContainersAsync();
    this.body = JSON.stringify(containers.map(c => c.name));;
  },

  *dir(param) {
    const dir = getFilePath(param);
    if (!dir) {
      this.body = 'invalid directory';
      return;
    }
    let files =[];
    logger.info("dir: " + dir);
    let containerFiles = yield getBlobsAsync(dir);
    files = files.concat(containerFiles);

    files = files.map(file => {
      //const stats = fs.lstatSync(path.resolve(dir, file));
      return {
        name: file.name,
        isDirectory: file.blobType === "BlockBlob",
        size: file.contentLength,
        mtime: file.lastModified,
      };
    });
    this.body = files;
  },

  *imageInfo(param) {
    const filepath = getFilePath(param);
    if (!filepath) {
      this.body = 'invalid location';
      return;
    }

    this.body = yield getImageInfo(filepath);
  },

  *download(param) {
    const filepath = getFilePath(param);
    if (!filepath) {
      this.body = 'invalid location';
      return;
    }

    yield sendfile(this, filepath);
    if (!this.status) {
      this.throw(404);
    }
  },

  *image(param) {
    const filepath = getFilePath(param);
    if (!filepath) {
      this.body = 'invalid location';
      return;
    }

    if (!config.cacheDir) {
      yield sendfile(this, filepath);
      return;
    }

    const type = this.query.type;
    if (type !== 'sq100' && type !== 'max800') {
      this.body = 'invalid type';
      return;
    }

    const cacheFilepath = util.getImageCacheFilepath(filepath, type);
    yield util.createImageCache(type, filepath, cacheFilepath);

    yield sendfile(this, cacheFilepath);
    if (!this.status) {
      this.throw(404);
    }
  },

  *upload(param) {
    const dir = getFilePath(param);
    if (!dir) {
      this.body = 'invalid location';
      return;
    }

    const parts = parse(this);
    let part = yield parts;
    while (part) {
      const filename = path.resolve(dir, part.filename);
      const readStream = part;
      const writeStream = fs.createWriteStream(filename);
      yield new Promise((resolve, reject) => {
        readStream.on('error', reject);
        writeStream.on('error', reject);
        writeStream.on('finish', resolve);
        readStream.pipe(writeStream);
      });

      part = yield parts;
    }

    this.status = 200;
  },

  *createFolder(param) {
    const dir = getFilePath(param);
    if (!dir) {
      this.body = 'invalid location';
      return;
    }

    const folderName = this.request.body.name;

    const folderFilepath = path.resolve(dir, folderName);
    yield fs.mkdirAsync(folderFilepath);

    this.body = '{}';
  },

  *delete(param) {
    const dir = getFilePath(param);
    if (!dir) {
      this.body = 'invalid location';
      return;
    }

    const files = this.request.body;

    if (!config.trashDir) {
      for (const file of files) {
        yield fs.unlinkAsync(path.resolve(dir, file));
      }
      this.body = '{}';
      return;
    }

    for (const file of files) {
      const sourceFilepath = path.resolve(dir, file);
      const trashFilename = `${Date.now()}_${file}`;
      const trashFilepath = path.resolve(config.trashDir, trashFilename);
      yield fs.moveAsync(sourceFilepath, trashFilepath);
    }
    this.body = '{}';
  },
};

function init(app) {
  app.use(function* apiHandler(next) {
    const reqPath = decodeURIComponent(this.path);
    const result = /^\/api\/(\w+)\/?(.*)/.exec(reqPath);
    if (!result) {
      yield next;
      return;
    }

    const apiName = result[1];
    const param = result[2];
    if (!funcs[apiName]) {
      logger.warn(`Invalid api: ${apiName}`);
      return;
    }

    try {
      yield* funcs[apiName].call(this, param);
    } catch (err) {
      logger.warn(`Failed to handle api: ${apiName}`, err, err.stack);
      this.status = 500;
    }
  });
}

module.exports = init;
<|endoftext|>


<commit_before>// Dependencies
var net = require('net')
var config = require('../../config')

function DoorRemoteControl () {
  var self = this

  this.keymaster = null
  this.server = net.createServer(function (c) {
    c.on('data', function (data) {
      // Check if this client is
      // really the keymaster
      if (config.secureKey === data.toString().replace(/\r?\n/, '')) {
        self.keymaster = c
      }
    })
  })
}

DoorRemoteControl.open = function (cb) {
  if (!this.keymaster) {
    return cb(new Error('Keymaster wasn\'t found'))
  }

  this.keymaster.write('open\r\n')
  return cb()
}

DoorRemoteControl.status = function (cb) {
  this.keymaster.write('status\r\n')

  var ttl = setTimeout(function () {
    cb(new Error('off'))

    // Just to be sure
    cb = function () {}
  })

  this.keymaster.once('data', function (data) {
    if (data.toString().replace(/\r?\n/, '') === 'ok') {
      // Clear timeout
      clearTimeout(ttl)

      return cb()
    }
  })
}

module.exports = DoorRemoteControl
<commit_msg>fix door remote control<commit_after>// Dependencies
var net = require('net')
var config = require('../config')

function DoorRemoteControl () {
  var self = this

  this.keymaster = null
  this.server = net.createServer(function (c) {
    c.on('data', function (data) {
      // Check if this client is
      // really the keymaster
      if (config.secureKey === data.toString().replace(/\r?\n/, '')) {
        self.keymaster = c
      }
    })
  })
}

DoorRemoteControl.prototype.open = function (cb) {
  if (!this.keymaster) {
    return cb(new Error('Keymaster wasn\'t found'))
  }

  this.keymaster.write('open\r\n')
  return cb()
}

DoorRemoteControl.prototype.status = function (cb) {
  this.keymaster.write('status\r\n')

  var ttl = setTimeout(function () {
    cb(new Error('off'))

    // Just to be sure
    cb = function () {}
  })

  this.keymaster.once('data', function (data) {
    if (data.toString().replace(/\r?\n/, '') === 'ok') {
      // Clear timeout
      clearTimeout(ttl)

      return cb()
    }
  })
}

module.exports = DoorRemoteControl
<|endoftext|>


<commit_before>const gulp          = require('gulp'),
    eventStream     = require('event-stream'),
    gulpLoadPlugins = require('gulp-load-plugins'),
    map             = require('vinyl-map'),
    fs              = require('fs'),
    path            = require('path'),
    sequence        = require('run-sequence'),
    size            = require('gulp-size'),
    uri             = require('urijs'),
    s               = require('underscore.string'),
    argv            = require('yargs').argv,
    logger          = require('js-logger'),
    hawtio          = require('@hawtio/node-backend'),
    tslint          = require('gulp-tslint'),
    tslintRules     = require('./tslint.json');

const plugins = gulpLoadPlugins({});

const config = {
  proxyPort      : argv.port || 8181,
  targetPath     : argv.path || '/hawtio/jolokia',
  logLevel       : argv.debug ? logger.DEBUG : logger.INFO,
  main           : '.',
  ts             : ['plugins/**/*.ts'],
  less           : './less/**/*.less',
  templates      : ['plugins/**/*.html'],
  templateModule : 'hawtio-console-assembly-templates',
  dist           : './dist/',
  js             : 'hawtio-console-assembly.js',
  css            : 'hawtio-console-assembly.css',
  dts            : 'hawtio-console-assembly.d.ts',
  tsProject      : plugins.typescript.createProject('tsconfig.json'),
  tsLintOptions  : {
    rulesDirectory: './tslint-rules/'
  },
  sourceMap: argv.sourcemap
};

var normalSizeOptions = {
    showFiles: true
}, gZippedSizeOptions  = {
    showFiles: true,
    gzip: true
};

//------------------------------------------------------------------------------
// build tasks
//------------------------------------------------------------------------------

gulp.task('clean-defs', function() {
  return gulp.src(config.dist + '*.d.ts', { read: false })
    .pipe(plugins.clean());
});

gulp.task('tsc', ['clean-defs'], function() {
  var tsResult = gulp.src(config.ts)
    .pipe(plugins.debug({ title: 'tsc' }))
    .pipe(plugins.if(config.sourceMap, plugins.sourcemaps.init()))
    .pipe(config.tsProject())
    .on('error', plugins.notify.onError({
      message: '<%= error.message %>',
      title: 'Typescript compilation error'
    }));

  return eventStream.merge(
    tsResult.js
      .pipe(plugins.debug({ title: 'tsc js' }))
      .pipe(plugins.if(config.sourceMap, plugins.sourcemaps.write()))
      .pipe(gulp.dest('.')),
    tsResult.dts
      .pipe(plugins.debug({ title: 'tsc dts' }))
      .pipe(plugins.rename(config.dts))
      .pipe(gulp.dest(config.dist)));
});

/*
gulp.task('tslint', function(){
  gulp.src(config.ts)
    .pipe(tslint(config.tsLintOptions))
    .pipe(tslint.report('verbose'));
});

gulp.task('tslint-watch', function(){
  gulp.src(config.ts)
    .pipe(tslint(config.tsLintOptions))
    .pipe(tslint.report('prose', {
      emitError: false
    }));
});
*/

gulp.task('less', function() {
  return gulp.src(config.less)
    .pipe(plugins.less({
      paths: [ path.join(__dirname, 'less', 'includes') ]
    }))
    .pipe(plugins.concat(config.css))
    .pipe(gulp.dest('./dist'));
});

gulp.task('template', ['tsc'], function() {
  return gulp.src(config.templates)
    .pipe(plugins.angularTemplatecache({
      filename: 'templates.js',
      root: 'plugins/',
      standalone: true,
      module: config.templateModule,
      templateFooter: '}]); hawtioPluginLoader.addModule("' + config.templateModule + '");'
    }))
    .pipe(gulp.dest('.'));
});

gulp.task('concat', ['template'], function() {
  var gZipSize = size(gZippedSizeOptions);
  var license = tslintRules.rules['license-header'][1];
  return gulp.src(['compiled.js', 'templates.js'])
    .pipe(plugins.concat(config.js))
    .pipe(plugins.header(license))
    .pipe(size(normalSizeOptions))
    .pipe(gZipSize)
    .pipe(gulp.dest(config.dist));
});

gulp.task('clean', function() {
  return gulp.src(['templates.js', 'compiled.js', 'includes.js', 'target/site/'], { read: false })
    .pipe(plugins.clean());
});

gulp.task('watch', ['build'], function() {
  gulp.watch([
    'node_modules/@hawtio/**/dist/*.js',
    'node_modules/@hawtio/**/dist/*.css',
    'index.html',
    config.dist + '/' + config.js
  ], ['reload']);
  gulp.watch([
    'node_modules/@hawtio/**/dist/*.d.ts',
    config.ts,
    config.templates
  ], ['tsc', 'template', 'concat', 'clean']);
  gulp.watch(config.less, ['less', 'reload']);
});

gulp.task('connect', ['watch'], function() {
  hawtio.setConfig({
    logLevel: config.logLevel,
    port: 2772,
    staticProxies: [
    {
      proto: 'http',
      port: config.proxyPort,
      hostname: 'localhost',
      path: '/hawtio/jolokia',
      targetPath: config.targetPath
    }
    ],
    staticAssets: [{
      path: '/hawtio',
      dir: '.'

    }],
    fallback: 'index.html',
    liveReload: {
      enabled: true
    }
  });
  hawtio.use('/', (req, res, next) => {
    if (!s.startsWith(req.originalUrl, '/hawtio/')) {
      res.redirect('/hawtio/');
    } else {
      next();
    }
  });

  hawtio.use('/hawtio/img', (req, res) => {
    // We may want to serve from other dependencies
    const file = path.join(__dirname, 'node_modules', 'hawtio-integration', 'img', req.url);
    if (fs.existsSync(file)) {
      res.writeHead(200, {
        'Content-Type'       : 'application/octet-stream',
        'Content-Disposition': 'attachment; filename=' + file
      });
      fs.createReadStream(file).pipe(res);
    } else {
      res.writeHead(400, {'Content-Type': 'text/plain'});
      res.end(`File ${file} does not exist in dependencies`);
    }
  });

  hawtio.listen(function(server) {
    var host = server.address().address;
    var port = server.address().port;
    console.log("started from gulp file at ", host, ":", port);
  });
});

gulp.task('reload', function() {
  gulp.src('.')
    .pipe(hawtio.reload());
});

//------------------------------------------------------------------------------
// site tasks
//------------------------------------------------------------------------------

gulp.task('site-fonts', () =>
  gulp
    .src(
      [
        'node_modules/**/*.woff',
        'node_modules/**/*.woff2',
        'node_modules/**/*.ttf',
        'node_modules/**/fonts/*.eot',
        'node_modules/**/fonts/*.svg'
      ],
      { base: '.' }
    )
    .pipe(plugins.flatten())
    .pipe(plugins.chmod(0o644))
    .pipe(plugins.dedupe({ same: false }))
    .pipe(plugins.debug({ title: 'site font files' }))
    .pipe(gulp.dest('target/site/fonts/', { overwrite: false }))
);

gulp.task('site-files', function() {
  // in case there are hawtio-console-assembly specific images
  return gulp.src(['images/**', 'img/**'], { base: '.' })
    .pipe(plugins.debug({ title: 'site files' }))
    .pipe(gulp.dest('target/site'));
});

gulp.task('usemin', function() {
  return gulp.src('index.html')
    .pipe(plugins.usemin({
      css: [plugins.minifyCss({ keepBreaks: true }), 'concat'],
      js: [
        plugins.sourcemaps.init({
          loadMaps: true
        }),
        'concat',
        plugins.uglify(),
        plugins.rev(),
        plugins.sourcemaps.write('./')
      ]
    }))
    .pipe(plugins.debug({ title: 'usemin' }))
    .pipe(gulp.dest('target/site'));
});

gulp.task('tweak-urls', ['usemin'], () =>
  eventStream.merge(
    gulp.src('target/site/index.html')
      // adjust image paths
      .pipe(plugins.replace(/"node_modules\/[^/]+\/img\//gm, '"img/')),
    gulp.src('target/site/style.css')
      .pipe(plugins.replace(/url\(\.\.\//g, 'url('))
      // tweak fonts URL coming from PatternFly that does not repackage then in dist
      .pipe(plugins.replace(/url\(\.\.\/components\/font-awesome\//g, 'url('))
      .pipe(plugins.replace(/url\(\.\.\/components\/bootstrap\/dist\//g, 'url('))
      .pipe(plugins.replace(/url\(node_modules\/bootstrap\/dist\//g, 'url('))
      .pipe(plugins.replace(/url\(node_modules\/patternfly\/components\/bootstrap\/dist\//g, 'url('))
      .pipe(plugins.debug({ title: 'tweak-urls' }))
    )
    .pipe(gulp.dest('target/site')
  )
);

gulp.task('404', ['usemin'], function() {
  return gulp.src('target/site/index.html')
    .pipe(plugins.rename('404.html'))
    .pipe(gulp.dest('target/site'));
});

gulp.task('copy-images', function() {
  var dirs = fs.readdirSync('./node_modules');
  var patterns = [];
  dirs.forEach(function(dir) {
    var path = './node_modules/' + dir + '/img';
    try {
      if (fs.statSync(path).isDirectory()) {
        console.log('found image dir: ', path);
        var pattern = 'node_modules/' + dir + '/img/**';
        patterns.push(pattern);
      }
    } catch (e) {
      // ignore, file does not exist
    }
  });
  // Add PatternFly images package in dist
  patterns.push('node_modules/patternfly/dist/img/**');
  return gulp.src(patterns)
    .pipe(plugins.debug({ title: 'image copy' }))
    .pipe(gulp.dest('target/site/img'));
});

gulp.task('serve-site', function() {
  hawtio.setConfig({
    port: 2772,
    staticProxies: [
      {
        proto      : 'http',
        hostname   : 'localhost',
        port       : config.proxyPort,
        path       : '/hawtio/jolokia',
        targetPath : config.targetPath
      }
    ],
    staticAssets: [
      {
        path : '/hawtio',
        dir  : 'target/site'
      }
    ],
    liveReload : {
      enabled  : false
    }
  });
  return hawtio.listen(server => console.log('started from gulp file at ',
    server.address().address, ':', server.address().port));
});

gulp.task('build', callback => sequence(['tsc', 'less', 'template', 'concat'], 'clean', callback));

gulp.task('site', callback => sequence('clean', ['site-fonts', 'site-files', 'usemin', 'tweak-urls', '404', 'copy-images'], callback));

gulp.task('mvn', callback => sequence('build', 'site'));

gulp.task('default', callback => sequence('connect', callback));
<commit_msg>fix path to images from @hawtio/integration<commit_after>const gulp          = require('gulp'),
    eventStream     = require('event-stream'),
    gulpLoadPlugins = require('gulp-load-plugins'),
    map             = require('vinyl-map'),
    fs              = require('fs'),
    path            = require('path'),
    sequence        = require('run-sequence'),
    size            = require('gulp-size'),
    uri             = require('urijs'),
    s               = require('underscore.string'),
    argv            = require('yargs').argv,
    logger          = require('js-logger'),
    hawtio          = require('@hawtio/node-backend'),
    tslint          = require('gulp-tslint'),
    tslintRules     = require('./tslint.json');

const plugins = gulpLoadPlugins({});

const config = {
  proxyPort      : argv.port || 8181,
  targetPath     : argv.path || '/hawtio/jolokia',
  logLevel       : argv.debug ? logger.DEBUG : logger.INFO,
  main           : '.',
  ts             : ['plugins/**/*.ts'],
  less           : './less/**/*.less',
  templates      : ['plugins/**/*.html'],
  templateModule : 'hawtio-console-assembly-templates',
  dist           : './dist/',
  js             : 'hawtio-console-assembly.js',
  css            : 'hawtio-console-assembly.css',
  dts            : 'hawtio-console-assembly.d.ts',
  tsProject      : plugins.typescript.createProject('tsconfig.json'),
  tsLintOptions  : {
    rulesDirectory: './tslint-rules/'
  },
  sourceMap: argv.sourcemap
};

var normalSizeOptions = {
    showFiles: true
}, gZippedSizeOptions  = {
    showFiles: true,
    gzip: true
};

//------------------------------------------------------------------------------
// build tasks
//------------------------------------------------------------------------------

gulp.task('clean-defs', function() {
  return gulp.src(config.dist + '*.d.ts', { read: false })
    .pipe(plugins.clean());
});

gulp.task('tsc', ['clean-defs'], function() {
  var tsResult = gulp.src(config.ts)
    .pipe(plugins.debug({ title: 'tsc' }))
    .pipe(plugins.if(config.sourceMap, plugins.sourcemaps.init()))
    .pipe(config.tsProject())
    .on('error', plugins.notify.onError({
      message: '<%= error.message %>',
      title: 'Typescript compilation error'
    }));

  return eventStream.merge(
    tsResult.js
      .pipe(plugins.debug({ title: 'tsc js' }))
      .pipe(plugins.if(config.sourceMap, plugins.sourcemaps.write()))
      .pipe(gulp.dest('.')),
    tsResult.dts
      .pipe(plugins.debug({ title: 'tsc dts' }))
      .pipe(plugins.rename(config.dts))
      .pipe(gulp.dest(config.dist)));
});

/*
gulp.task('tslint', function(){
  gulp.src(config.ts)
    .pipe(tslint(config.tsLintOptions))
    .pipe(tslint.report('verbose'));
});

gulp.task('tslint-watch', function(){
  gulp.src(config.ts)
    .pipe(tslint(config.tsLintOptions))
    .pipe(tslint.report('prose', {
      emitError: false
    }));
});
*/

gulp.task('less', function() {
  return gulp.src(config.less)
    .pipe(plugins.less({
      paths: [ path.join(__dirname, 'less', 'includes') ]
    }))
    .pipe(plugins.concat(config.css))
    .pipe(gulp.dest('./dist'));
});

gulp.task('template', ['tsc'], function() {
  return gulp.src(config.templates)
    .pipe(plugins.angularTemplatecache({
      filename: 'templates.js',
      root: 'plugins/',
      standalone: true,
      module: config.templateModule,
      templateFooter: '}]); hawtioPluginLoader.addModule("' + config.templateModule + '");'
    }))
    .pipe(gulp.dest('.'));
});

gulp.task('concat', ['template'], function() {
  var gZipSize = size(gZippedSizeOptions);
  var license = tslintRules.rules['license-header'][1];
  return gulp.src(['compiled.js', 'templates.js'])
    .pipe(plugins.concat(config.js))
    .pipe(plugins.header(license))
    .pipe(size(normalSizeOptions))
    .pipe(gZipSize)
    .pipe(gulp.dest(config.dist));
});

gulp.task('clean', function() {
  return gulp.src(['templates.js', 'compiled.js', 'includes.js', 'target/site/'], { read: false })
    .pipe(plugins.clean());
});

gulp.task('watch', ['build'], function() {
  gulp.watch([
    'node_modules/@hawtio/**/dist/*.js',
    'node_modules/@hawtio/**/dist/*.css',
    'index.html',
    config.dist + '/' + config.js
  ], ['reload']);
  gulp.watch([
    'node_modules/@hawtio/**/dist/*.d.ts',
    config.ts,
    config.templates
  ], ['tsc', 'template', 'concat', 'clean']);
  gulp.watch(config.less, ['less', 'reload']);
});

gulp.task('connect', ['watch'], function() {
  hawtio.setConfig({
    logLevel: config.logLevel,
    port: 2772,
    staticProxies: [
    {
      proto: 'http',
      port: config.proxyPort,
      hostname: 'localhost',
      path: '/hawtio/jolokia',
      targetPath: config.targetPath
    }
    ],
    staticAssets: [{
      path: '/hawtio',
      dir: '.'

    }],
    fallback: 'index.html',
    liveReload: {
      enabled: true
    }
  });
  hawtio.use('/', (req, res, next) => {
    if (!s.startsWith(req.originalUrl, '/hawtio/')) {
      res.redirect('/hawtio/');
    } else {
      next();
    }
  });

  hawtio.use('/hawtio/img', (req, res) => {
    // We may want to serve from other dependencies
    const file = path.join(__dirname, 'node_modules', '@hawtio/integration', 'img', req.url);
    if (fs.existsSync(file)) {
      res.writeHead(200, {
        'Content-Type'       : 'application/octet-stream',
        'Content-Disposition': 'attachment; filename=' + file
      });
      fs.createReadStream(file).pipe(res);
    } else {
      res.writeHead(400, {'Content-Type': 'text/plain'});
      res.end(`File ${file} does not exist in dependencies`);
    }
  });

  hawtio.listen(function(server) {
    var host = server.address().address;
    var port = server.address().port;
    console.log("started from gulp file at ", host, ":", port);
  });
});

gulp.task('reload', function() {
  gulp.src('.')
    .pipe(hawtio.reload());
});

//------------------------------------------------------------------------------
// site tasks
//------------------------------------------------------------------------------

gulp.task('site-fonts', () =>
  gulp
    .src(
      [
        'node_modules/**/*.woff',
        'node_modules/**/*.woff2',
        'node_modules/**/*.ttf',
        'node_modules/**/fonts/*.eot',
        'node_modules/**/fonts/*.svg'
      ],
      { base: '.' }
    )
    .pipe(plugins.flatten())
    .pipe(plugins.chmod(0o644))
    .pipe(plugins.dedupe({ same: false }))
    .pipe(plugins.debug({ title: 'site font files' }))
    .pipe(gulp.dest('target/site/fonts/', { overwrite: false }))
);

gulp.task('site-files', function() {
  // in case there are hawtio-console-assembly specific images
  return gulp.src(['images/**', 'img/**'], { base: '.' })
    .pipe(plugins.debug({ title: 'site files' }))
    .pipe(gulp.dest('target/site'));
});

gulp.task('usemin', function() {
  return gulp.src('index.html')
    .pipe(plugins.usemin({
      css: [plugins.minifyCss({ keepBreaks: true }), 'concat'],
      js: [
        plugins.sourcemaps.init({
          loadMaps: true
        }),
        'concat',
        plugins.uglify(),
        plugins.rev(),
        plugins.sourcemaps.write('./')
      ]
    }))
    .pipe(plugins.debug({ title: 'usemin' }))
    .pipe(gulp.dest('target/site'));
});

gulp.task('tweak-urls', ['usemin'], () =>
  eventStream.merge(
    gulp.src('target/site/index.html')
      // adjust image paths
      .pipe(plugins.replace(/"node_modules\/[^/]+\/img\//gm, '"img/')),
    gulp.src('target/site/style.css')
      .pipe(plugins.replace(/url\(\.\.\//g, 'url('))
      // tweak fonts URL coming from PatternFly that does not repackage then in dist
      .pipe(plugins.replace(/url\(\.\.\/components\/font-awesome\//g, 'url('))
      .pipe(plugins.replace(/url\(\.\.\/components\/bootstrap\/dist\//g, 'url('))
      .pipe(plugins.replace(/url\(node_modules\/bootstrap\/dist\//g, 'url('))
      .pipe(plugins.replace(/url\(node_modules\/patternfly\/components\/bootstrap\/dist\//g, 'url('))
      .pipe(plugins.debug({ title: 'tweak-urls' }))
    )
    .pipe(gulp.dest('target/site')
  )
);

gulp.task('404', ['usemin'], function() {
  return gulp.src('target/site/index.html')
    .pipe(plugins.rename('404.html'))
    .pipe(gulp.dest('target/site'));
});

gulp.task('copy-images', function() {
  var dirs = fs.readdirSync('./node_modules');
  var patterns = [];
  dirs.forEach(function(dir) {
    var path = './node_modules/' + dir + '/img';
    try {
      if (fs.statSync(path).isDirectory()) {
        console.log('found image dir: ', path);
        var pattern = 'node_modules/' + dir + '/img/**';
        patterns.push(pattern);
      }
    } catch (e) {
      // ignore, file does not exist
    }
  });
  // Add PatternFly images package in dist
  patterns.push('node_modules/patternfly/dist/img/**');
  return gulp.src(patterns)
    .pipe(plugins.debug({ title: 'image copy' }))
    .pipe(gulp.dest('target/site/img'));
});

gulp.task('serve-site', function() {
  hawtio.setConfig({
    port: 2772,
    staticProxies: [
      {
        proto      : 'http',
        hostname   : 'localhost',
        port       : config.proxyPort,
        path       : '/hawtio/jolokia',
        targetPath : config.targetPath
      }
    ],
    staticAssets: [
      {
        path : '/hawtio',
        dir  : 'target/site'
      }
    ],
    liveReload : {
      enabled  : false
    }
  });
  return hawtio.listen(server => console.log('started from gulp file at ',
    server.address().address, ':', server.address().port));
});

gulp.task('build', callback => sequence(['tsc', 'less', 'template', 'concat'], 'clean', callback));

gulp.task('site', callback => sequence('clean', ['site-fonts', 'site-files', 'usemin', 'tweak-urls', '404', 'copy-images'], callback));

gulp.task('mvn', callback => sequence('build', 'site'));

gulp.task('default', callback => sequence('connect', callback));
<|endoftext|>


<commit_before>const createMessage = require('../formater/createMessage')
const http = require("http")

const SEC = 1000
const MIN = 60 * SEC
const HOUR = 60 * MIN
const DAY = 24 * HOUR

const pingOBuy = () => {
  return new Promise(resolve => {
    http.get(`http://obuy.shinychang.net/`, res => {
      resolve('obuy is alive')
    })
  })
}

const tasks = [
  {interval: 5 * MIN, job: pingOBuy}
]

const heartbeat = (bot) => {
  const sendMessageToOwner = (content) => {
    const owner = {
      type: 'Person',
      id: process.env.SLACK_USER_ID
    }
    const reply = {
      "type": "Note",
      content
    }
    content && bot.send(createMessage(owner, reply))
  }
  setInterval(() => {
    tasks.forEach(task => {
      const lastRun = new Date(task.lastRun || null).getTime()
      if (Date.now() - lastRun > task.interval) {
        task.job().then(content => {
          sendMessageToOwner(content)
        }).catch(err => console.log(err))
        task.lastRun = Date.now()
      }
    })
  }, SEC)
}
module.exports = heartbeat
<commit_msg>Shut up<commit_after>const createMessage = require('../formater/createMessage')
const http = require("http")

const SEC = 1000
const MIN = 60 * SEC
const HOUR = 60 * MIN
const DAY = 24 * HOUR

const pingOBuy = () => {
  return new Promise(resolve => {
    http.get(`http://obuy.shinychang.net/`, res => {
      resolve()
    })
  })
}

const tasks = [
  {interval: 5 * MIN, job: pingOBuy}
]

const heartbeat = (bot) => {
  const sendMessageToOwner = (content) => {
    const owner = {
      type: 'Person',
      id: process.env.SLACK_USER_ID
    }
    const reply = {
      "type": "Note",
      content
    }
    content && bot.send(createMessage(owner, reply))
  }
  setInterval(() => {
    tasks.forEach(task => {
      const lastRun = new Date(task.lastRun || null).getTime()
      if (Date.now() - lastRun > task.interval) {
        task.job().then(content => {
          sendMessageToOwner(content)
        }).catch(err => console.log(err))
        task.lastRun = Date.now()
      }
    })
  }, SEC)
}
module.exports = heartbeat
<|endoftext|>


<commit_before> dojo.require("esri.widgets");
 dojo.require("esri.arcgis.utils");

 var map;
 var timeSlider;
 var timeProperties = null;
 var configOptions;

 function initMap(options) {
     configOptions = options;

     //read the legend header text from the localized strings file
     dojo.byId('legendHeader').innerHTML = configOptions.i18n.tools.legend.label;

     if (configOptions.bingMapsKey) {
         configOptions.bingmapskey = configOptions.bingMapsKey;
     }

     var itemInfo = configOptions.itemInfo || configOptions.webmap;
     var mapDeferred = esri.arcgis.utils.createMap(configOptions.itemInfo, "map", {
         mapOptions: {
             slider: true,
             sliderStyle: 'small',
             nav: false,
             showAttribution: true,
             wrapAround180: true
         },
         editable: false,
         ignorePopups: false,
         bingMapsKey: configOptions.bingmapskey
     });

     mapDeferred.addCallback(function(response) {
         document.title = configOptions.title || response.itemInfo.item.title;
         dojo.byId("title").innerHTML = configOptions.title || response.itemInfo.item.title;
         dojo.byId("subtitle").innerHTML = configOptions.subtitle || response.itemInfo.item.snippet || "";

         map = response.map;

         //get any time properties that are set on the map
         if (response.itemInfo.itemData.widgets && response.itemInfo.itemData.widgets.timeSlider) {
             timeProperties = response.itemInfo.itemData.widgets.timeSlider.properties;
         }
         if (map.loaded) {
             initUI(response);
         } else {
             dojo.connect(map, "onLoad", function() {
                 initUI(response);
             });
         }
         //resize the map when the browser resizes
         dojo.connect(dijit.byId('map'), 'resize', map, map.resize);
     });

     mapDeferred.addErrback(function(error) {
         alert(configOptions.i18n.viewer.errors.createMap + " : " + error.message);
     });

 }

 function initUI(response) {
     //add chrome theme for popup
     dojo.addClass(map.infoWindow.domNode, "chrome");
     //add the scalebar
     var scalebar = new esri.dijit.Scalebar({
         map: map,
         scalebarUnit: configOptions.i18n.viewer.main.scaleBarUnits //metric or english
     });

     //create the legend - exclude basemaps and any note layers
     var layerInfo = esri.arcgis.utils.getLegendLayers(response);
     if (layerInfo.length > 0) {
         var legendDijit = new esri.dijit.Legend({
             map: map,
             layerInfos: layerInfo
         }, "legendDiv");
         legendDijit.startup();
     } else {
         dojo.byId('legendDiv').innerHTML = configOptions.i18n.tools.legend.layerMessage;
     }

     //check to see if the web map has any time properties

     if (timeProperties) {

         var startTime = timeProperties.startTime;
         var endTime = timeProperties.endTime;
         var fullTimeExtent = new esri.TimeExtent(new Date(startTime), new Date(endTime));

         map.setTimeExtent(fullTimeExtent);
         //create the slider
         timeSlider = new esri.dijit.TimeSlider({
             style: "width: 100%;",
             loop: true
         }, dojo.byId("timeSliderDiv"));

         map.setTimeSlider(timeSlider);
         //Set time slider properties
         timeSlider.setThumbCount(timeProperties.thumbCount);
         timeSlider.setThumbMovingRate(timeProperties.thumbMovingRate);
         //define the number of stops
         if (timeProperties.numberOfStops) {
             timeSlider.createTimeStopsByCount(fullTimeExtent, timeProperties.numberOfStops);
         } else {
             timeSlider.createTimeStopsByTimeInterval(fullTimeExtent, timeProperties.timeStopInterval.interval, timeProperties.timeStopInterval.units);
         }
         //set the thumb index values if the count = 2
         if (timeSlider.thumbCount == 2) {
             timeSlider.setThumbIndexes([0, 1]);
         }

         dojo.connect(timeSlider, 'onTimeExtentChange', updateTimeSliderTitle);

         timeSlider.startup();
     }
 }
function updateTimeSliderTitle(timeExtent) {
    console.log(this);
    var slider = this;
    var start = null,
        end = null;

    if (!timeExtent) {
        // startup
        if (slider.thumbCount == 2) {
            start = slider.timeStops[0];
            end = slider.timeStops[1];
        } else {
            start = slider.timeStops[0];
        }
    } else {
        start = timeExtent.startTime;
        if ((timeExtent.endTime.getTime() - timeExtent.startTime.getTime()) > 0) {
            end = timeExtent.endTime;
        }
    }

    var startDatePattern = null;
    var endDatePattern = null;
    var startTimePattern = null;
    var endTimePattern = null;
    if (end && start.getFullYear() == end.getFullYear()) {
        if (start.getMonth() == end.getMonth()) {
            if (start.getDate() == end.getDate()) {
                if (start.getHours() == end.getHours()) {
                    if (start.getMinutes() == end.getMinutes()) {
                        if (start.getSeconds() == end.getSeconds()) {
                            // same second
                            startDatePattern = configOptions.i18n.tools.time.datePattern;
                            startTimePattern = configOptions.i18n.tools.time.millisecondTimePattern;
                            endTimePattern = configOptions.i18n.tools.time.millisecondTimePattern;
                        } else { // same minute
                            startDatePattern = configOptions.i18n.tools.time.datePattern;
                            startTimePattern = configOptions.i18n.tools.time.secondTimePattern;
                            endTimePattern = configOptions.i18n.tools.time.secondTimePattern;
                        }
                    } else { // same hour
                        startDatePattern = configOptions.i18n.tools.time.datePattern;
                        startTimePattern = configOptions.i18n.tools.time.minuteTimePattern;
                        endTimePattern = configOptions.i18n.tools.time.minuteTimePattern;
                    }
                } else { // same day
                    startDatePattern = configOptions.i18n.tools.time.datePattern;
                    startTimePattern = configOptions.i18n.tools.time.hourTimePattern;
                    endTimePattern = configOptions.i18n.tools.time.hourTimePattern;
                }
            } else { // same month
                if (end.getDate() - start.getDate() < 2) {
                    // less than 2 days
                    startDatePattern = configOptions.i18n.tools.time.datePattern;
                    startTimePattern = configOptions.i18n.tools.time.hourTimePattern;
                    endDatePattern = configOptions.i18n.tools.time.datePattern;
                    endTimePattern = configOptions.i18n.tools.time.hourTimePattern;
                } else {
                    startDatePattern = configOptions.i18n.tools.time.datePattern;
                    endDatePattern = configOptions.i18n.tools.time.datePattern;
                }
            }
        } else { // same year
            startDatePattern = configOptions.i18n.tools.time.datePattern;
            endDatePattern = configOptions.i18n.tools.time.datePattern;
        }
    } else if (end && end.getFullYear() - start.getFullYear() > 2) {
        startDatePattern = configOptions.i18n.tools.time.yearPattern;
        endDatePattern = configOptions.i18n.tools.time.yearPattern;
    } else {
        startDatePattern = configOptions.i18n.tools.time.datePattern;
        endDatePattern = configOptions.i18n.tools.time.datePattern;
    }

    var startTime = dojo.date.locale.format(start, {
        datePattern: startDatePattern,
        timePattern: startTimePattern,
        selector: (startDatePattern && startTimePattern) ? null : (startDatePattern ? "date" : "time")
    });
    var endTime = null;
    if (end) {
        endTime = dojo.date.locale.format(end, {
            datePattern: endDatePattern,
            timePattern: endTimePattern,
            selector: (endDatePattern && endTimePattern) ? null : (endDatePattern ? "date" : "time")
        });
    }

    var info;
    if (end) {
        info = dojo.string.substitute(configOptions.i18n.tools.time.timeRange, {
            start_time: startTime,
            end_time: endTime
        });
    } else {
        info = "" + startTime;
    }
    dojo.byId("timeSliderLabel").innerHTML = info;

}

 function formatDate(date, datePattern) {
     return dojo.date.locale.format(date, {
         selector: 'date',
         datePattern: datePattern
     });
 }
<commit_msg>Delete layout.js<commit_after><|endoftext|>


<commit_before>import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import {
  ControlLabel,
  FormGroup,
  FormControl,
  HelpBlock,
  Button
} from 'react-bootstrap';
import { Redirect } from 'react-router-dom';
import PropTypes from 'prop-types';

class ModifyTitle extends Component {
  constructor(props) {
    super(props);

    if (this.props.titleDetails) {
      this.state = {
        titleDetails: {
          title: this.props.titleDetails.title,
          allergens: this.props.titleDetails.allergens,
          servings: this.props.titleDetails.servings,
        },
        fireRedirect: false,
        disableSubmitButton: false
      };
    } else {
      this.state = {
        titleDetails: {
          title: '',
          allergens: '',
          servings: '',
        },
        fireRedirect: false,
        disableSubmitButton: true
      };
    }

    this.renderNextButton = this.renderNextButton.bind(this);
    this.handleTitleChange = this.handleTitleChange.bind(this);
    this.handleAllergensChange = this.handleAllergensChange.bind(this);
    this.handleServingsChange = this.handleServingsChange.bind(this);
    this.getValidationState = this.getValidationState.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }
  handleTitleChange(event) {
    let newState = {
      titleDetails: {
        ...this.state.titleDetails,
        title: event.target.value
      },
      disableSubmitButton: event.target.value.length > 0 ? false : true
    };
    this.setState(newState);
  }
  handleAllergensChange(event) {
    this.setState({
      allergens: event.target.value
    });
  }
  handleServingsChange(event) {
    this.setState({
      servings: event.target.value
    });
  }
  getValidationState() {
    const length = this.state.titleDetails.title.length;

    if (length > 0) return 'success';
    else return 'error';
  }
  handleSubmit(event) {
    event.preventDefault();
    if (this.getValidationState() === 'success') {
      this.props.modifyTempTitle(this.state.titleDetails);
      this.setState({
        fireRedirect: true
      });
    }
  }
  renderNextButton = () => {
    return this.props.nextButton ?
      (
        <form>
          <Button
            type="submit"
            bsSize="large"
            bsStyle="primary"
            style={this.props.nextButtonStyle}
            onClick={this.handleSubmit}
            disabled={this.state.disableSubmitButton}
            block
          >
            Next
          </Button>
          <Link to="/">
            <Button
              bsSize="large"
              onClick={() => {
                this.props.clearTempRecipe();
                this.props.clearSearchIngredientResults();
              }}
              block
            >
              Back
            </Button>
          </Link>
        </form>
      )
    : null;
  }
  render() {
    return (

Recipe Information

        <FormGroup
          controlId="recipeTitle"
          validationState={this.getValidationState()}
        >
          <ControlLabel>Title</ControlLabel>
          <FormControl
            type="text"
            value={this.state.titleDetails.title}
            placeholder="Enter an awesome title"
            onChange={this.handleTitleChange}
          />
          <FormControl.Feedback />
          <HelpBlock>A title is required.</HelpBlock>
        </FormGroup>
        <ControlLabel>Servings</ControlLabel>
        <FormControl
          type="text"
          value={this.state.titleDetails.servings}
          placeholder="How many people will this recipe feed?"
          onChange={this.handleServingsChange}
        />
        <ControlLabel>Allergens</ControlLabel>
        <FormControl
          type="text"
          value={this.state.titleDetails.allergens}
          placeholder="What allergens does this food contain?"
          onChange={this.handleAllergensChange}
        />
        { this.renderNextButton() }
        { this.state.fireRedirect && (
          <Redirect to="/modify-ingredients" />
        )}

    );
  }
};

ModifyTitle.propTypes = {
  nextButton: PropTypes.bool.isRequired,
  nextButtonStyle: PropTypes.object,
  titleDetails: PropTypes.object,
  modifyTempTitle: PropTypes.func.isRequired
};

export default ModifyTitle;
<commit_msg>Fix allergens and serving inputs to update according to new shape of the state.<commit_after>import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import {
  ControlLabel,
  FormGroup,
  FormControl,
  HelpBlock,
  Button
} from 'react-bootstrap';
import { Redirect } from 'react-router-dom';
import PropTypes from 'prop-types';

class ModifyTitle extends Component {
  constructor(props) {
    super(props);

    if (this.props.titleDetails) {
      this.state = {
        titleDetails: {
          title: this.props.titleDetails.title,
          allergens: this.props.titleDetails.allergens,
          servings: this.props.titleDetails.servings,
        },
        fireRedirect: false,
        disableSubmitButton: false
      };
    } else {
      this.state = {
        titleDetails: {
          title: '',
          allergens: '',
          servings: '',
        },
        fireRedirect: false,
        disableSubmitButton: true
      };
    }

    this.renderNextButton = this.renderNextButton.bind(this);
    this.handleTitleChange = this.handleTitleChange.bind(this);
    this.handleAllergensChange = this.handleAllergensChange.bind(this);
    this.handleServingsChange = this.handleServingsChange.bind(this);
    this.getValidationState = this.getValidationState.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }
  handleTitleChange(event) {
    let newState = {
      titleDetails: {
        ...this.state.titleDetails,
        title: event.target.value
      },
      disableSubmitButton: event.target.value.length > 0 ? false : true
    };
    this.setState(newState);
  }
  handleAllergensChange(event) {
    this.setState({
      titleDetails: {
        ...this.state.titleDetails,
        allergens: event.target.value
      }
    });
  }
  handleServingsChange(event) {
    this.setState({
      titleDetails: {
        ...this.state.titleDetails,
        servings: event.target.value
      }
    });
  }
  getValidationState() {
    const length = this.state.titleDetails.title.length;

    if (length > 0) return 'success';
    else return 'error';
  }
  handleSubmit(event) {
    event.preventDefault();
    if (this.getValidationState() === 'success') {
      this.props.modifyTempTitle(this.state.titleDetails);
      this.setState({
        fireRedirect: true
      });
    }
  }
  renderNextButton = () => {
    return this.props.nextButton ?
      (
        <form>
          <Button
            type="submit"
            bsSize="large"
            bsStyle="primary"
            style={this.props.nextButtonStyle}
            onClick={this.handleSubmit}
            disabled={this.state.disableSubmitButton}
            block
          >
            Next
          </Button>
          <Link to="/">
            <Button
              bsSize="large"
              onClick={() => {
                this.props.clearTempRecipe();
                this.props.clearSearchIngredientResults();
              }}
              block
            >
              Back
            </Button>
          </Link>
        </form>
      )
    : null;
  }
  render() {
    return (

Recipe Information

        <FormGroup
          controlId="recipeTitle"
          validationState={this.getValidationState()}
        >
          <ControlLabel>Title</ControlLabel>
          <FormControl
            type="text"
            value={this.state.titleDetails.title}
            placeholder="Enter an awesome title"
            onChange={this.handleTitleChange}
          />
          <FormControl.Feedback />
          <HelpBlock>A title is required.</HelpBlock>
        </FormGroup>
        <ControlLabel>Servings</ControlLabel>
        <FormControl
          type="text"
          value={this.state.titleDetails.servings}
          placeholder="How many people will this recipe feed?"
          onChange={this.handleServingsChange}
        />
        <ControlLabel>Allergens</ControlLabel>
        <FormControl
          type="text"
          value={this.state.titleDetails.allergens}
          placeholder="What allergens does this food contain?"
          onChange={this.handleAllergensChange}
        />
        { this.renderNextButton() }
        { this.state.fireRedirect && (
          <Redirect to="/modify-ingredients" />
        )}

    );
  }
};

ModifyTitle.propTypes = {
  nextButton: PropTypes.bool.isRequired,
  nextButtonStyle: PropTypes.object,
  titleDetails: PropTypes.object,
  modifyTempTitle: PropTypes.func.isRequired
};

export default ModifyTitle;
<|endoftext|>


<commit_before>
const RG = require('../../../client/src/battles');
const expect = require('chai').expect;
const TemplLevel = require('../../../client/src/template.level');

const Crypt = require('../../../client/data/tiles.crypt');
const Castle = require('../../../client/data/tiles.castle');
const Basic = require('../../../client/data/tiles.basic');

const tileDirTest = `
dir:UDLR
name:TEST_udlr
X=.
Y=.

#X...X#
Y......
.......
.......
.......
Y......
#.....#`;

const tileDirTestNSEW = `
dir: NSEW
name:TEST_nsew
X=#
Y=#

#X#.#X#
Y.....#
#.....#
.......
#.....#
Y.....#
###.###`;

const tileDirTestAdapter1 = `
dir: NSLR
name:TEST_nslr
X=#
Y=.

#X#.#X#
Y......
.......
.......
.......
Y......
###.###`;

const tileDirTestAdapter2 = `
dir: UDEW
name:TEST_udew
X=.
Y=#

#X...X#
Y.....#
#.....#
.......
#.....#
Y.....#
#.....#`;

describe('Template.Level', () => {
    it('creates a 2-d map of the level', () => {
        const level = new TemplLevel(10, 7);

        RG.RAND.setSeed(new Date().getTime());

        level.setGenParams([1, 2, 1, 1]);
        level.setRoomCount(30);
        level.use(Crypt);
        level.create();
        expect(Array.isArray(level.map)).to.be.true;
        // RG.printMap(level.map);
    });

    it('can create 2-d castles', () => {
        const level = new TemplLevel(12, 6);

        RG.RAND.setSeed(new Date().getTime());

        level.setFiller(Castle.tiles.fillerWall);
        level.setTemplates(Castle.Models.full);
        level.use(Castle);

        level.setGenParams([1, 1, 1, 1]);
        level.create();

        expect(level.map).to.have.length(7 * 12);
        expect(level.map[0]).to.have.length(7 * 6);

        RG.printMap(level.map);
    });

    it('can create 2-d castles with outer wall only', () => {
        const level = new TemplLevel(12, 6);
        RG.RAND.setSeed(new Date().getTime());

        level.use(Castle);
        level.setFiller(Castle.tiles.fillerFloor);
        level.setTemplates(Castle.Models.outerWall);

        level.setGenParams([1, 1, 1, 1]);
        level.create();

        expect(level.map).to.have.length(7 * 12);
        expect(level.map[0]).to.have.length(7 * 6);

        // RG.printMap(level.map);
    });

    it('can have custom starting room function specified', () => {
        const level = new TemplLevel(12, 6);
        RG.RAND.setSeed(new Date().getTime());

        const Castle2Gates = Object.assign({}, Castle);
        Castle2Gates.startRoomFunc = Castle.startFuncTwoGates;

        level.use(Castle2Gates);
        level.setFiller(Castle.tiles.fillerWall);
        level.setTemplates(Castle.Models.full);

        level.setGenParams([2, 2, 2, 2]);
        level.create();

        expect(level.map).to.have.length(9 * 12);
        expect(level.map[0]).to.have.length(9 * 6);

        // RG.printMap(level.map);
    });

    it('can also remove templates after creation', () => {
        const level = new TemplLevel(7, 7);
        level.use(Castle);
        level.setFiller(Castle.tiles.fillerFloor);
        level.setTemplates(Castle.Models.outerWall);

        let templ = level.findTemplate({name: 'corner_nw'});
        expect(templ.getProp('name')).to.equal('corner_nw');

        level.removeTemplate({name: 'corner_nw'});
        templ = level.findTemplate({name: 'corner_nw'});
        expect(templ).to.be.null;

    });

    it('can have arbitrary directions specified', () => {
        const level = new TemplLevel(11, 7);
        const templates = [tileDirTest, tileDirTest, tileDirTest];
        level.setFiller(Crypt.tiles.filler);
        const exitMap = {
            U: 'D', D: 'U', L: 'R', R: 'L'
        };
        const nsew2DirRemap = {
            N: 'U', S: 'D', E: 'R', W: 'L'
        };
        level.setTemplates(templates);
        level.setExitMap(exitMap, nsew2DirRemap);
        level.create();

        expect(level.map).to.have.length(7 * 11);
        expect(level.map[0]).to.have.length(7 * 7);

        RG.printMap(level.map);
    });

    it('can have mixed NSEW and arbitraty directions specified', () => {
        const level = new TemplLevel(8, 9);
        const templates = [tileDirTest, tileDirTestNSEW, tileDirTestAdapter1,
            tileDirTestAdapter2];
        level.setFiller(Crypt.tiles.filler);
        const exitMap = {
            N: 'S', S: 'N', E: 'W', W: 'E',
            U: 'D', D: 'U', L: 'R', R: 'L'
        };
        const nsew2DirRemap = {
            N: 'U', S: 'D', E: 'R', W: 'L'
        };
        level.setTemplates(templates);
        level.setExitMap(exitMap, nsew2DirRemap);
        level.create();

        expect(level.map).to.have.length(7 * 8);
        expect(level.map[0]).to.have.length(7 * 9);

        RG.printMap(level.map);
    });

    it('can create levels from rotated/transformed tiles', () => {
        const level = new TemplLevel(12, 7);
        level.setFiller(Crypt.tiles.filler);
        const templates = Basic.templates;
        level.setTemplates(templates);
        level.create();
        RG.printMap(level.map);
    });

    it('can create Crypts with rotated tiles', () => {
        const level = new TemplLevel(12, 7);
        level.setFiller(Crypt.tiles.filler);
        const templates = Crypt.templates.all;
        level.setTemplates(templates);
        level.create();
        // RG.printMap(level.map);
    });

    it('can create Castles with rotated tiles', () => {
        // RG.RAND.setSeed(new Date().getTime());
        const level = new TemplLevel(12, 7);
        level.setFiller(Castle.tiles.fillerWall);
        const templates = Castle.templates.all;
        level.setTemplates(templates);
        level.use(Castle);

        level.create();
        RG.printMap(level.map);
    });

    it.only('can create levels with 5x5 tiles', () => {
        const level = new TemplLevel(20, 11);
        level.setGenParams([2, 2, 2, 2]);
        level.roomCount = -1;
        level.setFiller(Basic.tiles5x5.filler);
        const templates = Basic.templates5x5;
        console.log(JSON.stringify(Basic.templates5x5, null, 2));
        level.setTemplates(templates);
        level.setExitMap(Basic.remap.exits, Basic.remap.nsew2Dir);
        level.create();
        RG.printMap(level.map);
    });

});
<commit_msg>Renamed Basic -> Basic5x5.<commit_after>
/* eslint quote-props: 0 */
const RG = require('../../../client/src/battles');
const expect = require('chai').expect;
const TemplLevel = require('../../../client/src/template.level');

const Crypt = require('../../../client/data/tiles.crypt');
const Castle = require('../../../client/data/tiles.castle');
const Basic = require('../../../client/data/tiles.basic').Basic;
const Basic5x5 = require('../../../client/data/tiles.basic').Basic5x5;

const tileDirTest = `
dir:UDLR
name:TEST_udlr
X=.
Y=.

#X...X#
Y......
.......
.......
.......
Y......
#.....#`;

const tileDirTestNSEW = `
dir: NSEW
name:TEST_nsew
X=#
Y=#

#X#.#X#
Y.....#
#.....#
.......
#.....#
Y.....#
###.###`;

const tileDirTestAdapter1 = `
dir: NSLR
name:TEST_nslr
X=#
Y=.

#X#.#X#
Y......
.......
.......
.......
Y......
###.###`;

const tileDirTestAdapter2 = `
dir: UDEW
name:TEST_udew
X=.
Y=#

#X...X#
Y.....#
#.....#
.......
#.....#
Y.....#
#.....#`;

describe('Template.Level', () => {
    it('creates a 2-d map of the level', () => {
        const level = new TemplLevel(10, 7);

        RG.RAND.setSeed(new Date().getTime());

        level.setGenParams([1, 2, 1, 1]);
        level.setRoomCount(30);
        level.use(Crypt);
        level.create();
        expect(Array.isArray(level.map)).to.be.true;
        // RG.printMap(level.map);
    });

    it('can create 2-d castles', () => {
        const level = new TemplLevel(12, 6);

        RG.RAND.setSeed(new Date().getTime());

        level.setFiller(Castle.tiles.fillerWall);
        level.setTemplates(Castle.Models.full);
        level.use(Castle);

        level.setGenParams([1, 1, 1, 1]);
        level.create();

        expect(level.map).to.have.length(7 * 12);
        expect(level.map[0]).to.have.length(7 * 6);

        RG.printMap(level.map);
    });

    it('can create 2-d castles with outer wall only', () => {
        const level = new TemplLevel(12, 6);
        RG.RAND.setSeed(new Date().getTime());

        level.use(Castle);
        level.setFiller(Castle.tiles.fillerFloor);
        level.setTemplates(Castle.Models.outerWall);

        level.setGenParams([1, 1, 1, 1]);
        level.create();

        expect(level.map).to.have.length(7 * 12);
        expect(level.map[0]).to.have.length(7 * 6);

        // RG.printMap(level.map);
    });

    it('can have custom starting room function specified', () => {
        const level = new TemplLevel(12, 6);
        RG.RAND.setSeed(new Date().getTime());

        const Castle2Gates = Object.assign({}, Castle);
        Castle2Gates.startRoomFunc = Castle.startFuncTwoGates;

        level.use(Castle2Gates);
        level.setFiller(Castle.tiles.fillerWall);
        level.setTemplates(Castle.Models.full);

        level.setGenParams([2, 2, 2, 2]);
        level.create();

        expect(level.map).to.have.length(9 * 12);
        expect(level.map[0]).to.have.length(9 * 6);

        // RG.printMap(level.map);
    });

    it('can also remove templates after creation', () => {
        const level = new TemplLevel(7, 7);
        level.use(Castle);
        level.setFiller(Castle.tiles.fillerFloor);
        level.setTemplates(Castle.Models.outerWall);

        let templ = level.findTemplate({name: 'corner_nw'});
        expect(templ.getProp('name')).to.equal('corner_nw');

        level.removeTemplate({name: 'corner_nw'});
        templ = level.findTemplate({name: 'corner_nw'});
        expect(templ).to.be.null;

    });

    it('can have arbitrary directions specified', () => {
        const level = new TemplLevel(11, 7);
        const templates = [tileDirTest, tileDirTest, tileDirTest];
        level.setFiller(Crypt.tiles.filler);
        const exitMap = {
            U: 'D', D: 'U', L: 'R', R: 'L'
        };
        const nsew2DirRemap = {
            N: 'U', S: 'D', E: 'R', W: 'L'
        };
        level.setTemplates(templates);
        level.setExitMap(exitMap, nsew2DirRemap);
        level.create();

        expect(level.map).to.have.length(7 * 11);
        expect(level.map[0]).to.have.length(7 * 7);

        RG.printMap(level.map);
    });

    it('can have mixed NSEW and arbitraty directions specified', () => {
        const level = new TemplLevel(8, 9);
        const templates = [tileDirTest, tileDirTestNSEW, tileDirTestAdapter1,
            tileDirTestAdapter2];
        level.setFiller(Crypt.tiles.filler);
        const exitMap = {
            N: 'S', S: 'N', E: 'W', W: 'E',
            U: 'D', D: 'U', L: 'R', R: 'L'
        };
        const nsew2DirRemap = {
            N: 'U', S: 'D', E: 'R', W: 'L'
        };
        level.setTemplates(templates);
        level.setExitMap(exitMap, nsew2DirRemap);
        level.create();

        expect(level.map).to.have.length(7 * 8);
        expect(level.map[0]).to.have.length(7 * 9);

        RG.printMap(level.map);
    });

    it('can create levels from rotated/transformed tiles', () => {
        const level = new TemplLevel(12, 7);
        level.setFiller(Crypt.tiles.filler);
        const templates = Basic.templates;
        level.setTemplates(templates);
        level.create();
        RG.printMap(level.map);
    });

    it('can create Crypts with rotated tiles', () => {
        const level = new TemplLevel(12, 7);
        level.setFiller(Crypt.tiles.filler);
        const templates = Crypt.templates.all;
        level.setTemplates(templates);
        level.create();
        // RG.printMap(level.map);
    });

    it('can create Castles with rotated tiles', () => {
        const level = new TemplLevel(12, 7);
        level.setFiller(Castle.tiles.fillerWall);
        const templates = Castle.templates.all;
        level.setTemplates(templates);
        level.use(Castle);

        level.create();
        RG.printMap(level.map);
    });

    it.only('can create levels with 5x5 tiles', () => {
        RG.RAND.setSeed(new Date().getTime());
        const level = new TemplLevel(25, 9);
        level.tryToMatchAllExits = false;

        level.use(Basic5x5);
        level.weights = {
            'room_term1': 10,
            corridor: 10
        };
        level.setGenParams([1, 1, 1, 1]);
        level.roomCount = -1;
        level.setFiller(Basic5x5.tiles.filler);
        const templates = Basic5x5.templates;
        console.log(JSON.stringify(Basic5x5.templates, null, 2));
        level.setTemplates(templates);
        level.setExitMap(Basic5x5.remap.exits, Basic5x5.remap.nsew2Dir);
        level.create();

        expect(level.map).to.exist;
        RG.printMap(level.map);
    });

});
<|endoftext|>