<commit_before>module.exports = function(grunt) {
	grunt.log.writeln('\n---- nwayo report -----');

	var
		// flags
		foundation = grunt.file.exists('css/vendor/foundation/foundation.scss'),
		jshtml     = !!(grunt.file.expand('tmpl/**/*.jshtml').length),

		editor     = grunt.file.exists('css/misc/editor.less'),
		staticHtml = !!(grunt.file.expand('misc/static/**/*.html').length),

		theme      = false,

		// Project configuration.
		tasks = {
			default: [],
			rebuild: ['default']
		},

		config = {
			pkg: grunt.file.readJSON('package.json'),

			copy: {},
			nwayo_copy: {},
			imagemin: {},
			inlinecss: {},
			'imagemagick-resize': {},
			'imagemagick-convert': {},

			// cleaner
			clean: {
				tmp_css: { src: ['.tmp-nwayo/*.css'], options: { force:true } },
				tmp_js:  { src: ['.tmp-nwayo/*.js'],  options: { force:true } },
				builds:  { src: ['../builds/*'],      options: { force:true } }
			},

			// watcher
			watch: {
				all: {
					files: ['gruntfile.js', 'package.json'],
					tasks: 'default'
				},
			}
		},

		// check list report
		checklist = function(name, found) {
			grunt.log.writeln('[ '+ ((found) ? '✔' : ' ') +' ] '+name);
		},

		// get css static libs
		getCssLibs = function(file) {
			var css = [];

			if (foundation) {
				css = [
					'css/libs/normalize.css',
					'.tmp-nwayo/foundation-scss.css'
				];

			} else if (!theme) {
				css = [
					'css/libs/reset.css',
					'css/libs/normalize.css',
					'css/libs/html5boilerplate.css'
				];
			}

			css.push(file);

			return css;
		}
	;

	// grunt general modules
	grunt.loadNpmTasks('grunt-contrib-copy');
	grunt.loadNpmTasks('grunt-contrib-imagemin');
	grunt.loadNpmTasks('grunt-imagemagick');

	grunt.task.registerMultiTask('nwayo_copy', '', function() {
		for (var i in this.data) {
			grunt.file.copy(this.data[i],i);
		}
	});

	checklist('Has theme?', theme);

	// --------------------------------
	// JS
	// --------------------------------
	grunt.loadNpmTasks('grunt-contrib-jshint');
	grunt.loadNpmTasks('grunt-contrib-requirejs');

	// js hint
	config.jshint = {
		core: {
			src: ['js/**/*.js', '!libs/**/*.js', '!js/vendor/**/*.js']
		}
	};

	// requirejs
	config.requirejs = {
		core: {
			options: {
				baseUrl:  './',
				name:     'js/core',
				include:  ['js/variants'],
				out:      '../builds/js/core.js',
				optimize: 'uglify', // 'none'
				preserveLicenseComments: false,
				skipModuleInsertion:     true,
				findNestedDependencies:  true,
				pragmasOnSave:           { excludeRequire: true }
			}
		}
	};

	// tasks
	tasks.core_js = [
		'jshint:core',
		'requirejs:core',
		'clean:tmp_js'
	];
	tasks.default.push('core_js');

	config.watch.core_js = {
		files: [
			'js/**/*.js',
			'libs/**/*.js'
		],
		tasks: 'core_js'
	};

	// --------------------------------
	// CSS
	// --------------------------------
	grunt.loadNpmTasks('grunt-contrib-less');
	grunt.loadNpmTasks('grunt-contrib-cssmin');

	// data-uri images
	config.imagemin.datauri = {
		options: { optimizationLevel:7, progressive:false, interlaced:false, pngquant:true, force:true },
		files: [{
			expand: true,
			cwd: 'assets/data-uri/',
			src: ['**/*.{png,jpg,gif}'],
			dest: '.tmp-nwayo/data-uri/'
		}]
	};

	// less
	config.less = {
		core: { files: { '.tmp-nwayo/core-less.css': 'css/loader.less' } }
	};

	// css
	config.cssmin = {
		core: { files: { '../builds/css/core.css': getCssLibs('.tmp-nwayo/core-less.css') } },
	};

	// task
	tasks.core_css = [
		'imagemin:datauri',
		'less:core',
		'cssmin:core',
		'clean:tmp_css'
	];
	tasks.default.push('core_css');

	config.watch.core_css = {
		files: [
			'assets/data-uri/**/*.{png,jpg,gif}',
			'css/**/*.css',
			'css/**/*.less',
			'!css/misc/**/*'
		],
		tasks: 'core_css'
	};

	// --------------------------------
	// FOUNDATION
	// --------------------------------
	checklist('Foundation', foundation);

	if (foundation) {

		grunt.loadNpmTasks('grunt-contrib-sass');

		config.sass = {
			foundation: { files: { '.tmp-nwayo/foundation-scss.css': 'css/vendor/foundation/foundation.scss' } },
		};

		tasks.core_css.unshift('sass:foundation');

		config.watch.core_css.files.push('css/**/*.scss');
	}

	// --------------------------------
	// JSHTML
	// --------------------------------
	checklist('JSRender templates', jshtml);

	if (jshtml) {
		grunt.loadNpmTasks('grunt-template-client');

		config.templateclient = {
			core: {
				options: {
					variable: 'nwayo_jshtml',
					prefix: 'window.kafe.dependencies.jQuery.templates(',
					suffix: ')'
				},
				src: ['tmpl/**/*.jshtml'],
				dest: '.tmp-nwayo/templateclient.js'
			}
		};

		tasks.core_js.unshift('templateclient:core');

		config.watch.core_js.files.push('tmpl/**/*.jshtml');
	}

	// --------------------------------
	// EDITOR
	// --------------------------------
	checklist('Editor styles', editor);

	if (editor) {
		config.less.editor   = { files: { '.tmp-nwayo/editor-less.css': 'css/misc/editor.less' } };
		config.cssmin.editor = { files: { '../builds/css/editor.css': getCssLibs('.tmp-nwayo/editor-less.css') }, };

		tasks.editor = [
			'less:editor',
			'cssmin:editor',
			'clean:tmp_css'
		];

		tasks.core_css.push('editor');

		config.watch.editor = {
			files: ['css/misc/editor.less'],
			tasks: 'editor'
		};
	}

	// --------------------------------
	// FONTS
	// --------------------------------
	config.copy.fonts = {
		expand: true,
		cwd:    'assets/fonts/',
		src:    '**',
		dest:   '../builds/fonts/',
		filter: 'isFile'
	};

	tasks.fonts = [
		'copy:fonts'
	];
	tasks.rebuild.push('fonts');

	config.watch.fonts = {
		files: ['assets/fonts/**/*.{eot,svg,ttf,woff}'],
		tasks: 'fonts'
	};

	// --------------------------------
	// IMAGES
	// --------------------------------
	config.imagemin.images = {
		options: { optimizationLevel:7, progressive:false, interlaced:false, pngquant:true, force:true },
		files: [{
			expand: true,
			cwd: 'assets/images/',
			src: ['**/*.{png,jpg,gif}'],
			dest: '../builds/images/'
		}]
	};

	tasks.images = [
		'imagemin:images'
	];
	tasks.rebuild.push('images');

	config.watch.images = {
		files: [ 'assets/images/**/*.{png,jpg,gif}'],
		tasks: 'images'
	};

	// --------------------------------
	// ICONS
	// --------------------------------
	(function(sizes) {
		tasks.icons = [];

		// apple touch icons
		var applecopytasks = [];

		for (var i in sizes) {
			var size = sizes[i];

			config['imagemagick-resize']['apple-'+size] = {
				from:  'assets/icons/',
				to:    '.tmp-nwayo/icons/apple-'+size+'/',
				files: 'share.png',
				props: { width:size, height:size }
			};

			config.nwayo_copy['apple-'+size] = {};
			config.nwayo_copy['apple-'+size]['../builds/touch-icon-'+size+'.png'] = '.tmp-nwayo/icons/apple-'+size+'/share.png';

			tasks.icons.push('imagemagick-resize:apple-'+size);
			applecopytasks.push('nwayo_copy:apple-'+size);
		}

		config.imagemin.icons_apple = {
			options: { optimizationLevel:7, progressive:false, interlaced:false, pngquant:true, force:true },
			files: [{
				expand: true,
				cwd: '.tmp-nwayo/icons/',
				src: ['**/*.{png,jpg,gif}'],
				dest: '.tmp-nwayo/icons/'
			}]
		};
		tasks.icons.push('imagemin:icons_apple');
		tasks.icons = tasks.icons.concat(applecopytasks);

		// share
		config.imagemin.icons_share = {
			options: { optimizationLevel:7, progressive:false, interlaced:false, pngquant:true, force:true },
			files: {'../builds/share-icon.png' : 'assets/icons/share.png'}
		};
		tasks.icons.push('imagemin:icons_share');

		// favicon
		config['imagemagick-convert'].favicon = {
			args: ['assets/icons/favicon.png', '../builds/favicon.ico']
		};
		tasks.icons.push('imagemagick-convert:favicon');

		// grunt
		config.clean.tmp_icons = { src: ['.tmp-nwayo/icons'], options: { force: true }};
		tasks.icons.push('clean:tmp_icons');

		tasks.rebuild.push('icons');

		config.watch.icons = {
			files: ['assets/icons/**/*.png'],
			tasks: 'icons'
		};

	})([57,72,76,114,120,144,152]);

	// --------------------------------
	// HTML STATIC
	// --------------------------------
	checklist('Static HTML', staticHtml);

	if (staticHtml) {
		grunt.loadNpmTasks('grunt-inline-css');

		config.less.static_html = { files: [{
			expand: true,
			cwd: 'css/misc/static/',
			src: ['**/*.less'],
			dest: '.tmp-nwayo/',
			ext: '-less.css'
		}]};

		config.inlinecss.static_html = { files: [{
			expand: true,
			cwd: 'misc/static/',
			src: ['**/*.html'],
			dest: '../builds/static/'
		}]};

		tasks.static_html = [
			'less:static_html',
			'inlinecss:static_html',
			'clean:tmp_css'
		];

		tasks.rebuild.push('static_html');

		config.watch.static_html = {
			files: ['css/misc/static/**/*.less','misc/static/**/*.html'],
			tasks: 'static_html'
		};
	}

	// --------------------------------
	// GRUNT
	// --------------------------------
	grunt.loadNpmTasks('grunt-contrib-clean');
	grunt.loadNpmTasks('grunt-contrib-watch');

	tasks.rebuild.unshift('clean:builds');

	grunt.initConfig(config);

	// tasks
	for (var name in tasks) {
		grunt.registerTask(name, tasks[name]);
	}

	grunt.log.writeln('-----------------------\n');
};

