Example #1
0
var generateTestUsers = module.exports.generateTestUsers = function(restCtx, total, callback, _createdUsers) {
    total = OaeUtil.getNumberParam(total, 1);
    _createdUsers = _createdUsers || [];
    if (total === 0) {
        var callbackArgs = [];
        callbackArgs.push(null);
        callbackArgs.push(_.indexBy(_createdUsers, function(user) { return user.user.id; }));
        callbackArgs = _.union(callbackArgs, _createdUsers);
        return callback.apply(callback, callbackArgs);
    }

    // Ensure that the provided rest context has been authenticated before trying to use it to
    // create users
    _ensureAuthenticated(restCtx, function(err) {
        if (err) {
            return callback(err);
        }

        var username = generateTestUserId('random-user');
        var displayName = generateTestGroupId('random-user');
        var email = generateTestEmailAddress(username);
        RestAPI.User.createUser(restCtx, username, 'password', displayName, {'email': email}, function(err, user) {
            if (err) {
                return callback(err);
            }

            _createdUsers.push({
                'user': user,
                'restContext': new RestContext(restCtx.host, {
                    'hostHeader': restCtx.hostHeader,
                    'username': username,
                    'userPassword': 'password',
                    'strictSSL': restCtx.strictSSL
                })
            });

            // Recursively continue creating users
            return generateTestUsers(restCtx, --total, callback, _createdUsers);

        });
    });
};
Scraper.prototype.prepare = function prepare () {
	var self = this;

	// Create makeRequest function with custom request params
	self.makeRequest = makeRequest.bind(null, self.options.request);

	// Create array of Resource for downloading
	self.options.urls = _.isArray(self.options.urls) ? self.options.urls : [self.options.urls];
	self.originalResources = _.map(self.options.urls, function createResource (obj) {
		var url = _.isObject(obj) && _.has(obj, 'url') ? obj.url : obj;
		var filename = _.isObject(obj) && _.has(obj, 'filename') ? obj.filename : self.options.defaultFilename;
		return new Resource(url, filename);
	});

	if (self.options.recursive) {
		self.options.sources = _.union(self.options.sources, recursiveSources);
	}

	return ensureDirAsync(self.options.directory);
};
Example #3
0
        searchDocumentProducer(resourcesToIndex[resourceType], function(err, documents) {
            if (err) {
                log().error({'err': err, 'resources': resourcesToIndex[resourceType]}, 'Error producing search documents from resources');
                return callback(err);
            }

            documents = _.map(documents, function(doc) {
                var newDoc = _.extend({}, doc, {'_type': SearchConstants.search.MAPPING_RESOURCE, 'resourceType': resourceType});
                if (newDoc['_extra']) {
                    newDoc['_extra'] = JSON.stringify(newDoc['_extra']);
                }

                log().trace({'before': doc, 'after': newDoc}, 'Converted resource document');
                return newDoc;
            });

            // Union current documents with the ones we just produced and continue recursively
            _documents = _.union(_documents, documents);
            return _produceAllResourceDocuments(resourcesToIndex, callback, _resourceTypes, _documents);
        });
Example #4
0
ResourceBuilder.buildJs = function(comps, pages, dir, version, dirnames){
  var compJs = _.flatten(_.map(comps, function(comp){ 
    return comp.getComponentJS();
  }));

  var pageJs = _.flatten(_.map(pages, function(page){ 
    return page.getPageJS();
  }));

  var allJs = _.union(Assets.globalJS(), pageJs, compJs);

  var localJs = util.removeExternal(allJs);
  var externalJs = util.removeInternal(allJs);

  var combined = combineAndMinifyJS(localJs, dir, version, dirnames);

  externalJs.push(combined);

  return externalJs;
}
Example #5
0
 db.get(user_id, function(err, user){
     if(err){
         console.log("error with get user by id : ", err);
         res.send({error: "Internal Server error"}, 500);
         res.end();
         return;
     }
     user.products = user.products || [];
     user.products = _.union(user.products, products);
     db.update(user.login, user, function(err, user){
         if(err){
                 console.log("error with update user : ", err);
                 res.send({error: "Internal Server error"}, 500);
                 res.end();
                 return;
         }
         res.send(user, 200);
         res.end()
     })
 })
