<commit_before>module.exports = (function(){
    "use strict";

    var _ = require("underscore"),
        mongoose = require('mongoose'),
        db = {};

    db.collectionName = 'users';
    db.schema = require('./schemas/user'),
    db.model = mongoose.model(db.collectionName, db.schema);
    db.privateFields = ["salt", "pass_hash"];

    function handleUser(err, doc, callback){
        if(err) {
            callback(err);
        }
        else if (doc != null) {
            callback(null, doc);
        }
        else {
            callback(new Error("User does not exist"));
        }
    }

    db.getByLogin = function(login, callback) {
        db.model.findOne({login: login}, this.buildIncludes()).lean().exec(function(err, doc){
            handleUser(err, doc, callback);
        });
    };

    db.getByEmail = function(email, callback) {
        db.model.findOne({email: email}, this.buildIncludes()).lean().exec(function(err, doc){
            handleUser(err, doc, callback);
         });
    };

    db.authenticate = function(login, password, callback){
        db.model.findOne({login: login}, function(err, doc){
            var valid = (doc != null) ? doc.authenticate(password) : false;

            if(!valid){
                handleUser(null, null, callback);
            }
            else {
                handleUser(err, doc, callback);
            }
        });
    };

    return _.extend(db, require("./mixins/crud"));
})();<commit_msg>GRAS-282 - Implemented database layer to handle user permissions.<commit_after>module.exports = (function(){
    "use strict";

    var _ = require("underscore"),
        mongoose = require('mongoose'),
        db = {};

    db.collectionName = 'users';
    db.schema = require('./schemas/user'),
    db.model = mongoose.model(db.collectionName, db.schema);
    db.privateFields = ["salt", "pass_hash"];

    function handleUser(err, doc, callback){
        if(err) {
            callback(err);
        }
        else if (doc != null) {
            callback(null, doc);
        }
        else {
            callback(new Error("User does not exist"));
        }
    }

    db.getByLogin = function(login, callback) {
        db.model.findOne({login: login}, this.buildIncludes()).lean().exec(function(err, doc){
            handleUser(err, doc, callback);
        });
    };

    db.getByEmail = function(email, callback) {
        db.model.findOne({email: email}, this.buildIncludes()).lean().exec(function(err, doc){
            handleUser(err, doc, callback);
         });
    };

    db.authenticate = function(login, password, callback){
        db.model.findOne({login: login}, function(err, doc){
            var valid = (doc != null) ? doc.authenticate(password) : false;

            if(!valid){
                handleUser(null, null, callback);
            }
            else {
                handleUser(err, doc, callback);
            }
        });
    };

    db.savePermissions = function(userId, nodeid, role, callback){
        db.model.findOne({_id: userId}, function(err, doc){
            if(err){
                callback(err);
            }
            else {
                var permissions = (!doc.permissions) ? [] : _.filter(doc.permissions, function(permission) {
                    return permission.nodeid.toString() != nodeid;
                });

                permissions[permissions.length] = {nodeid: nodeid, role: role};

                doc.permissions = permissions;
                doc.save(function(err, results){
                    callback(err, (!err) ? "Success" : null);
                });
         }
        });
    };

    db.deletePermission = function(userId, nodeId, callback){
        db.model.findOne({_id: userId}, function(err, doc){
            if(err){
                callback(err);
            }
            else {
                var permissions = (!doc.permissions) ? [] : _.filter(doc.permissions, function(permission) {
                    return permission.nodeid.toString() != nodeid;
                });

                doc.permissions = permissions;
                doc.save(function(err, results){
                    callback(err, (!err) ? "Success" : null);
                });
            }
        });
    };

    return _.extend(db, require("./mixins/crud"));
})();<|endoftext|>


<commit_before>import marked from 'marked';
import { GITHUB_URL } from 'constants/application';

marked.setOptions({
  renderer: new marked.Renderer(),
  gfm: true,
  tables: true,
  breaks: false,
  pedantic: false,
  sanitize: false,
  smartLists: true,
  smartypants: false,
});

