<commit_before>'use strict';

const ShellComponent = require('./shell-component');
const themes = require('iterm-colors/bundle.json');

module.exports = function init(app) {
  app.config.on('all-preferences-loaded', () => {
    const pref = app.packages.shell.preferences;
    pref['user-css'] = (pref['user-css'] || '').replace(/~/g, app.config.configFolder);
  });

  app.on('packages-init-done', () => {
    app.commands.execute('inject-js', `window.twemoji = require('${require.resolve('twemoji')}');`);
    app.commands.execute('inject-script', __dirname + '/hterm_all.js');
    setTimeout(()=>app.commands.execute('new-tab'), 100);
  });

  const pkg = {
    initializeTerminal(t) {
      if (!this._theme) {
        this._theme = this.preferences.theme;
      }
      if (this._theme) {
        const theme = themes[this._theme];
        if (theme.background) {
          t.prefs_.set('background-color', theme.background);
        }

        if (theme.foreground) {
          t.prefs_.set('foreground-color', theme.foreground);
        }

        if (theme.cursor_text) {
          t.prefs_.set('cursor-color', theme.cursor_text);
        }

        if (theme.palette) {
          t.prefs_.set('color-palette-overrides', theme.palette);
        }
      }

      delete this.preferences.theme;

      Object.keys(this.preferences).forEach(k => {
        t.prefs_.set(k, this.preferences[k]);
      });
    },

    get currentHTerm() {
      const current = app.tabs.current();
      if (!current) {
        return null;
      }
      return current.component.hterm || null;
    },

    get currentComponent() {
      const current = app.tabs.current();
      if (!current) {
        return null;
      }
      return current.component.hterm ? current.component : null;
    },

    get cursorRow() {
      const shell = this.currentHTerm;
      if (!shell) {
        return null;
      }
      return shell.screen_.cursorPosition.row;
    },

    get cursorCol() {
      const shell = this.currentHTerm;
      if (!shell) {
        return null;
      }
      return shell.screen_.cursorPosition.column;
    },

    get cursorRowText() {
      const shell = this.currentHTerm;
      if (!shell) {
        return null;
      }
      return shell.screen_.cursorRowNode_.textContent;
    },

    name: 'shell',
    path: __dirname
  };

  app.on('window-ready', () => {
    app.window.on('maximize', () => {
      pkg.currentHTerm.scrollPort_.onResize_();
    });
    setTimeout(()=>pkg.currentHTerm.scrollPort_.onResize_(), 500);
  });

  app.commands.register('new-tab', () => {
    const component = new ShellComponent(app, pkg);
    const tab = app.tabs.add(component);
    setTimeout(()=>pkg.currentHTerm.scrollPort_.onResize_(), 100);
    component.on('process-closed', () => {
      app.tabs.activateFirstTab();
      tab.close();
    });
  });

  app.commands.register('prev-word', () => {
    const component = pkg.currentComponent;
    const col = pkg.cursorCol;
    const text = pkg.cursorRowText;

    if (!text) {
      return;
    }

    let i = col - 1;
    while (i && text[i].match(/\s/)) {
      component.sendKey(0x25, 'keydown');
      i--;
    }

    while (i && !text[i].match(/\s/)) {
      component.sendKey(0x25, 'keydown');
      i--;
    }
  });

  app.commands.register('next-word', () => {
    const component = pkg.currentComponent;
    const col = pkg.cursorCol;
    const text = pkg.cursorRowText;

    if (!text) {
      return;
    }

    let i = col - 1;
    while (i && text[i].match(/\s/)) {
      component.sendKey(0x27, 'keydown');
      i++;
    }

    while (i && !text[i].match(/\s/)) {
      component.sendKey(0x27, 'keydown');
      i++;
    }
  });

  app.commands.register('start-line', () => {
    const component = pkg.currentComponent;
    const col = pkg.cursorCol;

    if (!col) {
      return;
    }

    let i = col - 1;
    while (i--) {
      component.sendKey(0x25, 'keydown');
    }
  });

  app.commands.register('end-line', () => {
    const component = pkg.currentComponent;
    const col = pkg.cursorCol;
    const text = pkg.cursorRowText;

    if (!text) {
      return;
    }

    let i = text.length - col + 1;
    while (i--) {
      component.sendKey(0x27, 'keydown');
    }
  });

  return pkg;
};
<commit_msg>removed weird resizing method<commit_after>'use strict';

const ShellComponent = require('./shell-component');
const themes = require('iterm-colors/bundle.json');

module.exports = function init(app) {
  app.config.on('all-preferences-loaded', () => {
    const pref = app.packages.shell.preferences;
    pref['user-css'] = (pref['user-css'] || '').replace(/~/g, app.config.configFolder);
  });

  app.on('packages-init-done', () => {
    app.commands.execute('inject-js', `window.twemoji = require('${require.resolve('twemoji')}');`);
    app.commands.execute('inject-script', __dirname + '/hterm_all.js');
    setTimeout(()=>app.commands.execute('new-tab'), 100);
  });

  const pkg = {
    initializeTerminal(t) {
      if (!this._theme) {
        this._theme = this.preferences.theme;
      }
      if (this._theme) {
        const theme = themes[this._theme];
        if (theme.background) {
          t.prefs_.set('background-color', theme.background);
        }

        if (theme.foreground) {
          t.prefs_.set('foreground-color', theme.foreground);
        }

        if (theme.cursor_text) {
          t.prefs_.set('cursor-color', theme.cursor_text);
        }

        if (theme.palette) {
          t.prefs_.set('color-palette-overrides', theme.palette);
        }
      }

      delete this.preferences.theme;

      Object.keys(this.preferences).forEach(k => {
        t.prefs_.set(k, this.preferences[k]);
      });
    },

    get currentHTerm() {
      const current = app.tabs.current();
      if (!current) {
        return null;
      }
      return current.component.hterm || null;
    },

    get currentComponent() {
      const current = app.tabs.current();
      if (!current) {
        return null;
      }
      return current.component.hterm ? current.component : null;
    },

    get cursorRow() {
      const shell = this.currentHTerm;
      if (!shell) {
        return null;
      }
      return shell.screen_.cursorPosition.row;
    },

    get cursorCol() {
      const shell = this.currentHTerm;
      if (!shell) {
        return null;
      }
      return shell.screen_.cursorPosition.column;
    },

    get cursorRowText() {
      const shell = this.currentHTerm;
      if (!shell) {
        return null;
      }
      return shell.screen_.cursorRowNode_.textContent;
    },

    name: 'shell',
    path: __dirname
  };

  app.commands.register('new-tab', () => {
    const component = new ShellComponent(app, pkg);
    const tab = app.tabs.add(component);
    setTimeout(()=>pkg.currentHTerm.scrollPort_.onResize_(), 100);
    component.on('process-closed', () => {
      app.tabs.activateFirstTab();
      tab.close();
    });
  });

  app.commands.register('prev-word', () => {
    const component = pkg.currentComponent;
    const col = pkg.cursorCol;
    const text = pkg.cursorRowText;

    if (!text) {
      return;
    }

    let i = col - 1;
    while (i && text[i].match(/\s/)) {
      component.sendKey(0x25, 'keydown');
      i--;
    }

    while (i && !text[i].match(/\s/)) {
      component.sendKey(0x25, 'keydown');
      i--;
    }
  });

  app.commands.register('next-word', () => {
    const component = pkg.currentComponent;
    const col = pkg.cursorCol;
    const text = pkg.cursorRowText;

    if (!text) {
      return;
    }

    let i = col - 1;
    while (i && text[i].match(/\s/)) {
      component.sendKey(0x27, 'keydown');
      i++;
    }

    while (i && !text[i].match(/\s/)) {
      component.sendKey(0x27, 'keydown');
      i++;
    }
  });

  app.commands.register('start-line', () => {
    const component = pkg.currentComponent;
    const col = pkg.cursorCol;

    if (!col) {
      return;
    }

    let i = col - 1;
    while (i--) {
      component.sendKey(0x25, 'keydown');
    }
  });

  app.commands.register('end-line', () => {
    const component = pkg.currentComponent;
    const col = pkg.cursorCol;
    const text = pkg.cursorRowText;

    if (!text) {
      return;
    }

    let i = text.length - col + 1;
    while (i--) {
      component.sendKey(0x27, 'keydown');
    }
  });

  return pkg;
};
<|endoftext|>


<commit_before>import 'intl';
import React from 'react';
import ReactDom from 'react-dom';
import { IntlProvider, addLocaleData } from 'react-intl';
import styled from 'styled-components';
import 'normalize.css';
import 'font-awesome/css/font-awesome.css';

import en from 'react-intl/locale-data/en';
import pt from 'react-intl/locale-data/pt';
addLocaleData([...en, ...pt]);
window.locales = ['en-US', 'pt-BR'];

const Wrapper = styled.div`
  overflow-x: hidden;
  text-rendering: optimizeLegibility;
  text-rendering: geometricPrecision;
  font-smooth: grayscale;
  font-smoothing: antialiased;
  -moz-font-smoothing: antialiased;
  -webkit-font-smoothing: antialiased;
  -webkit-font-smoothing: subpixel-antialiased;
  -moz-osx-font-smoothing: grayscale;
  ::selection {
    background: #000;
  }
  ::-moz-selection {
    background: #000;
  }
  h1,
  h2,
  h3,
  h4 {
    font-family: "Inconsolata", monospace;
    font-weight: normal;
  }
`;

import localeData from './locales';

let query = {};
window.location.search.slice(1).split('&').map(item => { const arr = item.split('='); query[arr[0]] = arr[1]; });

const languagePath = window.location.pathname.split('/')[1];

const language = query.hl || query.lang ||
                  languagePath ||
                  (navigator.languages && navigator.languages[0]) ||
                  navigator.language ||
                  navigator.userLanguage;
const languageWithoutRegionCode = language.toLowerCase().split(/[_-]+/)[0];
const messages = localeData[language] || localeData[languageWithoutRegionCode] || localeData.en;

import Head from 'components/head';

import Video from 'components/video';
import Header from 'components/header';
import Headline from 'components/headline';
import Demo from 'components/demo';
import Footer from 'components/footer';

import Content from 'components/content';

ReactDom.render(
  <IntlProvider locale={language} messages={messages}>
    <Wrapper>
      <Head />
      <Video />
      <Header />
      <Headline />
      <Demo />
      <Content />
      <Footer />
    </Wrapper>
  </IntlProvider>,
  document.getElementById('app')
);
<commit_msg>use custom method for better locale search<commit_after>import 'intl';
import React from 'react';
import ReactDom from 'react-dom';
import { IntlProvider, addLocaleData } from 'react-intl';
import styled from 'styled-components';
import 'normalize.css';
import 'font-awesome/css/font-awesome.css';

import en from 'react-intl/locale-data/en';
import pt from 'react-intl/locale-data/pt';
addLocaleData([...en, ...pt]);
window.locales = ['en-US', 'pt-BR'];

const Wrapper = styled.div`
  overflow-x: hidden;
  text-rendering: optimizeLegibility;
  text-rendering: geometricPrecision;
  font-smooth: grayscale;
  font-smoothing: antialiased;
  -moz-font-smoothing: antialiased;
  -webkit-font-smoothing: antialiased;
  -webkit-font-smoothing: subpixel-antialiased;
  -moz-osx-font-smoothing: grayscale;
  ::selection {
    background: #000;
  }
  ::-moz-selection {
    background: #000;
  }
  h1,
  h2,
  h3,
  h4 {
    font-family: "Inconsolata", monospace;
    font-weight: normal;
  }
`;

import localeData from './locales';

let query = {};
window.location.search.slice(1).split('&').map(item => { const arr = item.split('='); query[arr[0]] = arr[1]; });

const languagePath = window.location.pathname.split('/')[1];

const language = query.lang ||
                  languagePath ||
                  (navigator.languages && navigator.languages[0]) ||
                  navigator.language ||
                  navigator.userLanguage;

const findLocale = language => {
  let locale = false;
  const languageWRC = language.toLowerCase().split(/[_-]+/)[0];
  for(const key in localeData) {
    let keyWRC = key.toLowerCase().split(/[_-]+/)[0];
    if(!locale &&
      (key == language || key == languageWRC || keyWRC == languageWRC || keyWRC == language)
    ) {
      locale = key;
    }
  }
  return locale;
};