Example #6
0
setInterval(function () {

  var booksByTime = _.groupBy(books, 'ts');
  var tradesByTime = _.groupBy(trades, 'ts');

  var want = {};
  _.union(Object.keys(booksByTime), Object.keys(tradesByTime)).forEach(function(e) {
    want[e] = [];
    if(booksByTime[e]) want[e] = want[e].concat(booksByTime[e])
    if(tradesByTime[e]) want[e] = want[e].concat(tradesByTime[e])
  });

  if(Object.keys(want).length != 0) {
    fs.writeSync(data_file, JSON.stringify(want))
    fs.writeSync(data_file, ",\n");
  }

  books = [];
  trades = [];
}, 5000);
Example #7
0
 self._rolesParents(roleNames, function(err, parents){
   roles = _.union(roleNames, parents);
   async.whilst(
     function (){ 
       return parents.length >0;
     },
     function (cb) {
       self._rolesParents(parents, function(err, result){
         if(!err){
           roles = _.union(roles, parents);
           parents = result;
         }
         cb(err);
       });
     },
     function(err){
       cb(err, roles);
     }
   );
 });
Example #8
0
    return gulp.task('css:bower-concat', function () {
        tars_bower_deps = TarsBowerDeps.getTarsBowerDeps();
        bower_deps_paths = [];
        _.each(tars_bower_deps.depsCssFiles(), function (element, index) {
            bower_deps_paths.push('./markup/' + tarsConfig.fs.staticFolderName + '/scss/' + tarsConfig.bower_css_folder + '/' + element);

        });

        cssPaths = _.union(bower_deps_paths, cssPaths);
        return gulp.src(cssPaths)
            .pipe(concat('vendor' + buildOptions.hash + '.css'))
            // .pipe(gulpif(tarsConfig.es6_transpile, babel()))
            .on('error', notify.onError(function (error) {
                return '\nAn error occurred while concating bower js-files.\nLook in the console for details.\n' + error;
            }))
            .pipe(gulp.dest('./dev/' + tarsConfig.fs.staticFolderName + '/css'))
            .pipe(
                notifier('Bower Css\'ve been concatinated')
            );
    });
        initialize: function (options) {
            // track inheritance for easy debugging
            this._inherits = _.union(this._inherits || [],
                [myName, myParentName]);
            /*dbg:*/ console.debug('MUSTDO initialize ' + this._inherits[0], options);

            Super.prototype.initialize.apply(this, options);

            // bring supported options into the instance as properties
            this.mergeOptions(options, this.XyzzyViewOptions);

            // alternative to the modelEvents/collectionEvents config
            this.listenTo(this.model, 'change:property', this.whenPropertyChanged);
            this.listenTo(this.collection, 'add', this.whenAddedModel);

            this.on('tooltip:show', function (args) {
                //args.keys = view, model, collection as needed
            });

        },
Example #10
0
    q.all([blogsDatabase(), blogsFeed()]).spread(function(a, b) {

      let x;
      let l;
      let feedItems;

      /** Join them with union function after using sortBy function to rearrange them in correct data order
       * **/

      feedItems = _.union(_.sortBy(a, function(o) {
        return o.date * -1;
      }), _.sortBy(b, function(o) {
        return !o.date;
      }));

      for (x = 0, l = feedItems.length; x !== l; x += 1) {
        feed.item(feedItems[x]);
      }

    });
Example #11
0
 _renderStats: function () {
   if (!this._columnsReady()) {
     return;
   }
   var withWidgetAndGraph = this._columnsModel.getColumnsWithWidgetAndGraph();
   var withWidget = this._columnsModel.getColumnsWithWidget();
   var withGraph = this._columnsModel.getColumnsWithGraph();
   var withoutGraph = this._columnsModel.getColumnsWithoutGraph();
   var all;
   if (withWidgetAndGraph.length === 0 && withWidget.length === 0 &&
     withGraph.length === 0 && withoutGraph.length === 0) {
     renderLoading = false;
     this._infoboxModel.set({state: 'no-data'});
     this._showLoading();
   } else {
     this.$el.empty();
     all = _.union(withWidgetAndGraph, withWidget, withGraph, withoutGraph);
     this._renderColumns(all);
   }
 },