export default function formatMarkdown(markdown) {
  return marked(markdown)
    .replace(/#(commit|pull|issues)-(\w+)/g, `${GITHUB_URL}/$1/$2`)
    .replace(/<a (href=".*")>/g, '<a $1 class="link">');
}
<commit_msg>Updated markdown generation<commit_after>import marked from 'marked';
import { GITHUB_URL } from 'constants/application';

marked.setOptions({
  renderer: new marked.Renderer(),
  gfm: true,
  tables: true,
  breaks: false,
  pedantic: false,
  sanitize: false,
  smartLists: true,
  smartypants: false,
});

/**
 * This will updated the generated markdown so all links that contain:
 * - #commit-HASH
 * - #pull-NUMBER
 * - #issues-NUMBER
 *
 * to reference a github url.
 *
 * @param {String} markdown - the transformed markdown
 * @return {String} the markdown updated with github links.
 */
function addSimpleGithubLinking(markdown) {
  return markdown.replace(/#(commit|pull|issues)-(\w+)/g, `${GITHUB_URL}/$1/$2`);
}

/**
 * This will update the markdown so that links now have a class of "link" for some
 * base styles.
 * @param {String} markdown - the transformed markdown
 * @return {String} the markdown updated with link styles.
 */
function addLinkStyles(markdown) {
  return markdown.replace(/<a (href=".*")>/g, '<a $1 class="link">');
}

/**
 * This will update the markdown so that there is an additional empty line between the
 * `@see` declaration in prop types so that it gets formatted better.
 *
 * @param {String} markdown - the transformed markdown
 * @return {String} the markdown updated.
 */
function addAdditionalLineToSee(markdown) {
  return markdown.replace(/(\r?\n)(@see)/g, '$1$1$2');
}

const transforms = [
  addSimpleGithubLinking,
  addLinkStyles,
  addAdditionalLineToSee,
];

export default function formatMarkdown(markdown) {
  return transforms.reduce((formatted, transform) => transform(formatted), marked(markdown));
}
<|endoftext|>


<commit_before>'use strict';

var reportObjects = require('./nightwatchReportObjects.js');
var normalize = require('../lib/normalize.js');
var generator = require('../lib/reportGenerator');
var path = require('path');

/*
	======== A Handy Little Nodeunit Reference ========
	https://github.com/caolan/nodeunit

	Test methods:
		test.expect(numAssertions)
		test.done()
	Test assertions:
		test.ok(value, [message])
		test.equal(actual, expected, [message])
		test.notEqual(actual, expected, [message])
		test.deepEqual(actual, expected, [message])
		test.notDeepEqual(actual, expected, [message])
		test.strictEqual(actual, expected, [message])
		test.notStrictEqual(actual, expected, [message])
		test.throws(block, [error], [message])
		test.doesNotThrow(block, [error], [message])
		test.ifError(value)
*/

exports.reportGenerator = {
	setUp: function(done){
		done();
	},
	'file location': function(test){
		test.expect(1);
		var normalized = normalize(reportObjects.withOneFailure);
		generator.writeReport(normalized, {
			reportsDirectory: __dirname,
			reportFilename: 'testfilename.html',
			themeName: 'default',
			saveFile: false
		}, function(err, reportFilename, html){
			test.equal(reportFilename, path.join(__dirname, 'testfilename.html'));
			test.done();
		});
	},

	'theme assets': function(test){
		test.expect(1);
		var normalized = normalize(reportObjects.withOneFailure);
		generator.writeReport(normalized, {
			reportsDirectory: __dirname,
			reportFilename: 'testfilename.html',
			themeName: 'default',
			saveFile: false
		}, function(err, reportFilename, html){
			var assetpath = path.join(__dirname, '..', 'lib', 'themes', 'default', 'default.css');
			test.notEqual(-1, html.indexOf(assetpath));
			test.done();
		});

	}
};
<commit_msg>Added generator test to make sure errors were displayed.<commit_after>'use strict';

var reportObjects = require('./nightwatchReportObjects.js');
var normalize = require('../lib/normalize.js');
var generator = require('../lib/reportGenerator');
var path = require('path');

/*
	======== A Handy Little Nodeunit Reference ========
	https://github.com/caolan/nodeunit

	Test methods:
		test.expect(numAssertions)
		test.done()
	Test assertions:
		test.ok(value, [message])
		test.equal(actual, expected, [message])
		test.notEqual(actual, expected, [message])
		test.deepEqual(actual, expected, [message])
		test.notDeepEqual(actual, expected, [message])
		test.strictEqual(actual, expected, [message])
		test.notStrictEqual(actual, expected, [message])
		test.throws(block, [error], [message])
		test.doesNotThrow(block, [error], [message])
		test.ifError(value)
*/

exports.reportGenerator = {
	setUp: function(done){
		done();
	},
	'file location': function(test){
		test.expect(1);
		var normalized = normalize(reportObjects.withOneFailure);
		generator.writeReport(normalized, {
			reportsDirectory: __dirname,
			reportFilename: 'testfilename.html',
			themeName: 'default',
			saveFile: false
		}, function(err, reportFilename, html){
			test.equal(reportFilename, path.join(__dirname, 'testfilename.html'));
			test.done();
		});
	},

	'theme assets': function(test){
		test.expect(1);
		var normalized = normalize(reportObjects.withOneFailure);
		generator.writeReport(normalized, {
			reportsDirectory: __dirname,
			reportFilename: 'testfilename.html',
			themeName: 'default',
			saveFile: false
		}, function(err, reportFilename, html){
			var assetpath = path.join(__dirname, '..', 'lib', 'themes', 'default', 'default.css');
			test.notEqual(-1, html.indexOf(assetpath));
			test.done();
		});
	},

	'shows errors': function(test){
		test.expect(1);
		var normalized = normalize(reportObjects.withOneError);
		generator.writeReport(normalized, {
			reportsDirectory: __dirname,
			reportFilename: 'testfilename.html',
			themeName: 'default',
			saveFile: false
		}, function(err, filename, html){
			test.notEqual(-1, html.indexOf(normalized.errmessages[0].replace(/\"/g, """)));
			test.done();
		});
	}
};
<|endoftext|>


<commit_before>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var path = require('path');
var spawn = require('child_process').spawn;

var dotfiles = require('util/client_dotfiles');
var log = require('util/log');
var constants = require('deployment/constants');

var async = require('extern/async');
var sprintf = require('extern/sprintf').sprintf;

/**
 * Execute a hook in a deployed instance
 * {Object} instance The instance on which to execute the hook
 * {String} version The version on which to execute the hook
 * {String} hook The name of the hook to execute
 * {Array} args Arguments to the specified hook
 * {Number} timeout Number of milliseconds after which hook is killed if it
 *                  hasn't exited yet.
 * {Function} callback A callback fired with (err, killed, stderr, stdout)
 */
exports.execute = function(instance, version, hook, timeout, args, callback) {
  var env = {};
  var k;

  // This whole thing is a dirty hack because process.env doesn't have a
  // hasOwnProperty() method - misc.merge won't work, and we need a condional
  // to keep jslint happy...
  for (k in process.env) {
    if (true) {
      env[k] = process.env[k];
    }
  }

  if (timeout === null) {
    timeout = constants.timeouts[hook];
  }

  env.CAST_INSTANCE_NAME = instance.name;

  var versionRoot;
  var hookPath;
  var hookExists = false;

  async.series([
    // Get the version root
    function(callback) {
      instance.get_version_path(version, function(err, version) {
        versionRoot = version;
        hookPath = path.join(versionRoot, '.cast-project', 'hooks', hook);
        callback(err);
      });
    },

    // See if the hook exists
    function(callback) {
      path.exists(hookPath, function(exists) {
        hookExists = exists;
        callback();
      });
    },

    // If the hook does exist, execute it
    function(callback) {
      if (!hookExists) {
        callback();
        return;
      }
      var opts = {
        cwd: versionRoot,
        env: env
      };

      var stdout = '';
      var stderr = '';
      var hookRunning = false;

      log.info('executing hook: ' + hookPath);

      var hookProc = spawn(hookPath, args, opts);
      hookRunning = true;

      var hookTimeoutId = setTimeout(function() {
        if (hookRunning) {
          hookProc.kill('SIGTERM');
        }
      }, timeout);

      hookProc.stdout.on('data', function(chunk) {
        stdout += chunk;
      });

      hookProc.stderr.on('data', function(chunk) {
        stderr += chunk;
      });

      hookProc.on('exit', function(code) {
        var err = null;
        var killed = this.killed;

        if (!killed) {
          clearTimeout(hookTimeoutId);
        }

        if (killed) {
          err = new Error(sprintf('hook %s was killed because a timeout' +
                                  ' of %s ms was reached ', hook, timeout));
        }
        else if (code !== 0) {
          err = new Error('hook \'' + hook + '\' exited with status ' + code);
          log.info('hook exited with status ' + code + ':' + hookPath);
        }
        else {
          log.info('hook exited cleanly');
        }

        callback(err, killed, stdout, stderr);
      });
    }
  ],
  function(err) {
    callback(err);
  });
};
<commit_msg>Fix hooks (use async.waterfall and properly pass arguments to the callback).<commit_after>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var path = require('path');
var spawn = require('child_process').spawn;

var dotfiles = require('util/client_dotfiles');
var log = require('util/log');
var constants = require('deployment/constants');

var async = require('extern/async');
var sprintf = require('extern/sprintf').sprintf;

/**
 * Execute a hook in a deployed instance
 * {Object} instance The instance on which to execute the hook
 * {String} version The version on which to execute the hook
 * {String} hook The name of the hook to execute
 * {Array} args Arguments to the specified hook
 * {Number} timeout Number of milliseconds after which hook is killed if it
 *                  hasn't exited yet.
 * {Function} callback A callback fired with (err, killed, stderr, stdout)
 */
exports.execute = function(instance, version, hook, timeout, args, callback) {
  var env = {};
  var k;

  // This whole thing is a dirty hack because process.env doesn't have a
  // hasOwnProperty() method - misc.merge won't work, and we need a condional
  // to keep jslint happy...
  for (k in process.env) {
    if (true) {
      env[k] = process.env[k];
    }
  }

  if (timeout === null) {
    timeout = constants.timeouts[hook];
  }

  env.CAST_INSTANCE_NAME = instance.name;

  var versionRoot;
  var hookPath;
  var hookExists = false;

  async.waterfall([
    // Get the version root
    function(callback) {
      instance.get_version_path(version, function(err, version) {
        versionRoot = version;
        hookPath = path.join(versionRoot, '.cast-project', 'hooks', hook);
        callback(err);
      });
    },

    // See if the hook exists
    function(callback) {
      path.exists(hookPath, function(exists) {
        hookExists = exists;
        callback();
      });
    },

    // If the hook does exist, execute it
    function(callback) {
      if (!hookExists) {
        callback();
        return;
      }
      var opts = {
        cwd: versionRoot,
        env: env
      };

      var stdout = '';
      var stderr = '';
      var hookRunning = false;

      log.info('executing hook: ' + hookPath);

      var hookProc = spawn(hookPath, args, opts);
      hookRunning = true;

      var hookTimeoutId = setTimeout(function() {
        if (hookRunning) {
          hookProc.kill('SIGTERM');
        }
      }, timeout);

      hookProc.stdout.on('data', function(chunk) {
        stdout += chunk;
      });

      hookProc.stderr.on('data', function(chunk) {
        stderr += chunk;
      });

      hookProc.on('exit', function(code) {
        var err = null;
        var killed = this.killed;

        if (!killed) {
          clearTimeout(hookTimeoutId);
        }

        if (killed) {
          err = new Error(sprintf('hook %s was killed because a timeout' +
                                  ' of %s ms was reached ', hook, timeout));
        }
        else if (code !== 0) {
          err = new Error('hook \'' + hook + '\' exited with status ' + code);
          log.info('hook exited with status ' + code + ':' + hookPath);
        }
        else {
          log.info('hook exited cleanly');
        }

        callback(err, killed, stdout, stderr);
      });
    }
  ],

  function(err, killed, stdout, stderr) {
    callback(err, killed, stdout, stderr);
  });
};
<|endoftext|>


<commit_before>// the leader runs the registry and the git push
var utils = require('component-consoler');
var async = require('async')
var exec = require('child_process').exec
var Job = require('../tools/job')
var Container = require('../tools/container')
var tools = require('../tools')
var flatten = require('etcd-flatten')
var Schedule = require('./schedule')

module.exports = function(config, etcd){

	var hostname = config.network.hostname
	var systemContainers = {}

	var schedule = Schedule(config, etcd)

	var containerNameArray = config.system.containers || []

	containerNameArray.forEach(function(name){
		systemContainers[name] = true
	})

	function canRunJobCounter(job, hostname, done){
		var self = this;
		if(job.system){
			return done(null, true)
		}
		var jobObject = Job(job)
		etcd.get('/counter/' + hostname + jobObject.key(), function(err, data){
			var counter = 0
			if(!err && data){
				counter = parseInt(data.node.value)
			}
			if(isNaN(counter)){
				counter = 0
			}
			counter++
			etcd.set('/counter/' + hostname + jobObject.key(), counter, function(err){
				if(counter>5){
					schedule.removeJob({
						job:job,
						hostname:hostname,
						removeProc:true,
						failed:true
					}, function(){
						done(null, false)
					})
				}
				else{
					done(null, true)
				}
			})
		})
	}

	function writeContainer(opts, done){
		var self = this
		var job = opts.job
		var ip = opts.ip
		var container = opts.container

		var jobObject = Job(job)

		async.parallel([
			function(next){

				schedule.writeDockerEndpoint({
					ip:ip,
					container:container,
					job:job
				}, next)

			},

			function(next){
				etcd.set('/deploy/' + hostname + jobObject.key(), jobObject.containerName(), job.id, next)
			},

			function(next){
				etcd.set('/container/' + hostname + jobObject.key(), JSON.stringify(container), next)
			}
		], done)
	}

	function processSlave(done){
		var self = this;
		getSlaveState(function(err, state){
			var actionCount = 0
			removeSlaveContainers(state, function(err, removeCount){
				if(err){
					utils.error(err)
				}
				if(removeCount){
					actionCount += removeCount
				}
				runSlaveContainers(state, function(err, addCount){
					if(err){
						utils.error(err)
					}
					if(addCount){
						actionCount += addCount
					}
					done(err, actionCount)
				})
			})
		})
	}

	function getSlaveState(done){
		var self = this;
		async.parallel({
			deploy:function(next){
				etcd.get('/deploy/' + hostname, {
					recursive:true
				}, function(err, data){
					if(err || !data){
						return next(err)
					}
					var ret = {}
					var deps = flatten(data.node) || {}

					Object.keys(deps || {}).forEach(function(key){
						var val = deps[key]
						key = key.substr('/deploy/' + hostname)
						ret[key] = val
					})
					next(null, ret)
				})
			},
			docker:function(next){

				exec('docker ps', function(err, stdout, stderr){
					if(err) return next(err)

					var lines = (stdout.toString() || '').split(/\n/).filter(function(l){
						return l.match(/\w/)
					})

					var names = lines.map(function(line){
						var parts = line.split(/\s\s+/)
						return parts[6]
					}).filter(function(n){
						return n!='NAMES'
					})

					var ret = {}

					names.forEach(function(n){
						ret[n] = true
					})

					next(err, ret)
				})
			}
		}, done)
	}

	function slaveRunJob(job, done){
		var self = this;
		var jobObject = Job(job)

		self.canRunJobCounter(job, hostname, function(err, canRun){
			if(!canRun){
				return done('job failed')
			}

			var container = Container(job, config)

			console.log('start job')
			console.log(JSON.stringify(job, null, 4))

			container.prepare(config, function(err){
				container.start(function(err, data){

					self.writeContainer({
						hostname:hostname,
						ip:config.network.private,
						job:job,
						container:data
					}, done)

				})
			})

		})

	}

	function runSlaveContainers(data, done){
		var self = this;
		var jobCount = 0
		async.forEach(Object.keys(data.deploy || {}), function(deployPath, nextContainer){
			var containerName = data.deploy[deployPath]
			var containerPath = deployPath

			function processJob(){

				var nameParts = tools.jobNameParts(containerPath)

				self.loadJobByPath(containerPath, function(err, jobData){
					if(err || !jobData){
						return nextContainer()
					}
					jobCount++
					self.slaveRunJob(jobData, function(){
						nextContainer()
					})
				})
			}

			if(containerName){
				// our container is not running remove it!
				if(!data.docker[containerName]){
					var container = Container(containerName)
					container.remove(function(){
						processJob()
					})
				}
				// our container is running - all is good
				else{
					nextContainer()
				}
			}
			// start the container normally
			else{
				processJob()
			}

		}, function(err){
			done(err, jobCount)
		})

	}

	function removeSlaveContainers(data, done){
		var count = 0
		async.forEach(Object.keys(data.docker || {}), function(containerName, nextContainer){

			if(!containerName.match(/\w/)) return nextContainer()

			var hit = false
			Object.keys(data.deploy || {}).forEach(function(key){
				var c = data.deploy[key]
				if(c==containerName){
					hit = true
				}
			})

			// we dont want to remove etcd
			if(systemContainers[containerName] || hit){
				return nextContainer()
			}

			utils.log('remove', containerName)
			console.dir(data)

			count++

			var container = Container(containerName)

			container.stop(function(err){
				if(err) return nextContainer(err)
				container.remove(nextContainer)
			})

		}, function(err){
			done(err, count)
		})
	}

	return {
		canRunJobCounter:canRunJobCounter,
		writeContainer:writeContainer,
		processSlave:processSlave,
		getSlaveState:getSlaveState,
		slaveRunJob:slaveRunJob,
		runSlaveContainers:runSlaveContainers,
		removeSlaveContainers:removeSlaveContainers
	}
}<commit_msg>slave refactor finished<commit_after>// the leader runs the registry and the git push
var utils = require('component-consoler');
var async = require('async')
var exec = require('child_process').exec
var Job = require('../tools/job')
var Container = require('../tools/container')
var tools = require('../tools')
var flatten = require('etcd-flatten')
var Schedule = require('./schedule')

module.exports = function(config, etcd){

	var hostname = config.network.hostname
	var systemContainers = {}

	var schedule = Schedule(config, etcd)

	var containerNameArray = config.system.containers || []

	containerNameArray.forEach(function(name){
		systemContainers[name] = true
	})

	function canRunJobCounter(job, hostname, done){
		var self = this;
		if(job.system){
			return done(null, true)
		}
		var jobObject = Job(job)
		etcd.get('/counter/' + hostname + jobObject.key(), function(err, data){
			var counter = 0
			if(!err && data){
				counter = parseInt(data.node.value)
			}
			if(isNaN(counter)){
				counter = 0
			}
			counter++
			etcd.set('/counter/' + hostname + jobObject.key(), counter, function(err){
				if(counter>5){
					schedule.removeJob({
						job:job,
						hostname:hostname,
						removeProc:true,
						failed:true
					}, function(){
						done(null, false)
					})
				}
				else{
					done(null, true)
				}
			})
		})
	}

	function writeContainer(opts, done){
		var self = this
		var job = opts.job
		var ip = opts.ip
		var container = opts.container

		var jobObject = Job(job)

		async.parallel([
			function(next){

				schedule.writeDockerEndpoint({
					ip:ip,
					container:container,
					job:job
				}, next)

			},

			function(next){
				etcd.set('/deploy/' + hostname + jobObject.key(), jobObject.containerName(), job.id, next)
			},

			function(next){
				etcd.set('/container/' + hostname + jobObject.key(), JSON.stringify(container), next)
			}
		], done)
	}

	function processSlave(done){
		var self = this;
		getSlaveState(function(err, state){
			var actionCount = 0
			removeSlaveContainers(state, function(err, removeCount){
				if(err){
					utils.error(err)
				}
				if(removeCount){
					actionCount += removeCount
				}
				runSlaveContainers(state, function(err, addCount){
					if(err){
						utils.error(err)
					}
					if(addCount){
						actionCount += addCount
					}
					done(err, actionCount)
				})
			})
		})
	}

	function getSlaveState(done){
		var self = this;
		async.parallel({
			deploy:function(next){
				etcd.get('/deploy/' + hostname, {
					recursive:true
				}, function(err, data){
					if(err || !data){
						return next(err)
					}
					var ret = {}
					var deps = flatten(data.node) || {}

					Object.keys(deps || {}).forEach(function(key){
						var val = deps[key]
						key = key.substr('/deploy/' + hostname)
						ret[key] = val
					})
					next(null, ret)
				})
			},
			docker:function(next){

				exec('docker ps', function(err, stdout, stderr){
					if(err) return next(err)

					var lines = (stdout.toString() || '').split(/\n/).filter(function(l){
						return l.match(/\w/)
					})

					var names = lines.map(function(line){
						var parts = line.split(/\s\s+/)
						return parts[6]
					}).filter(function(n){
						return n!='NAMES'
					})

					var ret = {}

					names.forEach(function(n){
						ret[n] = true
					})

					next(err, ret)
				})
			}
		}, done)
	}

	function slaveRunJob(job, done){
		var self = this;
		var jobObject = Job(job)

		canRunJobCounter(job, hostname, function(err, canRun){
			if(!canRun){
				return done('job failed')
			}

			var container = Container(job, config)

			console.log('[start job]')
			console.log(JSON.stringify(job, null, 4))

			container.prepare(config, function(err){
				container.start(function(err, data){

					writeContainer({
						hostname:hostname,
						ip:config.network.private,
						job:job,
						container:data
					}, done)

				})
			})

		})

	}

	function runSlaveContainers(data, done){
		var self = this;
		var jobCount = 0
		async.forEach(Object.keys(data.deploy || {}), function(deployPath, nextContainer){
			var containerName = data.deploy[deployPath]
			var containerPath = deployPath

			function processJob(){

				var nameParts = tools.jobNameParts(containerPath)

				schedule.loadJobByPath(containerPath, function(err, jobData){
					if(err || !jobData){
						return nextContainer()
					}
					jobCount++
					slaveRunJob(jobData, function(){
						nextContainer()
					})
				})
			}

			if(containerName){
				// our container is not running remove it!
				if(!data.docker[containerName]){
					var container = Container(containerName)
					container.remove(function(){
						processJob()
					})
				}
				// our container is running - all is good
				else{
					nextContainer()
				}
			}
			// start the container normally
			else{
				processJob()
			}

		}, function(err){
			done(err, jobCount)
		})

	}

	function removeSlaveContainers(data, done){
		var count = 0
		async.forEach(Object.keys(data.docker || {}), function(containerName, nextContainer){

			if(!containerName.match(/\w/)) return nextContainer()

			var hit = false
			Object.keys(data.deploy || {}).forEach(function(key){
				var c = data.deploy[key]
				if(c==containerName){
					hit = true
				}
			})

			// we dont want to remove etcd
			if(systemContainers[containerName] || hit){
				return nextContainer()
			}

			console.log('[remove] ' + containerName)
			console.dir(data)

			count++

			var container = Container(containerName)

			container.stop(function(err){
				if(err) return nextContainer(err)
				container.remove(nextContainer)
			})

		}, function(err){
			done(err, count)
		})
	}

	return {
		canRunJobCounter:canRunJobCounter,
		writeContainer:writeContainer,
		processSlave:processSlave,
		getSlaveState:getSlaveState,
		slaveRunJob:slaveRunJob,
		runSlaveContainers:runSlaveContainers,
		removeSlaveContainers:removeSlaveContainers
	}
}<|endoftext|>


<commit_before>/*global describe:true, before:true, it:true */
var api = require('../lib/goear_api.js'),
    expect = require('chai').expect,
    util = require('util');

function filterTracks(tracks, quality) {
  return tracks.filter(function(t) {
    return quality <= t.quality;
  });
}

describe('GoEar API tests', function() {
  "use strict";

  describe('#search', function() {

    it("should return valid results", function(done) {
      api.search("David Guetta", function(err, data) {
        expect(err).to.be.null;
        expect(data).to.not.be.null;
        expect(data).to.be.an('object');
        expect(data).to.include.keys('tracks', 'totalCount');
        expect(data.tracks).to.be.a('array');
        expect(data.tracks).to.have.length.above(0);
        expect(data.totalCount).to.be.a('number');
        expect(data.tracks[0]).to.include.keys('id', 'title', 'quality', 'duration');
        done();
      });
    });

    it("should return valid content", function(done) {
      api.search("David Guetta - She Wolf", function(err, data) {
      	expect(err).to.be.null;
        expect(data).to.exist;
        expect(data.tracks).to.have.length.above(0);
        expect(data.tracks[0]).to.include.keys('id', 'title', 'quality', 'duration');
        expect(data.tracks[0].title).to.match(/she wolf/i);
        done();
      });
    });

    it("should return an empty result when searching for an unknown value", function(done) {
      api.search("123lkj123lkj", function(err, data) {
      	expect(err).to.be.null;
        expect(data).to.not.be.null;
        expect(data.tracks).to.be.empty;
        expect(data.totalCount).to.equals(0);
        done();
      });
    });

    it("should return valid values when using default options", function(done) {
      api.search("The Police", function(err, data) {
      	expect(data.tracks).to.have.length(10);
        expect(data.tracks[0]).to.include.keys('id', 'title', 'quality', 'duration', 'artist', 'link');
        var filteredTracks = filterTracks(data.tracks, 0);
        expect(filteredTracks).to.have.length(data.tracks.length);
        done();
      });
    });

    it("should respect minimum quality when specified in search options", function(done) {
      var minQuality = 192;
      api.search("U2", {
        minQuality: minQuality
      }, function(err, data) {
      	expect(data.totalCount).to.not.exist;
        var filteredTracks = filterTracks(data.tracks, minQuality);
        expect(filteredTracks).to.have.length(data.tracks.length);
        done();
      });
    });

    it("should respect resultsCount when specified in search options", function(done) {
      var resultsCount = 50;
      api.search("Eric Clapton", {
        resultsCount: resultsCount
      }, function(err, data) {
      	expect(data.tracks).to.have.length(resultsCount);
        done();
      });
    });

    it("should respect offset when specified in search options", function(done) {
      var searchTerm = "Genesis",
          offset = 2;
      api.search(searchTerm, {
        resultsCount: 20
      }, function(err, data) {
      	expect(err).to.be.null;
        expect(data.tracks).to.have.length(20);
        api.search(searchTerm, {
          offset: offset,
          resultsCount: 10
        }, function(secondErr, secondData) {
          expect(secondErr).to.be.null;
          expect(data.tracks[0]).to.not.be.eql(secondData.tracks[0]);
          expect(data.tracks[10]).to.be.eql(secondData.tracks[0]);
          done();
        });
      });
    });

    it("should return extended info when specified in search options", function(done) {
      api.search("Seal", {
        extendedInfo: true
      }, function(err, data) {
      	var result = data.tracks.every(function(t) {
          return t.artist && t.link;
        });
        expect(result).to.be.true;
        done();
      });
    });

    it("Should return available results when looking for more results than api could return in a reasonable time", function(done) {
      var startTime = Date.now(),
          resultsCount = 100,
          finished = false;
      api.search("Genesis Jesus", {
        resultsCount: resultsCount,
        minQuality: 320,
        timeout: 2500
      }, function(err, data) {
        expect(err).to.be.null;
        expect(data.tracks).to.have.length.above(0);
        expect(data.tracks).to.have.length.below(resultsCount);
        expect(Date.now() - startTime).to.be.above(2500);
        finished = true;
        done();
      });
    });

    setTimeout(function(finished) {
      // Test should be running
      expect(finished).to.not.be.true;
    }, 3000);
  });

});
<commit_msg>Added new test to ensure tracks urls are valid<commit_after>/*global describe:true, before:true, it:true */
var api = require('../lib/goear_api.js'),
    expect = require('chai').expect,
    util = require('util'),
    request = require('request');

function filterTracks(tracks, quality) {
  return tracks.filter(function(t) {
    return quality <= t.quality;
  });
}

describe('GoEar API tests', function() {
  "use strict";

  describe('#search', function() {

    it("should return valid results", function(done) {
      api.search("David Guetta", function(err, data) {
        expect(err).to.be.null;
        expect(data).to.not.be.null;
        expect(data).to.be.an('object');
        expect(data).to.include.keys('tracks', 'totalCount');
        expect(data.tracks).to.be.a('array');
        expect(data.tracks).to.have.length.above(0);
        expect(data.totalCount).to.be.a('number');
        expect(data.tracks[0]).to.include.keys('id', 'title', 'quality', 'duration');
        done();
      });
    });

    it("should return valid content", function(done) {
      api.search("David Guetta - She Wolf", function(err, data) {
        expect(err).to.be.null;
        expect(data).to.exist;
        expect(data.tracks).to.have.length.above(0);
        expect(data.tracks[0]).to.include.keys('id', 'title', 'quality', 'duration');
        expect(data.tracks[0].title).to.match(/she wolf/i);
        done();
      });
    });

    it("Should return a valid track URL", function(done) {
        api.search("David Guetta - She Wolf", function(err, data) {
            request({
                url: data.tracks[0].link,
                method: 'HEAD'
            }, function(err, resp, body) {
                done();
            });
        });
    });

    it("should return an empty result when searching for an unknown value", function(done) {
      api.search("123lkj123lkj", function(err, data) {
        expect(err).to.be.null;
        expect(data).to.not.be.null;
        expect(data.tracks).to.be.empty;
        expect(data.totalCount).to.equals(0);
        done();
      });
    });

    it("should return valid values when using default options", function(done) {
      api.search("The Police", function(err, data) {
        expect(data.tracks).to.have.length(10);
        expect(data.tracks[0]).to.include.keys('id', 'title', 'quality', 'duration', 'artist', 'link');
        var filteredTracks = filterTracks(data.tracks, 0);
        expect(filteredTracks).to.have.length(data.tracks.length);
        done();
      });
    });

    it("should respect minimum quality when specified in search options", function(done) {
      var minQuality = 192;
      api.search("U2", {
        minQuality: minQuality
      }, function(err, data) {
        expect(data.totalCount).to.not.exist;
        var filteredTracks = filterTracks(data.tracks, minQuality);
        expect(filteredTracks).to.have.length(data.tracks.length);
        done();
      });
    });

    it("should respect resultsCount when specified in search options", function(done) {
      var resultsCount = 50;
      api.search("Eric Clapton", {
        resultsCount: resultsCount
      }, function(err, data) {
        expect(data.tracks).to.have.length(resultsCount);
        done();
      });
    });

    it("should respect offset when specified in search options", function(done) {
      var searchTerm = "Genesis",
          offset = 2;
      api.search(searchTerm, {
        resultsCount: 20
      }, function(err, data) {
        expect(err).to.be.null;
        expect(data.tracks).to.have.length(20);
        api.search(searchTerm, {
          offset: offset,
          resultsCount: 10
        }, function(secondErr, secondData) {
          expect(secondErr).to.be.null;
          expect(data.tracks[0]).to.not.be.eql(secondData.tracks[0]);
          expect(data.tracks[10]).to.be.eql(secondData.tracks[0]);
          done();
        });
      });
    });

    it("should return extended info when specified in search options", function(done) {
      api.search("Seal", {
        extendedInfo: true
      }, function(err, data) {
        var result = data.tracks.every(function(t) {
          return t.artist && t.link;
        });
        expect(result).to.be.true;
        done();
      });
    });

    it("Should return available results when looking for more results than api could return in a reasonable time", function(done) {
      var startTime = Date.now(),
          resultsCount = 100,
          finished = false;
      api.search("Genesis Jesus", {
        resultsCount: resultsCount,
        minQuality: 320,
        timeout: 2500
      }, function(err, data) {
        expect(err).to.be.null;
        expect(data.tracks).to.have.length.above(0);
        expect(data.tracks).to.have.length.below(resultsCount);
        expect(Date.now() - startTime).to.be.above(2500);
        finished = true;
        done();
      });
    });

    setTimeout(function(finished) {
      // Test should be running
      expect(finished).to.not.be.true;
    }, 3000);
  });

});
<|endoftext|>


<commit_before>
const advert = require('../helpers/advert')
const Streamers = require("../models/Streamer")
const ZSCORE = parseInt(config.host.split(/-/)[1])
const connections = {}

function makeCID() {
  return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15)
}
setInterval(async () => {
  // console.log(Object.keys(connections))
  // console.log(await redis2.zrange('totalSiteVisitors', 0, 99))
  for (const [cid, connection] of Object.entries(connections)) {
    if (!connection.alive) {
      clearTimeout(connection.staleTimer)
      await redis2.zrem(`totalSiteVisitors`, cid)
      await redis2.zrem('totalPremiumVisitors', cid)
      if (connection.embedStream) {
        await redis2.zrem(`embedVisitors:${connection.embedStream}`, cid)
      }
      connection.socket.close()
      delete connections[cid]
    }
    else if (connection.lastMsg < new Date().getTime() - 29000) {
      connection.alive = false
      connection.send({ping: 1})
    }
    else {
      // stable connection
    }
  }
}, 30000)

function Connection(conn, cid) {
  this.socket = conn.socket
  this.cid = cid || makeCID()
  this.alive = true
  this.send = (obj) => {
    this.socket.send(JSON.stringify(obj))
  }
  this.lastMsg = new Date().getTime()
  this.rename = (newCID) => {
    let oldCID = this.cid
    let clone = {}
    for (let key in this) {
      if (this.hasOwnProperty(key)) {
        clone[key] = this[key]
      }
    }
    clone.cid = newCID
    delete connections[oldCID]
    return clone
  }
  this.startStaleTimer = () => {
    clearTimeout(this.staleTimer)
    const that = this
    this.staleTimer = setTimeout(async () => {
      if (that.embedStream && that.embedStream !== '__streamspread') {
        await redis2.zrem(`embedVisitors:${that.embedStream}`, that.cid)
        that.embedStream = '__stale'
        await redis2.zadd(`embedVisitors:${that.embedStream}`, ZSCORE, that.cid)
      }
    }, 20*60*1000)
  }
  this.socket.on('close', () => {
    this.alive = false
  })
  this.socket.on('error', (e) => {
    this.alive = false
  })

  this.socket.on('message', async (data) => {
    this.lastMsg = new Date().getTime()
    this.alive = true
    const reply = {}
    try {
      let json = JSON.parse(data)
      data = json
    }
    catch {}
    for (const [key, value] of Object.entries(data)) {
      // hello: request-cid
      if (key === 'hello') {
        let cid
        if (value === 1) {
          reply.setCID = this.cid
          cid = this.cid
        }
        else if (value && typeof value === 'string') {
          await redis2.zrem(`totalSiteVisitors`, this.cid)
          await redis2.zrem('totalPremiumVisitors', this.cid)
          if (this.embedStream) {
            await redis2.zrem(`embedVisitors:${this.embedStream}`, this.cid)
          }
          cid = value
          connections[cid] = this.rename(cid)
          if (connections[cid].staleTimer) {
            connections[cid].startStaleTimer()
          }
        }
        await redis2.zadd('totalSiteVisitors', ZSCORE, cid)
        if (connections[cid].premiumUser) {
          await redis2.zadd('totalPremiumVisitors', ZSCORE, cid)
        }
        if (connections[cid].embedStream) {
          await redis2.zadd(`embedVisitors:${this.embedStream}`, ZSCORE, cid)
        }
      }
      // do: reqStream
      else if (key === 'do' && value === 'reqStream') {
        this.embedStream = await advert.determineStream()
        await redis2.zadd(`embedVisitors:${this.embedStream}`, ZSCORE, this.cid)
        reply.setStream = this.embedStream
        this.startStaleTimer()
      }
      // do: reqStream
      else if (key === 'do' && value === 'reqWago') {
        reply.wago = 'test'
      }
    }
    if (Object.keys(reply).length) {
      if (data.ident && !reply.ident) {
        reply.ident = data.ident
      }
      this.send(reply)
    }
  })
}

module.exports = async function (connection, req) {
  let cid = makeCID()
  try {
    connections[cid] = new Connection(connection, cid)
  }
  catch (e) {console.log(e)}
}

// on server restart clear the current counts for this host
async function restart() {
  await redis2.zremrangebyscore('totalSiteVisitors', ZSCORE, ZSCORE)
  await redis2.zremrangebyscore('totalPremiumVisitors', ZSCORE, ZSCORE)
  const streams = await Streamers.find({})
  streams.forEach(async (stream) => {
    await redis2.zremrangebyscore(`embedVisitors:${stream.name}`, ZSCORE, ZSCORE)
  })
  await redis2.zremrangebyscore(`embedVisitors:__streamspread`, ZSCORE, ZSCORE)
  await redis2.zremrangebyscore(`embedVisitors:__stale`, ZSCORE, ZSCORE)
}
restart()<commit_msg>rework pings<commit_after>
const advert = require('../helpers/advert')
const Streamers = require("../models/Streamer")
const ZSCORE = parseInt(config.host.split(/-/)[1])
const connections = {}

function makeCID() {
  return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15)
}
setInterval(async () => {
  // console.log(Object.keys(connections))
  // console.log(await redis2.zrange('totalSiteVisitors', 0, 99))
  for (const [oid, connection] of Object.entries(connections)) {
    if (!connection.alive) {
      clearTimeout(connection.staleTimer)
      await redis2.zrem(`totalSiteVisitors`, connection.cid)
      await redis2.zrem('totalPremiumVisitors', connection.cid)
      if (connection.embedStream) {
        await redis2.zrem(`embedVisitors:${connection.embedStream}`, connection.cid)
      }
      delete connections[oid]
    }
    else if (connection.lastMsg < new Date().getTime() - 30000) {
      connection.ping()
    }
    else {
      // stable connection
    }
  }
}, 29000)