const messages = localeData[findLocale(language)] || localeData.en;

import Head from 'components/head';

import Video from 'components/video';
import Header from 'components/header';
import Headline from 'components/headline';
import Demo from 'components/demo';
import Footer from 'components/footer';

import Content from 'components/content';

ReactDom.render(
  <IntlProvider locale={language} messages={messages}>
    <Wrapper>
      <Head />
      <Video />
      <Header />
      <Headline />
      <Demo />
      <Content />
      <Footer />
    </Wrapper>
  </IntlProvider>,
  document.getElementById('app')
);
<|endoftext|>


<commit_before>var _           = require('lodash');
var fs          = require('fs-extra');
var os          = require('os');
var path        = require('path');
var gulp        = require('gulp');
var newer       = require('gulp-newer');
var imageResize = require('gulp-image-resize');
var parallel    = require('concurrent-transform');

var galleries   = require('./galleries');
var render      = require('./render');

exports.build = function(opts) {

  fs.mkdirp(opts.output);
  var list = galleries.fromDisk(opts.input, opts.mediaPrefix);

  gulp.task('thumbs', function () {
    var dest = opts.output + '/thumbs';
    gulp
    .src(opts.input + '/**/*.{jpg,png}')
    .pipe(newer(dest))
    .pipe(parallel(imageResize({width: 100, height: 100, crop: true}), os.cpus().length))
    .pipe(gulp.dest(dest));
  });

  gulp.task('index', function() {
    // TODO render index page
    // render.index(...);
  });

  gulp.task('public', function() {
    var dest = opts.output + '/public';
    gulp
    .src('public/**')
    .pipe(newer(dest))
    .pipe(gulp.dest(dest));
  });

  gulp.task('galleries', function() {
    list.forEach(function(folder) {
      var rendered = render.gallery(list, folder);
      var outputPath = path.join(opts.output, folder.url);
      fs.writeFileSync(outputPath, rendered);
    });
  });

  gulp.run('thumbs', 'public', 'index', 'galleries');

};
<commit_msg>index page = first gallery<commit_after>var _           = require('lodash');
var fs          = require('fs-extra');
var os          = require('os');
var path        = require('path');
var gulp        = require('gulp');
var newer       = require('gulp-newer');
var imageResize = require('gulp-image-resize');
var parallel    = require('concurrent-transform');

var galleries   = require('./galleries');
var render      = require('./render');

exports.build = function(opts) {

  fs.mkdirp(opts.output);
  var list = galleries.fromDisk(opts.input, opts.mediaPrefix);

  gulp.task('thumbs', function () {
    var dest = opts.output + '/thumbs';
    gulp
    .src(opts.input + '/**/*.{jpg,png}')
    .pipe(newer(dest))
    .pipe(parallel(imageResize({width: 100, height: 100, crop: true}), os.cpus().length))
    .pipe(gulp.dest(dest));
  });

  gulp.task('index', function() {
    var rendered = render.gallery(list, list[0]);
    var outputPath = path.join(opts.output, 'index.html');
    fs.writeFileSync(outputPath, rendered);
  });

  gulp.task('public', function() {
    var dest = opts.output + '/public';
    gulp
    .src('public/**')
    .pipe(newer(dest))
    .pipe(gulp.dest(dest));
  });

  gulp.task('galleries', function() {
    list.forEach(function(folder) {
      var rendered = render.gallery(list, folder);
      var outputPath = path.join(opts.output, folder.url);
      fs.writeFileSync(outputPath, rendered);
    });
  });

  gulp.run('thumbs', 'public', 'index', 'galleries');

};
<|endoftext|>


<commit_before>var Buffer = require('safe-buffer').Buffer
var markdown = require('markdown').parse
var pull = require('pull-stream')

var q = Promise.resolve()
var KB = 1024
var MB = KB * 1024

var currentEl = document.getElementById('current')
var resultsEl = document.getElementById('results')
var previewEl = document.getElementById('preview')
var runEl = document.getElementById('run')
currentEl.textContent = 'Ready'
runEl.onclick = runTests

var tests = {
	// Suspected worst-case.
	manyPairs: test({
		inSize: 16*KB,
		inCount: 10000,
		blockSize: 30*KB
	}),

	// Suspected worst-case.
	manyTriplets: test({
		inSize: 11*KB,
		inCount: 14000,
		blockSize: 30*KB
	}),

	// Large incoming buffers scenario.
	bigBuffers: test({
		inSize: 20*MB,
		inCount: 1,
		blockSize: 50*KB
	})
}
var implementations = {
	'pull-block master': require('./pull-block-master.js'),
	'pull-block dev #4': require('./pull-block-dev4.js'),
	'pull-block dev #5': require('./pull-block-dev5.js'),
	'pull-block dev': require('./pull-block-dev.js'),
	// 'pull-block v1.2.0': require('./pull-block-1.2.0.js')
}
var repeat = 6
var wait = {
	afterSetup: waitFor(1000),
	afterRun: waitFor(300),
	beforeSetup: waitFor(200)
}

function showButton(predicate) {
	return function(passThrough) {
		runEl.style.display = predicate ? 'inline-block' : 'none'
		return passThrough
	}
}

function setCurrent(text) {
	return function(passThrough) {
		currentEl.textContent = text
		return passThrough
	}
}

function clearResults(passThrough) {
	resultsEl.innerHTML = ''
	return passThrough
}

function addMDLine(a, b, c) {
	resultsEl.textContent += a+'|'+b+'|'+c+'\n'
	previewEl.innerHTML = markdown(resultsEl.textContent, 'Maruku')
}

function addResult(test, impl, results) {
	return function(passThrough) {
		var sum = results.reduce(function(acc, val){ return acc + val }, 0)
		var avg = Math.round(sum / results.length)
		if(resultsEl.textContent == ''){
			addMDLine('Test', 'Version', 'AVG')
			addMDLine('-', '-', '-')
		}
		addMDLine(test, impl, `${avg}ms`)
		return passThrough
	}
}

function addFail(test, impl) {
	return function(error) {
		addMDLine(test, impl, 'failed: '+error.toString())
	}
}

function waitFor(time) {
	return function(passThrough) {
		return new Promise(function(resolve, reject){
			setTimeout(function(){
				resolve(passThrough)
			}, time)
		})
	}
}

function test(opts) {
	return function setup(){
		var input = []

		for(var j = 0; j < opts.inCount; j++) {
			var buf = Buffer.alloc(opts.inSize)
			for (var i = 0; i < opts.inSize; i++) buf[i] = 'a'.charCodeAt(0)
			input.push(buf)
		}

		return {
			input: input,
			blockSize: opts.blockSize,
			results: []
		}
	}
}

function runWith(blockImpl, results){
	return function(context) {
		return new Promise(function(resolve, reject){
			var start = Date.now()
			pull(
				pull.values(context.input),
				blockImpl(context.blockSize),
				pull.onEnd(function(){
					results.push(Date.now() - start)
					resolve(context)
				})
			)
		})
	}
}

function teardown(context) {
	context.input.forEach(function(b){
		delete b
	})
	delete context.input
	return context
}

function runTests(){
	q = q
	.then(showButton(false))
	.then(clearResults)

	for (var testKey in tests) {
		var test = tests[testKey]
		var context = null

		q = q
		.then(setCurrent('Setting up '+testKey+' test'))
		.then(wait.beforeSetup)
		.then(test)
		.then(function(c){
			// Keep a reference to the setup, in case of errors.
			context = c
			return c
		})
		.then(wait.afterSetup)

		for (var implKey in implementations){
			var blockImpl = implementations[implKey]
			var results = []

			for (var r = 1; r <= repeat; r++){
				q = q
				q = q.then(setCurrent('Running '+testKey+' with '+implKey+' ['+r+'/'+repeat+']'))
				.then(runWith(blockImpl, results))
				.then(wait.afterRun)
			}

			q = q
			.then(addResult(testKey, implKey, results))
			.catch(addFail(testKey, implKey, context))
			.then(function(c){ return c || context })
		}

		q = q.then(teardown)
	}

	q = q
	.then(setCurrent('Tests completed'))
	.then(showButton(true))
}<commit_msg>Added testcases<commit_after>var Buffer = require('safe-buffer').Buffer
var markdown = require('markdown').parse
var pull = require('pull-stream')

var q = Promise.resolve()
var KB = 1024
var MB = KB * 1024

var currentEl = document.getElementById('current')
var resultsEl = document.getElementById('results')
var previewEl = document.getElementById('preview')
var runEl = document.getElementById('run')
currentEl.textContent = 'Ready'
runEl.onclick = runTests

var tests = {
	perfectHalves: test({
		inSize: 10*MB,
		inCount: 25,
		blockSize: 5*MB
	}),
	almostHalves: test({
		inSize: 10*MB,
		inCount: 25,
		blockSize: 4*MB
	}),
	perfect10ths: test({
		inSize: 10*MB,
		inCount: 25,
		blockSize: 1*MB
	}),
	almost10ths: test({
		inSize: 10*MB,
		inCount: 25,
		blockSize: 950*KB
	}),
	perfect100ths: test({
		inSize: 25*MB,
		inCount: 12,
		blockSize: 256*KB
	}),
	almost100ths: test({
		inSize: 25*MB,
		inCount: 12,
		blockSize: 200*KB
	}),
	hugeBuffers: test({
		inSize: 200*MB,
		inCount: 2,
		blockSize: 500*KB
	}),
	tinyBufs: test({
		inSize: 7*KB,
		inCount: 20000,
		blockSize: 40*KB
	}),
	microBufs: test({
		inSize: 512,
		inCount: 50000,
		blockSize: 40*KB
	}),
	manyPairs: test({
		inSize: 16*KB,
		inCount: 10000,
		blockSize: 30*KB
	}),
	perfectPairs: test({
		inSize: 15*KB,
		inCount: 10000,
		blockSize: 30*KB
	}),
	manyTriplets: test({
		inSize: 11*KB,
		inCount: 14000,
		blockSize: 30*KB
	}),
	bigBuffers: test({
		inSize: 20*MB,
		inCount: 1,
		blockSize: 50*KB
	})
}
var implementations = {
	'pull-block dev': require('./pull-block-dev.js'),
	'pull-block dev #5': require('./pull-block-dev5.js'),
	'pull-block dev #4': require('./pull-block-dev4.js'),
	'pull-block master': require('./pull-block-master.js')
	// 'pull-block v1.2.0': require('./pull-block-1.2.0.js')
}
var repeat = 6
var wait = {
	afterSetup: waitFor(1000),
	afterRun: waitFor(300),
	beforeSetup: waitFor(200)
}

function showButton(predicate) {
	return function(passThrough) {
		runEl.style.display = predicate ? 'inline-block' : 'none'
		return passThrough
	}
}

function setCurrent(text) {
	return function(passThrough) {
		currentEl.textContent = text
		return passThrough
	}
}

function clearResults(passThrough) {
	resultsEl.innerHTML = ''
	return passThrough
}

function addMDLine(a, b, c) {
	resultsEl.textContent += a+'|'+b+'|'+c+'\n'
	previewEl.innerHTML = markdown(resultsEl.textContent, 'Maruku')
}

function addResult(test, impl, results) {
	return function(passThrough) {
		var sum = results.reduce(function(acc, val){ return acc + val }, 0)
		var avg = Math.round(sum / results.length)
		if(resultsEl.textContent == ''){
			addMDLine('Test', 'Version', 'AVG')
			addMDLine('-', '-', '-')
		}
		addMDLine(test, impl, `${avg}ms`)
		return passThrough
	}
}

function addFail(test, impl) {
	return function(error) {
		addMDLine(test, impl, 'failed: '+error.toString())
	}
}

function waitFor(time) {
	return function(passThrough) {
		return new Promise(function(resolve, reject){
			setTimeout(function(){
				resolve(passThrough)
			}, time)
		})
	}
}

function test(opts) {
	return function setup(){
		var input = []

		for(var j = 0; j < opts.inCount; j++) {
			var buf = Buffer.alloc(opts.inSize)
			for (var i = 0; i < opts.inSize; i++) buf[i] = 'a'.charCodeAt(0)
			input.push(buf)
		}

		return {
			input: input,
			blockSize: opts.blockSize,
			results: []
		}
	}
}