Example #12
0
    hasElementInScope: function (target, includes) {
        // FIXME: These are supposed to be in specific namespaces
        var list = _.union([
                // HTML Namespace
                'applet',
                'caption',
                'html',
                'table',
                'td',
                'th',
                'marquee',
                'object',
                // MathML Namespace
                'mi',
                'mo',
                'mn',
                'ms',
                'mtext',
                'annotation-xml',
                // SVG Namespace
                'foreignObject',
                'desc',
                'title'
            ], includes),
            i = this.stack.length,
            node;

        while (i) {
            i -= 1;
            node = this.stack[i];
            if (node.name === target) {
                return true;
            }
            if (_.include(list, node.name)) {
                return false;
            }
        }

        // Safeguard. This should actually never happen, as 'html' should be the first item in the stack and terminate with false in the loop
        return false;
    },
Example #13
0
    		function(req, res) {
    			if (req.form.isValid) {
    				User.findOne({email: req.form.email}, function (error, user) {
    					if (user && user.password) {
    						var oldPasswordHash = encodeURIComponent(user.password);
    						var userId = user._id;
    						var resetLink = conf.site_url+"/reset-password/?userId="+userId+"&verify="+oldPasswordHash;
    						var resetMessage = "Olá, <br/>Clique no link para resetar sua senha no PopBroker:<br/><a href=\""+resetLink+"\">"+resetLink+"</a>";
    						mail.message({
    							'MIME-Version': '1.0',
    							'Content-type': 'text/html;charset=UTF-8',
    							from: 'PopBroker Suporte <'+ conf.site_email + '>',
    							to: user.email,
    							subject: conf.site_name + ': resetar senha'
    						}).body(resetMessage)
								.send(function(err) {
    								if (err) {
    									req.session.errors.push(
    										err.toString());
    									res.redirect('back');
    								}
    							});
							
							req.session.messages.push(
								'E-mail enviado com sucesso. Go verifique sua inbox!');
							res.redirect('back');
    					}
    					else {
    						req.session.errors.push(
    							"E-mail não encontrado na lista de usuários!");
    						res.redirect('back');
    					}
    				});
    			}
    			else {
    				req.session.errors = _.union(
		                req.session.errors||[],
		                req.form.errors);
					res.redirect('back');
    			}
    });
Example #14
0
          pg.query('select * from images where day_id= $1', [dayId], function(err, images){
            console.log('results from show day', results.rows);
            console.log('results2 from show day', results2.rows);
            console.log('results3 from show day', results3.rows);
            console.log('messages from show day', messages);
            console.log('images from show day', images);

            var likes = parseInt(results2.rows[0].count)  + parseInt(results3.rows[0].count);
            console.log('likes in show day', likes);
            console.log('username from show day', results);

            var day = results.rows[0];
            day.likes = likes;
            var messagesArray = messages.rows,
            imagesArray = (images.rows.length !== 0) ? images.rows : [];

            day.updates =_.union(messagesArray, imagesArray);

            cb(null, day);

          });
Example #15
0
Items.prototype.queryByCate = function() {
  console.log('======queryByCate');
  var args = Array.prototype.slice.call(arguments);
  var cateId = args[0];
  var start = null;
  var limit = null;
  var cb = args[1];
  if (args.length == 4) {
    start = args[2];
    limit = args[3];
  }

  var wheres = _.union([
    'i.catid=c.id',
    'c.id=?'
  ], this.defaultWheres);
  var table = this.tableName + ',' + prefix + 'k2_categories as c';
  var sql = this.buildSql(table, this.defaultFields, wheres, this.defaultOrder, [start, limit]);

  this.execSql(sql, cb, cateId);
};
	TemplateRenderer.prototype.init = function (config) {
		config = config || {};

		if (typeof config.staticsPath === 'string') {
			this.staticsPath = config.staticsPath;
		}

		if (Array.isArray(config.templateKeys)) {
			this.templateKeys = _.union(this.templateKeys, config.templateKeys);
		}

		if ('helpers' in config) {
			Object.keys(config.helpers).forEach(function (name) {
				this.addHelper(name, config.helpers[name]);
			}.bind(this));
		}

		if ('useShims' in config) {
			this.useShims = config.useShims;
		}
	};