function Connection(conn, cid) {
  this.socket = conn.socket
  this.cid = cid || makeCID()
  this.alive = true
  this.send = (obj) => {
    this.socket.send(JSON.stringify(obj))
  }
  this.lastMsg = new Date().getTime()
  this.ping = function() {
    this.alive = false
    this.send({ping: 1})
  }
  this.startStaleTimer = () => {
    clearTimeout(this.staleTimer)
    const that = this
    this.staleTimer = setTimeout(async () => {
      if (that.embedStream && that.embedStream !== '__streamspread') {
        await redis2.zrem(`embedVisitors:${that.embedStream}`, that.cid)
        that.embedStream = '__stale'
        await redis2.zadd(`embedVisitors:${that.embedStream}`, ZSCORE, that.cid)
      }
    }, 20*60*1000)
  }
  this.socket.on('close', () => {
    this.alive = false
  })
  this.socket.on('error', (e) => {
    this.alive = false
  })

  this.socket.on('message', async (data) => {
    this.lastMsg = new Date().getTime()
    this.alive = true
    const reply = {}
    try {
      let json = JSON.parse(data)
      data = json
    }
    catch {}
    for (const [key, value] of Object.entries(data)) {
      // Ping-Pong
      if (key === 'pong') {
        this.alive = true
        return
      }
      // hello: request-cid
      else if (key === 'hello') {
        if (value === 1) {
          reply.setCID = this.cid
        }
        else if (value && typeof value === 'string') {
          await redis2.zrem(`totalSiteVisitors`, this.cid)
          await redis2.zrem('totalPremiumVisitors', this.cid)
          if (this.embedStream) {
            await redis2.zrem(`embedVisitors:${this.embedStream}`, this.cid)
          }
          this.cid = value
          if (this.staleTimer) {
            this.startStaleTimer()
          }
        }
        await redis2.zadd('totalSiteVisitors', ZSCORE, this.cid)
        if (this.premiumUser) {
          await redis2.zadd('totalPremiumVisitors', ZSCORE, this.cid)
        }
        if (this.embedStream) {
          await redis2.zadd(`embedVisitors:${this.embedStream}`, ZSCORE, this.cid)
        }
      }
      // do: reqStream
      else if (key === 'do' && value === 'reqStream') {
        this.embedStream = await advert.determineStream()
        await redis2.zadd(`embedVisitors:${this.embedStream}`, ZSCORE, this.cid)
        reply.setStream = this.embedStream
        this.startStaleTimer()
      }
      // do: reqStream
      else if (key === 'do' && value === 'reqWago') {
        reply.wago = 'test'
      }
    }
    if (Object.keys(reply).length) {
      if (data.ident && !reply.ident) {
        reply.ident = data.ident
      }
      this.send(reply)
    }
  })
}

