<commit_before>'use strict';

var assign         = require('es5-ext/object/assign')
  , forEach        = require('es5-ext/object/for-each')
  , startsWith     = require('es5-ext/string/#/starts-with')
  , toArray        = require('es5-ext/array/to-array')
  , d              = require('d')
  , autoBind       = require('d/auto-bind')
  , memoize        = require('memoizee/plain')
  , isObservable   = require('observable-value/is-observable')
  , makeElement    = require('dom-ext/document/#/make-element')
  , castAttribute  = require('dom-ext/element/#/cast-attribute')
  , replaceContent = require('dom-ext/element/#/replace-content')
  , getId          = require('dom-ext/html-element/#/get-id')
  , nested         = require('dbjs/valid-dbjs-nested-object')
  , DOMComposite   = require('../_composite')
  , htmlAttributes = require('../_html-attributes')
  , setup          = require('../')

  , defineProperty = Object.defineProperty
  , getObservable, Fieldset, renderRow, renderRowSpan;

getObservable = function (name) {
	var current = this;
	name = String(name).split('/');
	while (name.length > 1) current = nested(current[name.shift()]);
	return current._get(name[0]);
};

renderRow = function (input, options) {
	var el = makeElement.bind(input.document)
	  , id = getId.call(input.control || input.dom);
	return el('tr',
		// label
		el('th', el('label', { for: id }, options.label, options.label ? ':' : '')),
		// input
		el('td', input,
			// required mark
			(options.requiredStatus !== false)
			? el('span', { class: 'required-status' }, '*') : null,
			// validation status mark
			(options.validationStatus !== false)
			? el('span', { class: 'validation-status' }, '✓') : null,
			// error message
			el('span', { class: 'error-message error-message-' +
				input._name.replace(/[:#\/]/g, '-') }),
			// hint
			options.hint && el('p', { 'class': 'hint' }, options.hint)));
};

renderRowSpan = function (input, options) {
	var el = makeElement.bind(input.document)
	  , id = getId.call(input.control || input.dom);
	return el('tr',
		// label
		el('td', { colspan: 2 },
			el('p', el('label', { for: id }, options.label ? ':' : '')),
			// input
			el('div', input,
				// required mark
				el('span', { class: 'required-status' }, '*'),
				// validation status mark
				el('span', { class: 'validation-status' }, '✓'),
				// error message
				el('span', { class: 'error-message error-message-' +
					input._name.replace(/[:#]/g, '-') }),
				// hint
				options.hint && el('p', { 'class': 'hint' }, options.hint))));
};

Fieldset = function (document, list/*, options*/) {
	var options = Object(arguments[2]);

	this.document = document;
	this.list = list;
	this.items = {};
	this.options = Object(options.control);
	this.customOptions = Object(options.controls);
	this.prepend = options.prepend;
	this.append = options.append;

	this.list = list.map(this.renderItem, this);
	if (isObservable(this.list)) this.list.on('change', this.reload);

	this.render();
	forEach(options, function (value, name) {
		if (!htmlAttributes[name] && !startsWith.call(name, 'data-')) return;
		castAttribute.call(this.dom, name, value);
	}, this);
	this.dom.classList.add('dbjs');

	this.reload();
};
Object.defineProperty(Fieldset, 'renderRow', d(renderRow));

Object.defineProperties(Fieldset.prototype, assign({
	render: d(function () {
		var el = makeElement.bind(this.document);
		this.dom = el('fieldset', el('table',
			this.domItems = el('tbody')));
	}),
	renderItem: d(function (observable) {
		var options = this.getOptions(observable.descriptor);
		if (options.render == null) options.render = renderRow;
		else if (options.render === 'span') options.render = renderRowSpan;
		return (this.items[observable.dbId] =
			observable.toDOMInputComponent(this.document, options));
	}),
	toDOM: d(function () { return this.dom; }),
	getOptions: d(DOMComposite.prototype.getOptions)
}, autoBind({
	reload: d(function () {
		replaceContent.call(this.domItems, this.prepend, this.list, this.append);
	})
})));

module.exports = exports = memoize(function (db) {
	var proto = setup(db).Base.prototype;

	defineProperty(db.Base, 'DOMFieldset', d(Fieldset));

	defineProperty(proto, 'toDOMFieldset', d(function (document/*, options*/) {
		var options = Object(arguments[1]), data, names;

		if (options.names != null) {
			names = options.names;
			if (!names.map) names = toArray(names);
			data = names.map(getObservable, this);
		} else {
			data = this.toSet('key').toArray().map(getObservable, this);
		}

		if (options.include) {
			throw new TypeError("`include` option is (postponed). Fix it");
		}

		return new db.Base.DOMFieldset(document, data, options);
	}));
}, { normalizer: require('memoizee/normalizers/get-1')() });

exports.Fieldset = Fieldset;
<commit_msg>Rely on ownDescriptor<commit_after>'use strict';

var assign         = require('es5-ext/object/assign')
  , forEach        = require('es5-ext/object/for-each')
  , startsWith     = require('es5-ext/string/#/starts-with')
  , toArray        = require('es5-ext/array/to-array')
  , d              = require('d')
  , autoBind       = require('d/auto-bind')
  , memoize        = require('memoizee/plain')
  , isObservable   = require('observable-value/is-observable')
  , makeElement    = require('dom-ext/document/#/make-element')
  , castAttribute  = require('dom-ext/element/#/cast-attribute')
  , replaceContent = require('dom-ext/element/#/replace-content')
  , getId          = require('dom-ext/html-element/#/get-id')
  , nested         = require('dbjs/valid-dbjs-nested-object')
  , DOMComposite   = require('../_composite')
  , htmlAttributes = require('../_html-attributes')
  , setup          = require('../')

  , defineProperty = Object.defineProperty
  , getObservable, Fieldset, renderRow, renderRowSpan;

getObservable = function (name) {
	var current = this;
	name = String(name).split('/');
	while (name.length > 1) current = nested(current[name.shift()]);
	return current._get(name[0]);
};

renderRow = function (input, options) {
	var el = makeElement.bind(input.document)
	  , id = getId.call(input.control || input.dom);
	return el('tr',
		// label
		el('th', el('label', { for: id }, options.label, options.label ? ':' : '')),
		// input
		el('td', input,
			// required mark
			(options.requiredStatus !== false)
			? el('span', { class: 'required-status' }, '*') : null,
			// validation status mark
			(options.validationStatus !== false)
			? el('span', { class: 'validation-status' }, '✓') : null,
			// error message
			el('span', { class: 'error-message error-message-' +
				input._name.replace(/[:#\/]/g, '-') }),
			// hint
			options.hint && el('p', { 'class': 'hint' }, options.hint)));
};

renderRowSpan = function (input, options) {
	var el = makeElement.bind(input.document)
	  , id = getId.call(input.control || input.dom);
	return el('tr',
		// label
		el('td', { colspan: 2 },
			el('p', el('label', { for: id }, options.label ? ':' : '')),
			// input
			el('div', input,
				// required mark
				el('span', { class: 'required-status' }, '*'),
				// validation status mark
				el('span', { class: 'validation-status' }, '✓'),
				// error message
				el('span', { class: 'error-message error-message-' +
					input._name.replace(/[:#]/g, '-') }),
				// hint
				options.hint && el('p', { 'class': 'hint' }, options.hint))));
};

Fieldset = function (document, list/*, options*/) {
	var options = Object(arguments[2]);

	this.document = document;
	this.list = list;
	this.items = {};
	this.options = Object(options.control);
	this.customOptions = Object(options.controls);
	this.prepend = options.prepend;
	this.append = options.append;

	this.list = list.map(this.renderItem, this);
	if (isObservable(this.list)) this.list.on('change', this.reload);

	this.render();
	forEach(options, function (value, name) {
		if (!htmlAttributes[name] && !startsWith.call(name, 'data-')) return;
		castAttribute.call(this.dom, name, value);
	}, this);
	this.dom.classList.add('dbjs');

	this.reload();
};
Object.defineProperty(Fieldset, 'renderRow', d(renderRow));

Object.defineProperties(Fieldset.prototype, assign({
	render: d(function () {
		var el = makeElement.bind(this.document);
		this.dom = el('fieldset', el('table',
			this.domItems = el('tbody')));
	}),
	renderItem: d(function (observable) {
		var options = this.getOptions(observable.ownDescriptor);
		if (options.render == null) options.render = renderRow;
		else if (options.render === 'span') options.render = renderRowSpan;
		return (this.items[observable.dbId] =
			observable.toDOMInputComponent(this.document, options));
	}),
	toDOM: d(function () { return this.dom; }),
	getOptions: d(DOMComposite.prototype.getOptions)
}, autoBind({
	reload: d(function () {
		replaceContent.call(this.domItems, this.prepend, this.list, this.append);
	})
})));

module.exports = exports = memoize(function (db) {
	var proto = setup(db).Base.prototype;

	defineProperty(db.Base, 'DOMFieldset', d(Fieldset));

	defineProperty(proto, 'toDOMFieldset', d(function (document/*, options*/) {
		var options = Object(arguments[1]), data, names;

		if (options.names != null) {
			names = options.names;
			if (!names.map) names = toArray(names);
			data = names.map(getObservable, this);
		} else {
			data = this.toSet('key').toArray().map(getObservable, this);
		}

		if (options.include) {
			throw new TypeError("`include` option is (postponed). Fix it");
		}

		return new db.Base.DOMFieldset(document, data, options);
	}));
}, { normalizer: require('memoizee/normalizers/get-1')() });

exports.Fieldset = Fieldset;
<|endoftext|>


<commit_before>var inherit;

(function (global, exports) {

    /**
     *
     * @param {String} [constructorName] The name of the constructor
     * @param {Object} classDefinition The definition for the prototype methods
     * @param {Object} [staticDefinition] The definition for the prototype methods
     * @param {Function} [baseClass] The prototype to inherit from
     *
     * @return {Function} returns a constructor function describing the class
     */
    inherit = function (constructorName, classDefinition, staticDefinition, baseClass) {

        var args = Array.prototype.slice.call(arguments);

        if (args[0] instanceof Object) {
            args.unshift(null);
        }

        if (args[2] instanceof Function) {
            args.splice(2, 0, null);
        }

        constructorName = args[0];
        classDefinition = args[1] || {};
        staticDefinition = args[2] || {};
        baseClass = args[3] || Object;

        var newClass = function () {
            if (this.ctor) {
                return this.ctor.apply(this, arguments);
            }
        };

        if (baseClass.constructor instanceof Function) {

            function Inheritance() {
            }

            Inheritance.prototype = baseClass.prototype;

            newClass.prototype = new Inheritance();
            newClass.prototype.constructor = classDefinition;

            if (classDefinition && constructorName) {
                newClass.prototype.constructor.name = constructorName;
            }

            newClass.prototype.base = baseClass.prototype;
            newClass.prototype.factory = newClass;

        } else {
            newClass.prototype = baseClass;
            newClass.prototype.constructor = classDefinition;
            newClass.prototype.base = baseClass;
        }

        for (var publicMethod in classDefinition) {
            if (classDefinition.hasOwnProperty(publicMethod)) {
                var baseFunction = newClass.prototype[publicMethod];
                newClass.prototype[publicMethod] = classDefinition[publicMethod];

                if (baseFunction instanceof Function) {
                    newClass.prototype[publicMethod].baseImplementation = baseFunction;
                }
            }
        }

        for (var staticMethod in staticDefinition) {
            if (staticDefinition.hasOwnProperty(staticMethod)) {
                newClass[staticMethod] = staticDefinition[staticMethod];
            }
        }

        newClass.prototype.callBase = inherit.callBase;

        return newClass;

    };

    inherit.callBase = function () {
        // get arguments
        var args = Array.prototype.slice.call(arguments);

        if (args.length == 0) {
            // use arguments from call
            args = Array.prototype.slice.call(arguments.callee.caller.arguments);
        }

        return arguments.callee.caller.baseImplementation.apply(this, args);
    };

    /***
     *
     * @param {String} [constructorName]
     * @param {Object} classDefinition The definition for the prototype methods
     * @param {Object} [staticDefinition]
     * @return {Function} returns a constructor function describing the class
     */
    Function.prototype.inherit = function (constructorName, classDefinition, staticDefinition) {

        var args = Array.prototype.slice.call(arguments);

        if (args[0] instanceof Object) {
            args.unshift(null);
        }

        return inherit(args[0], args[1], args[2], this);
    };

    Function.prototype.callBase = function () {
        var args = Array.prototype.slice.call(arguments);
        var that = args.shift();

        if (that && that.base) {
            var caller = arguments.callee.caller;

            if (this == caller) {
                return this.baseImplementation.apply(that, args);
            } else {
                return this.apply(that, args);
            }
        } else {
            throw "base not definied";
        }
    };

    Function.prototype.classof = function(factory) {
        if (!factory) {
            return false;
        }

        if (!(factory instanceof Function)) {
            throw new Error("factory must be a function");
        }

        return (factory === this || this.prototype instanceof factory);
    };

    /**
     * @property {Function} base class
     */
    inherit.Base = inherit({
        ctor: function () {
        }
    });

    exports.inherit = inherit;

})(this, typeof exports === "undefined" ? this : exports);

<commit_msg>fixed inherit constructur name<commit_after>var inherit;

(function (global, exports) {

    /**
     *
     * @param {String} [constructorName] The name of the constructor
     * @param {Object} classDefinition The definition for the prototype methods
     * @param {Object} [staticDefinition] The definition for the prototype methods
     * @param {Function} [baseClass] The prototype to inherit from
     *
     * @return {Function} returns a constructor function describing the class
     */
    inherit = function (constructorName, classDefinition, staticDefinition, baseClass) {

        var args = Array.prototype.slice.call(arguments);

        if (args[0] instanceof Object) {
            args.unshift(null);
        }

        if (args[2] instanceof Function) {
            args.splice(2, 0, null);
        }

        constructorName = args[0];
        classDefinition = args[1] || {};
        staticDefinition = args[2] || {};
        baseClass = args[3] || Object;

        var newClass = function () {
            if (this.ctor) {
                return this.ctor.apply(this, arguments);
            }
        };

        if (baseClass.constructor instanceof Function) {

            function Inheritance() {
            }

            Inheritance.prototype = baseClass.prototype;

            newClass.prototype = new Inheritance();
            newClass.prototype.constructor = {
                name: constructorName
            };

            newClass.prototype.base = baseClass.prototype;
            newClass.prototype.factory = newClass;

        } else {
            newClass.prototype = baseClass;
            newClass.prototype.constructor = classDefinition;
            newClass.prototype.base = baseClass;
        }

        for (var publicMethod in classDefinition) {
            if (classDefinition.hasOwnProperty(publicMethod)) {
                var baseFunction = newClass.prototype[publicMethod];
                newClass.prototype[publicMethod] = classDefinition[publicMethod];

                if (baseFunction instanceof Function) {
                    newClass.prototype[publicMethod].baseImplementation = baseFunction;
                }
            }
        }

        for (var staticMethod in staticDefinition) {
            if (staticDefinition.hasOwnProperty(staticMethod)) {
                newClass[staticMethod] = staticDefinition[staticMethod];
            }
        }

        newClass.prototype.callBase = inherit.callBase;

        return newClass;

    };

    inherit.callBase = function () {
        // get arguments
        var args = Array.prototype.slice.call(arguments);

        if (args.length === 0) {
            // use arguments from call
            args = Array.prototype.slice.call(arguments.callee.caller.arguments);
        }

        return arguments.callee.caller.baseImplementation.apply(this, args);
    };

    /***
     *
     * @param {String} [constructorName]
     * @param {Object} classDefinition The definition for the prototype methods
     * @param {Object} [staticDefinition]
     * @return {Function} returns a constructor function describing the class
     */
    Function.prototype.inherit = function (constructorName, classDefinition, staticDefinition) {

        var args = Array.prototype.slice.call(arguments);

        if (args[0] instanceof Object) {
            args.unshift(null);
        }

        return inherit(args[0], args[1], args[2], this);
    };

    Function.prototype.callBase = function () {
        var args = Array.prototype.slice.call(arguments);
        var that = args.shift();

        if (that && that.base) {
            var caller = arguments.callee.caller;

            if (this == caller) {
                return this.baseImplementation.apply(that, args);
            } else {
                return this.apply(that, args);
            }
        } else {
            throw "base not definied";
        }
    };

    Function.prototype.classof = function (factory) {
        if (!factory) {
            return false;
        }

        if (!(factory instanceof Function)) {
            throw new Error("factory must be a function");
        }

        return (factory === this || this.prototype instanceof factory);
    };

    /**
     * @property {Function} base class
     */
    inherit.Base = inherit({
        ctor: function () {
        }
    });

    exports.inherit = inherit;

})(this, typeof exports === "undefined" ? this : exports);

<|endoftext|>


<commit_before>/*
	Version : 0.0.1
	Created On : 11.03.2015

	-- hoverr_tera.js load this js
	-- It get data set by hoverr_tera.js
*/
(function() {
	var $isMobile = !!((/android|webos|iphone|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase()))),
		//$onceCalled = false,
		jqueryLink = '//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',
		debugRequired = true,
		$,
		_window_dataObject = {};

  if(window.hoverrneo === undefined) window.hoverrneo = {};

	// var Debugger = function () { };
	// Debugger.log = function (message) {
	// 	try {
	// 		if(debugRequired) console.log(message);
	// 	} catch (exception) {}
	// };

	var findContainer = function(callback){
		var tempObject = [];

		var inlineContainer = undefined,
		intr = window.setInterval(function(){
			if($(_window_dataObject.selector).length != 0){
				window.clearInterval(intr);

				$(_window_dataObject.selector).each(function(){
					var containerDiv = $('

');
					$(this).after(containerDiv);

					tempObject.push({
						containerDiv: containerDiv,
						width: containerDiv.width(),
						position: $(this).offset()
					});
				});

				if(typeof(callback) === "function" && callback !== undefined) callback(tempObject);
				else return tempObject;
			}
		}, 100);
	};

	// Set attribute for elements
	var setAttributes = function(el, attrs) {
		for(var key in attrs) { if (attrs.hasOwnProperty(key)) el.setAttribute(key, attrs[key]); }
	};

	var putAd = function(container){
		var iframe = document.createElement('iframe'),
		$width = container.width,
		$iframeWidth = _window_dataObject.dimension.width,
		$iframeHeight = _window_dataObject.dimension.height,

		$scale = (($width / $iframeWidth) <= 1) ? ($width / $iframeWidth) : 1,
		$left = "left: "+ (($width - $iframeWidth)/2) +"px;",
		$bottom = Math.ceil((($iframeHeight * $scale) - $iframeHeight)/2),
		$cssText,
		$top,
		$adTag = _window_dataObject.tag,
		$key = [window.hoverrneo.host, window.hoverrneo.section, window.hoverrneo.web_or_mobile, _window_dataObject.id, _window_dataObject.is_default],
		$pixelPingHtml = '';

		$cssText = "height:"+ $iframeHeight +"px !important; min-height:"+ $iframeHeight +"px !important; width:"+ $iframeWidth +"px !important; overflow:hidden;"+ $left +"bottom:"+ $bottom +"px;margin:0 auto; position:absolute; background: transparent; z-index: 2; -moz-transform: scale("+ $scale +"); -o-transform: scale("+ $scale +"); -webkit-transform: scale("+ $scale +"); transform: scale("+ $scale +"); max-width:initial !important;";

		setAttributes(iframe, {"height": $iframeHeight, "scrolling": "no", "frameBorder": 0, "allowtransparency": "true", "class": "_adSenceImagePush", "width": $iframeWidth, "loadStatus": 0, "data-width": $iframeWidth, "data-height": $iframeHeight, "style":$cssText});

		container.containerDiv.append(iframe);

		try{
			console.log('Log : Setting html content in try block !!');
			var doc = iframe.contentDocument || iframe.contentWindow.document;
			doc.open();
			doc.write('


<commit_before>
var fs = require('fs');
var exec = require ('child_process').exec;
var async = require ("async");
var app_path, ssh_file, local, email;
var i = 0;
var prompt = require ("prompt");
var config = {};

async.waterfall ([

    function (done){
        // Installs the whole setup
        console.log ("\n\nWELCOME TO THE NODE-AWS-DEPLOY INSTALLER");
        console.log ("This installs your application onto AWS and allows automatic deployment just by pushing to your remote git repository." +
            " Just answer a few questions and everything will be setup");
        prompt.start ();
        done ();
    },

    function (done){
        console.log (++i + ") Is this a 'remote' install? (If this is on a remote server the answer is y)");
        prompt.get (['(y/n)'], function (err, results){
            var answer = (results['(y/n)'] === 'y');
            local = !answer;
            config.sudo = (local) ? "" : "sudo";
            done ();
        });
    },

    function (done){
        if (local){
            console.log (++i + ") Enter your desired application's full path. (no file names. Example  '/User/me/MyCoolApplication')");
            prompt.get (['folder'], function (err, results){
                config.applicationDirectory = results['folder'];
                done ();
            });
        }
        else{
            done ();
        }
    },

    function (done){
        console.log (++i + ") Enter your application's name");
        prompt.get (['name'], function (err, results){
            config.applicationName = results['name'];
            done ();
        });
    },
    function (done){
        console.log (++i + ") Enter your application's entry point (defaults to 'start.js')");
        prompt.get (['entry point'], function(err, results) {
            config.appEntry = results['entry point'];
            done ();
        });
    },
    function (done){
        if (local){
            console.log ("Please take a second ensure you are set up to clone your repository. This might require you to create an ssh key pair or simply use credentials.");
            console.log ("When you have your repository cloned press <enter> to continue.");
            prompt.get (['<enter>'], function(err, results) {
                done ();
            });
        }
        else{
            done ();
        }
    },

    function (done){
        if (!local){
            // go get the ssh key
            try { ssh_file = fs.readFileSync ("/root/.ssh/id_rsa.pub");}
            catch (err) {ssh_file = null;}
            if (!ssh_file){
                done ("/tssh key not generated, please exit generate one, and re-run");
            }
            else{
                done ();
            }
        }
        else{
            done ();
        }
    },

    function (done){
        if (!local){
            console.log(++i + ") Please take a second to copy the ssh key from this server, listed below, and paste into your git repository service (such as github). This will authorize this server AMI to " +
                "clone your repository and perform git pulls. Press <enter> when done.");
            console.log ("\n" + ssh_file + "\n");
            prompt.get (['<enter>'], function(err, results) {
                done ();
            });
        }
        else{
            done ();
        }
    },
    function (done){
        if (!local){
            console.log (++i + ") Now that your Git repository has been configured, enter the ssh url for remote access so this server can clone it:");
            prompt.get (['Git repository URL'], function (err, results){
                var git_url = results['Git repository URL'];
                if (git_url){
                    console.log ("  Cloning your repository...");
                    var child = exec ('cd ' + config.applicationDirectory + ' ; cd .. ; ' + config.sudo + ' git clone ' + git_url, function (err, std, ster){
                        if (err){
                            done (err);
                        }
                        else{
                            console.log (std);
                            var dir = std.split ("Cloning into ");
                            dir = dir && dir[1] && dir[1].replace ("'", "").replace ("...", "");
                            if (dir){
                                config.applicationDirectory = '/home/ec2-user/' + dir;
                            }
                            done ();
                        }
                    });
                }
                else{
                    done ();
                }
            });
        }
        else{
            done ();
        }
    },
    function (done){
        if (!local){
            console.log (++i + ") Enter the pull information, what triggers it how its configured, etc...");
            console.log ("\t pullPort: <set this to the port for a pull requests> - defaults to 8000");
            console.log ("\t pullKey: <path to a ssh key file for the HTTPS Server>");
            console.log ("\t pullCert: <path to a ssh cert file for the HTTPS Server>");
            console.log ("\t pullCa: <array of paths to the certificate authority files> (optional)");
            console.log ("\t pullPassphrase: <string - phrase that the certificate was generated with> (optional)");
            console.log ("\t pullSecret: <secret phrase that this server uses to identify as a valid pull request> (optional))");
            console.log ("\t pullBranch: <the branch that this server should pull from on pull requests> (defaults to master))");
            prompt.get (["pullPort", "pullKey", "pullCert", "pullCa", "pullPassphrase", "pullSecret", "pullBranch"], function (err, results){
                for (var k in results){
                    config[k] = results[k];
                }
                done ();
            });

        }
        else{
            done ();
        }
    },
    function (done) {
        if (!local){
            console.log (++i + ") Enter AWS SDK Information so that this server can talk to others on a pull request");
            console.log ("\t accessKeyId: <AWS API Access key 'XXXXXXXXXXXXXXXXXXXX'>");
            console.log ("\t secretAccessKey: <AWS Secret Access key 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'>");
            console.log ("\t region: <aws region that the servers are located in. EX 'us-east-1'>");
            prompt.get (["accessKeyId", "secretAccessKey", "region"], function (err, results){
                for (var k in results){
                    config[k] = results[k];
                }
                done ();
            });

        }
        else{
            done ();
        }
    }

], function (err){
    if (!err){
        var data = JSON.stringify (config);
        fs.writeFileSync ("app-config.json", data);
        console.log ("Success installed: " + config.applicationName + ". The Configuration has been written out to app-config.json");
        if (!local){
            console.log ("To Launch the application type 'sudo start " + (config.applicationName || "node-aws-deploy") + "'");
            // rename the upstart file to the applicaiton name
            if (config.applicationName){
                var child = exec ("sudo mv /etc/init/node-aws-deploy /etc/init/" + config.applicationName, function (err, std, ster){
                    process.exit (0);
                });
            }
            else{
                process.exit (0);
            }
        }
        else{
            process.exit (0);
        }
    }
    else{
        console.log ("There were errors. Errors:" + err);
        process.exit (1);
    }
});

<commit_msg>Initial<commit_after>
var fs = require('fs');
var exec = require ('child_process').exec;
var async = require ("async");
var app_path, ssh_file, local, email;
var i = 0;
var prompt = require ("prompt");
var config = {};

async.waterfall ([

    function (done){
        // Installs the whole setup
        console.log ("\n\nWELCOME TO THE NODE-AWS-DEPLOY INSTALLER");
        console.log ("This installs your application onto AWS and allows automatic deployment just by pushing to your remote git repository." +
            " Just answer a few questions and everything will be setup");
        prompt.start ();
        done ();
    },
/*
    function (done){
        console.log (++i + ") Is this a 'remote' install? (If this is on a remote server the answer is y)");
        prompt.get (['(y/n)'], function (err, results){
            var answer = (results['(y/n)'] === 'y');
            local = !answer;
            config.sudo = (local) ? "" : "sudo";
            done ();
        });
    },

    function (done){
        if (local){
            console.log (++i + ") Enter your desired application's full path. (no file names. Example  '/User/me/MyCoolApplication')");
            prompt.get (['folder'], function (err, results){
                config.applicationDirectory = results['folder'];
                done ();
            });
        }
        else{
            done ();
        }
    },
*/
    function (done){
        console.log (++i + ") Enter your application's name");
        prompt.get (['name'], function (err, results){
            config.applicationName = results['name'];
            done ();
        });
    } /*,

    function (done){
        console.log (++i + ") Enter your application's entry point (defaults to 'start.js')");
        prompt.get (['entry point'], function(err, results) {
            config.appEntry = results['entry point'];
            done ();
        });
    },
    function (done){
        if (local){
            console.log ("Please take a second ensure you are set up to clone your repository. This might require you to create an ssh key pair or simply use credentials.");
            console.log ("When you have your repository cloned press <enter> to continue.");
            prompt.get (['<enter>'], function(err, results) {
                done ();
            });
        }
        else{
            done ();
        }
    },

    function (done){
        if (!local){
            // go get the ssh key
            try { ssh_file = fs.readFileSync ("/root/.ssh/id_rsa.pub");}
            catch (err) {ssh_file = null;}
            if (!ssh_file){
                done ("/tssh key not generated, please exit generate one, and re-run");
            }
            else{
                done ();
            }
        }
        else{
            done ();
        }
    },

    function (done){
        if (!local){
            console.log(++i + ") Please take a second to copy the ssh key from this server, listed below, and paste into your git repository service (such as github). This will authorize this server AMI to " +
                "clone your repository and perform git pulls. Press <enter> when done.");
            console.log ("\n" + ssh_file + "\n");
            prompt.get (['<enter>'], function(err, results) {
                done ();
            });
        }
        else{
            done ();
        }
    },
    function (done){
        if (!local){
            console.log (++i + ") Now that your Git repository has been configured, enter the ssh url for remote access so this server can clone it:");
            prompt.get (['Git repository URL'], function (err, results){
                var git_url = results['Git repository URL'];
                if (git_url){
                    console.log ("  Cloning your repository...");
                    var child = exec ('cd ' + config.applicationDirectory + ' ; cd .. ; ' + config.sudo + ' git clone ' + git_url, function (err, std, ster){
                        if (err){
                            done (err);
                        }
                        else{
                            console.log (std);
                            var dir = std.split ("Cloning into ");
                            dir = dir && dir[1] && dir[1].replace ("'", "").replace ("...", "");
                            if (dir){
                                config.applicationDirectory = '/home/ec2-user/' + dir;
                            }
                            done ();
                        }
                    });
                }
                else{
                    done ();
                }
            });
        }
        else{
            done ();
        }
    },
    function (done){
        if (!local){
            console.log (++i + ") Enter the pull information, what triggers it how its configured, etc...");
            console.log ("\t pullPort: <set this to the port for a pull requests> - defaults to 8000");
            console.log ("\t pullKey: <path to a ssh key file for the HTTPS Server>");
            console.log ("\t pullCert: <path to a ssh cert file for the HTTPS Server>");
            console.log ("\t pullCa: <array of paths to the certificate authority files> (optional)");
            console.log ("\t pullPassphrase: <string - phrase that the certificate was generated with> (optional)");
            console.log ("\t pullSecret: <secret phrase that this server uses to identify as a valid pull request> (optional))");
            console.log ("\t pullBranch: <the branch that this server should pull from on pull requests> (defaults to master))");
            prompt.get (["pullPort", "pullKey", "pullCert", "pullCa", "pullPassphrase", "pullSecret", "pullBranch"], function (err, results){
                for (var k in results){
                    config[k] = results[k];
                }
                done ();
            });

        }
        else{
            done ();
        }
    },
    function (done) {
        if (!local){
            console.log (++i + ") Enter AWS SDK Information so that this server can talk to others on a pull request");
            console.log ("\t accessKeyId: <AWS API Access key 'XXXXXXXXXXXXXXXXXXXX'>");
            console.log ("\t secretAccessKey: <AWS Secret Access key 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'>");
            console.log ("\t region: <aws region that the servers are located in. EX 'us-east-1'>");
            prompt.get (["accessKeyId", "secretAccessKey", "region"], function (err, results){
                for (var k in results){
                    config[k] = results[k];
                }
                done ();
            });

        }
        else{
            done ();
        }
    }
*/
], function (err){
    if (!err){
        var data = JSON.stringify (config);
        //fs.writeFileSync ("app-config.json", data);
        console.log ("Success installed: " + config.applicationName + ". The Configuration has been written out to app-config.json");
        if (!local){
            console.log ("To Launch the application type 'sudo start " + (config.applicationName || "node-aws-deploy") + "'");
            // rename the upstart file to the applicaiton name
            if (config.applicationName){
                var child = exec ("sudo mv /etc/init/node-aws-deploy.conf /etc/init/" + config.applicationName + ".conf", function (err, std, ster){
                    process.exit (0);
                });
            }
            else{
                process.exit (0);
            }
        }
        else{
            process.exit (0);
        }
    }
    else{
        console.log ("There were errors. Errors:" + err);
        process.exit (1);
    }
});

<|endoftext|>


<commit_before>#!/usr/bin/env node

// maintainer note - x.y.z-ab version in package.json -> x.y.z
var version = require('./package').version.replace(/-.*/, '')

var fs = require('fs')
var os = require('os')
var path = require('path')
var extract = require('extract-zip')
var download = require('electron-download')

var installedVersion = null
try {
  installedVersion = fs.readFileSync(path.join(__dirname, 'dist', 'version'), 'utf-8').replace(/^v/, '')
} catch (err) {
  // do nothing
}

var platform = os.platform()

function onerror (err) {
  throw err
}

var paths = {
  darwin: 'dist/Electron.app/Contents/MacOS/Electron',
  freebsd: 'dist/electron',
  linux: 'dist/electron',
  win32: 'dist/electron.exe'
}

if (!paths[platform]) throw new Error('Unknown platform: ' + platform)

if (installedVersion === version && fs.existsSync(path.join(__dirname, paths[platform]))) {
  process.exit(0)
}

// downloads if not cached
download({version: version, arch: process.env.npm_config_arch}, extractFile)

// unzips and makes path.txt point at the correct executable
function extractFile (err, zipPath) {
  if (err) return onerror(err)
  fs.writeFile(path.join(__dirname, 'path.txt'), paths[platform], function (err) {
    if (err) return onerror(err)
    extract(zipPath, {dir: path.join(__dirname, 'dist')}, function (err) {
      if (err) return onerror(err)
    })
  })
}
<commit_msg>Allow specifying StrictSSL in the NPM config file<commit_after>#!/usr/bin/env node

// maintainer note - x.y.z-ab version in package.json -> x.y.z
var version = require('./package').version.replace(/-.*/, '')

var fs = require('fs')
var os = require('os')
var path = require('path')
var extract = require('extract-zip')
var download = require('electron-download')

var installedVersion = null
try {
  installedVersion = fs.readFileSync(path.join(__dirname, 'dist', 'version'), 'utf-8').replace(/^v/, '')
} catch (err) {
  // do nothing
}

var platform = os.platform()

function onerror (err) {
  throw err
}

var paths = {
  darwin: 'dist/Electron.app/Contents/MacOS/Electron',
  freebsd: 'dist/electron',
  linux: 'dist/electron',
  win32: 'dist/electron.exe'
}

if (!paths[platform]) throw new Error('Unknown platform: ' + platform)

if (installedVersion === version && fs.existsSync(path.join(__dirname, paths[platform]))) {
  process.exit(0)
}

// downloads if not cached
download({version: version, arch: process.env.npm_config_arch, strictSSL: process.env.npm_config_strict_ssl}, extractFile)

// unzips and makes path.txt point at the correct executable
function extractFile (err, zipPath) {
  if (err) return onerror(err)
  fs.writeFile(path.join(__dirname, 'path.txt'), paths[platform], function (err) {
    if (err) return onerror(err)
    extract(zipPath, {dir: path.join(__dirname, 'dist')}, function (err) {
      if (err) return onerror(err)
    })
  })
}
<|endoftext|>


<commit_before>var StringDecoder = require('string_decoder').StringDecoder;
var util = require('util');
var url = require('url');
var qs = require('querystring');

var parsers = {};

parsers.body = function(request, response) {
	var decoder = new StringDecoder();
	var buf = '';

	request.on('data', function(data) {
		buf += decoder.write(data);
	});
	request.on('end', function() {
		request.emit('body', buf);
	});
};
parsers.json = function(request, response) {
	request.on('body', function(body) {
		try {
			body = JSON.parse(body);
		} catch (err) {
			return response.error(400, 'could not parse json');
		}
		request.emit('json', body || {});
	});
};
parsers.form = function(request, response) {
	request.on('body', function(body) {
		request.emit('form', qs.parse(body));
	});
};

var onparser = function(name) {
	if (!parsers[name]) return;
	if (this.parsing[name]) return;
	this.parsing[name] = true;
	parsers[name](this, this.response);
};
var parseURL = function(request) {
	return request._url || (request._url = url.parse(request.url, true));
};

module.exports = function(app) {
	app.use('request.query', {getter:true}, function() {
		return parseURL(this).query;
	});
	app.use('response.send', function(body) {
		var type = this.getHeader('Content-Type');
		body = body || '';

		if (Buffer.isBuffer(body)) {
			this.setHeader('Content-Length', body.length);
			this.end(body);
			return;
		}

		if (typeof body === 'string') {
			type = type || 'text/html; charset=utf-8';
		}
		if (typeof body === 'object') {
			body = JSON.stringify(body);
			type = type || 'application/json; charset=utf-8';
		}

		this.setHeader('Content-Type', type);
		this.setHeader('Content-Length', Buffer.byteLength(body));
		this.end(body);
	});
	app.use('response.redirect', function(location) {
		this.statusCode = 302;
		var host = this.request.headers.host;

		if (location.indexOf('://') === -1 || !host) {
			this.setHeader('Location', location);
			this.end();
			return;
		}

		var connection = this.request.connection;
		var protocol = connection && connection.encrypted ? 'https' : 'http';

		this.setHeader(protocol+'://'+host+location);
		this.end();
	});
	app.use('response.error', function(statusCode, message) {
		var options = {};

		if (typeof statusCode !== 'number') {
			message = statusCode;
			statusCode = 500;
		}

		if (util.isError(message)) {
			options.error = message;
			options.stack = options.error.stack;
			message = options.error.message;
		}

		options.message = message;
		options.statusCode = this.statusCode = statusCode;

		app.catch(this.request, this, options);
	});

	app.on('route', function(request, response) {
		request.parsing = request.parsing || {};
		request.on('newListener', onparser);
	});
};<commit_msg>fixed redirect method<commit_after>var StringDecoder = require('string_decoder').StringDecoder;
var util = require('util');
var url = require('url');
var qs = require('querystring');

var parsers = {};

parsers.body = function(request, response) {
	var decoder = new StringDecoder();
	var buf = '';

	request.on('data', function(data) {
		buf += decoder.write(data);
	});
	request.on('end', function() {
		request.emit('body', buf);
	});
};
parsers.json = function(request, response) {
	request.on('body', function(body) {
		try {
			body = JSON.parse(body);
		} catch (err) {
			return response.error(400, 'could not parse json');
		}
		request.emit('json', body || {});
	});
};
parsers.form = function(request, response) {
	request.on('body', function(body) {
		request.emit('form', qs.parse(body));
	});
};

var onparser = function(name) {
	if (!parsers[name]) return;
	if (this.parsing[name]) return;
	this.parsing[name] = true;
	parsers[name](this, this.response);
};
var parseURL = function(request) {
	return request._url || (request._url = url.parse(request.url, true));
};

module.exports = function(app) {
	app.use('request.query', {getter:true}, function() {
		return parseURL(this).query;
	});
	app.use('response.send', function(body) {
		var type = this.getHeader('Content-Type');
		body = body || '';

		if (Buffer.isBuffer(body)) {
			this.setHeader('Content-Length', body.length);
			this.end(body);
			return;
		}

		if (typeof body === 'string') {
			type = type || 'text/html; charset=utf-8';
		}
		if (typeof body === 'object') {
			body = JSON.stringify(body);
			type = type || 'application/json; charset=utf-8';
		}

		this.setHeader('Content-Type', type);
		this.setHeader('Content-Length', Buffer.byteLength(body));
		this.end(body);
	});
	app.use('response.redirect', function(location) {
		this.statusCode = 302;
		var headers = this.request.headers;
		var host = headers.host;

		if (location.indexOf('://') > -1 || !host) {
			this.setHeader('Location', location);
			this.end();
			return;
		}

		var conn = this.request.connection;
		var protocol = headers['x-forwarded-proto'] || (conn && conn.encrypted ? 'https' : 'http');

		this.setHeader('Location', protocol+'://'+host+location);
		this.end();
	});
	app.use('response.error', function(statusCode, message) {
		var options = {};

		if (typeof statusCode !== 'number') {
			message = statusCode;
			statusCode = 500;
		}

		if (util.isError(message)) {
			options.error = message;
			options.stack = options.error.stack;
			message = options.error.message;
		}

		options.message = message;
		options.statusCode = this.statusCode = statusCode;

		app.catch(this.request, this, options);
	});

	app.on('route', function(request, response) {
		request.parsing = request.parsing || {};
		request.on('newListener', onparser);
	});
};<|endoftext|>


<commit_before>require('canvas-testbed')(render, start, { context: 'webgl' })

var createText = require('../')
var createTexture = require('gl-texture2d')
var createBackground = require('./gl-checker-background')
var loadImage = require('img')
var fs = require('fs')
var lerp = require('lerp')
var ease = require('eases/quart-in')

var clear = require('gl-clear')({ color: [0.25,0.25,0.25,1] })

var Lato = require('./sdf/DejaVu-sdf.json')
var mat4 = require('gl-mat4')

var copy = fs.readFileSync(__dirname+'/sdf/frag.glsl', 'utf8')

var glslify = require('glslify')
var createShader = glslify({
    vertex: __dirname+'/sdf/vert.glsl',
    fragment: __dirname+'/sdf/frag.glsl'
})

var text,
    ortho = mat4.create(),
    scale = mat4.create(),
    shader,
    time = 600

var reg = /\/\/(.*)$/gm.exec(copy)

if (!reg)
    reg = { index: 0, '0': '' }

function render(gl, width, height, dt) {
    time += dt/1000
    clear(gl)

    if (!text)
        return

    //this is necessary since our image is semi-transparent!
    gl.enable(gl.BLEND)
    gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA)

    background.draw()

    mat4.ortho(ortho, 0, width, height, 0, 0, 1)

    var anim = ease(Math.sin(time/2)/2+0.5)
    var s = lerp(0.5, 2.0, anim)
    mat4.identity(scale)
    mat4.scale(scale, scale, [s, s, 0])

    //gl-basic-shader gives us some matrices we can use
    shader.bind()
    shader.uniforms.projection = ortho
    shader.uniforms.view = scale

    //just because we can...
    // text.letterSpacing = lerp(0, 20, anim)

    var bounds = text.getBounds()

    var white = [1,1,1,1]
    var x = 20,
        y = 10+bounds.height

    //NOTE: real syntax highlighting would want to manipulate
    //the underlying batch for vertex coloring
    shader.uniforms.tint = white
    text.draw(shader, x, y, 0, reg.index)

    shader.uniforms.tint = [140/255, 218/255, 115/255, 1.0]
    text.draw(shader, x, y, reg.index, reg.index+reg[0].length)

    shader.uniforms.tint = white
    text.draw(shader, x, y, reg.index+reg[0].length)
}

function start(gl, width, height) {
    //generate a basic shader with some custom frag source
    shader = createShader(gl)
    shader.bind()
    shader.uniforms.tint = [1, 1, 1, 1]

    background = createBackground(gl, {
        colors: [
            [0x50,0x50,0x50,0xff],
            [0x46,0x46,0x46,0xff]
        ]
    })

    //load textures, then build our text
    loadImage('sdf/DejaVu-sdf.png', function(err, img) {
        var tex = createTexture(gl, img)
        tex.generateMipmap()

        //smoother filtering
        tex.minFilter = gl.LINEAR_MIPMAP_LINEAR
        tex.magFilter = gl.LINEAR

        text = createText(gl, {
            font: Lato,
            wrapMode: 'pre',
            // wrapWidth: 1200,
            text: copy,
            textures: [ tex ]
        })
    })
}<commit_msg>comments<commit_after>require('canvas-testbed')(render, start, { context: 'webgl' })

var createText = require('../')
var createTexture = require('gl-texture2d')
var createBackground = require('./gl-checker-background')
var loadImage = require('img')
var fs = require('fs')
var lerp = require('lerp')
var ease = require('eases/quart-in')

var clear = require('gl-clear')({ color: [0.25,0.25,0.25,1] })

var Lato = require('./sdf/DejaVu-sdf.json')
var mat4 = require('gl-mat4')

var copy = fs.readFileSync(__dirname+'/sdf/frag.glsl', 'utf8')

var glslify = require('glslify')
var createShader = glslify({
    vertex: __dirname+'/sdf/vert.glsl',
    fragment: __dirname+'/sdf/frag.glsl'
})

var text,
    ortho = mat4.create(),
    scale = mat4.create(),
    shader,
    time = 600

var reg = /\/\/(.*)$/gm.exec(copy)

if (!reg)
    reg = { index: 0, '0': '' }

function render(gl, width, height, dt) {
    time += dt/1000
    clear(gl)

    if (!text)
        return

    gl.enable(gl.BLEND)
    gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA)

    background.draw()

    mat4.ortho(ortho, 0, width, height, 0, 0, 1)

    var anim = ease(Math.sin(time/2)/2+0.5)
    var s = lerp(0.5, 2.0, anim)
    mat4.identity(scale)
    mat4.scale(scale, scale, [s, s, 0])

    //gl-basic-shader gives us some matrices we can use
    shader.bind()
    shader.uniforms.projection = ortho
    shader.uniforms.view = scale

    var bounds = text.getBounds()

    var white = [1,1,1,1]
    var x = 20,
        y = 10+bounds.height

    //NOTE: real syntax highlighting would want to manipulate
    //the underlying batch for vertex coloring
    shader.uniforms.tint = white
    text.draw(shader, x, y, 0, reg.index)

    shader.uniforms.tint = [140/255, 218/255, 115/255, 1.0]
    text.draw(shader, x, y, reg.index, reg.index+reg[0].length)

    shader.uniforms.tint = white
    text.draw(shader, x, y, reg.index+reg[0].length)
}

function start(gl, width, height) {
    //generate a basic shader with some custom frag source
    shader = createShader(gl)
    shader.bind()
    shader.uniforms.tint = [1, 1, 1, 1]

    background = createBackground(gl, {
        colors: [
            [0x50,0x50,0x50,0xff],
            [0x46,0x46,0x46,0xff]
        ]
    })

    //load textures, then build our text
    loadImage('sdf/DejaVu-sdf.png', function(err, img) {
        var tex = createTexture(gl, img)
        tex.generateMipmap()

        //smoother filtering
        tex.minFilter = gl.LINEAR_MIPMAP_LINEAR
        tex.magFilter = gl.LINEAR

        text = createText(gl, {
            font: Lato,
            wrapMode: 'pre',
            // wrapWidth: 1200,
            text: copy,
            textures: [ tex ]
        })
    })
}<|endoftext|>


<commit_before>#!/usr/local/bin/node

var db = require("../lib/db.js")
var util = require("../lib/util.js")

var counter = 0
var totalChanged = 0

db.allBibs(function(bib,cursor,mongoConnection){

	process.stdout.clearLine()
	process.stdout.cursorTo(0)
	process.stdout.write( counter + " | " + totalChanged)

	counter++

	var hasChecked = (bib['sc:classifyCheck']) ? true : false

	if (!hasChecked){

			//build out the data we would use in classify
			var data = {
				_id: bib._id,
				oclc : [],
				isbn : [],
				issn : [],
				title : false,
				author : false
			}

			if (bib['sc:oclc']){
				for (var x in bib['sc:oclc']){
					data.oclc.push(bib['sc:oclc'][x])
				}
			}

			if (bib['lc:oclc']){
				for (var x in bib['lc:oclc']){
					data.oclc.push(bib['lc:oclc'][x])
				}
			}
			if (bib['sc:isbn']){
				for (var x in bib['sc:isbn']){
					data.isbn.push(bib['sc:isbn'][x])
				}
			}
			if (bib['sc:issn']){
				for (var x in bib['sc:issn']){
					data.issn.push(bib['sc:issn'][x])
				}
			}

			if (bib['author']){
				data.author = bib['author']
			}
			if (bib['title']){
				data.title = bib['title']
			}

			db.insertAPIClassifyRecord(data,function(err,results){

				cursor.resume()

				//console.log(data)
				//if (results) console.log(results.result)

			})

			return true

	}

	cursor.resume()

})

<commit_msg>classify api data job<commit_after>#!/usr/local/bin/node

var db = require("../lib/db.js")
var util = require("../lib/util.js")

var counter = 0
var totalChanged = 0

db.allBibs(function(bib,cursor,mongoConnection){

	process.stdout.clearLine()
	process.stdout.cursorTo(0)
	process.stdout.write( counter + " | " + totalChanged)

	if (!bib){
		console.log("Complete:", counter + " | " + totalChanged)
		return true;
	}

	counter++

	var hasChecked = (bib['sc:classifyCheck']) ? true : false

	if (!hasChecked){

			//build out the data we would use in classify
			var data = {
				_id: bib._id,
				oclc : [],
				isbn : [],
				issn : [],
				title : false,
				author : false
			}

			if (bib['sc:oclc']){
				for (var x in bib['sc:oclc']){
					data.oclc.push(bib['sc:oclc'][x])
				}
			}

			if (bib['lc:oclc']){
				for (var x in bib['lc:oclc']){
					data.oclc.push(bib['lc:oclc'][x])
				}
			}
			if (bib['sc:isbn']){
				for (var x in bib['sc:isbn']){
					data.isbn.push(bib['sc:isbn'][x])
				}
			}
			if (bib['sc:issn']){
				for (var x in bib['sc:issn']){
					data.issn.push(bib['sc:issn'][x])
				}
			}

			if (bib['author']){
				data.author = bib['author']
			}
			if (bib['title']){
				data.title = bib['title']
			}

			db.insertAPIClassifyRecord(data,function(err,results){

				totalChanged++

				cursor.resume()

				//console.log(data)
				//if (results) console.log(results.result)

			})

			return true

	}

	cursor.resume()

})

<|endoftext|>


<commit_before>const __bind = function(fn, me) {
  return function() {
    return fn.apply(me, arguments);
  };
};

class SomaPlayerBackground {
  constructor() {
    console.debug('initializing SomaPlayer background script');
    this.onTrack = __bind(this.onTrack, this);
    this.lastfm = SomaPlayerUtil.getLastfmConnection();
    this.createAudioTag();
    this.createTitleEl();
    this.createArtistEl();
  }

  createAudioTag() {
    this.audioTag = document.querySelector('audio');
    if (!this.audioTag) {
      console.debug('adding new audio tag');
      this.audioTag = document.createElement('audio');
      this.audioTag.setAttribute('autoplay', 'true');
      this.audioTag.setAttribute('data-station', '');
      document.body.appendChild(this.audioTag);
    }
  }

  createTitleEl() {
    this.titleEl = document.getElementById('title');
    if (!this.titleEl) {
      this.titleEl = document.createElement('div');
      this.titleEl.id = 'title';
      document.body.appendChild(this.titleEl);
    }
  }

  createArtistEl() {
    this.artistEl = document.getElementById('artist');
    if (!this.artistEl) {
      this.artistEl = document.createElement('div');
      this.artistEl.id = 'artist';
      document.body.appendChild(this.artistEl);
    }
  }

  play(station) {
    console.debug('playing station', station);
    this.resetTrackInfoIfNecessary(station);
    this.subscribe(station);
    this.socket.on('track', this.onTrack);
    this.audioTag.src = SomaPlayerConfig.somafm_station_url + station;
    this.audioTag.setAttribute('data-station', station);
    this.audioTag.removeAttribute('data-paused');
  }

  resetTrackInfoIfNecessary(station) {
    if (this.audioTag.getAttribute('data-station') === station) {
      return;
    }
    console.debug('changed station from',
                  this.audioTag.getAttribute('data-station'), 'to', station,
                  'clearing current track info');
    this.titleEl.textContent = '';
    this.artistEl.textContent = '';
  }

  displayCurrentTrack(station) {
    return SomaPlayerUtil.getCurrentTrackInfo(station).then(track => {
      this.titleEl.textContent = track.title;
      this.artistEl.textContent = track.artist;
    });
  }

  subscribe(station) {
    const emitSubscribe = () => {
      this.socket.emit('subscribe', station, response => {
        if (response.subscribed) {
          console.debug('subscribed to', station);
          this.displayCurrentTrack(station);
        } else {
          console.error('failed to subscribe to', station, response);
        }
      });
    };
    if (typeof this.socket === 'undefined') {
      console.debug('connecting to socket', SomaPlayerConfig.scrobbler_api_url);
      this.socket = io.connect(SomaPlayerConfig.scrobbler_api_url);
    }
    if (this.socket.connected) {
      emitSubscribe();
    } else {
      this.socket.on('connect', () => {
        emitSubscribe();
      });
    }
  }

  onTrack(track) {
    console.debug('new track:', track);
    this.titleEl.textContent = track.title;
    this.artistEl.textContent = track.artist;
    SomaPlayerUtil.getOptions().then(opts => {
      this.notifyOfTrack(track, opts);
      this.scrobbleTrack(track, opts);
    });
  }

  notifyOfTrack(track, opts) {
    // Default to showing notifications, so if user has not saved preferences,
    // assume they want notifications.
    if (opts.notifications === false) {
      return;
    }
    const notificationOpts = {
      type: 'basic',
      title: track.artist,
      message: track.title,
      iconUrl: 'icon48.png'
    };
    return chrome.notifications.create('', notificationOpts, () => {});
  }

  trackHasDuration(track) {
    return typeof track.duration === 'number' && track.duration > 0;
  }

  getScrobbleData(track, opts) {
    // http://www.last.fm/api/show/track.scrobble
    const data = {
      artist: (track.artist || '').replace(/"/g, "'"),
      track: (track.title || '').replace(/"/g, "'"),
      user: opts.lastfm_user,
      chosenByUser: 0,
      timestamp: Math.round((new Date()).getTime() / 1000)
    };
    if (typeof track.trackMBID === 'string') {
      data.mbid = track.trackMBID;
    }
    if (this.trackHasDuration(track)) {
      const milliseconds = track.duration;
      data.duration = milliseconds / 1000;
    }
    if (typeof track.album === 'string') {
      data.album = track.album;
    }
    return data;
  }

  scrobbleTrack(track, opts) {
    if (!(opts.lastfm_session_key && opts.lastfm_user && opts.scrobbling)) {
      return;
    }
    console.debug('scrobbling track for Last.fm user', opts.lastfm_user);
    const data = this.getScrobbleData(track, opts);
    const auth = { key: opts.lastfm_session_key };
    return this.lastfm.track.scrobble(data, auth, {
      success() {
        let e;
        try {
          const iframeWin = document.querySelector('iframe').contentWindow;
          iframeWin.document.querySelector('form').submit();
          console.debug('scrobbled track', track.title, track.artist);
        } catch (_error) {
          // Mysterious second submit after scrobble form has already POSTed
          // to Last.fm and the iframe has its origin changed to
          // ws.audioscrobbler.com, which can't be touched by the extension.
          e = _error;
          if (e.name !== 'SecurityError') {
            throw e;
          }
        }
      },
      error(data) {
        console.error('failed to scrobble track', track, 'response:', data);
      }
    });
  }

  pause(station) {
    console.debug('pausing station', station);
    this.unsubscribe(station);
    this.audioTag.pause();
    this.audioTag.currentTime = 0;
    this.audioTag.setAttribute('data-paused', 'true');
  }

  clear() {
    const info = this.getInfo();
    this.unsubscribe(info.station);
    this.audioTag.pause();
    this.audioTag.currentTime = 0;
    this.audioTag.setAttribute('data-station', '');
    this.audioTag.removeAttribute('data-paused');
  }

  unsubscribe(station) {
    if (!(typeof station === 'string' && station.length > 0)) {
      return;
    }
    if (typeof this.socket === 'undefined') {
      return;
    }
    console.debug('unsubscribing from', station, '...');
    this.socket.emit('unsubscribe', station, response => {
      if (response.unsubscribed) {
        console.debug('unsubscribed from', station);
      } else {
        console.error('failed to unsubscribe from', station);
      }
    });
    console.debug('removing track listener');
    this.socket.removeListener('track', this.onTrack);
  }

  getInfo() {
    let station = '';
    if (this.audioTag) {
      station = this.audioTag.getAttribute('data-station') || '';
    }
    return {
      station,
      artist: this.artistEl.textContent,
      title: this.titleEl.textContent,
      paused: this.audioTag.hasAttribute('data-paused') || station === ''
    };
  }

  setStations(stations) {
    console.debug('set stations', stations);
    SomaPlayerUtil.getOptions().then(opts => {
      opts.stations = stations;
      SomaPlayerUtil.setOptions(opts);
    });
  }

  getStations() {
    return new Promise(resolve => {
      SomaPlayerUtil.getOptions().then(opts => {
        resolve(opts.stations);
      });
    });
  }

  fetchStations() {
    const url = `${SomaPlayerConfig.somafm_api_url}channels.json`;
    console.debug(`fetching channels list from ${url}`);
    return new Promise((resolve, reject) => {
      SomaPlayerUtil.getJSON(url).then(data => {
        console.debug('fetched stations list', data);
        const simpleStations = this.extractStations(data);
        this.setStations(simpleStations);
        resolve(simpleStations);
      }).catch((xhr, status, error) => {
        console.error('failed to fetch stations list', error);
        reject(error);
      });
    });
  }

  extractStations(data) {
    const stations = data.channels.map(station => {
      return { id: station.id, title: station.title };
    });
    stations.sort(this.stationCompare);
    return stations;
  }

  stationCompare(a, b) {
    return a.title.toLowerCase().localeCompare(b.title.toLowerCase());
  }
}

let somaPlayerBG;

document.addEventListener('DOMContentLoaded', () => {
  somaPlayerBG = new SomaPlayerBackground();
});

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (typeof somaPlayerBG === 'undefined') {
    return;
  }
  console.debug('received:', request.action, request);
  if (request.action === 'play') {
    somaPlayerBG.play(request.station);
    sendResponse();
    return true;
  }
  if (request.action === 'pause') {
    somaPlayerBG.pause(request.station);
    sendResponse();
    return true;
  }
  if (request.action === 'info') {
    const info = somaPlayerBG.getInfo();
    console.debug('info:', info);
    sendResponse(info);
    return true;
  }
  if (request.action === 'clear') {
    somaPlayerBG.clear();
    sendResponse();
    return true;
  }
  if (request.action === 'fetch_stations') {
    somaPlayerBG.fetchStations().then(stations => {
      sendResponse(stations);
    }).catch(error => {
      sendResponse(null, error);
    });
    return true;
  }
  if (request.action === 'get_stations') {
    somaPlayerBG.getStations().then(stations => {
      console.debug('got saved list of stations:', stations);
      sendResponse(stations);
    });
    return true;
  }
});
<commit_msg>Don't scrobble track immediately upon starting<commit_after>const __bind = function(fn, me) {
  return function() {
    return fn.apply(me, arguments);
  };
};

class SomaPlayerBackground {
  constructor() {
    console.debug('initializing SomaPlayer background script');
    this.onTrack = __bind(this.onTrack, this);
    this.lastfm = SomaPlayerUtil.getLastfmConnection();
    this.createAudioTag();
    this.createTitleEl();
    this.createArtistEl();
  }

  createAudioTag() {
    this.audioTag = document.querySelector('audio');
    if (!this.audioTag) {
      console.debug('adding new audio tag');
      this.audioTag = document.createElement('audio');
      this.audioTag.setAttribute('autoplay', 'true');
      this.audioTag.setAttribute('data-station', '');
      document.body.appendChild(this.audioTag);
    }
  }

  createTitleEl() {
    this.titleEl = document.getElementById('title');
    if (!this.titleEl) {
      this.titleEl = document.createElement('div');
      this.titleEl.id = 'title';
      document.body.appendChild(this.titleEl);
    }
  }

  createArtistEl() {
    this.artistEl = document.getElementById('artist');
    if (!this.artistEl) {
      this.artistEl = document.createElement('div');
      this.artistEl.id = 'artist';
      document.body.appendChild(this.artistEl);
    }
  }

  play(station) {
    console.debug('playing station', station);
    this.resetTrackInfoIfNecessary(station);
    this.subscribe(station);
    this.socket.on('track', this.onTrack);
    this.audioTag.src = SomaPlayerConfig.somafm_station_url + station;
    this.audioTag.setAttribute('data-station', station);
    this.audioTag.removeAttribute('data-paused');
  }

  resetTrackInfoIfNecessary(station) {
    if (this.audioTag.getAttribute('data-station') === station) {
      return;
    }
    console.debug('changed station from',
                  this.audioTag.getAttribute('data-station'), 'to', station,
                  'clearing current track info');
    this.titleEl.textContent = '';
    this.artistEl.textContent = '';
  }

  displayCurrentTrack(station) {
    return SomaPlayerUtil.getCurrentTrackInfo(station).then(track => {
      this.titleEl.textContent = track.title;
      this.artistEl.textContent = track.artist;
    });
  }

  subscribe(station) {
    const emitSubscribe = () => {
      this.socket.emit('subscribe', station, response => {
        if (response.subscribed) {
          console.debug('subscribed to', station);
          this.displayCurrentTrack(station);
        } else {
          console.error('failed to subscribe to', station, response);
        }
      });
    };
    if (typeof this.socket === 'undefined') {
      console.debug('connecting to socket', SomaPlayerConfig.scrobbler_api_url);
      this.socket = io.connect(SomaPlayerConfig.scrobbler_api_url);
    }
    if (this.socket.connected) {
      emitSubscribe();
    } else {
      this.socket.on('connect', () => {
        emitSubscribe();
      });
    }
  }

  onTrack(track) {
    console.debug('new track:', track);
    this.titleEl.textContent = track.title;
    this.artistEl.textContent = track.artist;
    SomaPlayerUtil.getOptions().then(opts => {
      this.notifyOfTrack(track, opts);
      this.waitToScrobbleTrack(track, opts);
    });
  }

  waitToScrobbleTrack(track, opts) {
    let delay = 60000; // 60 seconds
    if (this.trackHasDuration(track)) {
      delay = track.duration / 2; // half the length of the song
    }
    console.debug('waiting', (delay / 1000), 'seconds to scrobble track');
    setTimeout(() => {
      this.scrobbleTrack(track, opts);
    }, delay);
  }

  notifyOfTrack(track, opts) {
    // Default to showing notifications, so if user has not saved preferences,
    // assume they want notifications.
    if (opts.notifications === false) {
      return;
    }
    const notificationOpts = {
      type: 'basic',
      title: track.artist,
      message: track.title,
      iconUrl: 'icon48.png'
    };
    return chrome.notifications.create('', notificationOpts, () => {});
  }

  trackHasDuration(track) {
    return typeof track.duration === 'number' && track.duration > 0;
  }

  getScrobbleData(track, opts) {
    // http://www.last.fm/api/show/track.scrobble
    const data = {
      artist: (track.artist || '').replace(/"/g, "'"),
      track: (track.title || '').replace(/"/g, "'"),
      user: opts.lastfm_user,
      chosenByUser: 0,
      timestamp: Math.round((new Date()).getTime() / 1000)
    };
    if (typeof track.trackMBID === 'string') {
      data.mbid = track.trackMBID;
    }
    if (this.trackHasDuration(track)) {
      const milliseconds = track.duration;
      data.duration = milliseconds / 1000;
    }
    if (typeof track.album === 'string') {
      data.album = track.album;
    }
    return data;
  }

  scrobbleTrack(track, opts) {
    if (!(opts.lastfm_session_key && opts.lastfm_user && opts.scrobbling)) {
      return;
    }
    console.debug('scrobbling track for Last.fm user', opts.lastfm_user);
    const data = this.getScrobbleData(track, opts);
    const auth = { key: opts.lastfm_session_key };
    return this.lastfm.track.scrobble(data, auth, {
      success() {
        let e;
        try {
          const iframeWin = document.querySelector('iframe').contentWindow;
          iframeWin.document.querySelector('form').submit();
          console.debug('scrobbled track', track.title, track.artist);
        } catch (_error) {
          // Mysterious second submit after scrobble form has already POSTed
          // to Last.fm and the iframe has its origin changed to
          // ws.audioscrobbler.com, which can't be touched by the extension.
          e = _error;
          if (e.name !== 'SecurityError') {
            throw e;
          }
        }
      },
      error(err) {
        console.error('failed to scrobble track', track, 'response:', err);
      }
    });
  }

  pause(station) {
    console.debug('pausing station', station);
    this.unsubscribe(station);
    this.audioTag.pause();
    this.audioTag.currentTime = 0;
    this.audioTag.setAttribute('data-paused', 'true');
  }

  clear() {
    const info = this.getInfo();
    this.unsubscribe(info.station);
    this.audioTag.pause();
    this.audioTag.currentTime = 0;
    this.audioTag.setAttribute('data-station', '');
    this.audioTag.removeAttribute('data-paused');
  }

  unsubscribe(station) {
    if (!(typeof station === 'string' && station.length > 0)) {
      return;
    }
    if (typeof this.socket === 'undefined') {
      return;
    }
    console.debug('unsubscribing from', station, '...');
    this.socket.emit('unsubscribe', station, response => {
      if (response.unsubscribed) {
        console.debug('unsubscribed from', station);
      } else {
        console.error('failed to unsubscribe from', station);
      }
    });
    console.debug('removing track listener');
    this.socket.removeListener('track', this.onTrack);
  }

  getInfo() {
    let station = '';
    if (this.audioTag) {
      station = this.audioTag.getAttribute('data-station') || '';
    }
    return {
      station,
      artist: this.artistEl.textContent,
      title: this.titleEl.textContent,
      paused: this.audioTag.hasAttribute('data-paused') || station === ''
    };
  }

  setStations(stations) {
    console.debug('set stations', stations);
    SomaPlayerUtil.getOptions().then(opts => {
      opts.stations = stations;
      SomaPlayerUtil.setOptions(opts);
    });
  }

  getStations() {
    return new Promise(resolve => {
      SomaPlayerUtil.getOptions().then(opts => {
        resolve(opts.stations);
      });
    });
  }

  fetchStations() {
    const url = `${SomaPlayerConfig.somafm_api_url}channels.json`;
    console.debug(`fetching channels list from ${url}`);
    return new Promise((resolve, reject) => {
      SomaPlayerUtil.getJSON(url).then(data => {
        console.debug('fetched stations list', data);
        const simpleStations = this.extractStations(data);
        this.setStations(simpleStations);
        resolve(simpleStations);
      }).catch((xhr, status, error) => {
        console.error('failed to fetch stations list', error);
        reject(error);
      });
    });
  }

  extractStations(data) {
    const stations = data.channels.map(station => {
      return { id: station.id, title: station.title };
    });
    stations.sort(this.stationCompare);
    return stations;
  }

  stationCompare(a, b) {
    return a.title.toLowerCase().localeCompare(b.title.toLowerCase());
  }
}

let somaPlayerBG;

document.addEventListener('DOMContentLoaded', () => {
  somaPlayerBG = new SomaPlayerBackground();
});

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (typeof somaPlayerBG === 'undefined') {
    return;
  }
  console.debug('received:', request.action, request);
  if (request.action === 'play') {
    somaPlayerBG.play(request.station);
    sendResponse();
    return true;
  }
  if (request.action === 'pause') {
    somaPlayerBG.pause(request.station);
    sendResponse();
    return true;
  }
  if (request.action === 'info') {
    const info = somaPlayerBG.getInfo();
    console.debug('info:', info);
    sendResponse(info);
    return true;
  }
  if (request.action === 'clear') {
    somaPlayerBG.clear();
    sendResponse();
    return true;
  }
  if (request.action === 'fetch_stations') {
    somaPlayerBG.fetchStations().then(stations => {
      sendResponse(stations);
    }).catch(error => {
      sendResponse(null, error);
    });
    return true;
  }
  if (request.action === 'get_stations') {
    somaPlayerBG.getStations().then(stations => {
      console.debug('got saved list of stations:', stations);
      sendResponse(stations);
    });
    return true;
  }
});
<|endoftext|>


<commit_before>define(['knockout'], function (ko) {
    ko.extenders.alphaNumeric = function(target) {
        //create a writable computed observable to intercept writes to our observable
        var result = ko.pureComputed({
            read: target,  //always return the original observables value
            write: function(newValue) {
                const isAlphaNumeric = RegExp('^[a-zA-Z0-9.]+$');
                let current = target();

                //only write if it changed
                if (isAlphaNumeric.test(newValue)) {
					target(newValue);
                } else {
					target.notifySubscribers(current);
                }
            }
        }).extend({ notify: 'always' });

        //initialize with current value to make sure it is rounded appropriately
        result(target());

        //return the new computed observable
        return result;
    }
});<commit_msg>Handle empty string in alphaNumeric extender - Fixes #1533<commit_after>define(['knockout'], function (ko) {
    ko.extenders.alphaNumeric = function(target) {
        //create a writable computed observable to intercept writes to our observable
        var result = ko.pureComputed({
            read: target,  //always return the original observables value
            write: function(newValue) {
                const isAlphaNumeric = RegExp('^[a-zA-Z0-9.]+$');
                let current = target();

                //only write if it changed
                if (isAlphaNumeric.test(newValue) || newValue === "") {
					target(newValue);
                } else {
					target.notifySubscribers(current);
                }
            }
        }).extend({ notify: 'always' });

        //initialize with current value to make sure it is rounded appropriately
        result(target());

        //return the new computed observable
        return result;
    }
});<|endoftext|>


<commit_before>/**
 * Experience Sampling event page.
 *
 * This background page handles the various events for registering participants
 * and showing new surveys in response to API events.
 *
 * Participants must fill out both a consent form and a startup survey (with
 * demographics) before they can begin to answer real survey questions.
 */

var cesp = {};  // namespace variable

cesp.readyForSurveys = false;
cesp.operatingSystem = "";

// Settings.
cesp.SERVER_URL = 'https://chrome-experience-sampling.appspot.com';
cesp.SUBMIT_SURVEY_ACTION = '/_ah/api/cesp/v1/submitsurvey';
cesp.XHR_TIMEOUT = 4000;
cesp.NOTIFICATION_TITLE = 'New Chrome survey available!';
cesp.NOTIFICATION_BODY = 'Your feedback makes Chrome better.';
cesp.NOTIFICATION_BUTTON = 'Take survey!';
cesp.MAX_SURVEYS_PER_DAY = 2;
cesp.ICON_FILE = 'icon.png';
cesp.NOTIFICATION_DEFAULT_TIMEOUT = 10;  // minutes
cesp.NOTIFICATION_TAG = 'chromeSurvey';
cesp.SURVEY_COUNT_RESET_ALARM_NAME = 'surveyCountReset';
cesp.NOTIFICATION_ALARM_NAME = 'notificationTimeout';
cesp.UNINSTALL_ALARM_NAME = 'uninstallAlarm';

// SETUP

/**
 * Sets up basic state for the extension. Called when extension is installed.
 * @param {object} details The details of the chrome.runtime.onInstalled event.
 */
function setupState(details) {
  // We check the event reason because onInstalled can trigger for other
  // reasons (extension or browser update).
  if (details.reason === 'install') {
    chrome.storage.local.set({'pending_responses': []});
    chrome.runtime.getPlatformInfo(function(platformInfo) {
      cesp.operatingSystem = platformInfo.os;
    });
    // Automatically uninstall the extension after 120 days.
    chrome.alarms.create(cesp.UNINSTALL_ALARM_NAME, {delayInMinutes: 172800});
    // Set the count of surveys shown to 0, and reset it each day at midnight.
    chrome.storage.local.set({cesp.SURVEYS_SHOWN_TODAY: 0});
    var midnight = new Date();
    midnight.setHours(0, 0, 0, 0);
    // midnight is the last midnight, so we set the alarm for one day from it.
    chrome.alarms.create(cesp.SURVEY_THROTTLE_RESET_ALARM,
        {when: midnight.getTime() + 86400000, periodInMinutes: 1440});
  }
}

/**
 * Handles the uninstall alarm.
 * @param {Alarm} alarm The alarm object from the onAlarm event.
*/
function handleUninstallAlarm(alarm) {
  if (alarm.name === cesp.UNINSTALL_ALARM_NAME)
    chrome.management.uninstallSelf();
}
chrome.alarms.onAlarm.addListener(handleUninstallAlarm);

/**
 * Resets the count of surveys shown to 0.
 * @param {Alarm} alarm The alarm object from the onAlarm event.
 */
function resetSurveyCount(alarm) {
  if (alarm.name === cesp.SURVEY_THROTTLE_RESET_ALARM)
    chrome.storage.local.set({cesp.SURVEYS_SHOWN_TODAY: 0});
}
chrome.alarms.onAlarm.addListener(resetSurveyCount);

/**
 * Retrieves the registration status from Local Storage.
 */
function getConsentStatus() {
  chrome.storage.local.get(constants.CONSENT_KEY, maybeShowConsentForm);
}

/**
 * Checks whether consent has been granted yet; if not, opens the consent form.
 * @param {object} consentLookup Object containing consent status (or empty).
 */
function maybeShowConsentForm(consentLookup) {
  if (!consentLookup || consentLookup[constants.CONSENT_KEY] == null ||
      consentLookup[constants.CONSENT_KEY] == constants.CONSENT_PENDING) {
    chrome.storage.onChanged.addListener(storageUpdated);
    chrome.tabs.create({'url': chrome.extension.getURL('consent.html')});
  } else if (consentLookup[constants.CONSENT_KEY] ==
             constants.CONSENT_REJECTED) {
    chrome.management.uninstallSelf();
  } else if (consentLookup[constants.CONSENT_KEY] ==
             constants.CONSENT_GRANTED) {
    // Someone might have filled out the consent form previously but not
    // filled out the setup survey. Check to see if that's the case.
    chrome.storage.local.get(constants.SETUP_KEY, maybeShowSetupSurvey);
  }
}

/**
 * Checks whether the setup survey has been completed yet. If it has been, we
 * are now ready to start showing surveys. If not, we need to listen for
 * when it's completed.
 * @param {object} setupLookup Object containing setup survey status (or empty).
 */
function maybeShowSetupSurvey(setupLookup) {
  if (!setupLookup || setupLookup[constants.SETUP_KEY] == null ||
      setupLookup[constants.SETUP_KEY] == constants.SETUP_PENDING) {
    chrome.tabs.create({'url': chrome.extension.getURL('surveys/setup.html')});
  } else if (setupLookup[constants.SETUP_KEY] == constants.SETUP_COMPLETED) {
    cesp.readyForSurveys = true;
  }
}

/**
 * Listens for the setup survey submission. When that happens, signals that
 * the experience sampling is now ready to begin.
 * @param {object} changes The changed portions of the database.
 * @param {string} areaName The name of the storage area.
 */
function storageUpdated(changes, areaName) {
  if (changes && changes[constants.SETUP_KEY] &&
      changes[constants.SETUP_KEY].newValue == constants.SETUP_COMPLETED) {
    cesp.readyForSurveys = true;
  }
}

// Performs consent and registration checks on startup and install.
chrome.runtime.onInstalled.addListener(getConsentStatus);
chrome.runtime.onStartup.addListener(getConsentStatus);
chrome.runtime.onInstalled.addListener(setupState);

// SURVEY HANDLING

/**
 * Clears our existing notification(s).
 * @param {Alarm} alarm The alarm object from the onAlarm event (optional).
 */
function clearNotifications(alarm) {
  if (alarm && alarm.name !== cesp.NOTIFICATION_ALARM_NAME)
    return;
  chrome.notifications.clear(cesp.NOTIFICATION_TAG, function(unused) {});
  chrome.alarms.clear(cesp.NOTIFICATION_ALARM_NAME);
}
// Clear the notification state when the survey times out.
chrome.alarms.onAlarm.addListener(clearNotifications);

/**
 * Creates a new notification to prompt the participant to take an experience
 * sampling survey.
 * @param {object} element The browser element of interest.
 * @param {object} decision The decision the participant made.
 */
function showSurveyNotification(element, decision) {
  if (!cesp.readyForSurveys) return;

  chrome.storage.local.get(cesp.SURVEYS_SHOWN_TODAY, function(items) {
    if (items[cesp.SURVEYS_SHOWN_TODAY] >= cesp.MAX_SURVEYS_PER_DAY) {
      return;
    }

    clearNotifications();

    var timePromptShown = new Date();
    var clickHandler = function(unused) {
      var timePromptClicked = new Date();
      loadSurvey(element, decision, timePromptShown, timePromptClicked);
      clearNotifications();
    };

    var opt = {
      type: 'basic',
      iconUrl: cesp.ICON_FILE,
      title: cesp.NOTIFICATION_TITLE,
      message: cesp.NOTIFICATION_BODY,
      eventTime: Date.now(),
      buttons: [{title: cesp.NOTIFICATION_BUTTON}]
    };
    chrome.notifications.create(
        cesp.NOTIFICATION_TAG,
        opt,
        function(id) {
          chrome.alarms.create(
              cesp.NOTIFICATION_ALARM_NAME,
              {delayInMinutes: cesp.NOTIFICATION_DEFAULT_TIMEOUT});
        });
    chrome.notifications.onClicked.addListener(clickHandler);
    chrome.notifications.onButtonClicked.addListener(clickHandler);

    chrome.storage.local.set({
      cesp.SURVEYS_SHOWN_TODAY: items[cesp.SURVEYS_SHOWN_TODAY] + 1
    });
  }
}

/**
 * Creates a new tab with the experience sampling survey page.
 * @param {object} element The browser element of interest.
 * @param {object} decision The decision the participant made.
 * @param {object} timePromptShown Date object of when the survey prompt
 *     notification was shown to the participant.
 * @param {object} timePromptClicked Date object of when the participant
 *     clicked the survey prompt notification.
 */
function loadSurvey(element, decision, timePromptShown, timePromptClicked) {
  if (!cesp.readyForSurveys) return;

  var surveyLocations = {
    SSL: 'ssl.html',
    EXAMPLE: 'survey-example.html'
  };
  var surveyURL;
  var eventType = constants.FindEventType(element['name']);
  switch (eventType) {
    case constants.EventType.SSL:
      surveyURL = surveyLocations.SSL;
      break;
    case constants.EventType.MALWARE:
    case constants.EventType.PHISHING:
    case constants.EventType.DOWNLOAD_MALICIOUS:
    case constants.EventType.EXTENSION_INSTALL:
      // TODO: Make surveys for each of these.
      surveyURL = surveyLocations.EXAMPLE;
      break;
    case constants.EventType.HARMFUL:
    case constants.EventType.SB_OTHER:
    case constants.EventType.DOWNLOAD_DANGEROUS:
    case constants.EventType.DOWNLOAD_DANGER_PROMPT:
      // Don't survey about these.
      return;
    case constants.EventType.UNKNOWN:
      throw new Error('Unknown event type: ' + element['name']);
      break;
  }
  chrome.tabs.create(
      {'url': chrome.extension.getURL('surveys/' + surveyURL)},
      function() { console.log('Opened survey.'); });
}

// Trigger the new survey prompt when the participant makes a decision about an
// experience sampling element.
chrome.experienceSamplingPrivate.onDecision.addListener(showSurveyNotification);

/**
 * A survey response (question and answer).
 * @constructor
 * @param {string} question The question being answered.
 * @param {string} answer The answer to that question.
 */
function Response(question, answer) {
  this.question = question;
  this.answer = answer;
}

/**
 * A completed survey.
 * @constructor
 * @param {string} type The type of survey.
 * @param {int} participantId The participant ID.
 * @param {Date} dateTaken The date and time when the survey was taken.
 * @param {Array.Response} responses An array of Response objects.
*/
function Survey(type, participantId, dateTaken, responses) {
  this.type = type;
  this.participantId = participantId;
  this.dateTaken = dateTaken;
  this.responses = responses;
}

/**
 * Sends a survey to the CESP backend via XHR.
 * @param {Survey} survey The completed survey to send to the backend.
 * @param {function(string)} successCallback A function to call on receiving a
 *     successful response (HTTP 204). It should look like
 *     "function(response) {...};" where "response" is the text of the response
 *     (if there is any).
 * @param {function(!number=)} errorCallback A function to call on receiving an
 *     error from the server, or on timing out. It should look like
 *     "function(status) {...};" where "status" is an HTTP status code integer,
 *     if there is one. For a timeout, there is no status.
 */
function sendSurvey(survey, successCallback, errorCallback) {
  var url = cesp.SERVER_URL + cesp.SUBMIT_SURVEY_ACTION;
  var method = "POST";
  var dateTaken = survey.dateTaken.toISOString();
  // Get rid of timezone "Z" on end of ISO String for AppEngine compatibility.
  if (dateTaken.slice(-1) === "Z") {
    dateTaken = dateTaken.slice(0, -1);
  }
  var data = {
    "date_taken": dateTaken,
    "participant_id": survey.participantId,
    "responses": [],
    "survey_type": survey.type
  };
  for (var i = 0; i < survey.responses.length; i++) {
    data.responses.push(survey.responses[i]);
  }
  var xhr = new XMLHttpRequest();
  function onLoadHandler(event) {
    if (xhr.readyState === 4) {
      if (xhr.status === 204) {
        successCallback(xhr.response);
      } else {
        errorCallback(xhr.status);
      }
    }
  }
  function onErrorHandler(event) {
    errorCallback(xhr.status);
  }
  function onTimeoutHandler(event) {
    errorCallback();
  }
  xhr.open(method, url, true);
  xhr.setRequestHeader('Content-Type', 'application/JSON');
  xhr.timeout = cesp.XHR_TIMEOUT;
  xhr.onload = onLoadHandler;
  xhr.onerror = onErrorHandler;
  xhr.ontimeout = onTimeoutHandler;
  xhr.send(JSON.stringify(data));
}
<commit_msg>Change cesp.readyForSurveys into a local storage value, and change the boolean checks on it to get the value from local storage and put the dependent code in callbacks.<commit_after>/**
 * Experience Sampling event page.
 *
 * This background page handles the various events for registering participants
 * and showing new surveys in response to API events.
 *
 * Participants must fill out both a consent form and a startup survey (with
 * demographics) before they can begin to answer real survey questions.
 */

var cesp = {};  // namespace variable

cesp.operatingSystem = "";

// Settings.
cesp.SERVER_URL = 'https://chrome-experience-sampling.appspot.com';
cesp.SUBMIT_SURVEY_ACTION = '/_ah/api/cesp/v1/submitsurvey';
cesp.XHR_TIMEOUT = 4000;
cesp.NOTIFICATION_TITLE = 'New Chrome survey available!';
cesp.NOTIFICATION_BODY = 'Your feedback makes Chrome better.';
cesp.NOTIFICATION_BUTTON = 'Take survey!';
cesp.MAX_SURVEYS_PER_DAY = 2;
cesp.ICON_FILE = 'icon.png';
cesp.NOTIFICATION_DEFAULT_TIMEOUT = 10;  // minutes
cesp.NOTIFICATION_TAG = 'chromeSurvey';
cesp.SURVEY_COUNT_RESET_ALARM_NAME = 'surveyCountReset';
cesp.NOTIFICATION_ALARM_NAME = 'notificationTimeout';
cesp.UNINSTALL_ALARM_NAME = 'uninstallAlarm';
cesp.READY_FOR_SURVEYS = 'readyForSurveys';

// SETUP

/**
 * A helper method for updating the value in local storage.
 * @param {bool} newState The desired new state for the ready for surveys flag.
 */
function setReadyForSurveysStorageValue(newState) {
  var items = {};
  items[cesp.READY_FOR_SURVEYS] = newState;
  chrome.storage.local.set(items);
}

/**
 * Sets up basic state for the extension. Called when extension is installed.
 * @param {object} details The details of the chrome.runtime.onInstalled event.
 */
function setupState(details) {
  // We check the event reason because onInstalled can trigger for other
  // reasons (extension or browser update).
  if (details.reason === 'install') {
    setReadyForSurveysStorageValue(false);
    chrome.storage.local.set({'pending_responses': []});
    chrome.runtime.getPlatformInfo(function(platformInfo) {
      cesp.operatingSystem = platformInfo.os;
    });
    // Automatically uninstall the extension after 120 days.
    chrome.alarms.create(cesp.UNINSTALL_ALARM_NAME, {delayInMinutes: 172800});
    // Set the count of surveys shown to 0, and reset it each day at midnight.
    chrome.storage.local.set({cesp.SURVEYS_SHOWN_TODAY: 0});
    var midnight = new Date();
    midnight.setHours(0, 0, 0, 0);
    // midnight is the last midnight, so we set the alarm for one day from it.
    chrome.alarms.create(cesp.SURVEY_THROTTLE_RESET_ALARM,
        {when: midnight.getTime() + 86400000, periodInMinutes: 1440});
  }
}

/**
 * Handles the uninstall alarm.
 * @param {Alarm} alarm The alarm object from the onAlarm event.
*/
function handleUninstallAlarm(alarm) {
  if (alarm.name === cesp.UNINSTALL_ALARM_NAME)
    chrome.management.uninstallSelf();
}
chrome.alarms.onAlarm.addListener(handleUninstallAlarm);

/**
 * Resets the count of surveys shown to 0.
 * @param {Alarm} alarm The alarm object from the onAlarm event.
 */
function resetSurveyCount(alarm) {
  if (alarm.name === cesp.SURVEY_THROTTLE_RESET_ALARM)
    chrome.storage.local.set({cesp.SURVEYS_SHOWN_TODAY: 0});
}
chrome.alarms.onAlarm.addListener(resetSurveyCount);

/**
 * Retrieves the registration status from Local Storage.
 */
function getConsentStatus() {
  chrome.storage.local.get(constants.CONSENT_KEY, maybeShowConsentForm);
}

/**
 * Checks whether consent has been granted yet; if not, opens the consent form.
 * @param {object} consentLookup Object containing consent status (or empty).
 */
function maybeShowConsentForm(consentLookup) {
  if (!consentLookup || consentLookup[constants.CONSENT_KEY] == null ||
      consentLookup[constants.CONSENT_KEY] == constants.CONSENT_PENDING) {
    chrome.storage.onChanged.addListener(storageUpdated);
    chrome.tabs.create({'url': chrome.extension.getURL('consent.html')});
  } else if (consentLookup[constants.CONSENT_KEY] ==
             constants.CONSENT_REJECTED) {
    chrome.management.uninstallSelf();
  } else if (consentLookup[constants.CONSENT_KEY] ==
             constants.CONSENT_GRANTED) {
    // Someone might have filled out the consent form previously but not
    // filled out the setup survey. Check to see if that's the case.
    chrome.storage.local.get(constants.SETUP_KEY, maybeShowSetupSurvey);
  }
}

/**
 * Checks whether the setup survey has been completed yet. If it has been, we
 * are now ready to start showing surveys. If not, we need to listen for
 * when it's completed.
 * @param {object} setupLookup Object containing setup survey status (or empty).
 */
function maybeShowSetupSurvey(setupLookup) {
  if (!setupLookup || setupLookup[constants.SETUP_KEY] == null ||
      setupLookup[constants.SETUP_KEY] == constants.SETUP_PENDING) {
    chrome.tabs.create({'url': chrome.extension.getURL('surveys/setup.html')});
  } else if (setupLookup[constants.SETUP_KEY] == constants.SETUP_COMPLETED) {
    setReadyForSurveysStorageValue(true);
  }
}

/**
 * Listens for the setup survey submission. When that happens, signals that
 * the experience sampling is now ready to begin.
 * @param {object} changes The changed portions of the database.
 * @param {string} areaName The name of the storage area.
 */
function storageUpdated(changes, areaName) {
  if (changes && changes[constants.SETUP_KEY] &&
      changes[constants.SETUP_KEY].newValue == constants.SETUP_COMPLETED) {
    setReadyForSurveysStorageValue(true);
  }
}

// Performs consent and registration checks on startup and install.
chrome.runtime.onInstalled.addListener(getConsentStatus);
chrome.runtime.onStartup.addListener(getConsentStatus);
chrome.runtime.onInstalled.addListener(setupState);

// SURVEY HANDLING

/**
 * Clears our existing notification(s).
 * @param {Alarm} alarm The alarm object from the onAlarm event (optional).
 */
function clearNotifications(alarm) {
  if (alarm && alarm.name !== cesp.NOTIFICATION_ALARM_NAME)
    return;
  chrome.notifications.clear(cesp.NOTIFICATION_TAG, function(unused) {});
  chrome.alarms.clear(cesp.NOTIFICATION_ALARM_NAME);
}
// Clear the notification state when the survey times out.
chrome.alarms.onAlarm.addListener(clearNotifications);

/**
 * Creates a new notification to prompt the participant to take an experience
 * sampling survey.
 * @param {object} element The browser element of interest.
 * @param {object} decision The decision the participant made.
 */
function showSurveyNotification(element, decision) {
  chrome.storage.local.get(cesp.READY_FOR_SURVEYS, function(items) {
    if (!items[cesp.READY_FOR_SURVEYS]) return;

    chrome.storage.local.get(cesp.SURVEYS_SHOWN_TODAY, function(items) {
      if (items[cesp.SURVEYS_SHOWN_TODAY] >= cesp.MAX_SURVEYS_PER_DAY) {
        return;
      }

      clearNotifications();

      var timePromptShown = new Date();
      var clickHandler = function(unused) {
        var timePromptClicked = new Date();
        loadSurvey(element, decision, timePromptShown, timePromptClicked);
        clearNotifications();
      };

      var opt = {
        type: 'basic',
        iconUrl: cesp.ICON_FILE,
        title: cesp.NOTIFICATION_TITLE,
        message: cesp.NOTIFICATION_BODY,
        eventTime: Date.now(),
        buttons: [{title: cesp.NOTIFICATION_BUTTON}]
      };
      chrome.notifications.create(
          cesp.NOTIFICATION_TAG,
          opt,
          function(id) {
            chrome.alarms.create(
                cesp.NOTIFICATION_ALARM_NAME,
                {delayInMinutes: cesp.NOTIFICATION_DEFAULT_TIMEOUT});
          });
      chrome.notifications.onClicked.addListener(clickHandler);
      chrome.notifications.onButtonClicked.addListener(clickHandler);

      chrome.storage.local.set({
        cesp.SURVEYS_SHOWN_TODAY: items[cesp.SURVEYS_SHOWN_TODAY] + 1
      });
    }
  });
}

/**
 * Creates a new tab with the experience sampling survey page.
 * @param {object} element The browser element of interest.
 * @param {object} decision The decision the participant made.
 * @param {object} timePromptShown Date object of when the survey prompt
 *     notification was shown to the participant.
 * @param {object} timePromptClicked Date object of when the participant
 *     clicked the survey prompt notification.
 */
function loadSurvey(element, decision, timePromptShown, timePromptClicked) {
  chrome.storage.local.get(cesp.READY_FOR_SURVEYS, function(items) {
    if (!items[cesp.READY_FOR_SURVEYS]) return;

    var surveyLocations = {
      SSL: 'ssl.html',
      EXAMPLE: 'survey-example.html'
    };
    var surveyURL;
    var eventType = constants.FindEventType(element['name']);
    switch (eventType) {
      case constants.EventType.SSL:
        surveyURL = surveyLocations.SSL;
        break;
      case constants.EventType.MALWARE:
      case constants.EventType.PHISHING:
      case constants.EventType.DOWNLOAD_MALICIOUS:
      case constants.EventType.EXTENSION_INSTALL:
        // TODO: Make surveys for each of these.
        surveyURL = surveyLocations.EXAMPLE;
        break;
      case constants.EventType.HARMFUL:
      case constants.EventType.SB_OTHER:
      case constants.EventType.DOWNLOAD_DANGEROUS:
      case constants.EventType.DOWNLOAD_DANGER_PROMPT:
        // Don't survey about these.
        return;
      case constants.EventType.UNKNOWN:
        throw new Error('Unknown event type: ' + element['name']);
        break;
    }
    chrome.tabs.create(
        {'url': chrome.extension.getURL('surveys/' + surveyURL)},
        function() { console.log('Opened survey.'); });
  });
}

// Trigger the new survey prompt when the participant makes a decision about an
// experience sampling element.
chrome.experienceSamplingPrivate.onDecision.addListener(showSurveyNotification);

/**
 * A survey response (question and answer).
 * @constructor
 * @param {string} question The question being answered.
 * @param {string} answer The answer to that question.
 */
function Response(question, answer) {
  this.question = question;
  this.answer = answer;
}

/**
 * A completed survey.
 * @constructor
 * @param {string} type The type of survey.
 * @param {int} participantId The participant ID.
 * @param {Date} dateTaken The date and time when the survey was taken.
 * @param {Array.Response} responses An array of Response objects.
*/
function Survey(type, participantId, dateTaken, responses) {
  this.type = type;
  this.participantId = participantId;
  this.dateTaken = dateTaken;
  this.responses = responses;
}

/**
 * Sends a survey to the CESP backend via XHR.
 * @param {Survey} survey The completed survey to send to the backend.
 * @param {function(string)} successCallback A function to call on receiving a
 *     successful response (HTTP 204). It should look like
 *     "function(response) {...};" where "response" is the text of the response
 *     (if there is any).
 * @param {function(!number=)} errorCallback A function to call on receiving an
 *     error from the server, or on timing out. It should look like
 *     "function(status) {...};" where "status" is an HTTP status code integer,
 *     if there is one. For a timeout, there is no status.
 */
function sendSurvey(survey, successCallback, errorCallback) {
  var url = cesp.SERVER_URL + cesp.SUBMIT_SURVEY_ACTION;
  var method = "POST";
  var dateTaken = survey.dateTaken.toISOString();
  // Get rid of timezone "Z" on end of ISO String for AppEngine compatibility.
  if (dateTaken.slice(-1) === "Z") {
    dateTaken = dateTaken.slice(0, -1);
  }
  var data = {
    "date_taken": dateTaken,
    "participant_id": survey.participantId,
    "responses": [],
    "survey_type": survey.type
  };
  for (var i = 0; i < survey.responses.length; i++) {
    data.responses.push(survey.responses[i]);
  }
  var xhr = new XMLHttpRequest();
  function onLoadHandler(event) {
    if (xhr.readyState === 4) {
      if (xhr.status === 204) {
        successCallback(xhr.response);
      } else {
        errorCallback(xhr.status);
      }
    }
  }
  function onErrorHandler(event) {
    errorCallback(xhr.status);
  }
  function onTimeoutHandler(event) {
    errorCallback();
  }
  xhr.open(method, url, true);
  xhr.setRequestHeader('Content-Type', 'application/JSON');
  xhr.timeout = cesp.XHR_TIMEOUT;
  xhr.onload = onLoadHandler;
  xhr.onerror = onErrorHandler;
  xhr.ontimeout = onTimeoutHandler;
  xhr.send(JSON.stringify(data));
}
<|endoftext|>