Example #17
0
 set: function(v) {
   // Set normalized array of words for searching
   var words = _.union(
     v.split(/\s+/).map( function(s) {
       return s.toLowerCase();
     }),
     v.split(/\s+/).map( function(s) {
       return unorm.nfkd(s.toLowerCase()).replace(/[\u0300-\u036F]/g, '');
     })
   );
   this.name_words = words;
   // Set the double metaphone entries. Currently just stores both primary and secondary without saying which is which
   var dm_words = [];
   words.forEach( function(w) { dm_words.push.apply(dm_words, _.values(dm.doubleMetaphone(w)) ) } );
   // Also include the words to make the searching easier. Perhaps this can be just one array?
   this.name_dm = dm_words.concat(words);
   // If we don't already have a slug set it
   if (!this.slug) this.slug = v;
   // Don't change the value
   return v;
 },
 _.each(type.properties,function(prop,idx){
   if(prop.permission !== 'read-only' && prop.name.indexOf('Modules.')!==0){
     
     propertyNamesOfType.push(prop.name);
     
     // property name
     if(props[prop.name]){ //if duplicated propertie name, merge available vales.
       _.extend(props[prop.name],{
         description : props[prop.name].description==prop.description.replace( /<p>|<\/p\>/g, '')?props[prop.name].description:''
       });
       if(prop.constants.length) props[prop.name].values = _.union(props[prop.name].values,prop.constants);
       
     }else{
       props[prop.name] = {
         "description": prop.description.replace( /<p>|<\/p\>/g, ''),
         "type": prop.type //[type.name]
       };
       if(prop.constants.length) props[prop.name].values = prop.constants;
     }
   }
 });
Example #19
0
module.exports = function(grunt) {
  grunt.initConfig(_.extend.apply(this, _.union([{
    pkg: grunt.file.readJSON('package.json')
  }], gruntConfig)));

  // Load tasks
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-cssmin');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-express-server');

  // RegisterTasks
  grunt.registerTask('build:css', ['concat:css','cssmin:css']);
  grunt.registerTask('build:js', ['jshint','concat:js','uglify:js']);
  grunt.registerTask('build', ['build:css','build:js']);
  grunt.registerTask('serve', ['express', 'watch']);
  grunt.registerTask('start', ['build', 'serve']);
  grunt.registerTask('default', []);
};
  selectRegions: function(e){
    var targ = this.$('#shipsToRegions'),
        setCountries = this.regions[targ.val()],
        shipsTo = this.$('#shipsTo'),
        oldVal = shipsTo.val() || [],
        wwIndex = oldVal.indexOf('ALL'),
        newVal;

    if(setCountries) {
      if (wwIndex > -1) {
        oldVal.splice(wwIndex, 1)
      }
      newVal = __.union(oldVal, setCountries);
      this.$('#shipsTo').val(newVal);
      this.$('.chosen').trigger('chosen:updated');
      this.prevShipsToVal = newVal;
    }
    //reset to blank
    targ.val("");
    this.$('.chosenRegions').trigger('chosen:updated');
  },
Prefetcher.startOtherFoldersPrefetch = function ()
{
	var
		oFolderList = MailCache.folderList(),
		sCurrFolder = oFolderList.currentFolderFullName(),
		aFoldersFromAccount = MailCache.getNamesOfFoldersToRefresh(),
		aSystemFolders = oFolderList ? [oFolderList.inboxFolderFullName(), oFolderList.sentFolderFullName(), oFolderList.draftsFolderFullName(), oFolderList.spamFolderFullName()] : [],
		aOtherFolders = (aFoldersFromAccount.length < 5) ? this.getOtherFolderNames(5 - aFoldersFromAccount.length) : [],
		aFolders = _.uniq(_.compact(_.union(aSystemFolders, aFoldersFromAccount, aOtherFolders))),
		bPrefetchStarted = false
	;

	_.each(aFolders, _.bind(function (sFolder) {
		if (!bPrefetchStarted && sCurrFolder !== sFolder)
		{
			bPrefetchStarted = this.startFolderPrefetch(oFolderList.getFolderByFullName(sFolder));
		}
	}, this));

	return bPrefetchStarted;
};
Example #22
0
var getMultipleRevisions = module.exports.getMultipleRevisions = function(revisionIds, opts, callback) {
    var columns = '*';

    // If specific fields were specified, convert it into the string: "field0","field1","field2",...
    if (opts && opts.fields) {
        // Always fetch the revisionId
        opts.fields = _.union(opts.fields, 'revisionId');
        columns = util.format('"%s"', opts.fields.join('","'));
    }

    Cassandra.runQuery(util.format('SELECT %s FROM "Revisions" WHERE "revisionId" IN (?)', columns), [revisionIds], function(err, rows) {
        if (err) {
            return callback(err);
        }

        // Generate the Revision objects
        var revisions = _.map(rows, _rowToRevision);

        return callback(null, revisions);
    });
};
Example #23
0
        searchDocumentProducer(resourcesToIndex[resourceType], function(errs, documents) {
            // Some resources might have triggered an error. We log those here,
            // but we try to include any documents that were generated
            _.each(errs, function(err) {
                log().error({'err': err}, 'Error producing search documents from resources');
            });

            documents = _.map(documents, function(doc) {
                var newDoc = _.extend({}, doc, {'_type': SearchConstants.search.MAPPING_RESOURCE, 'resourceType': resourceType});
                if (newDoc['_extra']) {
                    newDoc['_extra'] = JSON.stringify(newDoc['_extra']);
                }

                log().trace({'before': doc, 'after': newDoc}, 'Converted resource document');
                return newDoc;
            });

            // Union current documents with the ones we just produced and continue recursively
            _documents = _.union(_documents, documents);
            return _produceAllResourceDocuments(resourcesToIndex, callback, _resourceTypes, _documents);
        });