function runWith(blockImpl, results){
	return function(context) {
		return new Promise(function(resolve, reject){
			var start = Date.now()
			pull(
				pull.values(context.input),
				blockImpl(context.blockSize),
				pull.onEnd(function(){
					results.push(Date.now() - start)
					resolve(context)
				})
			)
		})
	}
}

function teardown(context) {
	context.input.forEach(function(b){
		delete b
	})
	delete context.input
	return context
}

function runTests(){
	q = q
	.then(showButton(false))
	.then(clearResults)

	for (var testKey in tests) {
		var test = tests[testKey]
		var context = null

		q = q
		.then(setCurrent('Setting up '+testKey+' test'))
		.then(wait.beforeSetup)
		.then(test)
		.then(function(c){
			// Keep a reference to the setup, in case of errors.
			context = c
			return c
		})
		.then(wait.afterSetup)

		for (var implKey in implementations){
			var blockImpl = implementations[implKey]
			var results = []

			for (var r = 1; r <= repeat; r++){
				q = q
				q = q.then(setCurrent('Running '+testKey+' with '+implKey+' ['+r+'/'+repeat+']'))
				.then(runWith(blockImpl, results))
				.then(wait.afterRun)
			}

			q = q
			.then(addResult(testKey, implKey, results))
			.catch(addFail(testKey, implKey, context))
			.then(function(c){ return c || context })
		}

		q = q.then(teardown)
	}

	q = q
	.then(setCurrent('Tests completed'))
	.then(showButton(true))
}<|endoftext|>


<commit_before>// @flow

export default class FooBar {
	constructor() {
		console.log("FooBar made!");
	}

	foo() {
		console.log("Foo!");
	}
}<commit_msg>Trivial change to get Travis/Coveralls to build<commit_after>// @flow

export default class FooBar {
	constructor() {
		console.log("FooBar constructed!");
	}

	foo() {
		console.log("Foo!");
	}
}<|endoftext|>


<commit_before>// cheap way of doing AA
c.width = 192, c.height = 108; // 16:9 aspect ratio

f = new AudioContext;
a = f.createScriptProcessor(0x200, t = 1, K = 1);
a.connect(f.destination);

// music
X = a.onaudioprocess = audioEvent => {
  L = audioEvent.outputBuffer.getChannelData(i=0);
  //R = audioEvent.outputBuffer.getChannelData(1);

  //L.map((sample, i) => {
  for(;i++<0x200;) {
  //for(;i++<L.length;) {
    // TODO: golf
    // debug: set Math.max(x <- to 0 when done
    /*
    X = Math.max(0., Math.min(
      -Math.abs(++t/5e5 - 5) + 5,
    1e0)) // 5 = demo length
    */
    //X = t/1e5
    //if(!i) console.log(X);
    ++t;
    X = 1 // debug

    // sequencer thing
    S=(notes,octave,rate,len) =>
      31 & t * Math.pow(2, notes[(t>>rate)%len] / 12 - octave)
    // version which supports whitespace for silence
      // notes.charCodeAt((t>>rate)%len) - 32 // Is the note a whitespace?
      //   ? 31 & t * Math.pow(2, notes.charCodeAt((t>>rate)%len) / 12 - octave)
      //   : 0

    // kick drum with variation
    L[i] = (((K=1e4/(t&0x3fff*(
      (t>>15)%16 - 15 ? 1 : 0.75
    )))&1)*35)

    // bass
    + (S('7050',4,17,4)&0xff) / K;

    L[i] *= !(t>>22);
    //R[i] = L[i];

    // hihat envelope TODO: golf
    //E=Math.min(1, (1e1/((t>>5)%0x80))) * 0.2;
    E=Math.min(0.2, (1e1/((t>>3)%512)));
    //if (i<2) console.log(t>>1);

    // LEFT CHANNEL
    // hihat
    L[i] += (((t%100)*(t%100)*(t>>5))&0x80)*E * !!(t>>19)
    // sierpinski thing
    //+ ((t*(t>>11))&0x80)*E * !!(t>>20)
    //+ ((t*(t>>11))&128)*E * !!(t>>20)
    // arpeggio
    //+ (!!(t/4&0x1000)*S((t>>17)%2 ? '027' : '037',1,11,3)*(0x1000-(t&0xfff))>>11) / K * !!(t>>21);
    + (!!(t/4&0x1000)*S((t>>17)%2 ? '027' : '037',1,10,4)) / K * !!(t>>21);
    //+ (t/4&4096?S((t>>17)%2 ? '027' : '037',5,11,3)*(4096-(t&4095))>>11 : 0) / K * !!(t>>21);

    // RIGHT CHANNEL
    // hihat
    /*
    R[i] += (((t%100)*(t%100)*(t>>4))&128)*E * !!(t>>19)
    // sierpinski thing
    + ((t*(t>>12))&128)*E * !!(t>>20)
    // arpeggio
    + (!!(t/4&4096)*S((t>>17)%2 ? '072' : '073',1,11,3)*(4096-(t&4095))>>11) / K * !!(t>>21);
    //+ (t/4&4096?S((t>>17)%2 ? '072' : '073',5,11,3)*(4096-(t&4095))>>11 : 0) / K * !!(t>>21);
    */

    L[i] *= X / 200;
    //R[i] *= X / 200;
    //if (L[i] > 1 || R[i] > 1) console.log('clipping');

    //i; // *something* in the prod build removes i without this line: WTF TODO

    // limit volume while testing
    //L[i] = Math.max(-0.5, Math.min(0.5, L[i]));
    //R[i] = Math.max(-0.5, Math.min(0.5, R[i]));
  }
}

// gfx
g=c.getContext`webgl`;
P = g.createProgram();

// NOTE: 2nd argument to drawArrays used to be 0, but undefined works
r = time => g.drawArrays(g.TRIANGLE_FAN,
  // Send resolution and time to shader
  g.uniform4f(g.getUniformLocation(P, 'a'), c.width, c.height, time / 1e3, X),
  3,
  g.uniform4f(g.getUniformLocation(P, 'b'), 1, 0, .2/K, requestAnimationFrame(r))
);

// vertex shader
g.shaderSource(S=g.createShader(g.VERTEX_SHADER), require('./vertex.glsl'));
g.compileShader(S);g.attachShader(P,S);

// fragment shader
g.shaderSource(S=g.createShader(g.FRAGMENT_SHADER), require('./fragment.glsl'));
g.compileShader(S);g.attachShader(P,S);

// Log compilation errors
// if (!getShaderParameter(S, 35713)) { // COMPILE_STATUS = 35713
//   throw getShaderInfoLog(S);
// }

g.bindBuffer(g.ARRAY_BUFFER, g.createBuffer(c.parentElement.style.margin = 0));
// 1st argument to enableVertexAttribArray used to be 0, but undefined works
// 1st argument to vertexAttribPointer used to be 0, but undefined works
g.vertexAttribPointer(
  g.enableVertexAttribArray(
    g.bufferData(g.ARRAY_BUFFER, Int8Array.of(-3, 1, 1, -3, 1, 1), g.STATIC_DRAW)
  ),
2, g.BYTE, r(c.style.height = '100vh'), g.linkProgram(P), g.useProgram(P));
<commit_msg>awesome arpeggio<commit_after>// cheap way of doing AA
c.width = 192, c.height = 108; // 16:9 aspect ratio

f = new AudioContext;
a = f.createScriptProcessor(0x200, t = 1, K = 1);
a.connect(f.destination);

// music debug
//t= 1744100
//t= 3744100
//t= 4744100

// music
X = a.onaudioprocess = audioEvent => {
  L = audioEvent.outputBuffer.getChannelData(i=0);
  //R = audioEvent.outputBuffer.getChannelData(1);

  //L.map((sample, i) => {
  for(;i++<0x200;) {
  //for(;i++<L.length;) {
    // TODO: golf
    // debug: set Math.max(x <- to 0 when done
    /*
    X = Math.max(0., Math.min(
      -Math.abs(++t/5e5 - 5) + 5,
    1e0)) // 5 = demo length
    */
    //X = t/1e5
    //if(!i) console.log(X);
    ++t;
    X = 1 // debug

    // sequencer thing
    S=(notes,octave,rate,len) =>
      31 & t * Math.pow(2, notes[(t>>rate)%len] / 12 - octave)
    // version which supports whitespace for silence
      // notes.charCodeAt((t>>rate)%len) - 32 // Is the note a whitespace?
      //   ? 31 & t * Math.pow(2, notes.charCodeAt((t>>rate)%len) / 12 - octave)
      //   : 0

    // kick drum with variation
    L[i] = (((K=1e4/(t&0x3fff*(
      (t>>15)%16 - 15 ? 1 : 0.75
    )))&1)*35)

    // bass
    + (S('7050',4,17,4)&0xff) / K;

    L[i] *= !(t>>22);
    //R[i] = L[i];

    // hihat envelope TODO: golf
    //E=Math.min(1, (1e1/((t>>5)%0x80))) * 0.2;
    E=Math.min(0.2, (1e1/((t>>3)%512)));
    if (i<2) console.log(t>>15);

    // LEFT CHANNEL
    // hihat
    L[i] += (((t%100)*(t%100)*(t>>5))&0x80)*E * !!(t>>19)
    // sierpinski thing
    //+ ((t*(t>>11))&0x80)*E * !!(t>>20)
    //+ ((t*(t>>11))&128)*E * !!(t>>20)
    // arpeggio
    //+ (!!(t/4&0x1000)*S((t>>17)%2 ? '027' : '037',1,11,3)*(0x1000-(t&0xfff))>>11) / K// * !!(t>>21);
    //+ (!!(t&300)*S((t>>17)%2 ? '027' : '037',1,12,4)) / K// * !!(t>>21);
    + (S((t>>17)%2 ? '027' : '037',1,13-(3*(t>>20)%12),4)) / K * !!(t>>20);
    //+ (t/4&4096?S((t>>17)%2 ? '027' : '037',5,11,3)*(4096-(t&4095))>>11 : 0) / K * !!(t>>21);

    // RIGHT CHANNEL
    // hihat
    /*
    R[i] += (((t%100)*(t%100)*(t>>4))&128)*E * !!(t>>19)
    // sierpinski thing
    + ((t*(t>>12))&128)*E * !!(t>>20)
    // arpeggio
    + (!!(t/4&4096)*S((t>>17)%2 ? '072' : '073',1,11,3)*(4096-(t&4095))>>11) / K * !!(t>>21);
    //+ (t/4&4096?S((t>>17)%2 ? '072' : '073',5,11,3)*(4096-(t&4095))>>11 : 0) / K * !!(t>>21);
    */

    L[i] *= X / 200;
    //R[i] *= X / 200;
    //if (L[i] > 1 || R[i] > 1) console.log('clipping');

    //i; // *something* in the prod build removes i without this line: WTF TODO

    // limit volume while testing
    //L[i] = Math.max(-0.5, Math.min(0.5, L[i]));
    //R[i] = Math.max(-0.5, Math.min(0.5, R[i]));
  }
}

// gfx
g=c.getContext`webgl`;
P = g.createProgram();

// NOTE: 2nd argument to drawArrays used to be 0, but undefined works
r = time => g.drawArrays(g.TRIANGLE_FAN,
  // Send resolution and time to shader
  g.uniform4f(g.getUniformLocation(P, 'a'), c.width, c.height, time / 1e3, X),
  3,
  g.uniform4f(g.getUniformLocation(P, 'b'), 1, 0, .2/K, requestAnimationFrame(r))
);

// vertex shader
g.shaderSource(S=g.createShader(g.VERTEX_SHADER), require('./vertex.glsl'));
g.compileShader(S);g.attachShader(P,S);

// fragment shader
g.shaderSource(S=g.createShader(g.FRAGMENT_SHADER), require('./fragment.glsl'));
g.compileShader(S);g.attachShader(P,S);

// Log compilation errors
// if (!getShaderParameter(S, 35713)) { // COMPILE_STATUS = 35713
//   throw getShaderInfoLog(S);
// }

g.bindBuffer(g.ARRAY_BUFFER, g.createBuffer(c.parentElement.style.margin = 0));
// 1st argument to enableVertexAttribArray used to be 0, but undefined works
// 1st argument to vertexAttribPointer used to be 0, but undefined works
g.vertexAttribPointer(
  g.enableVertexAttribArray(
    g.bufferData(g.ARRAY_BUFFER, Int8Array.of(-3, 1, 1, -3, 1, 1), g.STATIC_DRAW)
  ),
2, g.BYTE, r(c.style.height = '100vh'), g.linkProgram(P), g.useProgram(P));
<|endoftext|>