<commit_msg>Cleanup + Logging<commit_after>module.exports = function(grunt) {
	var
		tmp    = '.tmp-nwayo',
		builds = '../builds',
		assets = 'assets',
		line   = Array(80).join('-'),

		// flags
		foundation = grunt.file.exists('css/vendor/foundation/foundation.scss'),
		jshtml     = !!(grunt.file.expand('tmpl/**/*.jshtml').length),

		editor     = grunt.file.exists('css/misc/editor.less'),
		staticHtml = !!(grunt.file.expand('misc/static/**/*.html').length),

		theme      = false,

		// Project configuration.
		tasks = {
			default: [],
			rebuild: ['default']
		},

		config = {
			pkg: grunt.file.readJSON('package.json'),

			requirejs:             {},
			jshint:                {},
			less:                  {},
			sass:                  {},
			cssmin:                {},
			imagemin:              {},
			copy:                  {},
			inlinecss:             {},
			nwayo_copy:            {},
			'imagemagick-resize':  {},
			'imagemagick-convert': {},

			// cleaner
			clean: {
				tmp_css: { src: [tmp+'/*.css'], options: { force:true } },
				tmp_js:  { src: [tmp+'/*.js'],  options: { force:true } },
				builds:  { src: [builds+'/*'],  options: { force:true } }
			},

			// watcher
			watch: {
				all: {
					files: ['gruntfile.js', 'package.json'],
					tasks: 'default'
				}
			}
		},

		// check list report
		checklist = function(name, found) {
			grunt.log.writeln(' '+ ((found) ? '✔' : ' ') +'  '+name);
		},

		// get css static libs
		getCssLibs = function(file) {
			var css = [];

			if (foundation) {
				css = [
					'css/libs/normalize.css',
					tmp+'/foundation-scss.css'
				];

			} else if (!theme) {
				css = [
					'css/libs/reset.css',
					'css/libs/normalize.css',
					'css/libs/html5boilerplate.css'
				];
			}

			css.push(file);

			return css;
		}
	;

	grunt.log.subhead(Array(10).join('\n')+line+'\n NWAYO\n'+line);

	// grunt general modules
	grunt.loadNpmTasks('grunt-contrib-copy');
	grunt.loadNpmTasks('grunt-contrib-imagemin');
	grunt.loadNpmTasks('grunt-imagemagick');

	// grunt custom tasks
	grunt.task.registerMultiTask('nwayo_copy', '', function() {
		for (var i in this.data.files) {
			grunt.log.writeln('Copying '+this.data.files[i].src+'\nto      '+this.data.files[i].dest);
			grunt.file.copy(this.data.files[i].src, this.data.files[i].dest);
		}
	});

	grunt.task.registerTask('nwayo_loghead', '', function(title) {
		grunt.log.subhead('\n\n'+line+'\n '+title.toUpperCase()+'\n'+line);
	});

	checklist('Has theme?', theme);

	// --------------------------------
	// JS
	// --------------------------------
	grunt.loadNpmTasks('grunt-contrib-jshint');
	grunt.loadNpmTasks('grunt-contrib-requirejs');

	// js hint
	config.jshint.core = {
		src: ['js/**/*.js', '!libs/**/*.js', '!js/vendor/**/*.js']
	};

	// requirejs
	config.requirejs.core = {
		options: {
			baseUrl:  './',
			name:     'js/core',
			include:  ['js/variants'],
			out:      builds+'/js/core.js',
			optimize: 'uglify', // 'none'
			preserveLicenseComments: false,
			skipModuleInsertion:     true,
			findNestedDependencies:  true,
			pragmasOnSave:           { excludeRequire: true }
		}
	};

	// tasks
	tasks.core_js = [
		'jshint:core',
		'requirejs:core',
		'clean:tmp_js'
	];
	tasks.default.push('core_js');

	config.watch.core_js = {
		files: [
			'js/**/*.js',
			'libs/**/*.js'
		],
		tasks: 'core_js'
	};

	// --------------------------------
	// CSS
	// --------------------------------
	grunt.loadNpmTasks('grunt-contrib-less');
	grunt.loadNpmTasks('grunt-contrib-cssmin');

	// data-uri images
	config.imagemin.datauri = {
		options: { optimizationLevel:7, progressive:false, interlaced:false, pngquant:true, force:true },
		files: [{
			expand: true,
			cwd: assets+'/data-uri/',
			src: ['**/*.{png,jpg,gif}'],
			dest: tmp+'/data-uri/'
		}]
	};

	// less
	config.less.core = { files: [{
		src:  'css/loader.less',
		dest: tmp+'/core-less.css'
	}]};

	// css
	config.cssmin.core = { files: [{
		src:  getCssLibs(tmp+'/core-less.css'),
		dest: builds+'/css/core.css'
	}]};

	// task
	tasks.core_css = [
		'imagemin:datauri',
		'less:core',
		'cssmin:core',
		'clean:tmp_css'
	];
	tasks.default.push('core_css');

	config.watch.core_css = {
		files: [
			assets+'/data-uri/**/*.{png,jpg,gif}',
			'css/**/*.css',
			'css/**/*.less',
			'!css/misc/**/*'
		],
		tasks: 'core_css'
	};

	// --------------------------------
	// FOUNDATION
	// --------------------------------
	checklist('Foundation', foundation);

	if (foundation) {

		grunt.loadNpmTasks('grunt-contrib-sass');

		config.sass.foundation = { files: [{
			src:  'css/vendor/foundation/foundation.scss',
			dest: tmp+'/foundation-scss.css'
		}]};

		tasks.core_css.unshift('sass:foundation');

		config.watch.core_css.files.push('css/**/*.scss');
	}

	// --------------------------------
	// JSHTML
	// --------------------------------
	checklist('JSRender templates', jshtml);

	if (jshtml) {
		grunt.loadNpmTasks('grunt-template-client');

		config.templateclient.core = {
			options: {
				variable: 'nwayo_jshtml',
				prefix: 'window.kafe.dependencies.jQuery.templates(',
				suffix: ')'
			},
			src: ['tmpl/**/*.jshtml'],
			dest: tmp+'/templateclient.js'
		};

		tasks.core_js.unshift('templateclient:core');

		config.watch.core_js.files.push('tmpl/**/*.jshtml');
	}

	// --------------------------------
	// EDITOR
	// --------------------------------
	checklist('Editor styles', editor);

	if (editor) {
		config.less.editor = { files: [{
			src:  'css/misc/editor.less',
			dest: tmp+'/editor-less.css'
		}]};

		config.cssmin.editor = { files: [{
			src:  getCssLibs(tmp+'/editor-less.css'),
			dest: builds+'/css/editor.css'
		}]};

		tasks.editor = [
			'nwayo_loghead:editor styles',
			'less:editor',
			'cssmin:editor',
			'clean:tmp_css'
		];

		tasks.core_css.push('editor');

		config.watch.editor = {
			files: ['css/misc/editor.less'],
			tasks: 'editor'
		};
	}

	// --------------------------------
	// FONTS
	// --------------------------------
	config.copy.fonts = {
		expand: true,
		cwd:    assets+'/fonts/',
		src:    '**',
		dest:   builds+'/fonts/',
		filter: 'isFile'
	};

	tasks.fonts = [
		'nwayo_loghead:fonts',
		'copy:fonts'
	];
	tasks.rebuild.push('fonts');

	config.watch.fonts = {
		files: [assets+'/fonts/**/*.{eot,svg,ttf,woff}'],
		tasks: 'fonts'
	};

	// --------------------------------
	// IMAGES
	// --------------------------------
	config.imagemin.images = {
		options: { optimizationLevel:7, progressive:false, interlaced:false, pngquant:true, force:true },
		files: [{
			expand: true,
			cwd: assets+'/images/',
			src: ['**/*.{png,jpg,gif}'],
			dest: builds+'/images/'
		}]
	};

	tasks.images = [
		'nwayo_loghead:image optimization',
		'imagemin:images'
	];
	tasks.rebuild.push('images');

	config.watch.images = {
		files: [ assets+'/images/**/*.{png,jpg,gif}'],
		tasks: 'images'
	};

	// --------------------------------
	// ICONS
	// --------------------------------
	(function(sizes) {
		tasks.icons = ['nwayo_loghead:icons'];

		// apple touch icons
		var applecopytasks = [];

		for (var i in sizes) {
			var size = sizes[i];

			config['imagemagick-resize']['apple-'+size] = {
				from:  assets+'/icons/',
				to:    tmp+'/icons/apple-'+size+'/',
				files: 'share.png',
				props: { width:size, height:size }
			};

			config.nwayo_copy['apple-'+size] = { files: [{
				src:  tmp+'/icons/apple-'+size+'/share.png',
				dest: builds+'/touch-icon-'+size+'.png'
			}]};

			tasks.icons.push('imagemagick-resize:apple-'+size);
			applecopytasks.push('nwayo_copy:apple-'+size);
		}

		config.imagemin.icons_apple = {
			options: { optimizationLevel:7, progressive:false, interlaced:false, pngquant:true, force:true },
			files: [{
				expand: true,
				cwd: tmp+'/icons/',
				src: ['**/*.{png,jpg,gif}'],
				dest: tmp+'/icons/'
			}]
		};
		tasks.icons.push('imagemin:icons_apple');
		tasks.icons = tasks.icons.concat(applecopytasks);

		// share
		config.imagemin.icons_share = {
			options: { optimizationLevel:7, progressive:false, interlaced:false, pngquant:true, force:true },
			files: [{
				src:  assets+'/icons/share.png',
				dest: builds+'/share-icon.png'
			}]
		};
		tasks.icons.push('imagemin:icons_share');

		// favicon
		config['imagemagick-convert'].favicon = {
			args: [assets+'/icons/favicon.png', builds+'/favicon.ico']
		};
		tasks.icons.push('imagemagick-convert:favicon');

		// grunt
		config.clean.tmp_icons = { src: [tmp+'/icons'], options: { force: true }};
		tasks.icons.push('clean:tmp_icons');

		tasks.rebuild.push('icons');

		config.watch.icons = {
			files: [assets+'/icons/**/*.png'],
			tasks: 'icons'
		};

	})([57,72,76,114,120,144,152]);

	// --------------------------------
	// HTML STATIC
	// --------------------------------
	checklist('Static HTML', staticHtml);

	if (staticHtml) {
		grunt.loadNpmTasks('grunt-inline-css');

		config.less.static_html = { files: [{
			expand: true,
			cwd: 'css/misc/static/',
			src: ['**/*.less'],
			dest: tmp+'/',
			ext: '-less.css'
		}]};

		config.inlinecss.static_html = { files: [{
			expand: true,
			cwd: 'misc/static/',
			src: ['**/*.html'],
			dest: builds+'/static/'
		}]};

		tasks.static_html = [
			'nwayo_loghead:static html',
			'less:static_html',
			'inlinecss:static_html',
			'clean:tmp_css'
		];

		tasks.rebuild.push('static_html');

		config.watch.static_html = {
			files: ['css/misc/static/**/*.less','misc/static/**/*.html'],
			tasks: 'static_html'
		};
	}

	// --------------------------------
	// GRUNT
	// --------------------------------
	grunt.loadNpmTasks('grunt-contrib-clean');
	grunt.loadNpmTasks('grunt-contrib-watch');

	tasks.core_css.unshift('nwayo_loghead:css');
	tasks.core_js.unshift('nwayo_loghead:js');
	tasks.rebuild.unshift('nwayo_loghead:rebuilding site','clean:builds');

	grunt.initConfig(config);

	// tasks
	grunt.log.subhead(' Available tasks');
	for (var name in tasks) {
		grunt.registerTask(name, tasks[name]);
		grunt.log.writeln(' •  '+name);
	}
};