module.exports = async function (connection, req) {
  let cid = makeCID()
  try {
    connections[cid] = new Connection(connection, cid)
  }
  catch (e) {console.log(e)}
}

// on server restart clear the current counts for this host
async function restart() {
  await redis2.zremrangebyscore('totalSiteVisitors', ZSCORE, ZSCORE)
  await redis2.zremrangebyscore('totalPremiumVisitors', ZSCORE, ZSCORE)
  const streams = await Streamers.find({})
  streams.forEach(async (stream) => {
    await redis2.zremrangebyscore(`embedVisitors:${stream.name}`, ZSCORE, ZSCORE)
  })
  await redis2.zremrangebyscore(`embedVisitors:__streamspread`, ZSCORE, ZSCORE)
  await redis2.zremrangebyscore(`embedVisitors:__stale`, ZSCORE, ZSCORE)
}
restart()<|endoftext|>


<commit_before>import Path          from 'path';
import BrowserWindow from 'browser-window';
import Util          from '../common/Util.js';
import { IPCKeys }   from '../common/Constants.js';

/**
 * Manage the window.
 */
export default class WindowManager {
  /**
   * Initialize instance.
   *
   * @param {Main} context Application context.
   */
  constructor( context ) {
    /**
     * Application context.
     * @type {Main}
     */
    this._context = context;

    /**
     * Collection of a managed window.
     * @type {Map.<String, BrowserWindow>}
     */
    this._windows = new Map();

    /**
     * About dialog.
     * @type {BrowserWindow}
     */
    this._aboutDialog = null;

    context.ipc.on( IPCKeys.RequestCreateNewWindow, this._onRequestCreateNewWindow.bind( this ) );
    context.ipc.on( IPCKeys.RequestSendMessage, this._onRequestSendMessage.bind( this ) );
    context.ipc.on( IPCKeys.RequestGetWindowIDs, this._onRequestGetWindowIDs.bind( this ) );
  }