<commit_before>/**
 * A layer to abstract the differences between using different types of
 * authentication (Oauth vs. Basic). The Authenticator is responsible for
 * establishing credentials and applying them to outgoing requests.
 * @constructor
 */
function Authenticator() {
}

/**
 * @param {Object} request The request to modify, for the `request` library.
 * @return {Object} The `request` parameter, modified to include authentication
 *     information using the stored credentials.
 */
Authenticator.prototype.authenticateRequest = function(request) {
  throw new Error('not implemented');
};

/**
 * Establishes credentials. If credentials could be out of date and it is
 * possible to refresh them, does so.
 *
 * @return {Promise} Resolves when credentials have been successfully
 *     established and `authenticateRequest` calls can expect to succeed.
 */
Authenticator.prototype.ensureCredentials = function() {
  throw new Error('not implemented');
};

module.exports = Authenticator;
<commit_msg>Fixing lint issues<commit_after>/**
 * A layer to abstract the differences between using different types of
 * authentication (Oauth vs. Basic). The Authenticator is responsible for
 * establishing credentials and applying them to outgoing requests.
 * @constructor
 */
function Authenticator() {
}

/**
 * @param {Object} request The request to modify, for the `request` library.
 * @return {Object} The `request` parameter, modified to include authentication
 *     information using the stored credentials.
 */
Authenticator.prototype.authenticateRequest = function(request) {
  throw new Error('not implemented' + JSON.stringify(request));
};

/**
 * Establishes credentials. If credentials could be out of date and it is
 * possible to refresh them, does so.
 *
 * @return {Promise} Resolves when credentials have been successfully
 *     established and `authenticateRequest` calls can expect to succeed.
 */
Authenticator.prototype.ensureCredentials = function() {
  throw new Error('not implemented');
};

module.exports = Authenticator;
<|endoftext|>


<commit_before>class GoogleVision {
	constructor() {
		this.storage = Npm.require('@google-cloud/storage');
		this.vision = Npm.require('@google-cloud/vision');
		this.storageClient = {};
		this.visionClient = {};
		this.enabled = RocketChat.settings.get('GoogleVision_Enable');
		this.serviceAccount = {};
		RocketChat.settings.get('GoogleVision_Enable', (key, value) => {
			this.enabled = value;
		});
		RocketChat.settings.get('GoogleVision_ServiceAccount', (key, value) => {
			try {
				this.serviceAccount = JSON.parse(value);
				this.storageClient = this.storage({ credentials: this.serviceAccount });
				this.visionClient = this.vision({ credentials: this.serviceAccount });
			} catch (e) {
				this.serviceAccount = {};
			}
		});
		RocketChat.settings.get('GoogleVision_Block_Adult_Images', (key, value) => {
			if (value) {
				RocketChat.callbacks.add('beforeSaveMessage', this.blockUnsafeImages.bind(this), RocketChat.callbacks.priority.MEDIUM, 'googlevision-blockunsafe');
			} else {
				RocketChat.callbacks.remove('beforeSaveMessage', 'googlevision-blockunsafe');
			}
		});
		RocketChat.callbacks.add('afterFileUpload', this.annotate.bind(this));
	}

	incCallCount(count) {
		const currentMonth = new Date().getMonth();
		const maxMonthlyCalls = RocketChat.settings.get('GoogleVision_Max_Monthly_Calls') || 0;
		if (maxMonthlyCalls > 0) {
			if (RocketChat.settings.get('GoogleVision_Current_Month') !== currentMonth) {
				RocketChat.settings.set('GoogleVision_Current_Month', currentMonth);
				if (count > maxMonthlyCalls) {
					return false;
				}
			} else if (count + (RocketChat.settings.get('GoogleVision_Current_Month_Calls') || 0) > maxMonthlyCalls) {
				return false;
			}
		}
		RocketChat.models.Settings.update({ _id: 'GoogleVision_Current_Month_Calls' }, { $inc: { value: count } });
		return true;
	}

	blockUnsafeImages(message) {
		if (this.enabled && this.serviceAccount && message && message.file && message.file._id) {
			const file = RocketChat.models.Uploads.findOne({ _id: message.file._id });
			if (file && file.type && file.type.indexOf('image') !== -1 && file.store === 'googleCloudStorage' && file.googleCloudStorage) {
				if (this.incCallCount(1)) {
					const bucket = this.storageClient.bucket(file.googleCloudStorage.bucket);
					const bucketFile = bucket.file(`${file.googleCloudStorage.path}${file._id}`);
					const results = Meteor.wrapAsync(this.visionClient.detectSafeSearch, this.visionClient)(bucketFile);
					if (results && results.adult === true) {
						delete message.attachments[0];
						const user = RocketChat.models.Users.findOneById(message.u && message.u._id);
						if (user) {
							RocketChat.Notifications.notifyUser(user._id, 'message', {
								_id: Random.id(),
								rid: message.rid,
								ts: new Date,
								msg: TAPi18n.__('Adult_images_are_not_allowed', {}, user.language)
							});
						}
						throw new Error('GoogleVisionError: Image blocked');
					}
				} else {
					console.log('Google Vision: Usage limit exceeded');
				}
				return message;
			}
		}
	}

	annotate({ message }) {
		const visionTypes = [];
		if (RocketChat.settings.get('GoogleVision_Type_Document')) {
			visionTypes.push('document');
		}
		if (RocketChat.settings.get('GoogleVision_Type_Faces')) {
			visionTypes.push('faces');
		}
		if (RocketChat.settings.get('GoogleVision_Type_Landmarks')) {
			visionTypes.push('landmarks');
		}
		if (RocketChat.settings.get('GoogleVision_Type_Labels')) {
			visionTypes.push('labels');
		}
		if (RocketChat.settings.get('GoogleVision_Type_Logos')) {
			visionTypes.push('logos');
		}
		if (RocketChat.settings.get('GoogleVision_Type_Properties')) {
			visionTypes.push('properties');
		}
		if (RocketChat.settings.get('GoogleVision_Type_SafeSearch')) {
			visionTypes.push('safeSearch');
		}
		if (RocketChat.settings.get('GoogleVision_Type_Similar')) {
			visionTypes.push('similar');
		}
		if (this.enabled && this.serviceAccount && visionTypes.length > 0 && message.file && message.file._id) {
			const file = RocketChat.models.Uploads.findOne({ _id: message.file._id });
			if (file && file.type && file.type.indexOf('image') !== -1 && file.store === 'googleCloudStorage' && file.googleCloudStorage) {
				if (this.incCallCount(visionTypes.length)) {
					const bucket = this.storageClient.bucket(file.googleCloudStorage.bucket);
					const bucketFile = bucket.file(`${file.googleCloudStorage.path}${file._id}`);
					this.visionClient.detect(bucketFile, visionTypes, Meteor.bindEnvironment((error, results) => {
						if (!error) {
							RocketChat.models.Messages.setGoogleVisionData(message._id, this.getAnnotations(visionTypes, results));
						} else {
							console.trace('GoogleVision error: ', error.stack);
						}
					}));
				} else {
					console.log('Google Vision: Usage limit exceeded');
				}
			}
		}
	}

	getAnnotations(visionTypes, visionData) {
		if (visionTypes.length === 1) {
			_visionData = {};
			_visionData[`${visionTypes[0]}`] = visionData;
			visionData = _visionData;
		}
		const results = {};
		for (const index in visionData) {
			if (visionData.hasOwnProperty(index)) {
				switch (index) {
					case 'faces':
					case 'landmarks':
					case 'labels':
					case 'similar':
					case 'logos':
						results[index] = (results[index] || []).concat(visionData[index] || []);
						break;
					case 'safeSearch':
						results['safeSearch'] = visionData['safeSearch'];
					case 'properties':
						results['colors'] = visionData[index]['colors'];
						break;
				}
			}
		}
		return results;
	}
}

RocketChat.GoogleVision = new GoogleVision;
<commit_msg>Fix Codacy Issues<commit_after>class GoogleVision {
	constructor() {
		this.storage = Npm.require('@google-cloud/storage');
		this.vision = Npm.require('@google-cloud/vision');
		this.storageClient = {};
		this.visionClient = {};
		this.enabled = RocketChat.settings.get('GoogleVision_Enable');
		this.serviceAccount = {};
		RocketChat.settings.get('GoogleVision_Enable', (key, value) => {
			this.enabled = value;
		});
		RocketChat.settings.get('GoogleVision_ServiceAccount', (key, value) => {
			try {
				this.serviceAccount = JSON.parse(value);
				this.storageClient = this.storage({ credentials: this.serviceAccount });
				this.visionClient = this.vision({ credentials: this.serviceAccount });
			} catch (e) {
				this.serviceAccount = {};
			}
		});
		RocketChat.settings.get('GoogleVision_Block_Adult_Images', (key, value) => {
			if (value) {
				RocketChat.callbacks.add('beforeSaveMessage', this.blockUnsafeImages.bind(this), RocketChat.callbacks.priority.MEDIUM, 'googlevision-blockunsafe');
			} else {
				RocketChat.callbacks.remove('beforeSaveMessage', 'googlevision-blockunsafe');
			}
		});
		RocketChat.callbacks.add('afterFileUpload', this.annotate.bind(this));
	}

	incCallCount(count) {
		const currentMonth = new Date().getMonth();
		const maxMonthlyCalls = RocketChat.settings.get('GoogleVision_Max_Monthly_Calls') || 0;
		if (maxMonthlyCalls > 0) {
			if (RocketChat.settings.get('GoogleVision_Current_Month') !== currentMonth) {
				RocketChat.settings.set('GoogleVision_Current_Month', currentMonth);
				if (count > maxMonthlyCalls) {
					return false;
				}
			} else if (count + (RocketChat.settings.get('GoogleVision_Current_Month_Calls') || 0) > maxMonthlyCalls) {
				return false;
			}
		}
		RocketChat.models.Settings.update({ _id: 'GoogleVision_Current_Month_Calls' }, { $inc: { value: count } });
		return true;
	}

	blockUnsafeImages(message) {
		if (this.enabled && this.serviceAccount && message && message.file && message.file._id) {
			const file = RocketChat.models.Uploads.findOne({ _id: message.file._id });
			if (file && file.type && file.type.indexOf('image') !== -1 && file.store === 'googleCloudStorage' && file.googleCloudStorage) {
				if (this.incCallCount(1)) {
					const bucket = this.storageClient.bucket(file.googleCloudStorage.bucket);
					const bucketFile = bucket.file(`${file.googleCloudStorage.path}${file._id}`);
					const results = Meteor.wrapAsync(this.visionClient.detectSafeSearch, this.visionClient)(bucketFile);
					if (results && results.adult === true) {
						delete message.attachments[0];
						const user = RocketChat.models.Users.findOneById(message.u && message.u._id);
						if (user) {
							RocketChat.Notifications.notifyUser(user._id, 'message', {
								_id: Random.id(),
								rid: message.rid,
								ts: new Date,
								msg: TAPi18n.__('Adult_images_are_not_allowed', {}, user.language)
							});
						}
						throw new Error('GoogleVisionError: Image blocked');
					}
				} else {
					console.log('Google Vision: Usage limit exceeded');
				}
				return message;
			}
		}
	}

	annotate({ message }) {
		const visionTypes = [];
		if (RocketChat.settings.get('GoogleVision_Type_Document')) {
			visionTypes.push('document');
		}
		if (RocketChat.settings.get('GoogleVision_Type_Faces')) {
			visionTypes.push('faces');
		}
		if (RocketChat.settings.get('GoogleVision_Type_Landmarks')) {
			visionTypes.push('landmarks');
		}
		if (RocketChat.settings.get('GoogleVision_Type_Labels')) {
			visionTypes.push('labels');
		}
		if (RocketChat.settings.get('GoogleVision_Type_Logos')) {
			visionTypes.push('logos');
		}
		if (RocketChat.settings.get('GoogleVision_Type_Properties')) {
			visionTypes.push('properties');
		}
		if (RocketChat.settings.get('GoogleVision_Type_SafeSearch')) {
			visionTypes.push('safeSearch');
		}
		if (RocketChat.settings.get('GoogleVision_Type_Similar')) {
			visionTypes.push('similar');
		}
		if (this.enabled && this.serviceAccount && visionTypes.length > 0 && message.file && message.file._id) {
			const file = RocketChat.models.Uploads.findOne({ _id: message.file._id });
			if (file && file.type && file.type.indexOf('image') !== -1 && file.store === 'googleCloudStorage' && file.googleCloudStorage) {
				if (this.incCallCount(visionTypes.length)) {
					const bucket = this.storageClient.bucket(file.googleCloudStorage.bucket);
					const bucketFile = bucket.file(`${file.googleCloudStorage.path}${file._id}`);
					this.visionClient.detect(bucketFile, visionTypes, Meteor.bindEnvironment((error, results) => {
						if (!error) {
							RocketChat.models.Messages.setGoogleVisionData(message._id, this.getAnnotations(visionTypes, results));
						} else {
							console.trace('GoogleVision error: ', error.stack);
						}
					}));
				} else {
					console.log('Google Vision: Usage limit exceeded');
				}
			}
		}
	}

	getAnnotations(visionTypes, visionData) {
		if (visionTypes.length === 1) {
			const _visionData = {};
			_visionData[`${visionTypes[0]}`] = visionData;
			visionData = _visionData;
		}
		const results = {};
		for (const index in visionData) {
			if (visionData.hasOwnProperty(index)) {
				switch (index) {
					case 'faces':
					case 'landmarks':
					case 'labels':
					case 'similar':
					case 'logos':
						results[index] = (results[index] || []).concat(visionData[index] || []);
						break;
					case 'safeSearch':
						results['safeSearch'] = visionData['safeSearch'];
						break;
					case 'properties':
						results['colors'] = visionData[index]['colors'];
						break;
				}
			}
		}
		return results;
	}
}