<|endoftext|>


<commit_before>/**
 * Created by mgoria on 11/12/15.
 */

'use strict';

import {MissingLoginProviderException} from './Exception/MissingLoginProviderException';
import {IdentityProviderMismatchException} from './Exception/IdentityProviderMismatchException';
import {InvalidProviderIdentityException} from './Exception/InvalidProviderIdentityException';

/**
 * 3rd Party identity provider (Amazon, Facebook, Google, etc.)
 */
export class IdentityProvider {
  /**
   * @param providerName
   * @param providers
   * @returns {*}
   */
  getProviderDomain(providerName, providers) {
    let domainRegexp;

    switch(providerName) {
      case IdentityProvider.AMAZON_PROVIDER:
        domainRegexp = /^www\.amazon\.com$/;
        break;
      case IdentityProvider.FACEBOOK_PROVIDER:
        domainRegexp = /^graph\.facebook\.com$/;
        break;
      case IdentityProvider.GOOGLE_PROVIDER:
        domainRegexp = /^accounts\.google\.com$/;
        break;
      case IdentityProvider.AUTH0_PROVIDER:
        domainRegexp = /^.+\.auth0\.com$/;
        break;
      case IdentityProvider.COGNITO_USER_POOL_PROVIDER:
        domainRegexp = /^cognito\-idp\.[\w\d\-]+\.amazonaws\.com\/[\w\d\-]+$/;
        break;
    }

    if (!domainRegexp) {
      return null;
    }

    for (let providerDomain in providers) {
      if (!providers.hasOwnProperty(providerDomain)) {
        continue;
      }

      if (domainRegexp.test(providerDomain)) {
        return providerDomain;
      }
    }

    return null;
  }

  /**
   * @param {Object} providers
   * @param {String} providerName
   * @param {Object} identityMetadata
   */
  constructor(providers, providerName, identityMetadata) {
    let providerDomain = this.getProviderDomain(providerName, providers);

    if (!providerDomain) {
      throw new MissingLoginProviderException(providerName);
    }

    if (identityMetadata.provider && identityMetadata.provider !== providerName) {
      throw new IdentityProviderMismatchException(providerName, identityMetadata.provider);
    }

    let normalizedMetadata = this._normalizeIdentityMetadata(providerName, identityMetadata);

    this._userToken = normalizedMetadata.token;
    this._tokenExpTime = new Date(normalizedMetadata.expireTime);
    this._userId = normalizedMetadata.userId;
    this._providers = providers;
    this._name = providerDomain;
  }

  /**
   * @todo: Implement other identity providers
   * @param {String} providerName
   * @param {Object} identityMetadata
   * @returns {{token: String, userId: String, expireTime: Number}}
   * @private
   */
  _normalizeIdentityMetadata(providerName, identityMetadata) {
    let token = null;
    let expiresIn  = null;
    let userId = null;

    switch(providerName) {
      case IdentityProvider.FACEBOOK_PROVIDER:
        token = identityMetadata.accessToken;
        expiresIn = identityMetadata.expiresIn;
        userId = identityMetadata.userID;
        break;

      case IdentityProvider.COGNITO_USER_POOL_PROVIDER:
      case IdentityProvider.AMAZON_PROVIDER:
      case IdentityProvider.AUTH0_PROVIDER:
        token = identityMetadata.access_token;
        userId = identityMetadata.user_id;
        expiresIn = identityMetadata.expires_in || 3600;
        break;
    }

    if (!(token && expiresIn)) {
      throw new InvalidProviderIdentityException(providerName);
    }

    let expireTime = Date.now() + expiresIn * 1000;
    userId = userId || null;

    return {token, userId, expireTime};
  }

  /**
   * @returns {Object}
   */
  get providers() {
    return this._providers;
  }

  /**
   * @returns {String}
   */
  get name() {
    return this._name;
  }

  /**
   * @returns {String}
   */
  get userToken() {
    return this._userToken;
  }

  /**
   * @returns {Date}
   */
  get tokenExpirationTime() {
    return this._tokenExpTime;
  }

  /**
   * @returns {boolean}
   */
  isTokenValid() {
    if (this.userToken && this.tokenExpirationTime) {
      return this.tokenExpirationTime > new Date();
    }

    return false;
  }

  /**
   * @returns {String}
   */
  get userId() {
    return this._userId;
  }

  /**
   * @param {String} name
   * @returns {Object}
   */
  config(name) {
    if (!this.providers.hasOwnProperty(name)) {
      throw new MissingLoginProviderException(name);
    }

    return this.providers[name];
  }

  /**
   * @returns {String}
   */
  static get COGNITO_USER_POOL_PROVIDER() {
    return 'cognito-user-pool';
  }

  /**
   * @returns {String}
   */
  static get FACEBOOK_PROVIDER() {
    return 'facebook';
  }

  /**
   * @returns {String}
   */
  static get AMAZON_PROVIDER() {
    return 'amazon';
  }

  /**
   * @returns {String}
   */
  static get GOOGLE_PROVIDER() {
    return 'google';
  }

  /**
   * @returns {String}
   */
  static get AUTH0_PROVIDER() {
    return 'auth0';
  }
}
<commit_msg># Added cognito-user-pool security provider custom logic<commit_after>/**
 * Created by mgoria on 11/12/15.
 */

'use strict';

import {MissingLoginProviderException} from './Exception/MissingLoginProviderException';
import {IdentityProviderMismatchException} from './Exception/IdentityProviderMismatchException';
import {InvalidProviderIdentityException} from './Exception/InvalidProviderIdentityException';

/**
 * 3rd Party identity provider (Amazon, Facebook, Google, etc.)
 */
export class IdentityProvider {
  /**
   * @param providerName
   * @param providers
   * @returns {*}
   */
  getProviderDomain(providerName, providers) {
    let domainRegexp;

    switch(providerName) {
      case IdentityProvider.AMAZON_PROVIDER:
        domainRegexp = /^www\.amazon\.com$/;
        break;
      case IdentityProvider.FACEBOOK_PROVIDER:
        domainRegexp = /^graph\.facebook\.com$/;
        break;
      case IdentityProvider.GOOGLE_PROVIDER:
        domainRegexp = /^accounts\.google\.com$/;
        break;
      case IdentityProvider.AUTH0_PROVIDER:
        domainRegexp = /^.+\.auth0\.com$/;
        break;
      case IdentityProvider.COGNITO_USER_POOL_PROVIDER:
        domainRegexp = /^cognito\-idp\.[\w\d\-]+\.amazonaws\.com\/[\w\d\-]+$/;
        break;
    }

    if (!domainRegexp) {
      return null;
    }

    for (let providerDomain in providers) {
      if (!providers.hasOwnProperty(providerDomain)) {
        continue;
      }

      if (domainRegexp.test(providerDomain)) {
        return providerDomain;
      }
    }

    return null;
  }

  /**
   * @param {Object} providers
   * @param {String} providerName
   * @param {Object} identityMetadata
   */
  constructor(providers, providerName, identityMetadata) {
    let providerDomain = this.getProviderDomain(providerName, providers);

    if (!providerDomain) {
      throw new MissingLoginProviderException(providerName);
    }

    if (identityMetadata.provider && identityMetadata.provider !== providerName) {
      throw new IdentityProviderMismatchException(providerName, identityMetadata.provider);
    }

    let normalizedMetadata = this._normalizeIdentityMetadata(providerName, identityMetadata);

    this._userToken = normalizedMetadata.token;
    this._tokenExpTime = new Date(normalizedMetadata.expireTime);
    this._userId = normalizedMetadata.userId;
    this._providers = providers;
    this._name = providerDomain;
  }

  /**
   * @todo: Implement other identity providers
   * @param {String} providerName
   * @param {Object} identityMetadata
   * @returns {{token: String, userId: String, expireTime: Number}}
   * @private
   */
  _normalizeIdentityMetadata(providerName, identityMetadata) {
    let token = null;
    let expiresIn  = null;
    let expireTime = null;
    let userId = null;

    switch(providerName) {
      case IdentityProvider.FACEBOOK_PROVIDER:
        token = identityMetadata.accessToken;
        expiresIn = identityMetadata.expiresIn;
        userId = identityMetadata.userID;
        break;

      case IdentityProvider.COGNITO_USER_POOL_PROVIDER:
        let jwtTokenInstance = identityMetadata.getIdToken();
        token = jwtTokenInstance.getJwtToken();
        expireTime = jwtTokenInstance.getExpiration().unix() * 1000;
        break;

      case IdentityProvider.AMAZON_PROVIDER:
      case IdentityProvider.AUTH0_PROVIDER:
        token = identityMetadata.access_token;
        userId = identityMetadata.user_id;
        expiresIn = identityMetadata.expires_in || 3600;
        break;
    }

    userId = userId || null;
    expireTime = expireTime ||
      (expiresIn ?
        (Date.now() + expiresIn * 1000) :
        null);

    if (!(token && expireTime)) {
      throw new InvalidProviderIdentityException(providerName);
    }

    return {token, userId, expireTime};
  }

  /**
   * @returns {Object}
   */
  get providers() {
    return this._providers;
  }

  /**
   * @returns {String}
   */
  get name() {
    return this._name;
  }

  /**
   * @returns {String}
   */
  get userToken() {
    return this._userToken;
  }

  /**
   * @returns {Date}
   */
  get tokenExpirationTime() {
    return this._tokenExpTime;
  }

  /**
   * @returns {boolean}
   */
  isTokenValid() {
    if (this.userToken && this.tokenExpirationTime) {
      return this.tokenExpirationTime > new Date();
    }

    return false;
  }

  /**
   * @returns {String}
   */
  get userId() {
    return this._userId;
  }

  /**
   * @param {String} name
   * @returns {Object}
   */
  config(name) {
    if (!this.providers.hasOwnProperty(name)) {
      throw new MissingLoginProviderException(name);
    }

    return this.providers[name];
  }

  /**
   * @returns {String}
   */
  static get COGNITO_USER_POOL_PROVIDER() {
    return 'cognito-user-pool';
  }

  /**
   * @returns {String}
   */
  static get FACEBOOK_PROVIDER() {
    return 'facebook';
  }

  /**
   * @returns {String}
   */
  static get AMAZON_PROVIDER() {
    return 'amazon';
  }

  /**
   * @returns {String}
   */
  static get GOOGLE_PROVIDER() {
    return 'google';
  }

  /**
   * @returns {String}
   */
  static get AUTH0_PROVIDER() {
    return 'auth0';
  }
}
<|endoftext|>