  /**
   * Reload the focused window, For debug.
   */
  reload() {
    const w = BrowserWindow.getFocusedWindow();
    if( w ) {
      w.reload();
    }
  }

  /**
   * Switch the display of the developer tools window at focused window, For debug.
   */
  toggleDevTools() {
    const w = BrowserWindow.getFocusedWindow();
    if( w ) {
      w.toggleDevTools();
    }
  }

  /**
   * Create a new window.
   *
   * @return {BrowserWindow} Created window.
   */
  createNewWindow() {
    const w = new BrowserWindow( {
      'width': 400,
      'height': 400,
      'min-width': 400,
      'min-height': 400,
      'resizable': true
    } );

    const id = w.id;

    w.on( 'closed', () => {
      if( DEBUG ) { Util.log( 'Window was closed, id = ' + id ); }

      // Unregister
      this._windows.delete( id );

      if( this._windows.size === 0 && this._aboutDialog ) {
        this._aboutDialog.close();
      }
    } );

    const filePath = Path.join( __dirname, 'window-main.html' );
    w.loadURL( 'file://' + filePath + '#' + w.id );
    this._windows.set( id, w );

    return w;
  }

  /**
   * Show the about application window.
   */
  createAboutWindow() {
    if( this._aboutDialog ) { return; }

    const w = new BrowserWindow( {
      'width': 400,
      'height': 256,
      'resizable': false,
      'alwaysOnTop': true
    } );

    w.setMenu( null );

    w.on( 'closed', () => {
      if( DEBUG ) { Util.log( 'The about application window was closed.' ); }

      this._aboutDialog = null;
    } );

    const filePath = Path.join( __dirname, 'window-about.html' );
    w.loadURL( 'file://' + filePath );

    this._aboutDialog = w;
  }

  /**
   * Occurs when a show new window requested.
   *
   * @param {IPCEvent} ev Event data.
   */
  _onRequestCreateNewWindow( ev ) {
    const createdWindow = this.createNewWindow();
    ev.sender.send( IPCKeys.FinishCreateNewWindow );

    const windowIDs = [];
    for( let key of this._windows.keys() ) {
      windowIDs.push( key );
    }

    this._windows.forEach( ( w ) => {
      // Because it may not receive the message, explicit request ( RequestGetWindowIDs ) later
      if( w.id === createdWindow.id ) { return; }

      w.webContents.send( IPCKeys.UpdateWindowIDs, windowIDs );
    } );
  }

  /**
   * Occurs when a send message requested.
   *
   * @param {IPCEvent} ev      Event data.
   * @param {Number}   id      Target window's identifier.
   * @param {String}   message Message.
   */
  _onRequestSendMessage( ev, id, message ) {
    const w = this._windows.get( id );
    if( w ) {
      w.webContents.send( IPCKeys.UpdateMessage, message );
    }

    ev.sender.send( IPCKeys.FinishSendMessage );
  }

  /**
   * Occurs when a get window identifiers requested.
   *
   * @param {IPCEvent} ev Event data.
   */
  _onRequestGetWindowIDs( ev ) {
    const windowIDs = [];
    for( let key of this._windows.keys() ) {
      windowIDs.push( key );
    }

    ev.sender.send( IPCKeys.FinishGetWindowIDs, windowIDs );
  }
}
<commit_msg>#64 Change "for of" to "Array.form"<commit_after>import Path          from 'path';
import BrowserWindow from 'browser-window';
import Util          from '../common/Util.js';
import { IPCKeys }   from '../common/Constants.js';

/**
 * Manage the window.
 */
export default class WindowManager {
  /**
   * Initialize instance.
   *
   * @param {Main} context Application context.
   */
  constructor( context ) {
    /**
     * Application context.
     * @type {Main}
     */
    this._context = context;

    /**
     * Collection of a managed window.
     * @type {Map.<String, BrowserWindow>}
     */
    this._windows = new Map();

    /**
     * About dialog.
     * @type {BrowserWindow}
     */
    this._aboutDialog = null;

    context.ipc.on( IPCKeys.RequestCreateNewWindow, this._onRequestCreateNewWindow.bind( this ) );
    context.ipc.on( IPCKeys.RequestSendMessage, this._onRequestSendMessage.bind( this ) );
    context.ipc.on( IPCKeys.RequestGetWindowIDs, this._onRequestGetWindowIDs.bind( this ) );
  }

  /**
   * Reload the focused window, For debug.
   */
  reload() {
    const w = BrowserWindow.getFocusedWindow();
    if( w ) {
      w.reload();
    }
  }

  /**
   * Switch the display of the developer tools window at focused window, For debug.
   */
  toggleDevTools() {
    const w = BrowserWindow.getFocusedWindow();
    if( w ) {
      w.toggleDevTools();
    }
  }

  /**
   * Create a new window.
   *
   * @return {BrowserWindow} Created window.
   */
  createNewWindow() {
    const w = new BrowserWindow( {
      'width': 400,
      'height': 400,
      'min-width': 400,
      'min-height': 400,
      'resizable': true
    } );

    const id = w.id;

    w.on( 'closed', () => {
      if( DEBUG ) { Util.log( 'Window was closed, id = ' + id ); }

      // Unregister
      this._windows.delete( id );

      if( this._windows.size === 0 && this._aboutDialog ) {
        this._aboutDialog.close();
      }
    } );

    const filePath = Path.join( __dirname, 'window-main.html' );
    w.loadURL( 'file://' + filePath + '#' + w.id );
    this._windows.set( id, w );

    return w;
  }

  /**
   * Show the about application window.
   */
  createAboutWindow() {
    if( this._aboutDialog ) { return; }

    const w = new BrowserWindow( {
      'width': 400,
      'height': 256,
      'resizable': false,
      'alwaysOnTop': true
    } );

    w.setMenu( null );

    w.on( 'closed', () => {
      if( DEBUG ) { Util.log( 'The about application window was closed.' ); }

      this._aboutDialog = null;
    } );

    const filePath = Path.join( __dirname, 'window-about.html' );
    w.loadURL( 'file://' + filePath );

    this._aboutDialog = w;
  }

  /**
   * Occurs when a show new window requested.
   *
   * @param {IPCEvent} ev Event data.
   */
  _onRequestCreateNewWindow( ev ) {
    const createdWindow = this.createNewWindow();
    ev.sender.send( IPCKeys.FinishCreateNewWindow );

    const windowIDs = [];
    for( let key of this._windows.keys() ) {
      windowIDs.push( key );
    }

    this._windows.forEach( ( w ) => {
      // Because it may not receive the message, explicit request ( RequestGetWindowIDs ) later
      if( w.id === createdWindow.id ) { return; }

      w.webContents.send( IPCKeys.UpdateWindowIDs, windowIDs );
    } );
  }

  /**
   * Occurs when a send message requested.
   *
   * @param {IPCEvent} ev      Event data.
   * @param {Number}   id      Target window's identifier.
   * @param {String}   message Message.
   */
  _onRequestSendMessage( ev, id, message ) {
    const w = this._windows.get( id );
    if( w ) {
      w.webContents.send( IPCKeys.UpdateMessage, message );
    }

    ev.sender.send( IPCKeys.FinishSendMessage );
  }

  /**
   * Occurs when a get window identifiers requested.
   *
   * @param {IPCEvent} ev Event data.
   */
  _onRequestGetWindowIDs( ev ) {
    const windowIDs = Array.from( this._windows.keys() );
    ev.sender.send( IPCKeys.FinishGetWindowIDs, windowIDs );
  }
}
<|endoftext|>


<commit_before>import mapContextToProps from '@restart/context/mapContextToProps';
import isEqual from 'lodash/isEqual';
import PropTypes from 'prop-types';
import React from 'react';
import { ReactReduxContext } from 'react-redux';
import StaticContainer from 'react-static-container';
import warning from 'warning';

import RouterContext from './RouterContext';
import createRender from './createRender';
import createStoreRouterObject from './createStoreRouterObject';
import resolveRenderArgs from './resolveRenderArgs';