RocketChat.GoogleVision = new GoogleVision;
<|endoftext|>


<commit_before>import React, {Component} from 'react';
import PropTypes from 'prop-types'
import {View, StyleSheet, Animated} from 'react-native';

//import Expo, { Svg } from 'expo';
import Svg, {
    Circle,
    ClipPath,
    G,
    LinearGradient,
    Rect,
    Defs,
    Stop
}  from 'react-native-svg';

const AnimatedSvg = Animated.createAnimatedComponent(Svg);
const {interpolate} = require('d3-interpolate');

export default class SvgAnimatedLinearGradient extends Component {
    constructor(props) {
        super(props);

        this.state = {
            offsetValues: [
                '-2', '-1.5', '-1'
            ],
            offsets: [
                '0.0001', '0.0002', '0.0003' // Avoid duplicate value cause error in Android
            ],
            frequence: props.duration / 2
        }
        this._isMounted = false;
        this._animate = new Animated.Value(0)
        this.loopAnimation = this
            .loopAnimation
            .bind(this)
    }
    offsetValueBound(x) {
        if (x > 1) {
            return '1'
        }
        if (x < 0) {
            return '0'
        }
        return x
    }
    componentDidMount(props) {
        this._isMounted = true
        this.loopAnimation()
    }
    componentWillUnmount() {
        this._isMounted = false
    }
    loopAnimation() {
        if (!this._isMounted) return;
        // setup interpolate
        let interpolator = interpolate(this.state, {
            offsetValues: ['1', '1.5', '2']
        });

        // start animation
        let start = Date.now();
        this._animation = () => {
            const now = Date.now();
            let t = (now - start) / this.props.duration;
            if (t > 1) {
                t = 1
            }

            let newState = interpolator(t);
            let offsetValues = [];
            offsetValues[0] = this.offsetValueBound(newState.offsetValues[0]);
            offsetValues[1] = this.offsetValueBound(newState.offsetValues[1]);
            offsetValues[2] = this.offsetValueBound(newState.offsetValues[2]);

            // Make sure at least two offsets is different
            if (offsetValues[0] !== offsetValues[1] || offsetValues[0] !==  offsetValues[2] || offsetValues[1] !== offsetValues[2]) {
                this._isMounted && this.setState({offsets: offsetValues});
            }
            if (t < 1) {
                requestAnimationFrame(this._animation);
            }
        }
        requestAnimationFrame(this._animation);

        // Setup loop animation
        Animated.sequence([
            Animated.timing(this._animate, {
                toValue: 1,
                duration: this.state.frequence
            }),
            Animated.timing(this._animate, {
                toValue: 0,
                duration: this.state.frequence
            })
        ]).start((event) => {
            if (event.finished) {
                this.loopAnimation()
            }
        })
    }
    render() {

        return (
            <AnimatedSvg {...this.props}>
                <Defs>
                    <LinearGradient id="grad" x1={this.props.x1} y1={this.props.y1} x2={this.props.x2} y2={this.props.y2}>
                        <Stop
                            offset={this.state.offsets[0]}
                            stopColor={this.props.primaryColor}
                            stopOpacity="1"/>
                        <Stop
                            offset={this.state.offsets[1]}
                            stopColor={this.props.secondaryColor}
                            stopOpacity="1"/>
                        <Stop
                            offset={this.state.offsets[2]}
                            stopColor={this.props.primaryColor}
                            stopOpacity="1"/>
                    </LinearGradient>
                    <ClipPath id="clip">
                        <G>
                            {this.props.children}
                        </G>
                    </ClipPath>
                </Defs>

                <Rect
                    x="0"
                    y="0"
                    height={this.props.height}
                    width={this.props.width}
                    fill="url(#grad)"
                    clipPath="url(#clip)"/>
            </AnimatedSvg>
        );
    }
}
SvgAnimatedLinearGradient.propTypes = {
    primaryColor: PropTypes.string,
    secondaryColor: PropTypes.string,
    duration: PropTypes.number,
    width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
    height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
    x1: PropTypes.string,
    y1: PropTypes.string,
    x2: PropTypes.string,
    y2: PropTypes.string,
}
SvgAnimatedLinearGradient.defaultProps = {
    primaryColor: '#eeeeee',
    secondaryColor: '#dddddd',
    duration: 2000,
    width: 300,
    height: 200,
    x1: '0',
    y1: '0',
    x2: '100%',
    y2: '0'

}
<commit_msg>settable offset value<commit_after>import React, {Component} from 'react';
import PropTypes from 'prop-types'
import {View, StyleSheet, Animated} from 'react-native';

//import Expo, { Svg } from 'expo';
import Svg, {
    Circle,
    ClipPath,
    G,
    LinearGradient,
    Rect,
    Defs,
    Stop
}  from 'react-native-svg';

const AnimatedSvg = Animated.createAnimatedComponent(Svg);
const {interpolate} = require('d3-interpolate');

export default class SvgAnimatedLinearGradient extends Component {
    constructor(props) {
        super(props);

        const initialOffsetValues = props.offset
            ? [1, 1 + props.offset / 2, 1 + props.offset]
            : [1, 1.5, 2];
        this.state = {
            initialOffsetValues,
            offsetValues: [...initialOffsetValues].reverse().map(v => String(v * -1)),
            offsets: [
                '0.0001', '0.0002', '0.0003' // Avoid duplicate value cause error in Android
            ],
            frequence: props.duration / 2
        }
        this._isMounted = false;
        this._animate = new Animated.Value(0)
        this.loopAnimation = this
            .loopAnimation
            .bind(this)
    }
    offsetValueBound(x) {
        if (x > 1) {
            return '1'
        }
        if (x < 0) {
            return '0'
        }
        return x
    }
    componentDidMount(props) {
        this._isMounted = true
        this.loopAnimation()
    }
    componentWillUnmount() {
        this._isMounted = false
    }
    loopAnimation() {
        if (!this._isMounted) return;
        // setup interpolate
        let interpolator = interpolate(this.state, {
            offsetValues: this.state.initialOffsetValues.map(v => String(v))
        });

        // start animation
        let start = Date.now();
        this._animation = () => {
            const now = Date.now();
            let t = (now - start) / this.props.duration;
            if (t > 1) {
                t = 1
            }

            let newState = interpolator(t);
            let offsetValues = [];
            offsetValues[0] = this.offsetValueBound(newState.offsetValues[0]);
            offsetValues[1] = this.offsetValueBound(newState.offsetValues[1]);
            offsetValues[2] = this.offsetValueBound(newState.offsetValues[2]);

            // Make sure at least two offsets is different
            if (offsetValues[0] !== offsetValues[1] || offsetValues[0] !==  offsetValues[2] || offsetValues[1] !== offsetValues[2]) {
                this._isMounted && this.setState({offsets: offsetValues});
            }
            if (t < 1) {
                requestAnimationFrame(this._animation);
            }
        }
        requestAnimationFrame(this._animation);

        // Setup loop animation
        Animated.sequence([
            Animated.timing(this._animate, {
                toValue: 1,
                duration: this.state.frequence
            }),
            Animated.timing(this._animate, {
                toValue: 0,
                duration: this.state.frequence
            })
        ]).start((event) => {
            if (event.finished) {
                this.loopAnimation()
            }
        })
    }
    render() {

        return (
            <AnimatedSvg {...this.props}>
                <Defs>
                    <LinearGradient id="grad" x1={this.props.x1} y1={this.props.y1} x2={this.props.x2} y2={this.props.y2}>
                        <Stop
                            offset={this.state.offsets[0]}
                            stopColor={this.props.primaryColor}
                            stopOpacity="1"/>
                        <Stop
                            offset={this.state.offsets[1]}
                            stopColor={this.props.secondaryColor}
                            stopOpacity="1"/>
                        <Stop
                            offset={this.state.offsets[2]}
                            stopColor={this.props.primaryColor}
                            stopOpacity="1"/>
                    </LinearGradient>
                    <ClipPath id="clip">
                        <G>
                            {this.props.children}
                        </G>
                    </ClipPath>
                </Defs>

                <Rect
                    x="0"
                    y="0"
                    height={this.props.height}
                    width={this.props.width}
                    fill="url(#grad)"
                    clipPath="url(#clip)"/>
            </AnimatedSvg>
        );
    }
}
SvgAnimatedLinearGradient.propTypes = {
    primaryColor: PropTypes.string,
    secondaryColor: PropTypes.string,
    duration: PropTypes.number,
    width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
    height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
    x1: PropTypes.string,
    y1: PropTypes.string,
    x2: PropTypes.string,
    y2: PropTypes.string,
}
SvgAnimatedLinearGradient.defaultProps = {
    primaryColor: '#eeeeee',
    secondaryColor: '#dddddd',
    duration: 2000,
    width: 300,
    height: 200,
    x1: '0',
    y1: '0',
    x2: '100%',
    y2: '0',
    offset: 1,
}
<|endoftext|>


<commit_before>import React from 'react';
import { Link, IndexLink } from 'react-router'
import {connect} from 'react-redux'
import FloatingActionButton from 'material-ui/FloatingActionButton'
import NavigationArrowBack from 'material-ui/svg-icons/navigation/arrow-back';
import NavigationArrowForward from 'material-ui/svg-icons/navigation/arrow-forward';
import NavigationCheck from 'material-ui/svg-icons/navigation/check';
import ExportAOI, {MODE_DRAW_BBOX, MODE_NORMAL} from './ExportAOI'
import ExportInfo from './ExportInfo'
import ExportSummary from './ExportSummary'
import { createExportRequest, getProviders, stepperNextDisabled,
    stepperNextEnabled, exportInfoDone, submitJob, clearAoiInfo, clearExportInfo} from '../actions/exportsActions'
import  isEqual from 'lodash/isEqual';
import {browserHistory} from 'react-router';

export class BreadcrumbStepper extends React.Component {
    constructor() {
        super();
        this.getStepLabel = this.getStepLabel.bind(this);
        this.handleNext = this.handleNext.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
        this.handlePrev = this.handlePrev.bind(this);
        this.state = {
            stepIndex: 0,
        };
    }

    componentDidMount(){
        this.props.getProviders();
        this.props.setNextDisabled();
    }

    componentWillUnmount() {
        this.props.clearAoiInfo();
        this.props.clearExportInfo();
    }