<commit_before>module.exports = function (element, bindingParser) {
  var binding;
  var attributes = element.attributes;
  if (attributes) {
    for (var i = 0; i < attributes.length; ++i) {
      var attr = attributes[i];
      binding = bindingParser.parse(attr.nodeValue);
      if (binding) {
        element.setAttributeNS(attr.namespaceURI, attr.localName, binding.provide());
      }
    }
  }
  if (element.nodeType === 3) { // TEXT_NODE
    binding = bindingParser.parse(element.nodeValue);
    if (binding) {
    debugger;
      element.nodeValue = binding.provide();
    }
  }
};
<commit_msg>Removed debugger statement<commit_after>module.exports = function (element, bindingParser) {
  var binding;
  var attributes = element.attributes;
  if (attributes) {
    for (var i = 0; i < attributes.length; ++i) {
      var attr = attributes[i];
      binding = bindingParser.parse(attr.nodeValue);
      if (binding) {
        element.setAttributeNS(attr.namespaceURI, attr.localName, binding.provide());
      }
    }
  }
  if (element.nodeType === 3) { // TEXT_NODE
    binding = bindingParser.parse(element.nodeValue);
    if (binding) {
      element.nodeValue = binding.provide();
    }
  }
};
<|endoftext|>


<commit_before>const request = require('request')

const POLL_TIMEOUT = 30 * 1000

const APIS = [
  {
    url: 'https://api.rss2json.com/v1/api.json?rss_url=https://www.mi5.gov.uk/UKThreatLevel/UKThreatLevel.xml',
    eventName: 'mi5',
    disabled: true
  },
  {
    url: 'http://www.aljazeera.com/addons/alert.ashx',
    eventName: 'aljaz'
  },
  {
    url: 'http://polling.bbc.co.uk/news/latest_breaking_news_waf?audience=Domestic',
    eventName: 'bbc',
    payload: { tag: 'domestic' },
    customDecoder: (data) => data.asset
  },
  {
    url: 'http://polling.bbc.co.uk/news/latest_breaking_news_waf?audience=US',
    eventName: 'bbc2',
    payload: { tag: 'US & Canada' },
    customDecoder: (data) => data.asset
  },
  {
    url: 'http://uk.reuters.com/assets/breakingNews?view=json',
    eventName: 'reuters',
    payload: { tag: 'UK' }
  },
  {
    url: 'http://reuters.com/assets/breakingNews?view=json',
    eventName: 'reuters',
    payload: { tag: 'US?' }
  },
  { // this one is very loud
    url: 'http://uk.reuters.com/assets/jsonWireNews',
    eventName: 'reuwire',
    customDecoder: (data) => data.headlines
  }
]

const requestApi = (bot, api) => {
  if (api.disabled) return
  request(api.url, (err, res, body) => {
    if (err) return bot.log('warn', `Error polling ${api.url}: ${err}`)
    let payload
    try {
      if (res.body.trim() === '') body = '{}' // reuters sends empty on no news
      payload = JSON.parse(body)
    } catch (e) {
      if (!(e instanceof SyntaxError)) throw e
      return bot.log('error', `Syntax error decoding ${api.url}: ${payload} ${body}`)
    }
    if (api.customDecoder) {
      payload = api.customDecoder(payload)
    }
    if (api.payload) {
      Object.assign(api.payload, payload)
    }
    bot.fireEvents(`rawnews:${api.eventName}`, payload)
  })
}

const pollApis = (bot, skip) => {
  APIS.map(a => requestApi(bot, a))
  if (!skip && bot.config.get('news.poll')) {
    setTimeout(pollApis, POLL_TIMEOUT, bot)
  }
}

module.exports = {
  pollApis: pollApis,
  onload: (bot) => {
    if (bot.config.get('news.poll')) {
      pollApis(bot)
    } else {
      bot.log('info', 'Automatic polling of news disabled')
    }
  }
}
<commit_msg>Update BBC endpoint URL; disable AJ endpoint<commit_after>const request = require('request')

const POLL_TIMEOUT = 30 * 1000

const APIS = [
  {
    url: 'https://api.rss2json.com/v1/api.json?rss_url=https://www.mi5.gov.uk/UKThreatLevel/UKThreatLevel.xml',
    eventName: 'mi5',
    disabled: true
  },
  {
    url: 'http://www.aljazeera.com/addons/alert.ashx',
    disabled: true,
    eventName: 'aljaz'
  },
  {
    url: 'http://polling.bbc.co.uk/news/breaking-news/audience/domestic',
    eventName: 'bbc',
    payload: { tag: 'domestic' },
    customDecoder: (data) => data.asset
  },
  {
    url: 'http://polling.bbc.co.uk/news/breaking-news/audience/international',
    eventName: 'bbc',
    payload: { tag: 'international' },
    customDecoder: (data) => data.asset
  },
  {
    url: 'http://uk.reuters.com/assets/breakingNews?view=json',
    eventName: 'reuters',
    payload: { tag: 'UK' }
  },
  {
    url: 'http://reuters.com/assets/breakingNews?view=json',
    eventName: 'reuters',
    payload: { tag: 'US?' }
  },
  { // this one is very loud
    url: 'http://uk.reuters.com/assets/jsonWireNews',
    eventName: 'reuwire',
    customDecoder: (data) => data.headlines
  }
]

const requestApi = (bot, api) => {
  if (api.disabled) return
  request(api.url, (err, res, body) => {
    if (err) return bot.log('warn', `Error polling ${api.url}: ${err}`)
    let payload
    try {
      if (res.body.trim() === '') body = '{}' // reuters sends empty on no news
      payload = JSON.parse(body)
    } catch (e) {
      if (!(e instanceof SyntaxError)) throw e
      return bot.log('error', `Syntax error decoding ${api.url}: ${payload} ${body}`)
    }
    if (api.customDecoder) {
      payload = api.customDecoder(payload)
    }
    if (api.payload) {
      Object.assign(api.payload, payload)
    }
    bot.fireEvents(`rawnews:${api.eventName}`, payload)
  })
}

const pollApis = (bot, skip) => {
  APIS.map(a => requestApi(bot, a))
  if (!skip && bot.config.get('news.poll')) {
    setTimeout(pollApis, POLL_TIMEOUT, bot)
  }
}

module.exports = {
  pollApis: pollApis,
  onload: (bot) => {
    if (bot.config.get('news.poll')) {
      pollApis(bot)
    } else {
      bot.log('info', 'Automatic polling of news disabled')
    }
  }
}
<|endoftext|>


<commit_before>var express = require('express');
var app = express();

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

app.get('/', function (req, res) {
  res.send('Word Mapper says: Hello World!');
});

app.listen(80, function () {
  console.log('Word Mapper listening on port 80!');
});
<commit_msg>Fixing server port.<commit_after>var express = require('express');
var app = express();

// set the port of our application
// process.env.PORT lets the port be set by Heroku
var port = process.env.PORT || 80;

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

app.get('/', function (req, res) {
  res.send('Word Mapper says: Hello World!');
});

app.listen(port, function () {
  console.log('Word Mapper listening on port 80!');
});
<|endoftext|>


<commit_before>exports.messages = {
  admin: 'Starte VS Code als Administrator um die Änderungen durchführen zu können.',
  enabled: 'Icons aktiviert, starte VS Code bitte neu.',
  disabled: 'Icons deaktiviert, starte VS Code bitte neu.',
  already_disabled: 'Icons wurden bereits deaktiviert.',
  smthingwrong: 'Ups! Etwas ist schief gelaufen: ',
  restartIde: 'Visual Studio Code neu starten'
}
<commit_msg>add semicolon<commit_after>exports.messages = {
  admin: 'Starte VS Code als Administrator um die Änderungen durchführen zu können.',
  enabled: 'Icons aktiviert, starte VS Code bitte neu.',
  disabled: 'Icons deaktiviert, starte VS Code bitte neu.',
  already_disabled: 'Icons wurden bereits deaktiviert.',
  smthingwrong: 'Ups! Etwas ist schief gelaufen: ',
  restartIde: 'Visual Studio Code neu starten'
};
<|endoftext|>


<commit_before>module.exports = {
  "extends": "./",

  "parser": "babel-eslint",

  "env": {
    "es6": true
  },

  "rules": {

    // Override to warn about unnecessary Use Strict Directives
    "strict": [1, "never"],

    /**
     * ECMAScript 6
     * These rules are only relevant to ES6 environments and are off by default.
     */

    // require parens in arrow function arguments
    "arrow-parens": 0,

    // verify super() callings in constructors (off by default)
    "constructor-super": 2,

    // enforce the spacing around the * in generator functions (off by default)
    "generator-star-spacing": [2, { "before": true, "after": false }],

    // disallow to use this/super before super() calling in constructors. (off by default)
    "no-this-before-super": 2,

    // require let or const instead of var (off by default)
    "no-var": 1,

    // require method and property shorthand syntax for object literals (off by default)
    "object-shorthand": [1, "always"],

    // suggest using of const declaration for variables that are never modified after declared (off by default)
    "prefer-const": 1

  }
};
<commit_msg>Add the arrow-spacing rule<commit_after>module.exports = {
  "extends": "./",

  "parser": "babel-eslint",

  "env": {
    "es6": true
  },

  "rules": {

    // Override to warn about unnecessary Use Strict Directives
    "strict": [1, "never"],

    /**
     * ECMAScript 6
     * These rules are only relevant to ES6 environments and are off by default.
     */

    // require parens in arrow function arguments
    "arrow-parens": 0,

    // require parens in arrow function arguments
    "arrow-spacing": [2, { "before": true, "after": true }],

    // verify super() callings in constructors (off by default)
    "constructor-super": 2,

    // enforce the spacing around the * in generator functions (off by default)
    "generator-star-spacing": [2, { "before": true, "after": false }],

    // disallow to use this/super before super() calling in constructors. (off by default)
    "no-this-before-super": 2,

    // require let or const instead of var (off by default)
    "no-var": 1,

    // require method and property shorthand syntax for object literals (off by default)
    "object-shorthand": [1, "always"],

    // suggest using of const declaration for variables that are never modified after declared (off by default)
    "prefer-const": 1

  }
};
<|endoftext|>


<commit_before>jQuery(document).ready(
	function() {
		jQuery('input.ajaxQuantityField').each(
			function() {
				jQuery(this).attr('disabled', false);
				jQuery(this).change(
					function() {
						var name = jQuery(this).attr('name')+ '_SetQuantityLink';
						var setQuantityLink = jQuery('[name=' + name + ']');
						if(jQuery(setQuantityLink).length > 0) {
							setQuantityLink = jQuery(setQuantityLink).get(0);
							if(! this.value) this.value = 0;
							else this.value = this.value.replace(/[^0-9]+/g, '');
							var url = jQuery('base').attr('href') + setQuantityLink.value + '?quantity=' + this.value;
							jQuery.getJSON(url, null, setChanges);
						}
					}
				);
			}
		);
		jQuery('select.ajaxCountryField').each(
			function() {
				jQuery(this).attr('disabled', false);
				jQuery(this).change(
					function() {
						var id = '#' + jQuery(this).attr('id') + '_SetCountryLink';
						var setCountryLink = jQuery(id);
						if(jQuery(setCountryLink).length > 0) {
							setCountryLink = jQuery(setCountryLink).get(0);
							var url = jQuery('base').attr('href') + setCountryLink.value + '/' + this.value;
							jQuery.getJSON(url, null, setChanges);
						}
					}
				);
			}
		);
	}
);