Example #24
0
    SearchAPI.postIndexTask('group', resourceGroupIndexTask, resourceIndexOp, function(err) {
        if (err) {
            allErrs = _.union(allErrs, [err]);
        }

        // If there are group index tasks to invoke, do it
        OaeUtil.invokeIfNecessary(!_.isEmpty(memberGroupIndexTasks), SearchAPI.postIndexTask, 'group', memberGroupIndexTasks, membershipsIndexOp, function(err) {
            if (err) {
                allErrs = _.union(allErrs, [err]);
            }

            // If there are user index tasks to invoke, do it
            OaeUtil.invokeIfNecessary(!_.isEmpty(memberUserIndexTasks), SearchAPI.postIndexTask, 'user', memberUserIndexTasks, membershipsIndexOp, function(err) {
                if (err) {
                    allErrs = _.union(allErrs, [err]);
                }

                return callback(allErrs);
            });
        });
    });
Example #25
0
    q.await(function() {
      var query = path.split('?')[1];
      var translate = false;
      var lang;

      // remove query string and trailing slash
      path = path.split('?')[0].replace(/\/$/, '');

      if (query) {
        // If file= in path, use it as file name
        if (query.indexOf('file=') !== -1) {
          file = query.match(/file=([^&]*)/)[1];

          // remove filename and trailing slash
          path = path.split(file)[0].replace(/\/$/, '');
        }

        // If lang= in path, set lang and add to categories
        if (query.indexOf('lang=') !== -1) {
          lang = query.match(/lang=([^&]*)/)[1];
          metadata.lang = lang;
          metadata.categories = _.isArray(metadata.categories) ? _.union(metadata.categories, lang) : [lang];
        }

        translate = query.indexOf('translate=true') !== -1 ? true : false;
      }

      cb(null, {
        'metadata': metadata,
        'default_metadata': defaultMetadata,
        'content': '## A New Post\n\nEnter text in [Markdown](http://daringfireball.net/projects/markdown/). Use the toolbar above, or click the **?** button for formatting help.',
        'repo': repo,
        'path': path,
        'published': false,
        'persisted': false,
        'writable': true,
        'file': file,
        'translate': translate
      });
    });