    handleSubmit() {
        let provider_tasks = [];
        const providers = this.props.exportInfo.providers;

        //TODO: Set formats up as an array for future need of other formats other than geopackage!
        for(let provider in providers){
            provider_tasks.push({'provider': providers[provider], 'formats': ['gpkg']});
        }

        const data = {
            name: this.props.exportInfo.exportName,
            description: this.props.exportInfo.datapackDescription,
            event: this.props.exportInfo.projectName,
            include_zipfile : false,
            published : this.props.exportInfo.makePublic,
            provider_tasks : provider_tasks,
            selection: this.props.aoiInfo.geojson,
            tags : [],
        };
        this.props.submitJob(data);
        browserHistory.push('/');
    }

    handleNext() {
        const {stepIndex} = this.state;
        if (stepIndex == 1) {
            this.props.setExportInfoDone();
        }
        else {
            this.setState({stepIndex: stepIndex + 1});
        }
    };

    incrementStepper() {
        const {stepIndex} = this.state;
        this.setState({stepIndex: stepIndex + 1});
    }

    handlePrev() {
        const {stepIndex} = this.state;
        if (stepIndex > 0) {
            this.setState({stepIndex: stepIndex - 1});
        }
    };

    getStepLabel(stepIndex) {
        const labelStyle = {
            color: 'white',
            height: '50px',
            minWidth: '200px',
            display: 'inline-block',
            lineHeight: '50px',
            marginLeft: '24px'
        };

        switch(stepIndex) {
            case 0:
                return

                            STEP 1 OF 3:  Define Area of Interest

;
            case 1:
                return

                            STEP 2 OF 3:  Select Data & Formats

;
            case 2:
                return

                            STEP 3 OF 3:  Review & Submit

;
            default:
                return

                            STEPPER ERROR

;
        }
    }

    getStepContent(stepIndex) {
        switch (stepIndex) {
            case 0:
                return <ExportAOI/>;
            case 1:
                return <ExportInfo providers={this.props.providers}
                                    incrementStepper={this.incrementStepper}/>
            case 2:
                return <ExportSummary/>
            default:
                return <ExportAOI/>;
        }
    }

    getButtonContent(stepIndex) {
        const btnStyles = {
            submit: {
                color: 'black',
                marginRight: '12px',
                verticalAlign: 'middle',
                boxShadow: 'none',
                transition: 'none'
            },
            forward: {
                marginRight: '12px',
                verticalAlign: 'middle',
                boxShadow: 'none',
                transition: 'none'
            }
        };

        switch (stepIndex) {
            case 0:
                return <FloatingActionButton mini={true}
                            disabled={!this.props.stepperNextEnabled}
                            backgroundColor={'#55ba63'}
                            onClick={this.handleNext}
                            style={btnStyles.forward} >
                                <NavigationArrowForward/>
                        </FloatingActionButton>
            case 1:
                return <FloatingActionButton mini={true}
                            disabled={!this.props.stepperNextEnabled}
                            backgroundColor={'#55ba63'}
                            onClick={this.handleNext}
                            style={btnStyles.forward}>
                                <NavigationArrowForward/>
                        </FloatingActionButton>
            case 2:
                return <FloatingActionButton mini={false}
                            disabled={!this.props.stepperNextEnabled}
                            backgroundColor={'#55ba63'}
                            onClick={this.handleSubmit}
                            style={btnStyles.submit}>
                                <NavigationCheck/>
                        </FloatingActionButton>
            default:
                return
;
        }
    }

    render() {
        const { createExportRequest } = this.props
        const {stepIndex} = this.state;
        const styles = {
            stepper: {
                backgroundColor: '#161e2e',
                height: '35px',
                fontColor: 'white',
                fontFamily: 'Roboto',
                zIndex: 1,
            },
            stepLabel: {
                color: 'white',
                fontSize: '18px',
            },
            arrowBack: {
                fill: stepIndex == 0 ? '#e2e2e2' : '#4598bf',
                opacity: stepIndex == 0 ? '0.3' : '1',
                cursor: stepIndex == 0 ? 'default' : 'pointer',
                verticalAlign: 'middle',
                marginRight: '10px',
            },
        };

        return (

                    {this.getStepLabel(this.state.stepIndex)}

                        <NavigationArrowBack
                            style={styles.arrowBack}
                            onClick={this.handlePrev}
                        />
                        {this.getButtonContent(this.state.stepIndex)}

                {this.getStepContent(this.state.stepIndex)}

        );
    }
}

BreadcrumbStepper.propTypes = {
    aoiInfo: React.PropTypes.object,
    providers: React.PropTypes.array,
    stepperNextEnabled: React.PropTypes.bool,
    exportInfo: React.PropTypes.object,
    createExportRequest: React.PropTypes.func.isRequired,
    submitJob: React.PropTypes.func,
    getProviders: React.PropTypes.func,
    setNextDisabled: React.PropTypes.func,
    setNextEnabled: React.PropTypes.func,
    setExportInfoDone: React.PropTypes.func,
    clearAoiInfo: React.PropTypes.func,
    clearExportInfo: React.PropTypes.func,
};

function mapStateToProps(state) {
    return {
        aoiInfo: state.aoiInfo,
        providers: state.providers,
        stepperNextEnabled: state.stepperNextEnabled,
        exportInfo: state.exportInfo,
    };
}
function mapDispatchToProps(dispatch) {
    return {
        createExportRequest: () => {
            dispatch(createExportRequest());
        },
        submitJob: (data) => {
            dispatch(submitJob(data))
        },
        getProviders: () => {
            dispatch(getProviders())
        },
        setNextDisabled: () => {
            dispatch(stepperNextDisabled());
        },
        setNextEnabled: () => {
            dispatch(stepperNextEnabled());
        },
        setExportInfoDone: () => {
            dispatch(exportInfoDone());
        },
        clearAoiInfo: () => {
            dispatch(clearAoiInfo());
        },
        clearExportInfo: () => {
            dispatch(clearExportInfo());
        }
    }
}

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(BreadcrumbStepper);
<commit_msg>bind incrementStepper<commit_after>import React from 'react';
import { Link, IndexLink } from 'react-router'
import {connect} from 'react-redux'
import FloatingActionButton from 'material-ui/FloatingActionButton'
import NavigationArrowBack from 'material-ui/svg-icons/navigation/arrow-back';
import NavigationArrowForward from 'material-ui/svg-icons/navigation/arrow-forward';
import NavigationCheck from 'material-ui/svg-icons/navigation/check';
import ExportAOI, {MODE_DRAW_BBOX, MODE_NORMAL} from './ExportAOI'
import ExportInfo from './ExportInfo'
import ExportSummary from './ExportSummary'
import { createExportRequest, getProviders, stepperNextDisabled,
    stepperNextEnabled, exportInfoDone, submitJob, clearAoiInfo, clearExportInfo} from '../actions/exportsActions'
import  isEqual from 'lodash/isEqual';
import {browserHistory} from 'react-router';

export class BreadcrumbStepper extends React.Component {
    constructor() {
        super();
        this.getStepLabel = this.getStepLabel.bind(this);
        this.handleNext = this.handleNext.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
        this.handlePrev = this.handlePrev.bind(this);
        this.incrementStepper = this.incrementStepper.bind(this);
        this.state = {
            stepIndex: 0,
        };
    }

    componentDidMount(){
        this.props.getProviders();
        this.props.setNextDisabled();
    }

    componentWillUnmount() {
        this.props.clearAoiInfo();
        this.props.clearExportInfo();
    }

    handleSubmit() {
        let provider_tasks = [];
        const providers = this.props.exportInfo.providers;

        //TODO: Set formats up as an array for future need of other formats other than geopackage!
        for(let provider in providers){
            provider_tasks.push({'provider': providers[provider], 'formats': ['gpkg']});
        }

        const data = {
            name: this.props.exportInfo.exportName,
            description: this.props.exportInfo.datapackDescription,
            event: this.props.exportInfo.projectName,
            include_zipfile : false,
            published : this.props.exportInfo.makePublic,
            provider_tasks : provider_tasks,
            selection: this.props.aoiInfo.geojson,
            tags : [],
        };
        this.props.submitJob(data);
        browserHistory.push('/');
    }

    handleNext() {
        const {stepIndex} = this.state;
        if (stepIndex == 1) {
            this.props.setExportInfoDone();
        }
        else {
            this.setState({stepIndex: stepIndex + 1});
        }
    };

    incrementStepper() {
        const {stepIndex} = this.state;
        this.setState({stepIndex: stepIndex + 1});
    }

    handlePrev() {
        const {stepIndex} = this.state;
        if (stepIndex > 0) {
            this.setState({stepIndex: stepIndex - 1});
        }
    };

    getStepLabel(stepIndex) {
        const labelStyle = {
            color: 'white',
            height: '50px',
            minWidth: '200px',
            display: 'inline-block',
            lineHeight: '50px',
            marginLeft: '24px'
        };

        switch(stepIndex) {
            case 0:
                return

                            STEP 1 OF 3:  Define Area of Interest

;
            case 1:
                return

                            STEP 2 OF 3:  Select Data & Formats

;
            case 2:
                return

                            STEP 3 OF 3:  Review & Submit

;
            default:
                return

                            STEPPER ERROR

;
        }
    }

    getStepContent(stepIndex) {
        switch (stepIndex) {
            case 0:
                return <ExportAOI/>;
            case 1:
                return <ExportInfo providers={this.props.providers}
                                    incrementStepper={this.incrementStepper}/>
            case 2:
                return <ExportSummary/>
            default:
                return <ExportAOI/>;
        }
    }

    getButtonContent(stepIndex) {
        const btnStyles = {
            submit: {
                color: 'black',
                marginRight: '12px',
                verticalAlign: 'middle',
                boxShadow: 'none',
                transition: 'none'
            },
            forward: {
                marginRight: '12px',
                verticalAlign: 'middle',
                boxShadow: 'none',
                transition: 'none'
            }
        };

        switch (stepIndex) {
            case 0:
                return <FloatingActionButton mini={true}
                            disabled={!this.props.stepperNextEnabled}
                            backgroundColor={'#55ba63'}
                            onClick={this.handleNext}
                            style={btnStyles.forward} >
                                <NavigationArrowForward/>
                        </FloatingActionButton>
            case 1:
                return <FloatingActionButton mini={true}
                            disabled={!this.props.stepperNextEnabled}
                            backgroundColor={'#55ba63'}
                            onClick={this.handleNext}
                            style={btnStyles.forward}>
                                <NavigationArrowForward/>
                        </FloatingActionButton>
            case 2:
                return <FloatingActionButton mini={false}
                            disabled={!this.props.stepperNextEnabled}
                            backgroundColor={'#55ba63'}
                            onClick={this.handleSubmit}
                            style={btnStyles.submit}>
                                <NavigationCheck/>
                        </FloatingActionButton>
            default:
                return
;
        }
    }

    render() {
        const { createExportRequest } = this.props
        const {stepIndex} = this.state;
        const styles = {
            stepper: {
                backgroundColor: '#161e2e',
                height: '35px',
                fontColor: 'white',
                fontFamily: 'Roboto',
                zIndex: 1,
            },
            stepLabel: {
                color: 'white',
                fontSize: '18px',
            },
            arrowBack: {
                fill: stepIndex == 0 ? '#e2e2e2' : '#4598bf',
                opacity: stepIndex == 0 ? '0.3' : '1',
                cursor: stepIndex == 0 ? 'default' : 'pointer',
                verticalAlign: 'middle',
                marginRight: '10px',
            },
        };

        return (

                    {this.getStepLabel(this.state.stepIndex)}

                        <NavigationArrowBack
                            style={styles.arrowBack}
                            onClick={this.handlePrev}
                        />
                        {this.getButtonContent(this.state.stepIndex)}

                {this.getStepContent(this.state.stepIndex)}

        );
    }
}

BreadcrumbStepper.propTypes = {
    aoiInfo: React.PropTypes.object,
    providers: React.PropTypes.array,
    stepperNextEnabled: React.PropTypes.bool,
    exportInfo: React.PropTypes.object,
    createExportRequest: React.PropTypes.func.isRequired,
    submitJob: React.PropTypes.func,
    getProviders: React.PropTypes.func,
    setNextDisabled: React.PropTypes.func,
    setNextEnabled: React.PropTypes.func,
    setExportInfoDone: React.PropTypes.func,
    clearAoiInfo: React.PropTypes.func,
    clearExportInfo: React.PropTypes.func,
};