function setChanges(changes) {
	for(var i in changes) {
		var change = changes[i];
		if(typeof(change.parameter) != 'undefined' && typeof(change.value) != 'undefined') {
			var parameter = change.parameter;
			var value = escapeHTML(change.value);
			if(change.id) {
				var id = '#' + change.id;
				jQuery(id).attr(parameter, value);
			}
			else if(change.name) {
				var name = change.name;
				jQuery('[name=' + name + ']').each(
					function() {
						jQuery(this).attr(parameter, value);
					}
				);
			}
		}
	}
}

function escapeHTML(str) {
   var div = document.createElement('div');
   var text = document.createTextNode(str);
   div.appendChild(text);
   return div.innerHTML;
}<commit_msg>fixes from IVO - THANK YOU<commit_after>jQuery(document).ready(
	function() {
		jQuery('input.ajaxQuantityField').each(
			function() {
				jQuery(this).removeAttr('disabled');
				jQuery(this).change(
					function() {
						var name = jQuery(this).attr('name')+ '_SetQuantityLink';
						var setQuantityLink = jQuery('[name=' + name + ']');
						if(jQuery(setQuantityLink).length > 0) {
							setQuantityLink = jQuery(setQuantityLink).get(0);
							if(! this.value) this.value = 0;
							else this.value = this.value.replace(/[^0-9]+/g, '');
							var url = jQuery('base').attr('href') + setQuantityLink.value + '?quantity=' + this.value;
							jQuery.getJSON(url, null, setChanges);
						}
					}
				);
			}
		);
		jQuery('select.ajaxCountryField').each(
			function() {
				jQuery(this).removeAttr('disabled');
				jQuery(this).change(
					function() {
						var id = '#' + jQuery(this).attr('id') + '_SetCountryLink';
						var setCountryLink = jQuery(id);
						if(jQuery(setCountryLink).length > 0) {
							setCountryLink = jQuery(setCountryLink).get(0);
							var url = jQuery('base').attr('href') + setCountryLink.value + '/' + this.value;
							jQuery.getJSON(url, null, setChanges);
						}
					}
				);
			}
		);
	}
);

function setChanges(changes) {
	for(var i in changes) {
		var change = changes[i];
		if(typeof(change.parameter) != 'undefined' && typeof(change.value) != 'undefined') {
			var parameter = change.parameter;
			var value = escapeHTML(change.value);
			if(change.id) {
				var id = '#' + change.id;
				if(parameter == 'innerHTML'){
					jQuery(id).html(value);
				}
				else{
				jQuery(id).attr(parameter, value);
			}
			}
			else if(change.name) {
				var name = change.name;
				jQuery('[name=' + name + ']').each(
					function() {
						jQuery(this).attr(parameter, value);
					}
				);
			}
		}
	}
}

function escapeHTML(str) {
   var div = document.createElement('div');
   var text = document.createTextNode(str);
   div.appendChild(text);
   return div.innerHTML;
}<|endoftext|>


<commit_before>// Quirks mode reference -- http://www.quirksmode.org/dom/w3c_css.html
var styleSheets = document.styleSheets,
    styleSheetRules = [].map.call(styleSheets, function (sheet) { return sheet.cssRules || sheet.rules || []; }),
    rules = [];

styleSheetRules.forEach(function (sheetRules) {
  rules.push.apply(rules, sheetRules);
});

// TODO: Don't forget about imports ;_;

// TODO: Might need to normalize rules formats

// Create a new style sheet
// TODO: Cross-browser with same technique as getComputedStyle -- should be abstracted into module
var retSheet = document.createElement('style');

// Iterate over the rules
function Rule(_rule) {
  // Save the original rule and style
  this._rule = _rule;
  this._style = _rule.style;

  // Create a location for storing overrides
  this.overrides = {};
}
Rule.prototype = {
  getValue: function (prop) {
    // Attempt to resolve value from overrides and fallback to getPropertyValue
    // TODO: getPropertyValue will not work in IE
    return this.overrides[prop] || this._style.getPropertyValue(prop);
  },
  setValue: function (prop, val) {
    // Save the property to overrides
    this.overrides[prop] = val;
  },
  desaturate: function (prop) {
    // Grab the original value
    var origVal = this.getValue(prop);

    // If there was no value, skip it
    if (!origVal) { return; }

    // Otherwise, desaturate it
    // TODO: Convert into {r,g,b} -> h,s,l -> h,0,l
    this.setValue(prop, Math.random() >= 0.5 ? 'black' : 'white');
  },
  exportChanges: function () {
    // Create an object with new definitions
    // TODO: selectorText is incorrect in IE according to quirksmode
    var selector = this._rule.selectorText;

    var overrides = this.overrides,
        changedNames = Object.getOwnPropertyNames(overrides),
        changes = changedNames.map(function (name) {
          return name + ': ' + overrides[name] + ';';
        });

    return {
      selector: selector,
      value: changes.join('\n')
    };
  }
};

var retRules = rules.map(function (_rule) {
  // Create a rule
  var rule = new Rule(_rule);

  // Desaturate the rule
  rule.desaturate('color');
  rule.desaturate('background-color');

  // Export it
  var ruleObj = rule.exportChanges();

  console.log(ruleObj);

  // Create a CSS rule
  var retVal = ruleObj.selector + ' { ' + ruleObj.value + ' } ';
  return retVal;
});

// Create a new rule set for the sheet
retSheet.innerHTML = retRules.join('\n');