Example #26
0
	makeDatabaseText.substr(skipOfs).split("\n\n").forEach(function(block) {
		// accumulated state
		var depText;
		
		var i, line, lines = block.split("\n");
		for(i = 0; i < lines.length; ++i) {
			line = lines[i];

			if(line.indexOf("# Not a target") === 0)
				return; // bomb out of the entire thing

			var colonIdx = line.indexOf(':');
			if(colonIdx > 0 && line[colonIdx+1] === '=') {
				// VAR := value
				variables[line.substr(0,colonIdx).trim()] = line.substr(colonIdx+2).trim();
			} else if(line.indexOf('=') > 0 && line.indexOf('=') < colonIdx) {
				// avoid this line I see on mac os x:
				// __CF_USER_TEXT_ENCODING = 0x1F5:0:0
				;
			} else if(colonIdx > 0) {
				line = line.replace(/#.*$/, '');
				colonIdx = line.indexOf(':');
				if(colonIdx > 0) {
					depText = line.trim();
				}
			}
		}

		if(depText && depText.length && depText[0] !== '%') {
			var colonIdx = depText.indexOf(':');
			var target = depText.substr(0,colonIdx).trim();
			var sources = splitFileList(depText.substr(colonIdx+1));

			if(!deps[target]) {
				deps[target] = sources;
			} else {
				deps[target] = underscore.union(deps[target], sources);
			}
		}
	});
    }, function(err, result) {
        if (result) {
            var needToSave = true;

            record.hashs.every(function(txHash) {
                if (_.contains(result.hashs, txHash)) {
                    needToSave = false;
                }
                return needToSave;
            });

            if (needToSave) {
                result.i_pays_value = result.i_pays_value - (-record.i_pays_value);
                result.i_gets_value = result.i_gets_value - (-record.i_gets_value);
                result.hashs = _.union(result.hashs, record.hashs);
                result.price = au.toExp(result.i_pays_value / result.i_gets_value);
                result.save(function(err) {
                    if (err) {
                        throw new Error(err);
                    } else if (callback) {
                        callback();
                    }
                });
            } else {
                console.log("find same hash in existing hashes");
                if (callback) {
                    callback();
                }
            }
        } else {
            var row = new txHisotry(record);
            row.save(function(err) {
                if (err) {
                    throw new Error(err);
                } else if (callback) {
                    callback();
                }
            });
        }
    })
	async.each( this._selectors, function( thisSelector, callback ) {
		thisSelector = _.extend( {
			fields : [],
			where : {},
			sort : null,
			skip : 0,
			limit : 0
		}, thisSelector );

		var allConditions = [];
		if( thisSelector.where ) allConditions.push( thisSelector.where );

		var projection = {};

		var mongoQuery = allConditions.length > 1 ? { $and : allConditions } : _.first( allConditions );
		if( thisSelector.fields !== "*" ) {
			thisSelector.fields = _.union( thisSelector.fields, "_id" ); // _id field is mandatory
			
			_.each( thisSelector.fields, function( thisField ) {
				projection[ thisField ] = true;
			} );
		}

		var cursor = _this._collection.find( mongoQuery, projection );
		if( thisSelector.skip ) cursor.skip( thisSelector.skip );
		if( thisSelector.limit ) cursor.limit( thisSelector.limit );
		
		cursor.toArray( function( err, records ) {
			if( err ) return callback( err );

			_.each( records, function( thisRecord ) {
				var recordId = thisRecord._id;

				recordsById[ recordId ] = recordsById[ recordId ] || {};
				_.extend( recordsById[ recordId ], thisRecord );
			} );

			callback();
		} );
	}, function( err ) {
Example #29
0
	this.getCollisions = function(row, col, caller) {

		var collisions = [];
		if (this.grid[row][col].collideable) {
			collisions.push(this.grid[row][col]);
		}

		var objs = _.union(this.snakes, this.foods);
		for (var i = 0; i < objs.length; i++) {
			var contains = false;
			if (objs[i] === caller) {
				contains = objs[i].containsWithoutHead(row, col);
			} else {
				contains = objs[i].contains(row, col);
			}
			if (contains) {
				collisions.push(objs[i]);
			}
		}

		return collisions;
	};
// Add page metadata, containing title, description and keywords.
function pageMetadata(aOptions, aTitle, aDescription, aKeywords) {
  var titles = ['OpenUserJS'];
  if (typeof (aTitle) === "string" && aTitle !== "") {
    titles.unshift(aTitle);
  } else if (_.isArray(aTitle)) {
    titles = aTitle.concat(titles);
  }
  aOptions.title = titles.join(' | ');

  aOptions.pageMetaDescription = 'Download userscripts to enhance your browser.';
  if (typeof (aDescription) !== "undefined" && aDescription !== null) {
    aOptions.pageMetaDescription = aDescription;
  }

  var pageMetaKeywords = ['userscript', 'userscripts', 'javascript', 'Greasemonkey', 'Scriptish',
    'Tampermonkey', 'extension', 'browser'];
  if (typeof (aKeywords) !== "undefined" && aKeywords !== null && _.isArray(aKeywords)) {
    pageMetaKeywords = _.union(pageMetaKeywords, aKeywords);
  }

  aOptions.pageMetaKeywords = pageMetaKeywords.join(', ');
}