function mapStateToProps(state) {
    return {
        aoiInfo: state.aoiInfo,
        providers: state.providers,
        stepperNextEnabled: state.stepperNextEnabled,
        exportInfo: state.exportInfo,
    };
}
function mapDispatchToProps(dispatch) {
    return {
        createExportRequest: () => {
            dispatch(createExportRequest());
        },
        submitJob: (data) => {
            dispatch(submitJob(data))
        },
        getProviders: () => {
            dispatch(getProviders())
        },
        setNextDisabled: () => {
            dispatch(stepperNextDisabled());
        },
        setNextEnabled: () => {
            dispatch(stepperNextEnabled());
        },
        setExportInfoDone: () => {
            dispatch(exportInfoDone());
        },
        clearAoiInfo: () => {
            dispatch(clearAoiInfo());
        },
        clearExportInfo: () => {
            dispatch(clearExportInfo());
        }
    }
}

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(BreadcrumbStepper);
<|endoftext|>


<commit_before>import moment from 'moment';
import s from 'underscore.string';

RocketChat.callbacks.add('afterSaveMessage', function(message, room) {
	// skips this callback if the message was edited
	if (message.editedAt) {
		return message;
	}

	if (message.ts && Math.abs(moment(message.ts).diff()) > 60000) {
		return message;
	}

	const getMessageLink = (room, sub) => {
		const roomPath = RocketChat.roomTypes.getRouteLink(room.t, sub);
		const path = Meteor.absoluteUrl(roomPath ? roomPath.replace(/^\//, '') : '');
		const style = [
			'color: #fff;',
			'padding: 9px 12px;',
			'border-radius: 4px;',
			'background-color: #04436a;',
			'text-decoration: none;'
		].join(' ');
		const message = TAPi18n.__('Offline_Link_Message');
		return `<p style="text-align:center;margin-bottom:8px;"><a style="${ style }" href="${ path }">${ message }</a>`;
	};

	const divisorMessage = '
';
	let messageHTML = s.escapeHTML(message.msg);

	message = RocketChat.callbacks.run('renderMessage', message);
	if (message.tokens && message.tokens.length > 0) {
		message.tokens.forEach((token) => {
			token.text = token.text.replace(/([^\$])(\$[^\$])/gm, '$1$$$2');
			messageHTML = messageHTML.replace(token.token, token.text);
		});
	}

	const header = RocketChat.placeholders.replace(RocketChat.settings.get('Email_Header') || '');
	let footer = RocketChat.placeholders.replace(RocketChat.settings.get('Email_Footer') || '');
	messageHTML = messageHTML.replace(/\n/gm, '
');

	const usersToSendEmail = {};
	if (room.t === 'd') {
		usersToSendEmail[message.rid.replace(message.u._id, '')] = 'direct';
	} else {
		let isMentionAll = message.mentions.find(mention => mention._id === 'all');

		if (isMentionAll) {
			const maxMembersForNotification = RocketChat.settings.get('Notifications_Max_Room_Members');
			if (maxMembersForNotification !== 0 && room.usernames.length > maxMembersForNotification) {
				isMentionAll = undefined;
			}
		}

		let query;
		if (isMentionAll) {
			// Query all users in room limited by the max room members setting
			query = RocketChat.models.Subscriptions.findByRoomId(room._id);
		} else {
			// Query only mentioned users, will be always a few users
			const userIds = message.mentions.map(mention => mention._id);
			query = RocketChat.models.Subscriptions.findByRoomIdAndUserIdsOrAllMessages(room._id, userIds);
		}

		query.forEach((sub) => {
			if (sub.disableNotifications) {
				return delete usersToSendEmail[sub.u._id];
			}

			const emailNotifications = sub.emailNotifications;

			if (emailNotifications === 'nothing') {
				return delete usersToSendEmail[sub.u._id];
			}

			const mentionedUser = isMentionAll || message.mentions.find(mention => mention._id === sub.u._id);

			if (emailNotifications === 'default' || emailNotifications == null) {
				if (mentionedUser) {
					return usersToSendEmail[sub.u._id] = 'default';
				}
				return delete usersToSendEmail[sub.u._id];
			}

			if (emailNotifications === 'mentions' && mentionedUser) {
				return usersToSendEmail[sub.u._id] = 'mention';
			}

			if (emailNotifications === 'all') {
				return usersToSendEmail[sub.u._id] = 'all';
			}
		});
	}
	const userIdsToSendEmail = Object.keys(usersToSendEmail);

	let defaultLink;

	const linkByUser = {};
	if (RocketChat.roomTypes.hasCustomLink(room.t)) {
		RocketChat.models.Subscriptions.findByRoomIdAndUserIds(room._id, userIdsToSendEmail).forEach((sub) => {
			linkByUser[sub.u._id] = getMessageLink(room, sub);
		});
	} else {
		defaultLink = getMessageLink(room, {
			name: room.name
		});
	}

	if (userIdsToSendEmail.length > 0) {
		const usersOfMention = RocketChat.models.Users.getUsersToSendOfflineEmail(userIdsToSendEmail).fetch();

		if (usersOfMention && usersOfMention.length > 0) {
			usersOfMention.forEach((user) => {
				if (usersToSendEmail[user._id] === 'default') {
					if (!user.settings || !user.settings.preferences || !user.settings.preferences.emailNotificationMode || user.settings.preferences.emailNotificationMode === 'all') { //Mention/DM
						usersToSendEmail[user._id] = 'mention';
					} else {
						return;
					}
				}

				if (usersToSendEmail[user._id] === 'direct') {
					const userEmailPreferenceIsDisable = !user.settings || !user.settings.preferences || !user.settings.preferences.emailNotificationMode || user.settings.preferences.emailNotificationMode === 'disabled';
					const directMessageEmailPreference = RocketChat.models.Subscriptions.findOneByRoomIdAndUserId(message.rid, message.rid.replace(message.u._id, '')).emailNotifications;

					if (directMessageEmailPreference === 'nothing') {
						return;
					}

					if (directMessageEmailPreference === 'default' && userEmailPreferenceIsDisable) {
						return;
					}
				}

				// Checks if user is in the room he/she is mentioned (unless it's public channel)
				if (room.t !== 'c' && room.usernames.indexOf(user.username) === -1) {
					return;
				}

				// Footer in case direct reply is enabled.
				if (RocketChat.settings.get('Direct_Reply_Enable')) {
					footer = RocketChat.placeholders.replace(RocketChat.settings.get('Email_Footer_Direct_Reply') || '');
				}

				let emailSubject;
				switch (usersToSendEmail[user._id]) {
					case 'all':
						emailSubject = RocketChat.placeholders.replace(RocketChat.settings.get('Offline_Mention_All_Email'), {
							user: message.u.username,
							room: room.name || room.label
						});
						break;
					case 'direct':
						emailSubject = RocketChat.placeholders.replace(RocketChat.settings.get('Offline_DM_Email'), {
							user: message.u.username,
							room: room.name
						});
						break;
					case 'mention':
						emailSubject = RocketChat.placeholders.replace(RocketChat.settings.get('Offline_Mention_Email'), {
							user: message.u.username,
							room: room.name
						});
						break;
				}
				user.emails.some((email) => {
					if (email.verified) {
						email = {
							to: email.address,
							from: RocketChat.settings.get('From_Email'),
							subject: emailSubject,
							html: header + messageHTML + divisorMessage + (linkByUser[user._id] || defaultLink) + footer
						};
						// If direct reply enabled, email content with headers
						if (RocketChat.settings.get('Direct_Reply_Enable')) {
							email.headers = {
								// Reply-To header with format "username+messageId@domain"
								'Reply-To': `${ RocketChat.settings.get('Direct_Reply_Username').split('@')[0].split(RocketChat.settings.get('Direct_Reply_Separator'))[0] }${ RocketChat.settings.get('Direct_Reply_Separator') }${ message._id }@${ RocketChat.settings.get('Direct_Reply_Username').split('@')[1] }`
							};
						}

						Meteor.defer(() => {
							Email.send(email);
						});

						return true;
					}
				});
			});
		}
	}

	return message;

}, RocketChat.callbacks.priority.LOW, 'sendEmailOnMessage');
<commit_msg>Small tweak to PR #8810 to take into account if the subscription setting has never been set<commit_after>import moment from 'moment';
import s from 'underscore.string';

RocketChat.callbacks.add('afterSaveMessage', function(message, room) {
	// skips this callback if the message was edited
	if (message.editedAt) {
		return message;
	}

	if (message.ts && Math.abs(moment(message.ts).diff()) > 60000) {
		return message;
	}

	const getMessageLink = (room, sub) => {
		const roomPath = RocketChat.roomTypes.getRouteLink(room.t, sub);
		const path = Meteor.absoluteUrl(roomPath ? roomPath.replace(/^\//, '') : '');
		const style = [
			'color: #fff;',
			'padding: 9px 12px;',
			'border-radius: 4px;',
			'background-color: #04436a;',
			'text-decoration: none;'
		].join(' ');
		const message = TAPi18n.__('Offline_Link_Message');
		return `<p style="text-align:center;margin-bottom:8px;"><a style="${ style }" href="${ path }">${ message }</a>`;
	};

	const divisorMessage = '
';
	let messageHTML = s.escapeHTML(message.msg);

	message = RocketChat.callbacks.run('renderMessage', message);
	if (message.tokens && message.tokens.length > 0) {
		message.tokens.forEach((token) => {
			token.text = token.text.replace(/([^\$])(\$[^\$])/gm, '$1$$$2');
			messageHTML = messageHTML.replace(token.token, token.text);
		});
	}

	const header = RocketChat.placeholders.replace(RocketChat.settings.get('Email_Header') || '');
	let footer = RocketChat.placeholders.replace(RocketChat.settings.get('Email_Footer') || '');
	messageHTML = messageHTML.replace(/\n/gm, '
');

	const usersToSendEmail = {};
	if (room.t === 'd') {
		usersToSendEmail[message.rid.replace(message.u._id, '')] = 'direct';
	} else {
		let isMentionAll = message.mentions.find(mention => mention._id === 'all');

		if (isMentionAll) {
			const maxMembersForNotification = RocketChat.settings.get('Notifications_Max_Room_Members');
			if (maxMembersForNotification !== 0 && room.usernames.length > maxMembersForNotification) {
				isMentionAll = undefined;
			}
		}

		let query;
		if (isMentionAll) {
			// Query all users in room limited by the max room members setting
			query = RocketChat.models.Subscriptions.findByRoomId(room._id);
		} else {
			// Query only mentioned users, will be always a few users
			const userIds = message.mentions.map(mention => mention._id);
			query = RocketChat.models.Subscriptions.findByRoomIdAndUserIdsOrAllMessages(room._id, userIds);
		}

		query.forEach((sub) => {
			if (sub.disableNotifications) {
				return delete usersToSendEmail[sub.u._id];
			}

			const emailNotifications = sub.emailNotifications;

			if (emailNotifications === 'nothing') {
				return delete usersToSendEmail[sub.u._id];
			}

			const mentionedUser = isMentionAll || message.mentions.find(mention => mention._id === sub.u._id);

			if (emailNotifications === 'default' || emailNotifications == null) {
				if (mentionedUser) {
					return usersToSendEmail[sub.u._id] = 'default';
				}
				return delete usersToSendEmail[sub.u._id];
			}

			if (emailNotifications === 'mentions' && mentionedUser) {
				return usersToSendEmail[sub.u._id] = 'mention';
			}

			if (emailNotifications === 'all') {
				return usersToSendEmail[sub.u._id] = 'all';
			}
		});
	}
	const userIdsToSendEmail = Object.keys(usersToSendEmail);

	let defaultLink;

	const linkByUser = {};
	if (RocketChat.roomTypes.hasCustomLink(room.t)) {
		RocketChat.models.Subscriptions.findByRoomIdAndUserIds(room._id, userIdsToSendEmail).forEach((sub) => {
			linkByUser[sub.u._id] = getMessageLink(room, sub);
		});
	} else {
		defaultLink = getMessageLink(room, {
			name: room.name
		});
	}

	if (userIdsToSendEmail.length > 0) {
		const usersOfMention = RocketChat.models.Users.getUsersToSendOfflineEmail(userIdsToSendEmail).fetch();

		if (usersOfMention && usersOfMention.length > 0) {
			usersOfMention.forEach((user) => {
				if (usersToSendEmail[user._id] === 'default') {
					if (!user.settings || !user.settings.preferences || !user.settings.preferences.emailNotificationMode || user.settings.preferences.emailNotificationMode === 'all') { //Mention/DM
						usersToSendEmail[user._id] = 'mention';
					} else {
						return;
					}
				}

				if (usersToSendEmail[user._id] === 'direct') {
					const userEmailPreferenceIsDisable = !user.settings || !user.settings.preferences || !user.settings.preferences.emailNotificationMode || user.settings.preferences.emailNotificationMode === 'disabled';
					const directMessageEmailPreference = RocketChat.models.Subscriptions.findOneByRoomIdAndUserId(message.rid, message.rid.replace(message.u._id, '')).emailNotifications;

					if (directMessageEmailPreference === 'nothing') {
						return;
					}

					if ((directMessageEmailPreference === 'default' || directMessageEmailPreference == null) && userEmailPreferenceIsDisable) {
						return;
					}
				}

				// Checks if user is in the room he/she is mentioned (unless it's public channel)
				if (room.t !== 'c' && room.usernames.indexOf(user.username) === -1) {
					return;
				}

				// Footer in case direct reply is enabled.
				if (RocketChat.settings.get('Direct_Reply_Enable')) {
					footer = RocketChat.placeholders.replace(RocketChat.settings.get('Email_Footer_Direct_Reply') || '');
				}

				let emailSubject;
				switch (usersToSendEmail[user._id]) {
					case 'all':
						emailSubject = RocketChat.placeholders.replace(RocketChat.settings.get('Offline_Mention_All_Email'), {
							user: message.u.username,
							room: room.name || room.label
						});
						break;
					case 'direct':
						emailSubject = RocketChat.placeholders.replace(RocketChat.settings.get('Offline_DM_Email'), {
							user: message.u.username,
							room: room.name
						});
						break;
					case 'mention':
						emailSubject = RocketChat.placeholders.replace(RocketChat.settings.get('Offline_Mention_Email'), {
							user: message.u.username,
							room: room.name
						});
						break;
				}
				user.emails.some((email) => {
					if (email.verified) {
						email = {
							to: email.address,
							from: RocketChat.settings.get('From_Email'),
							subject: emailSubject,
							html: header + messageHTML + divisorMessage + (linkByUser[user._id] || defaultLink) + footer
						};
						// If direct reply enabled, email content with headers
						if (RocketChat.settings.get('Direct_Reply_Enable')) {
							email.headers = {
								// Reply-To header with format "username+messageId@domain"
								'Reply-To': `${ RocketChat.settings.get('Direct_Reply_Username').split('@')[0].split(RocketChat.settings.get('Direct_Reply_Separator'))[0] }${ RocketChat.settings.get('Direct_Reply_Separator') }${ message._id }@${ RocketChat.settings.get('Direct_Reply_Username').split('@')[1] }`
							};
						}

						Meteor.defer(() => {
							Email.send(email);
						});

						return true;
					}
				});
			});
		}
	}

	return message;

}, RocketChat.callbacks.priority.LOW, 'sendEmailOnMessage');
<|endoftext|>


<commit_before>/**
 * var connection = new Connection({ tag:             'kotoumi',
 *                                   hostName:        'localhost',
 *                                   port:            24224,
 *                                   receiveHostName: 'localhost',
 *                                   receivePort:     10030 });
 */

var EventEmitter = require('events').EventEmitter;
var fluent = require('fluent-logger');
var FluentReceiver = require('./receiver').FluentReceiver;

var DEFAULT_FLUENT_TAG =
      Connection.DEFAULT_FLUENT_TAG =
        'kotoumi';
var DEFAULT_FLUENT_HOST_NAME =
      Connection.DEFAULT_FLUENT_HOST_NAME =
        'localhost';
var DEFAULT_FLUENT_PORT =
      Connection.DEFAULT_FLUENT_PORT =
        24224;
var DEFAULT_RECEIVE_HOST_NAME =
      Connection.DEFAULT_RECEIVE_HOST_NAME =
        'localhost';

var ERROR_GATEWAY_TIMEOUT =
      Connection.ERROR_GATEWAY_TIMEOUT =
        504;

var DEFAULT_RESPONSE_TIMEOUT =
      Connection.DEFAULT_RESPONSE_TIMEOUT =
        60 * 1000;

function Connection(params) {
  this._params = params || {};
  this._init();
}

Connection.prototype = new EventEmitter();

Connection.prototype._init = function() {
  this._callbacks = {};
  this.tag = this._params.tag || DEFAULT_FLUENT_TAG;
  this._initSender();
  this._initReceiver();
};

Connection.prototype._initSender = function(wait) {
  var options = { host: this._params.hostName || DEFAULT_FLUENT_HOST_NAME,
                  port: this._params.port || DEFAULT_FLUENT_PORT };
  var sender = fluent.createFluentSender(this.tag, options);
  this._sender = sender;
  this._sender.on('error', (function(error) {
    this.emit('error', error);
  }).bind(this));
};

Connection.prototype._initReceiver = function() {
  this.receiveHostName = this._params.receiveHostName || DEFAULT_RECEIVE_HOST_NAME;
  this.receivePort = this._params.receivePort;

  var receiver = new FluentReceiver(this.receivePort);
  receiver.listen((function() {
    this.receivePort = receiver.port;
  }).bind(this));

  this._receiver = receiver;
  this._receiver.on(this.tag + '.message',
                    this._handleMessage.bind(this));
};

function isSuccess(code) {
  return Math.floor(code / 100) == 2;
}

Connection.prototype._handleMessage = function(envelope) {
  this.emit('message', envelope);

  var inReplyTo = envelope['inReplyTo'];
  if (inReplyTo) {
    var errorCode = envelope.statusCode;
    if (!errorCode || isSuccess(errorCode))
      errorCode = null;
    this.emit('inReplyTo:' + inReplyTo, errorCode, envelope);
  }
};

var count = 0;
function createId() {
  return Date.now() + ':' + (count++);
}

function getCurrentTime() {
  // The method toISOString() returns a GMT (ex. 2013-01-10T08:34:41.252Z)
  // on node. However, a local time (ex. 2013-01-10T17:34:41.252+09:00) is
  // more helpful for debugging. We should use it in the feature...
  return new Date().toISOString();
}

function toPositiveInteger(number) {
  if (!number)
    return 0;

  var integer = parseInt(number);
  if (isNaN(integer))
    return 0;

  return Math.max(integer, 0);
}

Connection.prototype.emitMessage = function(type, body, callback, options) {
  options = options || {};
  var id = createId();
  var envelope = {
    id:         id,
    date:       getCurrentTime(),
    replyTo:    this.receiveHostName + ':' + this.receivePort,
    statusCode: 200,
    type:       type,
    body:       body
  };
  if (callback) {
    var event = 'inReplyTo:' + id;
    this.once(event, callback);
    options.timeout = toPositiveInteger(options.timeout) ||
                        DEFAULT_RESPONSE_TIMEOUT;
    setTimeout((function() {
      if (this.listeners(event).length) {
        this.removeAllListeners(event);
        callback(ERROR_GATEWAY_TIMEOUT, null);
      }
    }).bind(this), options.timeout);
  }
  this._sender.emit('message', envelope);
  return envelope;
};

Connection.prototype.close = function() {
  this.removeAllListeners();

  if (this._sender && typeof this._sender.end == 'function') {
    this._sender.end();
    this._sender.removeAllListeners();
    delete this._sender;
  }

  if (this._receiver && typeof this._receiver.close == 'function') {
    this._receiver.close();
    this._receiver.removeAllListeners();
    delete this._receiver;
  }
};

exports.Connection = Connection;
<commit_msg>Set session id of the related socket to an envelope<commit_after>/**
 * var connection = new Connection({ tag:             'kotoumi',
 *                                   hostName:        'localhost',
 *                                   port:            24224,
 *                                   receiveHostName: 'localhost',
 *                                   receivePort:     10030 });
 */

var EventEmitter = require('events').EventEmitter;
var fluent = require('fluent-logger');
var FluentReceiver = require('./receiver').FluentReceiver;

var DEFAULT_FLUENT_TAG =
      Connection.DEFAULT_FLUENT_TAG =
        'kotoumi';
var DEFAULT_FLUENT_HOST_NAME =
      Connection.DEFAULT_FLUENT_HOST_NAME =
        'localhost';
var DEFAULT_FLUENT_PORT =
      Connection.DEFAULT_FLUENT_PORT =
        24224;
var DEFAULT_RECEIVE_HOST_NAME =
      Connection.DEFAULT_RECEIVE_HOST_NAME =
        'localhost';

var ERROR_GATEWAY_TIMEOUT =
      Connection.ERROR_GATEWAY_TIMEOUT =
        504;

var DEFAULT_RESPONSE_TIMEOUT =
      Connection.DEFAULT_RESPONSE_TIMEOUT =
        60 * 1000;

function Connection(params) {
  this._params = params || {};
  this._init();
}

Connection.prototype = new EventEmitter();

Connection.prototype._init = function() {
  this._callbacks = {};
  this.tag = this._params.tag || DEFAULT_FLUENT_TAG;
  this._initSender();
  this._initReceiver();
};

Connection.prototype._initSender = function(wait) {
  var options = { host: this._params.hostName || DEFAULT_FLUENT_HOST_NAME,
                  port: this._params.port || DEFAULT_FLUENT_PORT };
  var sender = fluent.createFluentSender(this.tag, options);
  this._sender = sender;
  this._sender.on('error', (function(error) {
    this.emit('error', error);
  }).bind(this));
};

Connection.prototype._initReceiver = function() {
  this.receiveHostName = this._params.receiveHostName || DEFAULT_RECEIVE_HOST_NAME;
  this.receivePort = this._params.receivePort;

  var receiver = new FluentReceiver(this.receivePort);
  receiver.listen((function() {
    this.receivePort = receiver.port;
  }).bind(this));

  this._receiver = receiver;
  this._receiver.on(this.tag + '.message',
                    this._handleMessage.bind(this));
};

function isSuccess(code) {
  return Math.floor(code / 100) == 2;
}

Connection.prototype._handleMessage = function(envelope) {
  this.emit('message', envelope);

  var inReplyTo = envelope['inReplyTo'];
  if (inReplyTo) {
    var errorCode = envelope.statusCode;
    if (!errorCode || isSuccess(errorCode))
      errorCode = null;
    this.emit('inReplyTo:' + inReplyTo, errorCode, envelope);
  }
};

var count = 0;
function createId() {
  return Date.now() + ':' + (count++);
}

function getCurrentTime() {
  // The method toISOString() returns a GMT (ex. 2013-01-10T08:34:41.252Z)
  // on node. However, a local time (ex. 2013-01-10T17:34:41.252+09:00) is
  // more helpful for debugging. We should use it in the feature...
  return new Date().toISOString();
}

function toPositiveInteger(number) {
  if (!number)
    return 0;

  var integer = parseInt(number);
  if (isNaN(integer))
    return 0;

  return Math.max(integer, 0);
}

Connection.prototype.emitMessage = function(type, body, callback, options) {
  options = options || {};
  var id = createId();
  var envelope = {
    id:         id,
    date:       getCurrentTime(),
    replyTo:    this.receiveHostName + ':' + this.receivePort,
    statusCode: 200,
    type:       type,
    body:       body
  };
  if (options.socket) {
    envelope.sessionId = options.socket.sessionid;
  }
  if (callback) {
    var event = 'inReplyTo:' + id;
    this.once(event, callback);
    options.timeout = toPositiveInteger(options.timeout) ||
                        DEFAULT_RESPONSE_TIMEOUT;
    setTimeout((function() {
      if (this.listeners(event).length) {
        this.removeAllListeners(event);
        callback(ERROR_GATEWAY_TIMEOUT, null);
      }
    }).bind(this), options.timeout);
  }
  this._sender.emit('message', envelope);
  return envelope;
};

Connection.prototype.close = function() {
  this.removeAllListeners();

  if (this._sender && typeof this._sender.end == 'function') {
    this._sender.end();
    this._sender.removeAllListeners();
    delete this._sender;
  }

  if (this._receiver && typeof this._receiver.close == 'function') {
    this._receiver.close();
    this._receiver.removeAllListeners();
    delete this._receiver;
  }
};

exports.Connection = Connection;
<|endoftext|>