export default function createBaseRouter({
  renderPending,
  renderReady,
  renderError,
  render = createRender({
    renderPending,
    renderReady,
    renderError,
  }),
}) {
  const propTypes = {
    store: PropTypes.object.isRequired,
    match: PropTypes.object.isRequired,
    resolvedMatch: PropTypes.object.isRequired,
    matchContext: PropTypes.any,
    resolver: PropTypes.shape({
      resolveElements: PropTypes.func.isRequired,
    }).isRequired,
    onResolveMatch: PropTypes.func.isRequired,
    initialRenderArgs: PropTypes.object,
  };

  class BaseRouter extends React.Component {
    constructor(props) {
      super(props);

      const {
        store,
        match,
        resolver,
        matchContext,
        initialRenderArgs,
      } = props;

      this.router = createStoreRouterObject(store);

      this.state = {
        isInitialRender: true,
        match,
        resolver,
        matchContext,
        iteration: 0,
        renderArgs: initialRenderArgs || null,
        element: initialRenderArgs ? render(initialRenderArgs) : null,
      };

      this.mounted = true;

      this.lastIteration = 0;
      this.pendingResolvedMatch = false;
    }

    // We use componentDidMount and componentDidUpdate to resolve the match if
    // needed because element resolution is asynchronous anyway, and this lets
    // us not worry about setState not being available in the constructor, or
    // about having to pass around nextProps.

    componentDidMount() {
      if (!this.props.initialRenderArgs) {
        this.resolveMatch();
      }

      if (__DEV__ && typeof window !== 'undefined') {
        /* eslint-env browser */
        /* eslint-disable no-underscore-dangle */
        if (window.__FOUND_HOT_RELOAD__) {
          warning(
            !window.__FOUND_REPLACE_ROUTE_CONFIG__,
            'Replacing existing hot reloading hook. Do not render more than one router instance when using hot reloading.',
          );

          window.__FOUND_REPLACE_ROUTE_CONFIG__ = this.router.replaceRouteConfig;
        }
        /* eslint-enable no-underscore-dangle */
        /* eslint-env browser: false */
      }
    }

    static getDerivedStateFromProps({ match, resolver, matchContext }, state) {
      if (state.isInitialRender) {
        return { isInitialRender: false };
      }

      if (
        match !== state.match ||
        resolver !== state.resolver ||
        !isEqual(matchContext, state.matchContext)
      ) {
        return {
          match,
          resolver,
          matchContext,
          iteration: state.iteration + 1,
        };
      }

      return null;
    }

    componentDidUpdate() {
      if (this.state.iteration > this.lastIteration) {
        this.lastIteration = this.state.iteration;
        this.resolveMatch();
      }
    }

    componentWillUnmount() {
      this.mounted = false;

      if (__DEV__ && typeof window !== 'undefined') {
        /* eslint-env browser */
        /* eslint-disable no-underscore-dangle */
        if (window.__FOUND_HOT_RELOAD__) {
          delete window.__FOUND_REPLACE_ROUTE_CONFIG__;
        }
        /* eslint-enable no-underscore-dangle */
        /* eslint-env browser: false */
      }
    }

    async resolveMatch() {
      const pendingIteration = this.lastIteration;
      const pendingMatch = this.props.match;

      try {
        for await (const renderArgs of resolveRenderArgs(
          this.router,
          this.props,
        )) {
          // Don't do anything if we're resolving an outdated match.
          if (!this.mounted || this.lastIteration !== pendingIteration) {
            return;
          }

          // If we're about to mark the match resolved, delay the rerender
          // until we do so.
          this.pendingResolvedMatch = !!(
            (renderArgs.elements || renderArgs.error) &&
            this.props.resolvedMatch !== pendingMatch
          );

          this.setState({
            renderArgs,
            element: render(renderArgs),
          });

          if (this.pendingResolvedMatch) {
            // If this is a new match, update the store, so we can rerender at
            // the same time as all of the links and other components connected
            // to the router state.
            this.pendingResolvedMatch = false;
            this.props.onResolveMatch(pendingMatch);
          }
        }
      } catch (e) {
        if (!this.mounted || this.lastIteration !== pendingIteration) {
          return;
        }

        if (e.isFoundRedirectException) {
          this.router.replace(e.location);
          return;
        }

        /* istanbul ignore next: paranoid guard */
        throw e;
      }
    }

    render() {
      const { iteration, renderArgs, element } = this.state;

      // Don't rerender synchronously if we have another rerender coming. Just
      // memoizing the element here doesn't do anything because we're using
      // context.
      return (
        <StaticContainer
          shouldUpdate={
            this.lastIteration === iteration && !this.pendingResolvedMatch
          }
        >
          <RouterContext.Provider
            value={{
              router: this.router,
              match: renderArgs,
            }}
          >
            {element}
          </RouterContext.Provider>
        </StaticContainer>
      );
    }
  }

  BaseRouter.propTypes = propTypes;

  // FIXME: For some reason, using contextType doesn't work here.
  return mapContextToProps(
    {
      consumers: ReactReduxContext,
      mapToProps: ({ store }) => ({ store }),
      displayName: 'withStore(BaseRouter)',
    },
    BaseRouter,
  );
}
<commit_msg>fix: Memoize router context (#716)<commit_after>import mapContextToProps from '@restart/context/mapContextToProps';
import isEqual from 'lodash/isEqual';
import PropTypes from 'prop-types';
import React from 'react';
import { ReactReduxContext } from 'react-redux';
import StaticContainer from 'react-static-container';
import warning from 'warning';

import RouterContext from './RouterContext';
import createRender from './createRender';
import createStoreRouterObject from './createStoreRouterObject';
import resolveRenderArgs from './resolveRenderArgs';

export default function createBaseRouter({
  renderPending,
  renderReady,
  renderError,
  render = createRender({
    renderPending,
    renderReady,
    renderError,
  }),
}) {
  const propTypes = {
    store: PropTypes.object.isRequired,
    match: PropTypes.object.isRequired,
    resolvedMatch: PropTypes.object.isRequired,
    matchContext: PropTypes.any,
    resolver: PropTypes.shape({
      resolveElements: PropTypes.func.isRequired,
    }).isRequired,
    onResolveMatch: PropTypes.func.isRequired,
    initialRenderArgs: PropTypes.object,
  };

  class BaseRouter extends React.Component {
    constructor(props) {
      super(props);

      const {
        store,
        match,
        resolver,
        matchContext,
        initialRenderArgs,
      } = props;

      this.router = createStoreRouterObject(store);

      this.state = {
        isInitialRender: true,
        match,
        resolver,
        matchContext,
        iteration: 0,
        routerContext: {
          router: this.router,
          match: initialRenderArgs || null,
        },
        element: initialRenderArgs ? render(initialRenderArgs) : null,
      };

      this.mounted = true;

      this.lastIteration = 0;
      this.pendingResolvedMatch = false;
    }

    // We use componentDidMount and componentDidUpdate to resolve the match if
    //  needed because element resolution is asynchronous anyway, and this lets
    //  us not worry about setState not being available in the constructor, or
    //  about having to pass around nextProps.

    componentDidMount() {
      if (!this.props.initialRenderArgs) {
        this.resolveMatch();
      }

      if (__DEV__ && typeof window !== 'undefined') {
        /* eslint-env browser */
        /* eslint-disable no-underscore-dangle */
        if (window.__FOUND_HOT_RELOAD__) {
          warning(
            !window.__FOUND_REPLACE_ROUTE_CONFIG__,
            'Replacing existing hot reloading hook. Do not render more than one router instance when using hot reloading.',
          );

          window.__FOUND_REPLACE_ROUTE_CONFIG__ = this.router.replaceRouteConfig;
        }
        /* eslint-enable no-underscore-dangle */
        /* eslint-env browser: false */
      }
    }

    static getDerivedStateFromProps({ match, resolver, matchContext }, state) {
      if (state.isInitialRender) {
        return { isInitialRender: false };
      }

      if (
        match !== state.match ||
        resolver !== state.resolver ||
        !isEqual(matchContext, state.matchContext)
      ) {
        return {
          match,
          resolver,
          matchContext,
          iteration: state.iteration + 1,
        };
      }

      return null;
    }

    componentDidUpdate() {
      if (this.state.iteration > this.lastIteration) {
        this.lastIteration = this.state.iteration;
        this.resolveMatch();
      }
    }

    componentWillUnmount() {
      this.mounted = false;

      if (__DEV__ && typeof window !== 'undefined') {
        /* eslint-env browser */
        /* eslint-disable no-underscore-dangle */
        if (window.__FOUND_HOT_RELOAD__) {
          delete window.__FOUND_REPLACE_ROUTE_CONFIG__;
        }
        /* eslint-enable no-underscore-dangle */
        /* eslint-env browser: false */
      }
    }

    async resolveMatch() {
      const pendingIteration = this.lastIteration;
      const pendingMatch = this.props.match;

      try {
        for await (const renderArgs of resolveRenderArgs(
          this.router,
          this.props,
        )) {
          // Don't do anything if we're resolving an outdated match.
          if (!this.mounted || this.lastIteration !== pendingIteration) {
            return;
          }

          // If we're about to mark the match resolved, delay the rerender
          //  until we do so.
          this.pendingResolvedMatch = !!(
            (renderArgs.elements || renderArgs.error) &&
            this.props.resolvedMatch !== pendingMatch
          );

          this.setState({
            routerContext: {
              router: this.router,
              match: renderArgs,
            },
            element: render(renderArgs),
          });

          if (this.pendingResolvedMatch) {
            // If this is a new match, update the store, so we can rerender at
            //  the same time as all of the links and other components
            //  connected to the router state.
            this.pendingResolvedMatch = false;
            this.props.onResolveMatch(pendingMatch);
          }
        }
      } catch (e) {
        if (!this.mounted || this.lastIteration !== pendingIteration) {
          return;
        }

        if (e.isFoundRedirectException) {
          this.router.replace(e.location);
          return;
        }

        /* istanbul ignore next: paranoid guard */
        throw e;
      }
    }

    render() {
      const { iteration, routerContext, element } = this.state;

      // Don't rerender synchronously if we have another rerender coming.
      return (
        <StaticContainer
          shouldUpdate={
            this.lastIteration === iteration && !this.pendingResolvedMatch
          }
        >
          <RouterContext.Provider value={routerContext}>
            {element}
          </RouterContext.Provider>
        </StaticContainer>
      );
    }
  }

  BaseRouter.propTypes = propTypes;

  // FIXME: For some reason, using contextType doesn't work here.
  return mapContextToProps(
    {
      consumers: ReactReduxContext,
      mapToProps: ({ store }) => ({ store }),
      displayName: 'withStore(BaseRouter)',
    },
    BaseRouter,
  );
}
<|endoftext|>


<commit_before>import createOnBlur from './events/createOnBlur'
import createOnChange from './events/createOnChange'
import createOnDragStart from './events/createOnDragStart'
import createOnDrop from './events/createOnDrop'
import createOnFocus from './events/createOnFocus'
import { partial, noop } from 'lodash'

const processProps = (props, _value) => {
  const { type, value, ...rest } = props
  if (type === 'checkbox') {
    return {
      ...rest,
      checked: !!value,
      type
    }
  }
  if (type === 'radio') {
    return {
      ...rest,
      checked: value === _value,
      type,
      value: _value
    }
  }
  return props
}

const createFieldProps = (getIn, name,
  { asyncError, blur, change, focus, initial, state, submitError,
    value, _value, ...rest }, syncError, initialPropValue, defaultValue = '', asyncValidate = noop) => {
  const error = syncError || asyncError || submitError
  const onChange = createOnChange(change)
  const initialValue = initial || initialPropValue
  return processProps({
    active: state && !!getIn(state, 'active'),
    dirty: value !== initialValue,
    error,
    invalid: !!error,
    name,
    onBlur: createOnBlur(blur, partial(asyncValidate, name)),
    onChange,
    onDragStart: createOnDragStart(name, value),
    onDrop: createOnDrop(name, change),
    onFocus: createOnFocus(name, focus),
    onUpdate: onChange,
    pristine: value === initialValue,
    touched: !!(state && getIn(state, 'touched')),
    valid: !error,
    value: value === undefined ? defaultValue : value,
    visited: state && !!getIn(state, 'visited'),
    ...rest
  }, _value)
}

export default createFieldProps
<commit_msg>avoided null values. fixes problem reported on #703<commit_after>import createOnBlur from './events/createOnBlur'
import createOnChange from './events/createOnChange'
import createOnDragStart from './events/createOnDragStart'
import createOnDrop from './events/createOnDrop'
import createOnFocus from './events/createOnFocus'
import { partial, noop } from 'lodash'

const processProps = (props, _value) => {
  const { type, value, ...rest } = props
  if (type === 'checkbox') {
    return {
      ...rest,
      checked: !!value,
      type
    }
  }
  if (type === 'radio') {
    return {
      ...rest,
      checked: value === _value,
      type,
      value: _value
    }
  }
  return props
}

const createFieldProps = (getIn, name,
  { asyncError, blur, change, focus, initial, state, submitError,
    value, _value, ...rest }, syncError, initialPropValue, defaultValue = '', asyncValidate = noop) => {
  const error = syncError || asyncError || submitError
  const onChange = createOnChange(change)
  const initialValue = initial || initialPropValue
  return processProps({
    active: state && !!getIn(state, 'active'),
    dirty: value !== initialValue,
    error,
    invalid: !!error,
    name,
    onBlur: createOnBlur(blur, partial(asyncValidate, name)),
    onChange,
    onDragStart: createOnDragStart(name, value),
    onDrop: createOnDrop(name, change),
    onFocus: createOnFocus(name, focus),
    onUpdate: onChange,
    pristine: value === initialValue,
    touched: !!(state && getIn(state, 'touched')),
    valid: !error,
    value: value == null ? defaultValue : value,
    visited: state && !!getIn(state, 'visited'),
    ...rest
  }, _value)
}

export default createFieldProps
<|endoftext|>


<commit_before>(function (angular) {

    'use strict';

    var comentariosModule = angular.module('comentariosModule',['ngAnimate', 'ngSanitize', 'ui.bootstrap', 'xeditable']);

    // Service para comentarios. Cargar y guardar notas
    comentariosModule.service('pimcComentarios', ['$http', '$q', 'pimcService', function($http, $q, pimcService){
        var comentariosController = this;

        comentariosController.cargarNotas = function(elementoRelacional, elementoID) {
            // Obtenemos URL de consulta
            var consultaComentarios = pimcService.crearURLOperacion('Consulta', elementoRelacional + "Notas")

            // Organizamos el ID del elementoRelacional
            var parametros = {};
            parametros[pimcService.idElementoRelaciona[elementoRelacional]] = elementoID;

            // Realizamos la consulta en la base de datos
            return $http.get(consultaComentarios, {params:parametros}).then(function(data) {
                if (Object.keys(data.data).length != 0) {
                    var resultadoConsulta = data.data;
                    var notas = [];
                    if (Object.keys(resultadoConsulta).length != 0) {
                        resultadoConsulta;
                        resultadoConsulta.forEach(function(notaDB) {
                            var nuevaNota = {};
                            nota.estado = pimcService.datosEstados.LIMPIO;
                            nota.contenido = notaDB;
                        });
                        // LOG
                        pimcService.debug(notas);
                    }
                    return notas;
                } else {
                    return [];
                }
            });

        };

        comentariosController.guardarNotas = function(elementoRelacional, notas) {
            var conexiones = [];
            // Realizamos cambios de acuerdo al estado
            notas.forEach(function(nota) {
                // Insertamos notas nuevas
                if (nota.estado === pimcService.datosEstados.INSERTADO) {
                    // Obtenemos URL de consulta
                    var URLInsertar = pimcService.crearURLOperacion('Insertar', elementoRelacional + "Notas");
                    conexiones.push($http.get(URLInsertar, {params:nota.contenido}));
                } else if (nota.estado === pimcService.datosEstados.MODIFICADO) {
                    // Modificamos notas viejas
                    // Obtenemos URL de consulta
                    var URLModificar = pimcService.crearURLOperacion('Modificar', elementoRelacional + "Notas");
                    var parametros = nota.contenido;
                    parametros.idUnico = "notaID";
                    conexiones.push($http.get(URLModificar, {params:parametros}));
                } else if (nota.estado === pimcService.datosEstados.ELIMINADO) {
                    // Obtenemos URL de consulta
                    var URLEliminar = pimcService.crearURLOperacion('Eliminar', elementoRelacional + "Notas");
                    var data = {
                        idUnico:'notaID',
                        notaID:nota.notaID
                    };
                    conexiones.push($http.get(URLEliminar, {params:data}));
                };
            });
            return $q.all(conexiones).then( function(responses) {
                    for (var res in responses) {
                        pimcService.debug(res + ' = ' + responses[res].data);
                    }
                }, function(responses) {
                for (var res in responses) {
                        pimcService.debug("[ERROR]" + res + ' = ' + responses[res]);
                    }
            });
        };

    }]);

    comentariosModule.controller('comentariosComponentController',['pimcService', 'pimcBarraEstadoService', function(pimcService, pimcBarraEstadoService) {
        var controladorComentarios = this;
        controladorComentarios.notas = [];
        controladorComentarios.agregarNotaVacia = function() {
            pimcBarraEstadoService.registrarAccion("Nota vacia agregada");
            controladorComentarios.notas.push({
                estado:pimcService.datosEstados.INSERTADO,
                contenido: {
                    nota: "",
                    tipoNota: "",
                    referencia: "",
                    fechaCreacion: "",
                    fechaHistorica: "",
                    fechaHistFormato: ""
                }
            });
            controladorComentarios.reportarCambio();
        }
        controladorComentarios.eliminarNota = function(indexNota) {
            pimcBarraEstadoService.registrarAccion("Nota " + indexNota + " eliminada");
            if (controladorComentarios.notas[indexNota].estado === pimcService.datosEstados.INSERTADO) {
                controladorComentarios.notas.splice(indexNota, 1);
            } else {
                controladorComentarios.notas[indexNota].estado = pimcService.datosEstados.ELIMINADO;
            }
            controladorComentarios.reportarCambio();
        };
        controladorComentarios.modificarNota = function(indexNota, elementoModificado) {
            pimcBarraEstadoService.registrarAccion("Nota " + indexNota + " modificada");
            if (controladorComentarios.notas[indexNota].estado === pimcService.datosEstados.INSERTADO) {
                controladorComentarios.notas[indexNota].estado = pimcService.datosEstados.MODIFICADO;
            }
        };

    }]);

    comentariosModule.filter('filtrarEliminados',['pimcService' ,function(pimcService) {
            return function (notas) {
                if (!notas) return [];
                var filtrados = [];
                angular.forEach(notas, function(key,val) {
                    if (val.estado != pimcService.datosEstados.ELIMINADO) {
                        filtrados.push(val);
                    }
                });
                return filtrados;
            }
        }]);

    comentariosModule.component('pimcComentariosAnotaciones', {
        bindings:{
            notas:'=',
            reportarCambio:'&'
        },
        controller: 'comentariosComponentController',
        controllerAs: 'controladorComentarios',
        templateUrl: 'views/global/comentarios/comentariosTemplate.html'
    });

})(window.angular);<commit_msg>cambiando comentario para usar angular.foreach dle resultado de la consulta<commit_after>(function (angular) {

    'use strict';

    var comentariosModule = angular.module('comentariosModule',['ngAnimate', 'ngSanitize', 'ui.bootstrap', 'xeditable']);

    // Service para comentarios. Cargar y guardar notas
    comentariosModule.service('pimcComentarios', ['$http', '$q', 'pimcService', function($http, $q, pimcService){
        var comentariosController = this;

        comentariosController.cargarNotas = function(elementoRelacional, elementoID) {
            // Obtenemos URL de consulta
            var consultaComentarios = pimcService.crearURLOperacion('Consulta', elementoRelacional + "Notas")

            // Organizamos el ID del elementoRelacional
            var parametros = {};
            parametros[pimcService.idElementoRelaciona[elementoRelacional]] = elementoID;

            // Realizamos la consulta en la base de datos
            return $http.get(consultaComentarios, {params:parametros}).then(function(data) {
                if (Object.keys(data.data).length != 0) {
                    var resultadoConsulta = data.data;
                    var notas = [];
                    if (Object.keys(resultadoConsulta).length != 0) {
                        resultadoConsulta;
                        angular.forEach(resultadoConsulta, function(notaDB, key) {
                            var nuevaNota = {};
                            nuevaNota.estado = pimcService.datosEstados.LIMPIO;
                            nuevaNota.contenido = notaDB;
                            notas.push(nuevaNota);
                        });
                        // LOG
                        pimcService.debug(notas);
                    }
                    return notas;
                } else {
                    return [];
                }
            });

        };

        comentariosController.guardarNotas = function(elementoRelacional, notas) {
            var conexiones = [];
            // Realizamos cambios de acuerdo al estado
            notas.forEach(function(nota) {
                // Insertamos notas nuevas
                if (nota.estado === pimcService.datosEstados.INSERTADO) {
                    // Obtenemos URL de consulta
                    var URLInsertar = pimcService.crearURLOperacion('Insertar', elementoRelacional + "Notas");
                    conexiones.push($http.get(URLInsertar, {params:nota.contenido}));
                } else if (nota.estado === pimcService.datosEstados.MODIFICADO) {
                    // Modificamos notas viejas
                    // Obtenemos URL de consulta
                    var URLModificar = pimcService.crearURLOperacion('Modificar', elementoRelacional + "Notas");
                    var parametros = nota.contenido;
                    parametros.idUnico = "notaID";
                    conexiones.push($http.get(URLModificar, {params:parametros}));
                } else if (nota.estado === pimcService.datosEstados.ELIMINADO) {
                    // Obtenemos URL de consulta
                    var URLEliminar = pimcService.crearURLOperacion('Eliminar', elementoRelacional + "Notas");
                    var data = {
                        idUnico:'notaID',
                        notaID:nota.notaID
                    };
                    conexiones.push($http.get(URLEliminar, {params:data}));
                };
            });
            return $q.all(conexiones).then( function(responses) {
                    for (var res in responses) {
                        pimcService.debug(res + ' = ' + responses[res].data);
                    }
                }, function(responses) {
                for (var res in responses) {
                        pimcService.debug("[ERROR]" + res + ' = ' + responses[res]);
                    }
            });
        };

    }]);

    comentariosModule.controller('comentariosComponentController',['pimcService', 'pimcBarraEstadoService', function(pimcService, pimcBarraEstadoService) {
        var controladorComentarios = this;
        controladorComentarios.notas = [];
        controladorComentarios.agregarNotaVacia = function() {
            pimcBarraEstadoService.registrarAccion("Nota vacia agregada");
            controladorComentarios.notas.push({
                estado:pimcService.datosEstados.INSERTADO,
                contenido: {
                    nota: "",
                    tipoNota: "",
                    referencia: "",
                    fechaCreacion: "",
                    fechaHistorica: "",
                    fechaHistFormato: ""
                }
            });
            controladorComentarios.reportarCambio();
        }
        controladorComentarios.eliminarNota = function(indexNota) {
            pimcBarraEstadoService.registrarAccion("Nota " + indexNota + " eliminada");
            if (controladorComentarios.notas[indexNota].estado === pimcService.datosEstados.INSERTADO) {
                controladorComentarios.notas.splice(indexNota, 1);
            } else {
                controladorComentarios.notas[indexNota].estado = pimcService.datosEstados.ELIMINADO;
            }
            controladorComentarios.reportarCambio();
        };
        controladorComentarios.modificarNota = function(indexNota, elementoModificado) {
            pimcBarraEstadoService.registrarAccion("Nota " + indexNota + " modificada");
            if (controladorComentarios.notas[indexNota].estado === pimcService.datosEstados.INSERTADO) {
                controladorComentarios.notas[indexNota].estado = pimcService.datosEstados.MODIFICADO;
            }
        };

    }]);

    comentariosModule.filter('filtrarEliminados',['pimcService' ,function(pimcService) {
            return function (notas) {
                if (!notas) return [];
                var filtrados = [];
                angular.forEach(notas, function(key,val) {
                    if (val.estado != pimcService.datosEstados.ELIMINADO) {
                        filtrados.push(val);
                    }
                });
                return filtrados;
            }
        }]);

    comentariosModule.component('pimcComentariosAnotaciones', {
        bindings:{
            notas:'=',
            reportarCambio:'&'
        },
        controller: 'comentariosComponentController',
        controllerAs: 'controladorComentarios',
        templateUrl: 'views/global/comentarios/comentariosTemplate.html'
    });

})(window.angular);<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */
/* eslint no-unused-expressions: 0 */

'use strict';
import {LitElement, html} from 'https://unpkg.com/@polymer/lit-element@0.6.2?module';

class MessagingSample extends LitElement {
  constructor() {
    super();
    this.connected = false;
  }

  disconnect() {
    this._localConnection.close();
    this._remoteConnection.close();
  }

  async connect() {
    console.log('connect!');
    try {
      const dataChannelParams = {ordered: true};
      window.localConnection = this._localConnection = new RTCPeerConnection();
      this._localConnection.addEventListener('icecandidate', async e => {
        console.log('local connection ICE candidate: ', e.candidate);
        await this._remoteConnection.addIceCandidate(e.candidate);
      });
      window.remoteConnection = this._remoteConnection = new RTCPeerConnection();
      this._remoteConnection.addEventListener('icecandidate', async e => {
        console.log('remote connection ICE candidate: ', e.candidate);
        await this._localConnection.addIceCandidate(e.candidate);
      });

      window.localChannel = this._localChannel = this._localConnection
        .createDataChannel('messaging-channel', dataChannelParams);
      this._localChannel.binaryType = 'arraybuffer';
      this._localChannel.addEventListener('open', () => {
        console.log('Local channel open!');
        this.connected = true;
      });
      this._localChannel.addEventListener('close', () => {
        console.log('Local channel closed!');
        this.connected = false;
      });
      this._localChannel.addEventListener('message', this._onLocalMessageReceived.bind(this));

      this._remoteConnection.addEventListener('datachannel', this._onRemoteDataChannel.bind(this));

      const initLocalOffer = async() => {
        const localOffer = await this._localConnection.createOffer();
        console.log(`Got local offer ${JSON.stringify(localOffer)}`);
        const localDesc = this._localConnection.setLocalDescription(localOffer);
        const remoteDesc = this._remoteConnection.setRemoteDescription(localOffer);
        return Promise.all([localDesc, remoteDesc]);
      };

      const initRemoteAnswer = async() => {
        const remoteAnswer = await this._remoteConnection.createAnswer();
        console.log(`Got remote answer ${JSON.stringify(remoteAnswer)}`);
        const localDesc = this._remoteConnection.setLocalDescription(remoteAnswer);
        const remoteDesc = this._localConnection.setRemoteDescription(remoteAnswer);
        return Promise.all([localDesc, remoteDesc]);
      };

      await initLocalOffer();
      await initRemoteAnswer();
    } catch (e) {
      console.log(e);
    }
  }

  _onLocalMessageReceived(event) {
    console.log(`Remote message received by local: ${event.data}`);
    this.localMessages += event.data + '\n';
  }

  _onRemoteDataChannel(event) {
    console.log(`onRemoteDataChannel: ${JSON.stringify(event)}`);
    window.remoteChannel = this._remoteChannel = event.channel;
    this._remoteChannel.binaryType = 'arraybuffer';
    this._remoteChannel.addEventListener('message', this._onRemoteMessageReceived.bind(this));
    this._remoteChannel.addEventListener('close', () => {
      console.log('Remote channel closed!');
      this.connected = false;
    });
  }

  _onRemoteMessageReceived(event) {
    console.log(`Local message received by remote: ${event.data}`);
    this.remoteMessages += event.data + '\n';
  }

  static get properties() {
    return {
      connected: {type: Boolean},
      localMessages: {type: String},
      remoteMessages: {type: String}
    };
  }

  render() {
    return html`

      <button ?disabled="${this.connected}" @click="${this.connect.bind(this)}">Connect</button>
      <button ?disabled="${!this.connected}" @click="${this.disconnect.bind(this)}">Disconnect</button>

      Local outgoing message:
      <textarea class="message" id="localOutgoing"
                placeholder="Local outgoing message goes here."></textarea>
      <button ?disabled="${!this.connected}" @click="${e => this._sendMessage('#localOutgoing', this._localChannel)}
      id="sendLocal">Send message from local</button>

      Local incoming messages:
      <textarea class="message" id="localIncoming" disabled
                placeholder="Local incoming messages arrive here.">${this.localMessages}</textarea>

      Remote outgoing message:
      <textarea class="message" id="remoteOutgoing"
                placeholder="Remote outgoing message goes here."></textarea>
      <button ?disabled="${!this.connected}" @click="${e => this._sendMessage('#remoteOutgoing', this._remoteChannel)}"
      id="sendRemote">Send message from remote</button>

      Remote incoming messages:
      <textarea class="message" id="remoteIncoming" disabled
                placeholder="Remote incoming messages arrive here.">${this.remoteMessages}</textarea>

`;
  }

  _sendMessage(selector, channel) {
    const textarea = this.shadowRoot.querySelector(selector)
    const value = textarea.value;
    if (value === '') {
      console.log('Not sending empty message!');
      return;
    }
    console.log('Sending remote message: ', value);
    channel.send(value);
    textarea.value = '';
  }
}

customElements.define('messaging-sample', MessagingSample);
<commit_msg>Fix lint error<commit_after>/*
 *  Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */
/* eslint no-unused-expressions: 0 */

'use strict';
import {LitElement, html} from 'https://unpkg.com/@polymer/lit-element@0.6.2?module';

class MessagingSample extends LitElement {
  constructor() {
    super();
    this.connected = false;
  }

  disconnect() {
    this._localConnection.close();
    this._remoteConnection.close();
  }

  async connect() {
    console.log('connect!');
    try {
      const dataChannelParams = {ordered: true};
      window.localConnection = this._localConnection = new RTCPeerConnection();
      this._localConnection.addEventListener('icecandidate', async e => {
        console.log('local connection ICE candidate: ', e.candidate);
        await this._remoteConnection.addIceCandidate(e.candidate);
      });
      window.remoteConnection = this._remoteConnection = new RTCPeerConnection();
      this._remoteConnection.addEventListener('icecandidate', async e => {
        console.log('remote connection ICE candidate: ', e.candidate);
        await this._localConnection.addIceCandidate(e.candidate);
      });

      window.localChannel = this._localChannel = this._localConnection
        .createDataChannel('messaging-channel', dataChannelParams);
      this._localChannel.binaryType = 'arraybuffer';
      this._localChannel.addEventListener('open', () => {
        console.log('Local channel open!');
        this.connected = true;
      });
      this._localChannel.addEventListener('close', () => {
        console.log('Local channel closed!');
        this.connected = false;
      });
      this._localChannel.addEventListener('message', this._onLocalMessageReceived.bind(this));

      this._remoteConnection.addEventListener('datachannel', this._onRemoteDataChannel.bind(this));

      const initLocalOffer = async () => {
        const localOffer = await this._localConnection.createOffer();
        console.log(`Got local offer ${JSON.stringify(localOffer)}`);
        const localDesc = this._localConnection.setLocalDescription(localOffer);
        const remoteDesc = this._remoteConnection.setRemoteDescription(localOffer);
        return Promise.all([localDesc, remoteDesc]);
      };

      const initRemoteAnswer = async () => {
        const remoteAnswer = await this._remoteConnection.createAnswer();
        console.log(`Got remote answer ${JSON.stringify(remoteAnswer)}`);
        const localDesc = this._remoteConnection.setLocalDescription(remoteAnswer);
        const remoteDesc = this._localConnection.setRemoteDescription(remoteAnswer);
        return Promise.all([localDesc, remoteDesc]);
      };

      await initLocalOffer();
      await initRemoteAnswer();
    } catch (e) {
      console.log(e);
    }
  }

  _onLocalMessageReceived(event) {
    console.log(`Remote message received by local: ${event.data}`);
    this.localMessages += event.data + '\n';
  }

  _onRemoteDataChannel(event) {
    console.log(`onRemoteDataChannel: ${JSON.stringify(event)}`);
    window.remoteChannel = this._remoteChannel = event.channel;
    this._remoteChannel.binaryType = 'arraybuffer';
    this._remoteChannel.addEventListener('message', this._onRemoteMessageReceived.bind(this));
    this._remoteChannel.addEventListener('close', () => {
      console.log('Remote channel closed!');
      this.connected = false;
    });
  }

  _onRemoteMessageReceived(event) {
    console.log(`Local message received by remote: ${event.data}`);
    this.remoteMessages += event.data + '\n';
  }

  static get properties() {
    return {
      connected: {type: Boolean},
      localMessages: {type: String},
      remoteMessages: {type: String}
    };
  }

  render() {
    return html`

      <button ?disabled="${this.connected}" @click="${this.connect.bind(this)}">Connect</button>
      <button ?disabled="${!this.connected}" @click="${this.disconnect.bind(this)}">Disconnect</button>

      Local outgoing message:
      <textarea class="message" id="localOutgoing"
                placeholder="Local outgoing message goes here."></textarea>
      <button ?disabled="${!this.connected}" @click="${e => this._sendMessage('#localOutgoing', this._localChannel)}
      id="sendLocal">Send message from local</button>

      Local incoming messages:
      <textarea class="message" id="localIncoming" disabled
                placeholder="Local incoming messages arrive here.">${this.localMessages}</textarea>

      Remote outgoing message:
      <textarea class="message" id="remoteOutgoing"
                placeholder="Remote outgoing message goes here."></textarea>
      <button ?disabled="${!this.connected}" @click="${e => this._sendMessage('#remoteOutgoing', this._remoteChannel)}"
      id="sendRemote">Send message from remote</button>

      Remote incoming messages:
      <textarea class="message" id="remoteIncoming" disabled
                placeholder="Remote incoming messages arrive here.">${this.remoteMessages}</textarea>

`;
  }

  _sendMessage(selector, channel) {
    const textarea = this.shadowRoot.querySelector(selector);
    const value = textarea.value;
    if (value === '') {
      console.log('Not sending empty message!');
      return;
    }
    console.log('Sending remote message: ', value);
    channel.send(value);
    textarea.value = '';
  }
}

customElements.define('messaging-sample', MessagingSample);
<|endoftext|>