// Append the sheet
document.getElementsByTagName('head')[0].appendChild(retSheet);<commit_msg>Desaturation is in but blue and red desaturate to the same value? =(<commit_after>// Quirks mode reference -- http://www.quirksmode.org/dom/w3c_css.html
var styleSheets = document.styleSheets,
    styleSheetRules = [].map.call(styleSheets, function (sheet) { return sheet.cssRules || sheet.rules || []; }),
    rules = [];

styleSheetRules.forEach(function (sheetRules) {
  rules.push.apply(rules, sheetRules);
});

// TODO: Don't forget about imports ;_;

// TODO: Might need to normalize rules formats

// Create a new style sheet
// TODO: Cross-browser with same technique as getComputedStyle -- should be abstracted into module
var retSheet = document.createElement('style');

// TODO: Get full list from http://www.w3.org/TR/css3-color/#svg-color
// TOOD: Use https://github.com/cloudhead/less.js/blob/master/lib/less/colors.js
var COLORS = {
      red: {r: 255, g: 0, b: 0},
      green: {r: 0, g: 128, b: 0},
      blue: {r: 0, g: 0, b: 255}
    };
function RgbColor(color) {
  // TODO: Robustify this...
  this.rgb = COLORS[color];
}
RgbColor.prototype = {
  // Attribution to https://github.com/cloudhead/less.js/blob/5e0ed82e71d812a5c133ab2dcdb5a8a978298fe7/lib/less/tree/color.js#L83-L105
  toHSL: function () {
    var r = this.rgb.r / 255,
        g = this.rgb.g / 255,
        b = this.rgb.b / 255;

    var max = Math.max(r, g, b), min = Math.min(r, g, b);
    var h, s, l = (max + min) / 2, d = max - min;

    if (max === min) {
        h = s = 0;
    } else {
        s = l > 0.5 ? d / (2 - max - min) : d / (max + min);

        switch (max) {
            case r: h = (g - b) / d + (g < b ? 6 : 0); break;
            case g: h = (b - r) / d + 2; break;
            case b: h = (r - g) / d + 4; break;
        }
        h /= 6;
    }
    return { h: h * 360, s: s, l: l};
  }
};

// Iterate over the rules
function Rule(_rule) {
  // Save the original rule and style
  this._rule = _rule;
  this._style = _rule.style;

  // Create a location for storing overrides
  this.overrides = {};
}
Rule.prototype = {
  getValue: function (prop) {
    // Attempt to resolve value from overrides and fallback to getPropertyValue
    // TODO: getPropertyValue will not work in IE
    return this.overrides[prop] || this._style.getPropertyValue(prop);
  },
  setValue: function (prop, val) {
    // Save the property to overrides
    this.overrides[prop] = val;
  },
  desaturate: function (prop) {
    // Grab the original value
    var origVal = this.getValue(prop);

    // If there was no value, skip it
    if (!origVal) { return; }

    // Otherwise, desaturate it
    var color = new RgbColor(origVal),
        hsl = color.toHSL();
    this.setValue(prop, 'hsl(' + hsl.h + ', 0%, ' + hsl.l * 100 + '%)');
  },
  exportChanges: function () {
    // Create an object with new definitions
    // TODO: selectorText is incorrect in IE according to quirksmode
    var selector = this._rule.selectorText;

    var overrides = this.overrides,
        changedNames = Object.getOwnPropertyNames(overrides),
        changes = changedNames.map(function (name) {
          return name + ': ' + overrides[name] + ';';
        });

    return {
      selector: selector,
      value: changes.join('\n')
    };
  }
};

var retRules = rules.map(function (_rule) {
  // Create a rule
  var rule = new Rule(_rule);

  // Desaturate the rule
  rule.desaturate('color');
  rule.desaturate('background-color');

  // Export it
  var ruleObj = rule.exportChanges();

  console.log(ruleObj);

  // Create a CSS rule
  var retVal = ruleObj.selector + ' { ' + ruleObj.value + ' } ';
  return retVal;
});

// Create a new rule set for the sheet
retSheet.innerHTML = retRules.join('\n');

// Append the sheet
document.getElementsByTagName('head')[0].appendChild(retSheet);<|endoftext|>


<commit_before>'use strict';

var path              = require('path'),
    fs                = require('fs'),
    through           = require('through2'),
    sass              = require('node-sass'),
    gutil             = require('gulp-util'),
    slash             = require('gulp-slash'),
    rework            = require('rework'),
    visit             = require('rework-visit'),
    convert           = require('convert-source-map'),
    SourceMapConsumer = require('source-map').SourceMapConsumer,
    mime              = require('mime');

/**
 * Search for the relative file reference from the startPath up to the process
 * working directory, avoiding any other directories with a package.json or bower.json.
 * @param {string} startPath The location of the uri declaration and the place to start the search from
 * @param {string} uri The content of the url() statement, expected to be a relative file path
 * @returns {string} dataURI of the file where found or undefined otherwise
 */
function encodeRelativeURL(startPath, uri) {

  /**
   * Test whether the given directory is the root of its own package
   * @param {string} absolutePath An absolute path
   * @returns {boolean} True where a package.json or bower.json exists, else False
   */
  function notPackage(absolutePath) {
    return ['package.json', 'bower.json'].every(function fileNotFound(file) {
      return !(fs.existsSync(path.resolve(absolutePath, file)));
    });
  }

  /**
   * Enqueue subdirectories that are not packages and are not in the root path
   * @param {Array} queue The queue to add to
   * @param {string} basePath The path to consider
   */
  function enqueue(queue, basePath) {
    fs.readdirSync(basePath)
      .filter(function notHidden(filename) {
        return (filename.charAt(0) !== '.');
      })
      .map(function toAbsolute(filename) {
        return path.join(basePath, filename);
      })
      .filter(function directoriesOnly(absolutePath) {
        return fs.statSync(absolutePath).isDirectory();
      })
      .filter(function notInRootPath(absolutePath) {
        return (pathToRoot.indexOf(absolutePath) < 0);
      })
      .filter(notPackage)
      .forEach(function enqueue(absolutePath) {
        queue.push(absolutePath);
      });
  }

  // ignore data uris and ensure we are at a valid start path
  var absoluteStart = !(/^data\:/.test(uri)) && path.resolve(startPath);
  if (absoluteStart) {

    // find path to the root, stopping at cwd, package.json or bower.json
    var pathToRoot = [];
    var isWorking;
    do {
      pathToRoot.push(absoluteStart);
      isWorking     = (absoluteStart !== process.cwd()) && notPackage(absoluteStart);
      absoluteStart = path.resolve(absoluteStart, '..');
    } while (isWorking);

    // start a queue with the path to the root
    var queue = pathToRoot.concat();

    // process the queue until empty
    //  the queue pattern ensures that we favour paths closest the the start path
    while (queue.length) {

      // shift the first item off the queue, consider it the base for our relative uri
      var basePath = queue.shift();
      var fullPath = path.resolve(basePath, uri);

      // file exists so convert to a dataURI and end
      if (fs.existsSync(fullPath)) {
        var type     = mime.lookup(fullPath);
        var contents = fs.readFileSync(fullPath);
        var base64   = new Buffer(contents).toString('base64');
        return 'data:' + type + ';base64,' + base64;
      }
      // enqueue subdirectories that are not packages and are not in the root path
      else {
        enqueue(queue, basePath);
      }
    }
  }
}

/**
 * Use node-sass to compile the files of the input stream.
 * Outputs a stream of compiled files and their source-maps, alternately.
 * @see https://github.com/sass/node-sass#outputstyle
 * @param {Array.<string>} [libraryPaths] Any number of library path strings
 * @returns {stream.Through} A through stream that performs the operation of a gulp stream
 */
module.exports = function (bannerWidth, libraryPaths) {
  var output  = [ ];
  var libList = (libraryPaths || [ ]).filter(function isString(value) {
    return (typeof value === 'string');
  });
  return through.obj(function (file, encoding, done) {
    var stream = this;

    // setup parameters
    var sourcePath = file.path.replace(path.basename(file.path), '');
    var sourceName = path.basename(file.path, path.extname(file.path));
    var mapName    = sourceName + '.css.map';
    var sourceMapConsumer;

    /**
     * Push file contents to the output stream.
     * @param {string} ext The extension for the file, including dot
     * @param {string|object?} contents The contents for the file or fields to assign to it
     * @return {vinyl.File} The file that has been pushed to the stream
     */
    function pushResult(ext, contents) {
      var pending = new gutil.File({
        cwd:      file.cwd,
        base:     file.base,
        path:     sourcePath + sourceName + ext,
        contents: (typeof contents === 'string') ? new Buffer(contents) : null
      });
      if (typeof contents === 'object') {
        for (var key in contents) {
          pending[key] = contents[key];
        }
      }
      stream.push(pending);
      return pending;
    }

    /**
     * Plugin for css rework that follows SASS transpilation
     * @param {object} stylesheet AST for the CSS output from SASS
     */
    function reworkPlugin(stylesheet) {

      // visit each node (selector) in the stylesheet recursively using the official utility method
      //  each node may have multiple declarations
      visit(stylesheet, function visitor(declarations) {
        declarations
          .forEach(eachDeclaration);
      });

      /**
       * Process a declaration from the syntax tree.
       * @param declaration
       */
      function eachDeclaration(declaration) {
        var URL_STATEMENT_REGEX = /(url\s*\()\s*(?:(['"])((?:(?!\2).)*)(\2)|([^'"](?:(?!\)).)*[^'"]))\s*(\))/g;

        // reverse the original source-map to find the original sass file
        var cssStart = declaration.position.start;
        var sassStart = sourceMapConsumer.originalPositionFor({
          line  : cssStart.line,
          column: cssStart.column
        });
        if (!sassStart.source) {
          throw new Error('failed to decode node-sass source map'); // this can occur with regressions in libsass
        }
        var sassDir = path.dirname(sassStart.source);

        // allow multiple url() values in the declaration
        //  split by url statements and process the content
        //  additional capture groups are needed to match quotations correctly
        //  escaped quotations are not considered
        declaration.value = declaration.value
          .split(URL_STATEMENT_REGEX)
          .map(eachSplitOrGroup)
          .join('');

        /**
         * Encode the content portion of url() statements.
         * There are 4 capture groups in the split making every 5th unmatched.
         * @param {string} token A single split item
         * @param i The index of the item in the split
         * @returns {string} Every 3 or 5 items is an encoded url everything else is as is
         */
        function eachSplitOrGroup(token, i) {

          // we can get groups as undefined under certain match circumstances
          var initialised = token || '';

          // the content of the url() statement is either in group 3 or group 5
          var mod = i % 7;
          if ((mod === 3) || (mod === 5)) {

            // remove query string or hash suffix
            var uri = initialised.split(/[?#]/g).shift();
            return uri && encodeRelativeURL(sassDir, uri) || initialised;
          }
          // everything else, including parentheses and quotation (where present) and media statements
          else {
            return initialised;
          }
        }
      }
    }

    /**
     * Handler for successful transpilation using node-sass.
     * This functions gets called with an object containing a CSS file and its source-map,
     * which is modified and passed through CSS rework, before being pushed to the results.
     * @param {string} css Compiled css
     * @param {string} map The source-map for the compiled css
     */
    function successHandler(css, map) {

      // adjust source-map
      var sourceMap = convert.fromJSON(map).toObject();
      sourceMap.sources.forEach(function (value, i, array) {
        array[i] = path.resolve(value.replace(/^\//, '').replace(/\b\/+\b/g, '/'));  // ensure single slash absolute
      });

      // prepare the adjusted sass source-map for later look-ups
      sourceMapConsumer = new SourceMapConsumer(sourceMap);

      // embed sourcemap in css
      var cssWithMap = css.replace(
        /\/\*#\s*sourceMappingURL=[^*]*\*\//m,
        '/*# sourceMappingURL=data:application/json;base64,' + convert.fromObject(sourceMap).toBase64() + ' */'
      );

      // rework css
      var reworked = rework(cssWithMap, '')
        .use(reworkPlugin)
        .toString({
          sourcemap        : true,
          sourcemapAsObject: true
        });

      // adjust overall sourcemap
      delete reworked.map.file;
      delete reworked.map.sourcesContent;
      reworked.map.sources.forEach(function (value, i, array) {
        array[i] = '/' + slash(path.relative(process.cwd(), value));   // ensure root relative
      });

      // write stream output
      pushResult('.css', reworked.code + '\n/*# sourceMappingURL=' + mapName  + ' */');
      pushResult('.css.map', JSON.stringify(reworked.map, null, 2));
      done();
    }

    /**
     * Handler for error in node-sass.
     * @param {string} error The error text from node-sass
     */
    function errorHandler(error) {
      var analysis = /(.*)\:(\d+)\:\s*error\:\s*(.*)/.exec(error);
      var resolved = path.resolve(analysis[1]);
      var filename = [ '.scss', '.css']
        .map(function (ext) {
          return resolved + ext;
        })
        .filter(function (fullname) {
          return fs.existsSync(fullname);
        })
        .pop();
      var message  = analysis ?
        ((filename || resolved) + ':' + analysis[2] + ':0: ' + analysis[3] + '\n') :
        ('TODO parse this error\n' + error + '\n');
      if (output.indexOf(message) < 0) {
        output.push(message);
      }
      done();
    }

    /**
     * Perform the sass render with the given sourceMap, error, and success
     * parameters.
     * @param {string|boolean} map The source map filename or false for none
     * @param {function ({string})} error Handler for error
     * @param {function ({string}, {string})} success Handler for success
     */
    function render(map, error, success) {
      sass.render({
        file        : file.path,
        data        : file.contents.toString(),
        success     : success,
        error       : error,
        includePaths: libList,
        outputStyle : 'compressed',
        stats       : { },
        sourceMap   : map
      });
    }

    // run first without source-map as this can cause process exit where errors exist
    render(false, errorHandler, function () {
      render(mapName, errorHandler, successHandler);
    });

  }, function (done) {

    // display the output buffer with padding before and after and between each item
    if (output.length) {
      var width = Number(bannerWidth) || 0;
      var hr    = new Array(width + 1);   // this is a good trick to repeat a character N times
      var start = (width > 0) ? (hr.join('\u25BC') + '\n') : '';
      var stop  = (width > 0) ? (hr.join('\u25B2') + '\n') : '';
      process.stdout.write(start + '\n' + output.join('\n') + '\n' + stop);
    }
    done();
  });
};<commit_msg>added `fs.existsSync()` before `fs.statSync()` to address crash caused by broken symlinks in `node_modules`<commit_after>'use strict';

var path              = require('path'),
    fs                = require('fs'),
    through           = require('through2'),
    sass              = require('node-sass'),
    gutil             = require('gulp-util'),
    slash             = require('gulp-slash'),
    rework            = require('rework'),
    visit             = require('rework-visit'),
    convert           = require('convert-source-map'),
    SourceMapConsumer = require('source-map').SourceMapConsumer,
    mime              = require('mime');

/**
 * Search for the relative file reference from the startPath up to the process
 * working directory, avoiding any other directories with a package.json or bower.json.
 * @param {string} startPath The location of the uri declaration and the place to start the search from
 * @param {string} uri The content of the url() statement, expected to be a relative file path
 * @returns {string} dataURI of the file where found or undefined otherwise
 */
function encodeRelativeURL(startPath, uri) {

  /**
   * Test whether the given directory is the root of its own package
   * @param {string} absolutePath An absolute path
   * @returns {boolean} True where a package.json or bower.json exists, else False
   */
  function notPackage(absolutePath) {
    return ['package.json', 'bower.json'].every(function fileNotFound(file) {
      return !(fs.existsSync(path.resolve(absolutePath, file)));
    });
  }

  /**
   * Enqueue subdirectories that are not packages and are not in the root path
   * @param {Array} queue The queue to add to
   * @param {string} basePath The path to consider
   */
  function enqueue(queue, basePath) {
    fs.readdirSync(basePath)
      .filter(function notHidden(filename) {
        return (filename.charAt(0) !== '.');
      })
      .map(function toAbsolute(filename) {
        return path.join(basePath, filename);
      })
      .filter(function directoriesOnly(absolutePath) {
        return fs.existsSync(absolutePath) && fs.statSync(absolutePath).isDirectory();
      })
      .filter(function notInRootPath(absolutePath) {
        return (pathToRoot.indexOf(absolutePath) < 0);
      })
      .filter(notPackage)
      .forEach(function enqueue(absolutePath) {
        queue.push(absolutePath);
      });
  }

  // ignore data uris and ensure we are at a valid start path
  var absoluteStart = !(/^data\:/.test(uri)) && path.resolve(startPath);
  if (absoluteStart) {

    // find path to the root, stopping at cwd, package.json or bower.json
    var pathToRoot = [];
    var isWorking;
    do {
      pathToRoot.push(absoluteStart);
      isWorking     = (absoluteStart !== process.cwd()) && notPackage(absoluteStart);
      absoluteStart = path.resolve(absoluteStart, '..');
    } while (isWorking);

    // start a queue with the path to the root
    var queue = pathToRoot.concat();

    // process the queue until empty
    //  the queue pattern ensures that we favour paths closest the the start path
    while (queue.length) {

      // shift the first item off the queue, consider it the base for our relative uri
      var basePath = queue.shift();
      var fullPath = path.resolve(basePath, uri);

      // file exists so convert to a dataURI and end
      if (fs.existsSync(fullPath)) {
        var type     = mime.lookup(fullPath);
        var contents = fs.readFileSync(fullPath);
        var base64   = new Buffer(contents).toString('base64');
        return 'data:' + type + ';base64,' + base64;
      }
      // enqueue subdirectories that are not packages and are not in the root path
      else {
        enqueue(queue, basePath);
      }
    }
  }
}

/**
 * Use node-sass to compile the files of the input stream.
 * Outputs a stream of compiled files and their source-maps, alternately.
 * @see https://github.com/sass/node-sass#outputstyle
 * @param {Array.<string>} [libraryPaths] Any number of library path strings
 * @returns {stream.Through} A through stream that performs the operation of a gulp stream
 */
module.exports = function (bannerWidth, libraryPaths) {
  var output  = [ ];
  var libList = (libraryPaths || [ ]).filter(function isString(value) {
    return (typeof value === 'string');
  });
  return through.obj(function (file, encoding, done) {
    var stream = this;

    // setup parameters
    var sourcePath = file.path.replace(path.basename(file.path), '');
    var sourceName = path.basename(file.path, path.extname(file.path));
    var mapName    = sourceName + '.css.map';
    var sourceMapConsumer;

    /**
     * Push file contents to the output stream.
     * @param {string} ext The extension for the file, including dot
     * @param {string|object?} contents The contents for the file or fields to assign to it
     * @return {vinyl.File} The file that has been pushed to the stream
     */
    function pushResult(ext, contents) {
      var pending = new gutil.File({
        cwd:      file.cwd,
        base:     file.base,
        path:     sourcePath + sourceName + ext,
        contents: (typeof contents === 'string') ? new Buffer(contents) : null
      });
      if (typeof contents === 'object') {
        for (var key in contents) {
          pending[key] = contents[key];
        }
      }
      stream.push(pending);
      return pending;
    }

    /**
     * Plugin for css rework that follows SASS transpilation
     * @param {object} stylesheet AST for the CSS output from SASS
     */
    function reworkPlugin(stylesheet) {

      // visit each node (selector) in the stylesheet recursively using the official utility method
      //  each node may have multiple declarations
      visit(stylesheet, function visitor(declarations) {
        declarations
          .forEach(eachDeclaration);
      });

      /**
       * Process a declaration from the syntax tree.
       * @param declaration
       */
      function eachDeclaration(declaration) {
        var URL_STATEMENT_REGEX = /(url\s*\()\s*(?:(['"])((?:(?!\2).)*)(\2)|([^'"](?:(?!\)).)*[^'"]))\s*(\))/g;

        // reverse the original source-map to find the original sass file
        var cssStart = declaration.position.start;
        var sassStart = sourceMapConsumer.originalPositionFor({
          line  : cssStart.line,
          column: cssStart.column
        });
        if (!sassStart.source) {
          throw new Error('failed to decode node-sass source map'); // this can occur with regressions in libsass
        }
        var sassDir = path.dirname(sassStart.source);

        // allow multiple url() values in the declaration
        //  split by url statements and process the content
        //  additional capture groups are needed to match quotations correctly
        //  escaped quotations are not considered
        declaration.value = declaration.value
          .split(URL_STATEMENT_REGEX)
          .map(eachSplitOrGroup)
          .join('');

        /**
         * Encode the content portion of url() statements.
         * There are 4 capture groups in the split making every 5th unmatched.
         * @param {string} token A single split item
         * @param i The index of the item in the split
         * @returns {string} Every 3 or 5 items is an encoded url everything else is as is
         */
        function eachSplitOrGroup(token, i) {

          // we can get groups as undefined under certain match circumstances
          var initialised = token || '';

          // the content of the url() statement is either in group 3 or group 5
          var mod = i % 7;
          if ((mod === 3) || (mod === 5)) {

            // remove query string or hash suffix
            var uri = initialised.split(/[?#]/g).shift();
            return uri && encodeRelativeURL(sassDir, uri) || initialised;
          }
          // everything else, including parentheses and quotation (where present) and media statements
          else {
            return initialised;
          }
        }
      }
    }

    /**
     * Handler for successful transpilation using node-sass.
     * This functions gets called with an object containing a CSS file and its source-map,
     * which is modified and passed through CSS rework, before being pushed to the results.
     * @param {string} css Compiled css
     * @param {string} map The source-map for the compiled css
     */
    function successHandler(css, map) {

      // adjust source-map
      var sourceMap = convert.fromJSON(map).toObject();
      sourceMap.sources.forEach(function (value, i, array) {
        array[i] = path.resolve(value.replace(/^\//, '').replace(/\b\/+\b/g, '/'));  // ensure single slash absolute
      });

      // prepare the adjusted sass source-map for later look-ups
      sourceMapConsumer = new SourceMapConsumer(sourceMap);

      // embed sourcemap in css
      var cssWithMap = css.replace(
        /\/\*#\s*sourceMappingURL=[^*]*\*\//m,
        '/*# sourceMappingURL=data:application/json;base64,' + convert.fromObject(sourceMap).toBase64() + ' */'
      );

      // rework css
      var reworked = rework(cssWithMap, '')
        .use(reworkPlugin)
        .toString({
          sourcemap        : true,
          sourcemapAsObject: true
        });

      // adjust overall sourcemap
      delete reworked.map.file;
      delete reworked.map.sourcesContent;
      reworked.map.sources.forEach(function (value, i, array) {
        array[i] = '/' + slash(path.relative(process.cwd(), value));   // ensure root relative
      });

      // write stream output
      pushResult('.css', reworked.code + '\n/*# sourceMappingURL=' + mapName  + ' */');
      pushResult('.css.map', JSON.stringify(reworked.map, null, 2));
      done();
    }

    /**
     * Handler for error in node-sass.
     * @param {string} error The error text from node-sass
     */
    function errorHandler(error) {
      var analysis = /(.*)\:(\d+)\:\s*error\:\s*(.*)/.exec(error);
      var resolved = path.resolve(analysis[1]);
      var filename = [ '.scss', '.css']
        .map(function (ext) {
          return resolved + ext;
        })
        .filter(function (fullname) {
          return fs.existsSync(fullname);
        })
        .pop();
      var message  = analysis ?
        ((filename || resolved) + ':' + analysis[2] + ':0: ' + analysis[3] + '\n') :
        ('TODO parse this error\n' + error + '\n');
      if (output.indexOf(message) < 0) {
        output.push(message);
      }
      done();
    }

    /**
     * Perform the sass render with the given sourceMap, error, and success
     * parameters.
     * @param {string|boolean} map The source map filename or false for none
     * @param {function ({string})} error Handler for error
     * @param {function ({string}, {string})} success Handler for success
     */
    function render(map, error, success) {
      sass.render({
        file        : file.path,
        data        : file.contents.toString(),
        success     : success,
        error       : error,
        includePaths: libList,
        outputStyle : 'compressed',
        stats       : { },
        sourceMap   : map
      });
    }

    // run first without source-map as this can cause process exit where errors exist
    render(false, errorHandler, function () {
      render(mapName, errorHandler, successHandler);
    });

  }, function (done) {

    // display the output buffer with padding before and after and between each item
    if (output.length) {
      var width = Number(bannerWidth) || 0;
      var hr    = new Array(width + 1);   // this is a good trick to repeat a character N times
      var start = (width > 0) ? (hr.join('\u25BC') + '\n') : '';
      var stop  = (width > 0) ? (hr.join('\u25B2') + '\n') : '';
      process.stdout.write(start + '\n' + output.join('\n') + '\n' + stop);
    }
    done();
  });
};<|endoftext|>


<commit_before>import path from 'path';
import mkdirp from 'mkdirp';
import {getURLForHunspellDictionary} from './node-spellchecker';
import {getInstalledKeyboardLanguages} from 'keyboard-layout';
import {Observable} from 'rx';

import {fs} from './promisify';
import {normalizeLanguageCode} from './utility';

let d = require('debug-electron')('electron-spellchecker:dictionary-sync');

const app = process.type === 'renderer' ?
  require('electron').remote.app :
  require('electron').app;

const {downloadFileOrUrl} =
  require('electron-remote').requireTaskPool(require.resolve('electron-remote/remote-ajax'));

/**
 * DictioanrySync handles downloading and saving Hunspell dictionaries. Pass it
 * to {{SpellCheckHandler}} to configure a custom cache directory.
 */
export default class DictionarySync {
  /**
   * Creates a DictionarySync
   *
   * @param  {String} cacheDir    The path to a directory to store dictionaries.
   *                              If not given, the Electron user data directory
   *                              will be used.
   */
  constructor(cacheDir=null) {
    this.cacheDir = cacheDir || path.join(app.getPath('userData'), 'dictionaries');
    mkdirp.sync(this.cacheDir);
  }

  /**
   * Override the default logger for this class. You probably want to use
   * {{setGlobalLogger}} instead
   *
   * @param {Function} fn   The function which will operate like console.log
   */
  static setLogger(fn) {
    d = fn;
  }

  /**
   * Loads the dictionary for a given language code, trying first to load a
   * local version, then downloading it. You probably don't want this method
   * directly, but the wrapped version
   * {{loadDictionaryForLanguageWithAlternatives}} which is in {{SpellCheckHandler}}.
   *
   * @param  {String} langCode        The language code (i.e. 'en-US')
   * @param  {Boolean} cacheOnly      If true, don't load the file content into
   *                                  memory, only download it
   *
   * @return {Promise<Buffer|String>}     A Buffer of the file contents if
   *                                      {{cacheOnly}} is False, or the path to
   *                                      the file if True.
   */
  async loadDictionaryForLanguage(langCode, cacheOnly=false) {
    d(`Loading dictionary for language ${langCode}`);
    if (process.platform === 'darwin') return new Buffer([]);

    let lang = normalizeLanguageCode(langCode);
    let target = path.join(this.cacheDir, `${lang}.bdic`);

    let fileExists = false;
    try {
      if (fs.existsSync(target)) {
        fileExists = true;
        d(`Returning local copy: ${target}`);
        let ret = await fs.readFile(target, {});

        if (ret.length < 64*1024) {
          throw new Error("File exists but is most likely bogus");
        }
      }
    } catch (e) {
      d(`Failed to read file ${target}: ${e.message}`);
    }

    if (fileExists) {
      try {
        await fs.unlink(target);
      } catch (e) {
        d("Can't clear out file, bailing");
        throw e;
      }
    }

    let url = getURLForHunspellDictionary(lang);
    d(`Actually downloading ${url}`);
    await downloadFileOrUrl(url, target);

    if (cacheOnly) return target;

    let ret = await fs.readFile(target, {});
    if (ret.length < 64*1024) {
      throw new Error("File exists but is most likely bogus");
    }

    return ret;
  }

  /**
   * Pre-download dictionaries for languages that the user is likely to speak
   * (based usually on their keyboard layouts). Note that this method only works
   * on Windows currently.
   *
   * @param  {Array<String>} languageList     Override the list of languages to
   *                                          download, for testing.
   *
   * @return {Promise<Array<String>>}         A list of strings to dictionaries
   *                                          that were downloaded.
   */
  preloadDictionaries(languageList=null) {
    return Observable.from(languageList || getInstalledKeyboardLanguages())
      .flatMap((x) => Observable.fromPromise(this.loadDictionaryForLanguage(x, true)))
      .reduce((acc,x) => { acc.push(x); return acc; }, [])
      .toPromise();
  }
}
<commit_msg>I am dum<commit_after>import path from 'path';
import mkdirp from 'mkdirp';
import {getURLForHunspellDictionary} from './node-spellchecker';
import {getInstalledKeyboardLanguages} from 'keyboard-layout';
import {Observable} from 'rx';

import {fs} from './promisify';
import {normalizeLanguageCode} from './utility';

let d = require('debug-electron')('electron-spellchecker:dictionary-sync');

const app = process.type === 'renderer' ?
  require('electron').remote.app :
  require('electron').app;

const {downloadFileOrUrl} =
  require('electron-remote').requireTaskPool(require.resolve('electron-remote/remote-ajax'));

/**
 * DictioanrySync handles downloading and saving Hunspell dictionaries. Pass it
 * to {{SpellCheckHandler}} to configure a custom cache directory.
 */
export default class DictionarySync {
  /**
   * Creates a DictionarySync
   *
   * @param  {String} cacheDir    The path to a directory to store dictionaries.
   *                              If not given, the Electron user data directory
   *                              will be used.
   */
  constructor(cacheDir=null) {
    this.cacheDir = cacheDir || path.join(app.getPath('userData'), 'dictionaries');
    mkdirp.sync(this.cacheDir);
  }

  /**
   * Override the default logger for this class. You probably want to use
   * {{setGlobalLogger}} instead
   *
   * @param {Function} fn   The function which will operate like console.log
   */
  static setLogger(fn) {
    d = fn;
  }

  /**
   * Loads the dictionary for a given language code, trying first to load a
   * local version, then downloading it. You probably don't want this method
   * directly, but the wrapped version
   * {{loadDictionaryForLanguageWithAlternatives}} which is in {{SpellCheckHandler}}.
   *
   * @param  {String} langCode        The language code (i.e. 'en-US')
   * @param  {Boolean} cacheOnly      If true, don't load the file content into
   *                                  memory, only download it
   *
   * @return {Promise<Buffer|String>}     A Buffer of the file contents if
   *                                      {{cacheOnly}} is False, or the path to
   *                                      the file if True.
   */
  async loadDictionaryForLanguage(langCode, cacheOnly=false) {
    d(`Loading dictionary for language ${langCode}`);
    if (process.platform === 'darwin') return new Buffer([]);

    let lang = normalizeLanguageCode(langCode);
    let target = path.join(this.cacheDir, `${lang}.bdic`);

    let fileExists = false;
    try {
      if (fs.existsSync(target)) {
        fileExists = true;
        d(`Returning local copy: ${target}`);
        let ret = await fs.readFile(target, {});

        if (ret.length < 64*1024) {
          throw new Error("File exists but is most likely bogus");
        }

	return ret;
      }
    } catch (e) {
      d(`Failed to read file ${target}: ${e.message}`);
    }

    if (fileExists) {
      try {
        await fs.unlink(target);
      } catch (e) {
        d("Can't clear out file, bailing");
        throw e;
      }
    }

    let url = getURLForHunspellDictionary(lang);
    d(`Actually downloading ${url}`);
    await downloadFileOrUrl(url, target);

    if (cacheOnly) return target;

    let ret = await fs.readFile(target, {});
    if (ret.length < 64*1024) {
      throw new Error("File exists but is most likely bogus");
    }

    return ret;
  }

  /**
   * Pre-download dictionaries for languages that the user is likely to speak
   * (based usually on their keyboard layouts). Note that this method only works
   * on Windows currently.
   *
   * @param  {Array<String>} languageList     Override the list of languages to
   *                                          download, for testing.
   *
   * @return {Promise<Array<String>>}         A list of strings to dictionaries
   *                                          that were downloaded.
   */
  preloadDictionaries(languageList=null) {
    return Observable.from(languageList || getInstalledKeyboardLanguages())
      .flatMap((x) => Observable.fromPromise(this.loadDictionaryForLanguage(x, true)))
      .reduce((acc,x) => { acc.push(x); return acc; }, [])
      .toPromise();
  }
}
<|endoftext|>


<commit_before>import path from 'path';
import mkdirp from 'mkdirp';
import {getURLForHunspellDictionary} from '@paulcbetts/spellchecker';
import {getInstalledKeyboardLanguages} from 'keyboard-layout';
import {Observable} from 'rx';

import {fs} from './promisify';
import {normalizeLanguageCode} from './utility';

const d = require('debug')('electron-spellchecker:dictionary-sync');

const app = process.type === 'renderer' ?
  require('electron').remote.app :
  require('electron').app;

const {downloadFileOrUrl} = process.type === 'browser' ?
  require('electron-remote').requireTaskPool(require.resolve('electron-remote/remote-ajax')) :
  require('electron-remote/remote-ajax');

export default class DictionarySync {
  constructor(cacheDir=null) {
    this.cacheDir = cacheDir || path.join(app.getPath('userData'), 'dictionaries');
    mkdirp.sync(this.cacheDir);
  }

  async loadDictionaryForLanguage(langCode, cacheOnly=false) {
    d(`Loading dictionary for language ${langCode}`);
    if (process.platform === 'darwin') return new Buffer([]);

    let lang = normalizeLanguageCode(langCode);
    let target = path.join(this.cacheDir, `${lang}.bdic`);

    let fileExists = false;
    try {
      if (fs.existsSync(target)) {
        fileExists = true;
        d(`Returning local copy: ${target}`);
        return await fs.readFile(target, {});
      }
    } catch (e) {
      d(`Failed to read file ${target}: ${e.message}`);
      throw e;
    }

    if (fileExists) {
      try {
        await fs.unlink(target);
      } catch (e) {
        d("Can't clear out file, bailing");
        throw e;
      }
    }

    let url = getURLForHunspellDictionary(lang);
    d(`Actually downloading ${url}`);
    await downloadFileOrUrl(url, target);

    if (cacheOnly) return target; return await fs.readFile(target, {});
  }

  preloadDictionaries(languageList=null) {
    return Observable.from(languageList || getInstalledKeyboardLanguages())
      .flatMap((x) => Observable.fromPromise(this.loadDictionaryForLanguage(x, true)))
      .reduce((acc,x) => { acc.push(x); return acc; }, [])
      .toPromise();
  }
}
<commit_msg>Always create remote windows so we don't have to deal with CORS nonsense<commit_after>import path from 'path';
import mkdirp from 'mkdirp';
import {getURLForHunspellDictionary} from '@paulcbetts/spellchecker';
import {getInstalledKeyboardLanguages} from 'keyboard-layout';
import {Observable} from 'rx';

import {fs} from './promisify';
import {normalizeLanguageCode} from './utility';

const d = require('debug')('electron-spellchecker:dictionary-sync');

const app = process.type === 'renderer' ?
  require('electron').remote.app :
  require('electron').app;

const {downloadFileOrUrl} =
  require('electron-remote').requireTaskPool(require.resolve('electron-remote/remote-ajax'));

export default class DictionarySync {
  constructor(cacheDir=null) {
    this.cacheDir = cacheDir || path.join(app.getPath('userData'), 'dictionaries');
    mkdirp.sync(this.cacheDir);
  }

  async loadDictionaryForLanguage(langCode, cacheOnly=false) {
    d(`Loading dictionary for language ${langCode}`);
    if (process.platform === 'darwin') return new Buffer([]);

    let lang = normalizeLanguageCode(langCode);
    let target = path.join(this.cacheDir, `${lang}.bdic`);

    let fileExists = false;
    try {
      if (fs.existsSync(target)) {
        fileExists = true;
        d(`Returning local copy: ${target}`);
        return await fs.readFile(target, {});
      }
    } catch (e) {
      d(`Failed to read file ${target}: ${e.message}`);
      throw e;
    }

    if (fileExists) {
      try {
        await fs.unlink(target);
      } catch (e) {
        d("Can't clear out file, bailing");
        throw e;
      }
    }

    let url = getURLForHunspellDictionary(lang);
    d(`Actually downloading ${url}`);
    await downloadFileOrUrl(url, target);

    if (cacheOnly) return target; return await fs.readFile(target, {});
  }

  preloadDictionaries(languageList=null) {
    return Observable.from(languageList || getInstalledKeyboardLanguages())
      .flatMap((x) => Observable.fromPromise(this.loadDictionaryForLanguage(x, true)))
      .reduce((acc,x) => { acc.push(x); return acc; }, [])
      .toPromise();
  }
}
<|endoftext|>


<commit_before>// Tracking categories.
export const VIDEO_CATEGORY = 'Discovery Video';
export const NAVIGATION_CATEGORY = 'Discovery Navigation';

// Action types.
export const DISCO_RESULTS = 'DISCO_RESULTS';

// Keys for extensions and theme data in the discovery pane JSON blob.
export const DISCO_DATA_THEME = 'theme';
export const DISCO_DATA_EXTENSION = 'extension';
export const DISCO_DATA_UNKNOWN = 'unknown';
// Built-in extensions and themes to ignore.
export const DISCO_DATA_GUID_IGNORE_LIST = [
  '{972ce4c6-7e08-4474-a285-3208198ce6fd}', // Default theme.
  'e10srollout@mozilla.org', // e10s
  'firefox@getpocket.com', // Pocket
  'loop@mozilla.org', // Firefox Hello
  'aushelper@mozilla.org', // Application Update Service Helper
  'webcompat@mozilla.org', // Web Compat
];
<commit_msg>Adding Nightly System Add-ons to the ignore list<commit_after>// Tracking categories.
export const VIDEO_CATEGORY = 'Discovery Video';
export const NAVIGATION_CATEGORY = 'Discovery Navigation';

// Action types.
export const DISCO_RESULTS = 'DISCO_RESULTS';

// Keys for extensions and theme data in the discovery pane JSON blob.
export const DISCO_DATA_THEME = 'theme';
export const DISCO_DATA_EXTENSION = 'extension';
export const DISCO_DATA_UNKNOWN = 'unknown';
// Built-in extensions and themes to ignore.
export const DISCO_DATA_GUID_IGNORE_LIST = [
  '{972ce4c6-7e08-4474-a285-3208198ce6fd}', // Default theme.
  'e10srollout@mozilla.org', // e10s
  'firefox@getpocket.com', // Pocket
  'loop@mozilla.org', // Firefox Hello
  'aushelper@mozilla.org', // Application Update Service Helper
  'webcompat@mozilla.org', // Web Compat
  'flyweb@mozilla.org', // FlyWeb
  'formautofill@mozilla.org', // Form Autofill
  'presentation@mozilla.org', // Presentation
  'shield-recipe-client@mozilla.org', // Shield Recipe Client
];
<|endoftext|>