<commit_before>'use strict';

var protocol = {
  http: require('http'),
  https: require('https')
};

var url = require('url');

function corsHeaders() {
  return [
    'Access-Control-Allow-Origin',
    'Access-Control-Request-Method',
    'Access-Control-Allow-Methods',
    'Access-Control-Allow-Headers'
  ].reduce(function (headers, method) {
    headers[method] = '*';

    return headers;
  }, {});
}

function PicoProxy(options) {
  options = options || {};

  if (!(this instanceof PicoProxy)) {
    return new PicoProxy(options);
  }

  this._target = url.parse(options.target || 'http://127.0.0.1');
  this._protocol = options.protocol || 'http';
  this._targetProtocol = this._target.protocol.slice(0, -1);
  this._cors = options.cors || true;

  this._proxy = this.createServer(function (req, res) {
    var request = protocol[this._protocol].request(this.createRequestOptions(req), function (serverRes) {
      res.writeHead(serverRes.statusCode, serverRes.headers);
      serverRes.pipe(res, { end: true });
    });

    req.pipe(request, { end: true });
  }.bind(this));

  return this;
}

PicoProxy.prototype.createRequestOptions = function (req) {
  var requestUrl = url.parse(req.url);
  var requestOptions = {
    method: req.method,
    hostname: this._target.hostname,
    path: requestUrl.path
  };

  Object.keys(req.headers)
    .forEach(function (header) {
      requestOptions[header] = header === 'host' ? requestOptions.hostname : req.headers[header];
    });

  return requestOptions;
};

PicoProxy.prototype.listen = function (port, cb) {
  port = port || 8080;
  this._proxy.listen(port, cb);

  return this;
};

PicoProxy.prototype.close = function () {
  this._proxy.close();
};

PicoProxy.prototype.createServer = function (cb) {
  return protocol[this._protocol].createServer(function (req, res) {
    if (this._cors && req.method.toLowerCase() === 'options') {
      res.writeHead(200, corsHeaders());

      return res.end();
    }

    cb(req, res);
  }.bind(this));
};

exports = module.exports = PicoProxy;
<commit_msg>enable overrides of cors headers<commit_after>'use strict';

var protocol = {
  http: require('http'),
  https: require('https')
};

var url = require('url');

function corsHeaders(overrides) {
  return [
    'Access-Control-Allow-Origin',
    'Access-Control-Request-Method',
    'Access-Control-Allow-Methods',
    'Access-Control-Allow-Headers'
  ].reduce(function (headers, method) {
    headers[method] = overrides[method] || '*';

    return headers;
  }, {});
}

function PicoProxy(options) {
  options = options || {};

  if (!(this instanceof PicoProxy)) {
    return new PicoProxy(options);
  }

  this._target = url.parse(options.target || 'http://127.0.0.1');
  this._protocol = options.protocol || 'http';
  this._targetProtocol = this._target.protocol.slice(0, -1);
  this._cors = options.cors || true;
  this._corsOverrides = {
    'Access-Control-Allow-Headers': options.allowHeaders || '*',
    'Access-Control-Allow-Methods': options.allowMethods || '*',
  };

  this._proxy = this.createServer(function (req, res) {
    var request = protocol[this._protocol].request(this.createRequestOptions(req), function (serverRes) {
      if (this._cors) {
        serverRes.headers['Access-Control-Allow-Origin'] = '*'
      }

      res.writeHead(serverRes.statusCode, serverRes.headers);
      serverRes.pipe(res, { end: true });
    }.bind(this));

    req.pipe(request, { end: true });
  }.bind(this));

  return this;
}

PicoProxy.prototype.createRequestOptions = function (req) {
  var requestUrl = url.parse(req.url);

  return {
    method: req.method,
    hostname: this._target.hostname,
    path: requestUrl.path,
    headers: Object.keys(req.headers).reduce(function (reqHeaders, header) {
      reqHeaders[header] = header === 'host' ? this._target.hostname : req.headers[header];

      return reqHeaders;
    }.bind(this), {})
  };
};

PicoProxy.prototype.listen = function (port, cb) {
  port = port || 8080;
  this._proxy.listen(port, cb);

  return this;
};

PicoProxy.prototype.close = function () {
  this._proxy.close();
};

PicoProxy.prototype.createServer = function (cb) {
  return protocol[this._protocol].createServer(function (req, res) {
    if (this._cors) {
      res.writeHead(200, corsHeaders(this._corsOverrides));
    }

    if (this._cors && req.method.toLowerCase() === 'options') {
      return res.end();
    }

    cb(req, res);
  }.bind(this));
};

exports = module.exports = PicoProxy;
<|endoftext|>


<commit_before>'use strict';

var route = require('koa-route'),
  parse = require('co-busboy'),
  fs = require('co-fs'),
  saveTo = require('save-to'),
  Random = require('random-js'),
  random = new Random(Random.engines.nativeMath),
  path = require('path'),
  os = require('os'),
  nodecr = require('../config/co-nodecr');

exports.init = function (app) {
  app.use(route.post('/api/upload-photo', uploadPhoto));
};

function * uploadPhoto(next) {
  var parts = parse(this, {
    autoFields: true
  });

  var tmpDir = path.join(os.tmpdir(), "postr");
  try {
    yield fs.mkdir(tmpDir);
  } catch (e) {
    if (e.code !== "EEXIST") {
      throw e;
    }
  }
  var count;
  var part;
  var filepath = null;
  for (count = 0; part = yield parts; ++count) {
    if (count > 1) {
      throw new Error("Only expected one file uploaded");
    }
    filepath = path.join(tmpDir, random.uuid4() + path.extname(part.filename));
    yield saveTo(part, filepath);
  }
  if (!filepath) {
    throw new Error("Expected at least one file to be uploaded");
  }

  this.body = {
    text: yield nodecr.process(filepath, 'eng', null, null, [{
      rotate: '90deg'
    }])
  };
}<commit_msg>don't pass funky data to imagemagick yet<commit_after>'use strict';

var route = require('koa-route'),
  parse = require('co-busboy'),
  fs = require('co-fs'),
  saveTo = require('save-to'),
  Random = require('random-js'),
  random = new Random(Random.engines.nativeMath),
  path = require('path'),
  os = require('os'),
  nodecr = require('../config/co-nodecr');

exports.init = function (app) {
  app.use(route.post('/api/upload-photo', uploadPhoto));
};

function * uploadPhoto(next) {
  var parts = parse(this, {
    autoFields: true
  });

  var tmpDir = path.join(os.tmpdir(), "postr");
  try {
    yield fs.mkdir(tmpDir);
  } catch (e) {
    if (e.code !== "EEXIST") {
      throw e;
    }
  }
  var count;
  var part;
  var filepath = null;
  for (count = 0; part = yield parts; ++count) {
    if (count > 1) {
      throw new Error("Only expected one file uploaded");
    }
    filepath = path.join(tmpDir, random.uuid4() + path.extname(part.filename));
    yield saveTo(part, filepath);
  }
  if (!filepath) {
    throw new Error("Expected at least one file to be uploaded");
  }

  this.body = {
    text: yield nodecr.process(filepath, 'eng', 1)
  };
}<|endoftext|>


<commit_before>var cores_partidos = {"PT": "#b70000", "PSTU":"#ce2200", "PCDOB":"#e5361f", "PCB":"#dd511f", "PSL":"#e26033", "PCO":"#e27037", "PSOL":"#e88900", "PMDB":"#f49600", "PROS":"#f2ad00", "PPL":"#efb600", "PSB":"#f4ba00", "PTB":"#f7c800", "PDT":"#ffcf06", "PPS":"#ffdb43", "SD":"#ffde55", "PSC":"#ffe966", "PTDOB":"#eded54", "PMN":"#d0e224", "PSD":"#bcd64d", "PEN":"#abc966", "PR":"#9ec666", "PV":"#97c281", "PP":"#8cbe8e", "PTC":"#71bca7", "PTN":"#4eb3c4", "PRB":"#4eaac6", "PSDC":"#5c9dc4", "PRTB":"#6195bc", "PHS":"#5e85b5", "PRP":"#5d7aba", "DEM":"#4966b7", "PSDB":"#4861bc"}

function _converte_numPartido_sigla(numero) {
    var conversao = {"21": "PCB", "54": "PPL","11": "PP","77": "SD","28": "PRTB","70": "PTDOB","33": "PMN","10": "PRB","55": "PSD","14": "PTB","51": "PEN","90": "PROS","13": "PT","45": "PSDB","15": "PMDB","50": "PSOL","31": "PHS","65": "PCDOB","20": "PSC","12": "PDT","22": "PR","40": "PSB","25": "DEM","16": "PSTU","17": "PSL","44": "PRP","29": "PCO","19": "PTN","27": "PSDC","43": "PV","36": "PTC","23": "PPS" }
    return conversao[numero];
}

//Dicionário com o ponto central escolhido para cada estado e o zoom com o qual ele deve ser apresentado
var estados = {'BR': { center: [-16.287239525774244,-55.51463843650], zoom: 4 },'AC': { center: [-10.982749041623823, -70.68940429687499], zoom: 6 },'AL': { center: [-11.084500864717155, -36.6009521484375], zoom: 7 },'AM': { center: [-8.561535597066094, -66.35791015625], zoom: 5 },'AP': { center: [1.463325357489324, -52.588427734375], zoom: 7 },'BA': { center: [-14.393038580274138, -42.146923828125], zoom: 6 },'CE': { center: [-5.50735844762961, -39.861767578125], zoom: 7 },'DF': { center: [-16.065822729893808, -47.819366455078125], zoom: 9 },'ES': { center: [-20.43051299702225, -40.5889892578125], zoom: 7 },'GO': { center: [-17.877960306212524, -49.361572265625], zoom: 6 },'MA': { center: [-6.766007882805485, -45.37353515625], zoom: 6 },'MG': { center: [-19.650219977065594, -45.42720703125], zoom: 6 },'MS': { center: [-21.396123272467616, -54.82177734374999], zoom: 6 },'MT': { center: [-13.175771224423402, -55.83251953125], zoom: 6 },'PA': { center: [-7.653079918274038, -54.88818359374999], zoom: 5 },'PB': { center: [-8.6425975109493255, -36.7767333984375], zoom: 7 },'PE': { center: [-10.352823015039577, -38.06762695312499], zoom: 6 },'PI': { center: [-8.044498849647323, -42.86865234375], zoom: 6 },'PR': { center: [-26.627044746156027, -51.65771484375], zoom: 6 },'RJ': { center: [-23.494179051660386, -43.06103515625], zoom: 7 },'RN': { center: [-7.347174076651375, -36.6778564453125 ], zoom: 7 },'RO': { center: [-12.398042159726009, -63.12744140625], zoom: 6 },'RR': { center: [0.2332268264771233, -62.34765625], zoom: 6 },'RS': { center: [-31.57786119581683, -53.618896484375], zoom: 6 },'SC': { center: [-28.364017546608678, -51.065576171875], zoom: 7 },'SE': { center: [-10.760607953624762, -37.66724853515625], zoom: 8 },'SP': { center: [-24.736945920943844,-49.30263671875], zoom: 6 },'TO': { center: [-10.48227924591501, -48.306884765625], zoom: 6 }};
<commit_msg>Atualizando posicionamento dos estados<commit_after>var cores_partidos = {"PT": "#b70000", "PSTU":"#ce2200", "PCDOB":"#e5361f", "PCB":"#dd511f", "PSL":"#e26033", "PCO":"#e27037", "PSOL":"#e88900", "PMDB":"#f49600", "PROS":"#f2ad00", "PPL":"#efb600", "PSB":"#f4ba00", "PTB":"#f7c800", "PDT":"#ffcf06", "PPS":"#ffdb43", "SD":"#ffde55", "PSC":"#ffe966", "PTDOB":"#eded54", "PMN":"#d0e224", "PSD":"#bcd64d", "PEN":"#abc966", "PR":"#9ec666", "PV":"#97c281", "PP":"#8cbe8e", "PTC":"#71bca7", "PTN":"#4eb3c4", "PRB":"#4eaac6", "PSDC":"#5c9dc4", "PRTB":"#6195bc", "PHS":"#5e85b5", "PRP":"#5d7aba", "DEM":"#4966b7", "PSDB":"#4861bc"}

function _converte_numPartido_sigla(numero) {
    var conversao = {"21": "PCB", "54": "PPL","11": "PP","77": "SD","28": "PRTB","70": "PTDOB","33": "PMN","10": "PRB","55": "PSD","14": "PTB","51": "PEN","90": "PROS","13": "PT","45": "PSDB","15": "PMDB","50": "PSOL","31": "PHS","65": "PCDOB","20": "PSC","12": "PDT","22": "PR","40": "PSB","25": "DEM","16": "PSTU","17": "PSL","44": "PRP","29": "PCO","19": "PTN","27": "PSDC","43": "PV","36": "PTC","23": "PPS" }
    return conversao[numero];
}

//Dicionário com o ponto central escolhido para cada estado e o zoom com o qual ele deve ser apresentado
var estados = {'BR': { center: [-16.287239525774244,-55.51463843650], zoom: 4 },'AC': { center: [-12.182749041623823, -70.68940429687499], zoom: 6 },'AL': { center: [-11.384500864717155, -36.6009521484375], zoom: 7 },'AM': { center: [-8.561535597066094, -66.35791015625], zoom: 5 },'AP': { center: [1.563325357489324, -52.588427734375], zoom: 7 },'BA': { center: [-13.793038580274138, -42.146923828125], zoom: 6 },'CE': { center: [-5.50735844762961, -39.861767578125], zoom: 7 },'DF': { center: [-16.065822729893808, -47.819366455078125], zoom: 9 },'ES': { center: [-20.43051299702225, -40.5889892578125], zoom: 7 },'GO': { center: [-17.577960306212524, -49.361572265625], zoom: 6 },'MA': { center: [-6.366007882805485, -45.37353515625], zoom: 6 },'MG': { center: [-19.350219977065594, -45.42720703125], zoom: 6 },'MS': { center: [-22.096123272467616, -54.82177734374999], zoom: 6 },'MT': { center: [-12.755771224423402, -55.83251953125], zoom: 6 },'PA': { center: [-7.653079918274038, -54.88818359374999], zoom: 5 },'PB': { center: [-8.6425975109493255, -36.7767333984375], zoom: 7 },'PE': { center: [-12.352823015039577, -38.06762695312499], zoom: 6 },'PI': { center: [-8.044498849647323, -42.86865234375], zoom: 6 },'PR': { center: [-27.427044746156027, -51.65771484375], zoom: 6 },'RJ': { center: [-23.194179051660386, -43.06103515625], zoom: 7 },'RN': { center: [-7.447174076651375, -36.6778564453125 ], zoom: 7 },'RO': { center: [-12.998042159726009, -63.12744140625], zoom: 6 },'RR': { center: [0.0032268264771233, -62.34765625], zoom: 6 },'RS': { center: [-31.77786119581683, -53.618896484375], zoom: 6 },'SC': { center: [-28.364017546608678, -51.065576171875], zoom: 7 },'SE': { center: [-10.860607953624762, -37.66724853515625], zoom: 8 },'SP': { center: [-24.736945920943844,-49.30263671875], zoom: 6 },'TO': { center: [-10.48227924591501, -48.306884765625], zoom: 6 }};
<|endoftext|>


<commit_before>'use strict'

const BroccoliFilter = require('broccoli-filter')

const tag = require('./tag')
const Injector = require('./injector')

class BroccoliInjectLivereload extends BroccoliFilter {

    constructor(inputNodes, options) {
        super(inputNodes, options)

        this.inputEncoding = null
        this.outputEncoding = null

        this._building = process.argv.indexOf('build') > 0

        this._livereloadPort = options.options && options.options.port || 35729
        this._injector = new Injector(options.target, tag(this._livereloadPort))
    }

    processString(contents, path) {

        if (this._building) {
            return contents
        }

        const inject = this._injector.matches(path)

        if (inject) {
            return this._injector.inject(contents)
        } else {
            return contents
        }
    }
}

module.exports = BroccoliInjectLivereload<commit_msg>chore: rename nested options object, now called livereload<commit_after>'use strict'

const BroccoliFilter = require('broccoli-filter')

const tag = require('./tag')
const Injector = require('./injector')

class BroccoliInjectLivereload extends BroccoliFilter {

    constructor(inputNodes, options) {
        super(inputNodes, options)

        this.inputEncoding = null
        this.outputEncoding = null

        this._building = process.argv.indexOf('build') > 0

        this._livereloadPort = options.livereload && options.livereload.port || 35729
        this._injector = new Injector(options.target, tag(this._livereloadPort))
    }

    processString(contents, path) {

        if (this._building) {
            return contents
        }

        const inject = this._injector.matches(path)

        if (inject) {
            return this._injector.inject(contents)
        } else {
            return contents
        }
    }
}

module.exports = BroccoliInjectLivereload<|endoftext|>


<commit_before>const config = require('config');
const request = require('request');
const music = require('./../music');
const YT = require('youtube-node');

const searchYTClient = new YT();
searchYTClient.setKey(config.get('api').youtube);

module.exports = [{
	aliases: [
		'twitch',
		'ttv'
	],
	name: 'twitch',
	uses: 1,
	admin: 0,
	command: (message) => {
		if (!message.mss.input) {
			message.channel.createMessage(message.__('twitch_none'));
		} else {
			const username = encodeURI(message.mss.input.substring(message.mss.input.lastIndexOf('/') + 1));

			if (!username) {
				message.channel.createMessage(message.__('twitch_invalid'));
			} else {
				const query = {
					method: 'GET',
					json: true,
					uri: `https://api.twitch.tv/kraken/streams/${username}`,
					headers: {
						'User-Agent': config.get('useragent'),
						'Client-ID': config.get('api').twitch
					}
				};

				request(query, (err, res, body) => {
					if (body.error) {
						message.channel.createMessage(message.__('err_generic'));
					} else if (!body.stream) {
						message.channel.createMessage(message.__('twitch_notlive'));
					} else {
						music.add(message, {
							type: 'youtube-dl',
							from: 'Twitch',
							media: `https://twitch.tv/${username}`,
							title: body.stream.channel.display_name,
							thumb: body.stream.preview.large,
							desc: body.stream.channel.status
						});
					}
				});
			}
		}
	}
}, {
	aliases: [
		'youtube',
		'yt'
	],
	name: 'youtube',
	uses: 1,
	admin: 0,
	command: (message) => {
		if (!message.mss.input) {
			message.channel.createMessage(message.__('youtube_none'));
		} else {
			searchYTClient.search(message.mss.input, 10, (error, result) => {
				const video = result.items.find(youtube => youtube.id.videoId);

				if (error) {
					console.log(error);
					message.channel.createMessage(error);
				} else if (!result || !result.items || !video) {
					message.channel.createMessage(message.__('youtube_404'));
				} else {
					music.add(message, {
						type: 'youtube-dl',
						from: 'YouTube',
						media: video.id.videoId,
						title: video.snippet.title,
						thumb: video.snippet.thumbnails.default.url,
						desc: video.snippet.description
					});
				}
			});
		}
	}
}, {
	aliases: [
		'tts',
		'dictate',
		'dectalk'
	],
	name: 'tts',
	uses: 1,
	admin: 0,
	command: (message) => {
		if (message.mss.input) {
			const data = {
				url: 'https://talk.moustacheminer.com/api/gen',
				method: 'POST',
				json: true,
				headers: {
					'User-Agent': config.get('useragent')
				},
				body: {
					dectalk: message.mss.input
				}
			};

			music.add(message, {
				type: 'post',
				from: 'DECtalk',
				media: data,
				title: 'DECtalk Text To Speech',
				thumb: 'https://upload.wikimedia.org/wikipedia/commons/2/2b/DECtalk_DCT01_and_Tink.jpg',
				desc: message.input
			});
		}
	}
}, {
	aliases: [
		'skip'
	],
	name: 'skip',
	uses: 1,
	admin: 1,
	command: (message) => {
		music.skip(message);
	}
}, {
	aliases: [
		'stop'
	],
	name: 'stop',
	uses: 1,
	admin: 1,
	command: (message) => {
		music.stop(message);
	}
}, {
	aliases: [
		'repeat'
	],
	name: 'repeat',
	uses: 1,
	admin: 1,
	command: (message) => {
		music.repeat(message);
	}
}, {
	aliases: [
		'list'
	],
	name: 'list',
	uses: 1,
	admin: 0,
	command: (message) => {
		music.list(message, (playlist, repeat) => {
			if (playlist.length === 0) {
				message.channel.createMessage(message.__('list_empty'));
			} else {
				let reply = '```\n';
				reply += repeat ? message.__('list_repeat_on') : message.__('list_repeat_off');
				reply += '\n';
				playlist.forEach((element, index) => {
					reply += `[${index || message.__('list_current')}] ${element.title}\n`;
				});
				reply += '```';

				if (reply && reply.length > 1900) {
					message.channel.createMessage(message.__('list_length'));
				} else {
					message.channel.createMessage(reply);
				}
			}
		});
	}
}];
<commit_msg>message.input not message.mss.input<commit_after>const config = require('config');
const request = require('request');
const music = require('./../music');
const YT = require('youtube-node');

const searchYTClient = new YT();
searchYTClient.setKey(config.get('api').youtube);

module.exports = [{
	aliases: [
		'twitch',
		'ttv'
	],
	name: 'twitch',
	uses: 1,
	admin: 0,
	command: (message) => {
		if (!message.mss.input) {
			message.channel.createMessage(message.__('twitch_none'));
		} else {
			const username = encodeURI(message.mss.input.substring(message.mss.input.lastIndexOf('/') + 1));

			if (!username) {
				message.channel.createMessage(message.__('twitch_invalid'));
			} else {
				const query = {
					method: 'GET',
					json: true,
					uri: `https://api.twitch.tv/kraken/streams/${username}`,
					headers: {
						'User-Agent': config.get('useragent'),
						'Client-ID': config.get('api').twitch
					}
				};

				request(query, (err, res, body) => {
					if (body.error) {
						message.channel.createMessage(message.__('err_generic'));
					} else if (!body.stream) {
						message.channel.createMessage(message.__('twitch_notlive'));
					} else {
						music.add(message, {
							type: 'youtube-dl',
							from: 'Twitch',
							media: `https://twitch.tv/${username}`,
							title: body.stream.channel.display_name,
							thumb: body.stream.preview.large,
							desc: body.stream.channel.status
						});
					}
				});
			}
		}
	}
}, {
	aliases: [
		'youtube',
		'yt'
	],
	name: 'youtube',
	uses: 1,
	admin: 0,
	command: (message) => {
		if (!message.mss.input) {
			message.channel.createMessage(message.__('youtube_none'));
		} else {
			searchYTClient.search(message.mss.input, 10, (error, result) => {
				const video = result.items.find(youtube => youtube.id.videoId);

				if (error) {
					console.log(error);
					message.channel.createMessage(error);
				} else if (!result || !result.items || !video) {
					message.channel.createMessage(message.__('youtube_404'));
				} else {
					music.add(message, {
						type: 'youtube-dl',
						from: 'YouTube',
						media: video.id.videoId,
						title: video.snippet.title,
						thumb: video.snippet.thumbnails.default.url,
						desc: video.snippet.description
					});
				}
			});
		}
	}
}, {
	aliases: [
		'tts',
		'dictate',
		'dectalk'
	],
	name: 'tts',
	uses: 1,
	admin: 0,
	command: (message) => {
		if (message.mss.input) {
			const data = {
				url: 'https://talk.moustacheminer.com/api/gen',
				method: 'POST',
				json: true,
				headers: {
					'User-Agent': config.get('useragent')
				},
				body: {
					dectalk: message.mss.input
				}
			};

			music.add(message, {
				type: 'post',
				from: 'DECtalk',
				media: data,
				title: 'DECtalk Text To Speech',
				thumb: 'https://upload.wikimedia.org/wikipedia/commons/2/2b/DECtalk_DCT01_and_Tink.jpg',
				desc: message.mss.input
			});
		}
	}
}, {
	aliases: [
		'skip'
	],
	name: 'skip',
	uses: 1,
	admin: 1,
	command: (message) => {
		music.skip(message);
	}
}, {
	aliases: [
		'stop'
	],
	name: 'stop',
	uses: 1,
	admin: 1,
	command: (message) => {
		music.stop(message);
	}
}, {
	aliases: [
		'repeat'
	],
	name: 'repeat',
	uses: 1,
	admin: 1,
	command: (message) => {
		music.repeat(message);
	}
}, {
	aliases: [
		'list'
	],
	name: 'list',
	uses: 1,
	admin: 0,
	command: (message) => {
		music.list(message, (playlist, repeat) => {
			if (playlist.length === 0) {
				message.channel.createMessage(message.__('list_empty'));
			} else {
				let reply = '```\n';
				reply += repeat ? message.__('list_repeat_on') : message.__('list_repeat_off');
				reply += '\n';
				playlist.forEach((element, index) => {
					reply += `[${index || message.__('list_current')}] ${element.title}\n`;
				});
				reply += '```';

				if (reply && reply.length > 1900) {
					message.channel.createMessage(message.__('list_length'));
				} else {
					message.channel.createMessage(reply);
				}
			}
		});
	}
}];
<|endoftext|>


<commit_before>define(['Page', 'Routes', 'Router', 'jQuery', 'Sugar'], function (Page, Routes, Router) {

    function initPage(pageName, callback) {
        var lowerCasePageName = pageName.toLowerCase();
        require([lowerCasePageName.camelize()], function (page) {
            Page.init(lowerCasePageName, page, callback);
        });
    }

    var routes = {};
    Object.each(Routes, function (key, value) {
        var values = value.split(' ');
        var pageName = values[0];
        var controller = values[1];
        routes[key] = function () {
            Page.loading(true);
            var args = Array.prototype.slice.call(arguments, 0);
            var callback = controller ? function (page) {
                page.controllers[controller].apply(null, args);
            } : null;
            //controller is always called before page template is rendered (when the page is swapped to), rest assured :)
            initPage(pageName, callback);
        };
    });

    var router = new Router(routes).configure({
        strict: false,
        html5history: true,
        convert_hash_in_init: false,
        notfound: function () {
            routes['/error/404']();
        }
    });

    var urlNotAtRoot = window.location.pathname && (window.location.pathname != '/');

    if (!router.historySupport && urlNotAtRoot) {
        window.location.href = '/#' + (window.location.pathname.startsWith('/') ? '' : '/') + window.location.pathname;
        return;
    }

    if (urlNotAtRoot) {
        router.init();
    } else {
        router.init('/');
    }

    $('body').on('click', 'a[href]', function (event) {
        var href = $(this).attr('href').compact();
        if (href && !href.startsWith('http') && !href.startsWith('//') && !href.startsWith('#') &&
            ($(this).attr('target') != '_blank') && !$(this).data('go') && !event.ctrlKey && !event.metaKey) {
            event.preventDefault();
            var hash = null;
            if (href.has('#')) {
                hash = href.from(href.indexOf('#'));
                href = href.remove(hash);
            }
            router.setRoute(href);
            if (hash && router.historySupport) {
                (function () {
                    window.location.hash = hash.remove('#');
                }).delay(100);
            }
        }
    });

    return router;

});
<commit_msg>As soon as an internal SPA link is clicked set loading to true.<commit_after>define(['Page', 'Routes', 'Router', 'jQuery', 'Sugar'], function (Page, Routes, Router) {

    function initPage(pageName, callback) {
        var lowerCasePageName = pageName.toLowerCase();
        require([lowerCasePageName.camelize()], function (page) {
            Page.init(lowerCasePageName, page, callback);
        });
    }

    var routes = {};
    Object.each(Routes, function (key, value) {
        var values = value.split(' ');
        var pageName = values[0];
        var controller = values[1];
        routes[key] = function () {
            Page.loading(true);
            var args = Array.prototype.slice.call(arguments, 0);
            var callback = controller ? function (page) {
                page.controllers[controller].apply(null, args);
            } : null;
            //controller is always called before page template is rendered (when the page is swapped to), rest assured :)
            initPage(pageName, callback);
        };
    });

    var router = new Router(routes).configure({
        strict: false,
        html5history: true,
        convert_hash_in_init: false,
        notfound: function () {
            routes['/error/404']();
        }
    });

    var urlNotAtRoot = window.location.pathname && (window.location.pathname != '/');

    if (!router.historySupport && urlNotAtRoot) {
        window.location.href = '/#' + (window.location.pathname.startsWith('/') ? '' : '/') + window.location.pathname;
        return;
    }

    if (urlNotAtRoot) {
        router.init();
    } else {
        router.init('/');
    }

    $('body').on('click', 'a[href]', function (event) {
        var href = $(this).attr('href').compact();
        if (href && !href.startsWith('http') && !href.startsWith('//') && !href.startsWith('#') &&
            ($(this).attr('target') != '_blank') && !$(this).data('go') && !event.ctrlKey && !event.metaKey) {
            event.preventDefault();
            Page.loading(true);
            var hash = null;
            if (href.has('#')) {
                hash = href.from(href.indexOf('#'));
                href = href.remove(hash);
            }
            router.setRoute(href);
            if (hash && router.historySupport) {
                (function () {
                    window.location.hash = hash.remove('#');
                }).delay(100);
            }
        }
    });

    return router;

});
<|endoftext|>


<commit_before>import Promise from 'bluebird';
import values from 'lodash/values';
import each from 'lodash/each';
import map from 'lodash/map';
import isUndefined from 'lodash/isUndefined';
import moment from 'moment';
import fs from 'fs-extra';
Promise.promisifyAll(fs);
import rimraf from 'rimraf';
import glob from 'glob';
import log from './log';
import * as CONSTANTS from './constants';
import Config, {
  EVENTS,
} from './config';
import Url from './url';
import Render from './render';
import Plugin from './plugin/index';
import Theme from './theme';
import {
  createCollection,
} from './collection';
import File from './file';

export default class Yarn {
  constructor(rootPath) {
    /**
     * Expose config object on instance.
     * @type {Config}
     */
    this.config = new Config();

    if (isUndefined(rootPath)) {
      rootPath = this.config.findLocalDir();
    }

    // Update root path.
    this.config.setRoot(rootPath);

    /**
     * All files found in our source path.
     * Key is the full path to the file, value is the actual File object.
     * @type {Object.<string, File>}
     */
    this.files = Object.create(null);

    /**
     * Mapping of Collection IDs to the instance.
     * @type {Object.<string, Collection>}
     */
    this.collections = Object.create(null);

    /**
     * Class responsible for handling themes.
     * @type {Theme}
     */
    this.theme = new Theme();
    this.theme.setGetConfig(this.getConfig);

    /**
     * Site wide data available in all templates.
     * @type {Object.<string, Object>}
     */
    this.data = Object.create(null);

    /**
     * Expose collections.
     * @type {Object}
     */
    this.data.collections = Object.create(null);

    // Subscribe to when config is updated.
    this.config.on(EVENTS.CONFIG_UPDATED, this.configUpdated.bind(this));

    // Kick off leading config update.
    this.configUpdated();
  }

  /**
   * Returns our config instance.
   * @return {Object}
   */
  getConfig = () => {
    return this.config;
  };

  configUpdated() {
    Url.setSlugOptions(this.config.slug);

    this.theme.update();

    // Configure template engine.
    Render.configureTemplate({
      paths: [
        this.theme.config.path.templates
      ]
    });

    // Configure markdown engine.
    Render.configureMarkdown(this.config.remarkable);

    /**
     * Expose site data from config file.
     * @type {Object}
     */
    this.data.site = this.config.site;

    // Update our collection configs.
    map(this.config.collections, (collectionConfig, collectionName) => {
      let instance = createCollection(
        collectionName,
        collectionConfig,
        this.getConfig
      );

      this.collections[instance.id] = instance;
    });
  }

  static getYarnData() {
    const packageJson = Url.pathFromRoot('./package.json');

    return {
      version: packageJson.version,
      time: moment((new Date()).getTime()).format()
    };
  }

  loadPlugins() {
    const id = log.startActivity('Loading plugins...');

    // Built-in plugins.
    Plugin.loadFromPackageJson(Url.pathFromRoot('./'), this.config.plugins);
    [
      this.theme.config.path.plugins, // Active theme plug-ins
      this.config.path.plugins // Site plug-ins
    ].forEach(path => Plugin.loadFromDirectory(path));

    log.endActivity(id);
  }

  async readFiles() {
    const id = log.startActivity('Reading files...');

    let ignorePatterns = values(CONSTANTS.YAML).concat(
      values(this.config.path).filter(path => path !== this.config.path.source)
    );

    each(this.collections, collection => {
      if (collection.static) {
        ignorePatterns.push(collection.path);
      }
    });

    let files = await Promise.fromCallback(cb => {
      glob(this.config.path.source + '/**/*', {
        nodir: true,
        ignore: ignorePatterns.map(path => `**/${path}/**`).concat(
          `${this.config.path.source}/node_modules/**`
        ),
        // Follow symlinks.
        follow: true
      }, cb);
    });

    files.map(filePath => {
      let sourceFile = new File(filePath, this.getConfig);
      this.files[sourceFile.id] = sourceFile;
    });

    // Populate every collection with its files.
    each(this.collections, collection => {
      collection.populate(this.files, this.collections);

      // Add collection data to our global data object.
      this.data.collections[collection.name] = collection.data;
    });

    log.endActivity(id);

    return Promise.resolve();
  }

  /**
   * Read theme files, processing any files that it needs to so that we get
   * the final path to the ready to write files.
   * @return {Proise} Promise object.
   */
  async readTheme() {
    let promise;

    // Reading theme files.
    const id = log.startActivity('Reading files...');
    try {
      promise = await this.theme.read();
    } catch (e) {
      log.error(e);
    }
    log.endActivity(id);

    // Expose theme data globally.
    this.data.theme = this.theme.data;

    return promise;
  }

  async loadState() {
    await this.readTheme();

    this.loadPlugins();

    await this.readFiles();
  }

  /**
   * Given a File we will write its contents and all related CollectionPages
   * that it exists to the destination directory.
   * @param {File} file File object.
   * @return {Promise} Promise containing all file system write promises.
   */
  async writeFile(file) {
    let promises = [];

    // For every collectionId the File belongs to rewrite that File within
    // the collection along with every CollectionPage.
    file.collectionIds.forEach(collectionId => {
      let collection = this.collections[collectionId];
      promises.push(collection.writeFile(file, this.data));

      collection.pages.forEach(page => {
        if (file.pageIds.has(page.id)) {
          promises.push(collection.writePage(page, this.data));
        }
      });
    });

    let promise;
    try {
      promise = await Promise.all(promises);
    } catch (e) {
      log.warn(e);
    }

    return promise;
  }

  /**
   * Notify instance that a file changed so we can then update and re-write
   * the compiled file and associated collection page files.
   * @param {string} filePath File path.
   * @return {Promise} Promise object.
   */
  async fileChanged(filePath) {
    let file = this.files[filePath];

    if (isUndefined(file)) {
      return;
    }

    // Update our in memory File state with data from the file system.
    file.updateDataFromFileSystem();

    return this.writeFile(file);
  }

  /**
   * Notify instance that a file was added to the project so we can update and
   * re-write the compiled file and associated collection page files.
   * @param {string} filePath File path.
   * @return {Promise} Promise object resolving with created File object if one
   *   is created, or false if none is created.
   */
  async fileAdded(filePath) {
    let file = this.files[filePath];

    // Return early if File already exists.
    if (!isUndefined(file)) {
      return false;
    }

    file = new File(filePath, this.getConfig);
    this.files[file.id] = file;

    let shouldWriteFile = false;

    // Populate every collection with its files.
    each(this.collections, collection => {
      let fileAdded;
      // @TODO: support adding files to static collections.
      if (collection.addFile) {
        fileAdded = collection.addFile(file);
      }

      if (fileAdded) {
        shouldWriteFile = true;
        collection.createCollectionPages();
      }
    });

    // Write changes to file system.
    if (shouldWriteFile) {
      await this.writeFile(file);
    }

    return file;
  }

  /**
   * Notify instance that a file was removed from the project so we can update
   * and re-write the destination folder without the file and its associated
   * pages.
   * @param {string} filePath File path.
   * @return {Promise} Promise object resolving with true if the File was
   *   removed, false if it wasn't.
   */
  async fileRemoved(filePath) {
    let file = this.files[filePath];

    // Return early if File does not exist.
    if (isUndefined(file)) {
      return false;
    }

    // Remove File.
    delete this.files[file.id];

    let promises = [];

    // Delete file.
    promises.push(fs.removeAsync(file.destination));

    // For every collectionId the File belongs to rewrite that File within
    // the collection along with every CollectionPage.
    file.collectionIds.forEach(collectionId => {
      let collection = this.collections[collectionId];

      // @TODO: support removing static files.
      if (collection.removeFile) {
        collection.removeFile(file);
      }

      // Update collection pages.
      collection.createCollectionPages();

      // Write all CollectionPages to disk.
      collection.pages.forEach(collectionPage => {
        promises.push(collection.writePage(collectionPage, this.data));
      });
    });

    try {
      await Promise.all(promises);
    } catch (e) {
      log.warn(e);
    }

    return true;
  }

  /**
   * Removes configured destination directory and all files contained.
   * @return {Promise} Promise object.
   */
  async cleanDestination() {
    let promise;

    const id = log.startActivity(
      `Cleaning destination ${this.config.path.destination}`
    );
    try {
      promise = await Promise.fromCallback(cb => {
        rimraf(this.config.path.destination, cb);
      });
    } catch (e) {
      log.error(e);
    }

    log.endActivity(id);

    return promise;
  }

  /**
   * Writes Theme files and assets to file system.
   * @return {Promise} Promise object.
   */
  async writeThemeFiles() {
    let promise;

    // Write theme static files.
    const id = log.startActivity('Writing theme files...');
    try {
      promise = await this.theme.write();
    } catch (e) {
      log.error(e);
    }
    log.endActivity(id);

    return promise;
  }

  /**
   * Builds the yarn site in its entirety.
   * @return {Promise} Promise of when we're done building.
   */
  async build() {
    let promise;

    if (this.config.clean_destination) {
      promise = await this.cleanDestination();
    }

    this.data.yarn = Yarn.getYarnData();

    await this.writeThemeFiles();

    const id = log.startActivity('Writing files...');
    try {
      promise = await Promise.all(map(this.collections, collection => {
        return collection.write(this.data);
      }));
    } catch (e) {
      log.error(e);
    }
    log.endActivity(id);

    return promise;
  }
}
<commit_msg>forgot to copy write log statement<commit_after>import Promise from 'bluebird';
import values from 'lodash/values';
import each from 'lodash/each';
import map from 'lodash/map';
import isUndefined from 'lodash/isUndefined';
import moment from 'moment';
import fs from 'fs-extra';
Promise.promisifyAll(fs);
import rimraf from 'rimraf';
import glob from 'glob';
import log from './log';
import * as CONSTANTS from './constants';
import Config, {
  EVENTS,
} from './config';
import Url from './url';
import Render from './render';
import Plugin from './plugin/index';
import Theme from './theme';
import {
  createCollection,
} from './collection';
import File from './file';

export default class Yarn {
  constructor(rootPath) {
    /**
     * Expose config object on instance.
     * @type {Config}
     */
    this.config = new Config();

    if (isUndefined(rootPath)) {
      rootPath = this.config.findLocalDir();
    }

    // Update root path.
    this.config.setRoot(rootPath);

    /**
     * All files found in our source path.
     * Key is the full path to the file, value is the actual File object.
     * @type {Object.<string, File>}
     */
    this.files = Object.create(null);

    /**
     * Mapping of Collection IDs to the instance.
     * @type {Object.<string, Collection>}
     */
    this.collections = Object.create(null);

    /**
     * Class responsible for handling themes.
     * @type {Theme}
     */
    this.theme = new Theme();
    this.theme.setGetConfig(this.getConfig);

    /**
     * Site wide data available in all templates.
     * @type {Object.<string, Object>}
     */
    this.data = Object.create(null);

    /**
     * Expose collections.
     * @type {Object}
     */
    this.data.collections = Object.create(null);

    // Subscribe to when config is updated.
    this.config.on(EVENTS.CONFIG_UPDATED, this.configUpdated.bind(this));

    // Kick off leading config update.
    this.configUpdated();
  }

  /**
   * Returns our config instance.
   * @return {Object}
   */
  getConfig = () => {
    return this.config;
  };

  configUpdated() {
    Url.setSlugOptions(this.config.slug);

    this.theme.update();

    // Configure template engine.
    Render.configureTemplate({
      paths: [
        this.theme.config.path.templates
      ]
    });

    // Configure markdown engine.
    Render.configureMarkdown(this.config.remarkable);

    /**
     * Expose site data from config file.
     * @type {Object}
     */
    this.data.site = this.config.site;

    // Update our collection configs.
    map(this.config.collections, (collectionConfig, collectionName) => {
      let instance = createCollection(
        collectionName,
        collectionConfig,
        this.getConfig
      );

      this.collections[instance.id] = instance;
    });
  }

  static getYarnData() {
    const packageJson = Url.pathFromRoot('./package.json');

    return {
      version: packageJson.version,
      time: moment((new Date()).getTime()).format()
    };
  }

  loadPlugins() {
    const id = log.startActivity('Loading plugins...');

    // Built-in plugins.
    Plugin.loadFromPackageJson(Url.pathFromRoot('./'), this.config.plugins);
    [
      this.theme.config.path.plugins, // Active theme plug-ins
      this.config.path.plugins // Site plug-ins
    ].forEach(path => Plugin.loadFromDirectory(path));

    log.endActivity(id);
  }

  async readFiles() {
    const id = log.startActivity('Reading files...');

    let ignorePatterns = values(CONSTANTS.YAML).concat(
      values(this.config.path).filter(path => path !== this.config.path.source)
    );

    each(this.collections, collection => {
      if (collection.static) {
        ignorePatterns.push(collection.path);
      }
    });

    let files = await Promise.fromCallback(cb => {
      glob(this.config.path.source + '/**/*', {
        nodir: true,
        ignore: ignorePatterns.map(path => `**/${path}/**`).concat(
          `${this.config.path.source}/node_modules/**`
        ),
        // Follow symlinks.
        follow: true
      }, cb);
    });

    files.map(filePath => {
      let sourceFile = new File(filePath, this.getConfig);
      this.files[sourceFile.id] = sourceFile;
    });

    // Populate every collection with its files.
    each(this.collections, collection => {
      collection.populate(this.files, this.collections);

      // Add collection data to our global data object.
      this.data.collections[collection.name] = collection.data;
    });

    log.endActivity(id);

    return Promise.resolve();
  }

  /**
   * Read theme files, processing any files that it needs to so that we get
   * the final path to the ready to write files.
   * @return {Proise} Promise object.
   */
  async readTheme() {
    let promise;

    // Reading theme files.
    const id = log.startActivity('Reading theme files...');
    try {
      promise = await this.theme.read();
    } catch (e) {
      log.error(e);
    }
    log.endActivity(id);

    // Expose theme data globally.
    this.data.theme = this.theme.data;

    return promise;
  }

  async loadState() {
    await this.readTheme();

    this.loadPlugins();

    await this.readFiles();
  }

  /**
   * Given a File we will write its contents and all related CollectionPages
   * that it exists to the destination directory.
   * @param {File} file File object.
   * @return {Promise} Promise containing all file system write promises.
   */
  async writeFile(file) {
    let promises = [];

    // For every collectionId the File belongs to rewrite that File within
    // the collection along with every CollectionPage.
    file.collectionIds.forEach(collectionId => {
      let collection = this.collections[collectionId];
      promises.push(collection.writeFile(file, this.data));

      collection.pages.forEach(page => {
        if (file.pageIds.has(page.id)) {
          promises.push(collection.writePage(page, this.data));
        }
      });
    });

    let promise;
    try {
      promise = await Promise.all(promises);
    } catch (e) {
      log.warn(e);
    }

    return promise;
  }

  /**
   * Notify instance that a file changed so we can then update and re-write
   * the compiled file and associated collection page files.
   * @param {string} filePath File path.
   * @return {Promise} Promise object.
   */
  async fileChanged(filePath) {
    let file = this.files[filePath];

    if (isUndefined(file)) {
      return;
    }

    // Update our in memory File state with data from the file system.
    file.updateDataFromFileSystem();

    return this.writeFile(file);
  }

  /**
   * Notify instance that a file was added to the project so we can update and
   * re-write the compiled file and associated collection page files.
   * @param {string} filePath File path.
   * @return {Promise} Promise object resolving with created File object if one
   *   is created, or false if none is created.
   */
  async fileAdded(filePath) {
    let file = this.files[filePath];

    // Return early if File already exists.
    if (!isUndefined(file)) {
      return false;
    }

    file = new File(filePath, this.getConfig);
    this.files[file.id] = file;

    let shouldWriteFile = false;

    // Populate every collection with its files.
    each(this.collections, collection => {
      let fileAdded;
      // @TODO: support adding files to static collections.
      if (collection.addFile) {
        fileAdded = collection.addFile(file);
      }

      if (fileAdded) {
        shouldWriteFile = true;
        collection.createCollectionPages();
      }
    });

    // Write changes to file system.
    if (shouldWriteFile) {
      await this.writeFile(file);
    }

    return file;
  }

  /**
   * Notify instance that a file was removed from the project so we can update
   * and re-write the destination folder without the file and its associated
   * pages.
   * @param {string} filePath File path.
   * @return {Promise} Promise object resolving with true if the File was
   *   removed, false if it wasn't.
   */
  async fileRemoved(filePath) {
    let file = this.files[filePath];

    // Return early if File does not exist.
    if (isUndefined(file)) {
      return false;
    }

    // Remove File.
    delete this.files[file.id];

    let promises = [];

    // Delete file.
    promises.push(fs.removeAsync(file.destination));

    // For every collectionId the File belongs to rewrite that File within
    // the collection along with every CollectionPage.
    file.collectionIds.forEach(collectionId => {
      let collection = this.collections[collectionId];

      // @TODO: support removing static files.
      if (collection.removeFile) {
        collection.removeFile(file);
      }

      // Update collection pages.
      collection.createCollectionPages();

      // Write all CollectionPages to disk.
      collection.pages.forEach(collectionPage => {
        promises.push(collection.writePage(collectionPage, this.data));
      });
    });

    try {
      await Promise.all(promises);
    } catch (e) {
      log.warn(e);
    }

    return true;
  }

  /**
   * Removes configured destination directory and all files contained.
   * @return {Promise} Promise object.
   */
  async cleanDestination() {
    let promise;

    const id = log.startActivity(
      `Cleaning destination ${this.config.path.destination}`
    );
    try {
      promise = await Promise.fromCallback(cb => {
        rimraf(this.config.path.destination, cb);
      });
    } catch (e) {
      log.error(e);
    }

    log.endActivity(id);

    return promise;
  }

  /**
   * Writes Theme files and assets to file system.
   * @return {Promise} Promise object.
   */
  async writeThemeFiles() {
    let promise;

    // Write theme static files.
    const id = log.startActivity('Writing theme files...');
    try {
      promise = await this.theme.write();
    } catch (e) {
      log.error(e);
    }
    log.endActivity(id);

    return promise;
  }

  /**
   * Builds the yarn site in its entirety.
   * @return {Promise} Promise of when we're done building.
   */
  async build() {
    let promise;

    if (this.config.clean_destination) {
      promise = await this.cleanDestination();
    }

    this.data.yarn = Yarn.getYarnData();

    await this.writeThemeFiles();

    const id = log.startActivity('Writing files...');
    try {
      promise = await Promise.all(map(this.collections, collection => {
        return collection.write(this.data);
      }));
    } catch (e) {
      log.error(e);
    }
    log.endActivity(id);

    return promise;
  }
}
<|endoftext|>


<commit_before>'use strict';

var etcd = require('../etcd');
var _ = require('underscore');
var config = require('./../../config/config.json');
var acl = require('./../acl');
var audit = require('./../audit');
var etcdBaseUrl = 'http://' + config.etcdHost + ':' + config.etcdPort + '/v2/keys/';

var getUserDetails = function (req) {
    return config.RequiresAuth ? req.user._json : {name: 'Anonymous'};
};

module.exports = {
    getApplications: function (cb) {
        etcd.client.get('v1/toggles/', {recursive: false}, function (err, result) {
            if (err) {
                if (err.errorCode === 100) { // key not found
                    return cb(null, []);
                }

                return cb(err);
            }

            var applications = _.map(result.node.nodes || [], function (node) {
                var splitKey = node.key.split('/');
                return splitKey[splitKey.length - 1];
            });
            cb(null, applications);
        });
    },

    addApplication: function (applicationName, req, cb) {
        var path = 'v1/toggles/' + applicationName;
        etcd.client.mkdir(path, function (err) {
            if (err) {
                return cb(err);
            }

            audit.addApplicationAudit(getUserDetails(req), applicationName, 'Created', function () {
                if (err) {
                    console.log(err); // todo: better logging
                }
            });

            // todo: not sure if this is correct
            if (config.RequiresAuth) {
                var userEmail = getUserDetails(req).getEmail(); // todo: need better user management
                acl.grant(userEmail, applicationName, function (grantErr) {
                    if (grantErr) {
                        cb(grantErr);
                        return;
                    }
                    cb();
                });
            } else {
                cb();
            }
        });
    },

    deleteApplication: function (applicationName, req, cb) {
        var path = 'v1/toggles/' + applicationName;
        etcd.client.delete(path, {recursive: true}, function (err) {
            if (err) {
                return cb(err);
            }

            audit.addApplicationAudit(getUserDetails(req), applicationName, 'Deleted', function () {
                if (err) {
                    console.log(err);
                }
            });

            if (config.RequiresAuth) {
                acl.revokeAll(applicationName, function (revokeErr) {
                    if (revokeErr) {
                        return cb(revokeErr);
                    }
                    cb();
                });
            } else {
                cb();
            }
        });
    },

    getApplicationMetaData: function (applicationName, cb) {
        etcd.client.get('v1/metadata/' + applicationName, {recursive: true}, function (err, result) {
            if (err) {
                if (err.errorCode === 100) { // key not found
                    cb(null, {});
                } else {
                    cb(err);
                }
                return;
            }
            var metaDataKeyValues = _.map(result.node.nodes, function (subNode) {
                var metaDataKey = _.last(subNode.key.split('/'));
                return [metaDataKey, subNode.value];
            });
            cb(null, _.object(metaDataKeyValues));
        });
    },

    deleteApplicationMetaData: function (applicationName, cb) {
        etcd.client.delete('v1/metadata/' + applicationName, {recursive: true}, function (err, result) {
            if (err) {
                if (err.errorCode === 100) { // key not found
                    cb();
                } else {
                    cb(err);
                }
                return;
            }
            cb();
        });
    },

    saveApplicationMetaData: function (applicationName, metaDataKey, metaDataValue, cb) {
        var path = 'v1/metadata/' + applicationName + '/' + metaDataKey;
        etcd.client.set(path, metaDataValue, function (err) {
            return cb(err);
        });
    }
};
<commit_msg>lowercase the email before inserting the acl entry<commit_after>'use strict';

var etcd = require('../etcd');
var _ = require('underscore');
var config = require('./../../config/config.json');
var acl = require('./../acl');
var audit = require('./../audit');
var etcdBaseUrl = 'http://' + config.etcdHost + ':' + config.etcdPort + '/v2/keys/';

var getUserDetails = function (req) {
    return config.RequiresAuth ? req.user._json : {name: 'Anonymous'};
};

module.exports = {
    getApplications: function (cb) {
        etcd.client.get('v1/toggles/', {recursive: false}, function (err, result) {
            if (err) {
                if (err.errorCode === 100) { // key not found
                    return cb(null, []);
                }

                return cb(err);
            }

            var applications = _.map(result.node.nodes || [], function (node) {
                var splitKey = node.key.split('/');
                return splitKey[splitKey.length - 1];
            });
            cb(null, applications);
        });
    },

    addApplication: function (applicationName, req, cb) {
        var path = 'v1/toggles/' + applicationName;
        etcd.client.mkdir(path, function (err) {
            if (err) {
                return cb(err);
            }

            audit.addApplicationAudit(getUserDetails(req), applicationName, 'Created', function () {
                if (err) {
                    console.log(err); // todo: better logging
                }
            });

            // todo: not sure if this is correct
            if (config.RequiresAuth) {
                var userEmail = getUserDetails(req).email.toLowerCase(); // todo: need better user management
                acl.grant(userEmail, applicationName, function (grantErr) {
                    if (grantErr) {
                        cb(grantErr);
                        return;
                    }
                    cb();
                });
            } else {
                cb();
            }
        });
    },

    deleteApplication: function (applicationName, req, cb) {
        var path = 'v1/toggles/' + applicationName;
        etcd.client.delete(path, {recursive: true}, function (err) {
            if (err) {
                return cb(err);
            }

            audit.addApplicationAudit(getUserDetails(req), applicationName, 'Deleted', function () {
                if (err) {
                    console.log(err);
                }
            });

            if (config.RequiresAuth) {
                acl.revokeAll(applicationName, function (revokeErr) {
                    if (revokeErr) {
                        return cb(revokeErr);
                    }
                    cb();
                });
            } else {
                cb();
            }
        });
    },

    getApplicationMetaData: function (applicationName, cb) {
        etcd.client.get('v1/metadata/' + applicationName, {recursive: true}, function (err, result) {
            if (err) {
                if (err.errorCode === 100) { // key not found
                    cb(null, {});
                } else {
                    cb(err);
                }
                return;
            }
            var metaDataKeyValues = _.map(result.node.nodes, function (subNode) {
                var metaDataKey = _.last(subNode.key.split('/'));
                return [metaDataKey, subNode.value];
            });
            cb(null, _.object(metaDataKeyValues));
        });
    },

    deleteApplicationMetaData: function (applicationName, cb) {
        etcd.client.delete('v1/metadata/' + applicationName, {recursive: true}, function (err, result) {
            if (err) {
                if (err.errorCode === 100) { // key not found
                    cb();
                } else {
                    cb(err);
                }
                return;
            }
            cb();
        });
    },

    saveApplicationMetaData: function (applicationName, metaDataKey, metaDataValue, cb) {
        var path = 'v1/metadata/' + applicationName + '/' + metaDataKey;
        etcd.client.set(path, metaDataValue, function (err) {
            return cb(err);
        });
    }
};
<|endoftext|>


<commit_before>'use strict';
const EventEmitter = require('events').EventEmitter;
const Layer = require('./properties/layer');
const View = require('./properties/view');
const TokendTransformer = require('./transformers/tokend');
const Immutable = require('immutable');
const isPlainObject = require('lodash.isplainobject');

/* eslint-disable eqeqeq */
/**
 * Deep-merge one Object into another. Do _not_ deep merge anything that isn't explicitly
 * a first-order instance of Object.
 *
 * @param  {Object} destination   The destination of the merge operation. This object is mutated
 * @param  {Object} source        The source that properties are merged from
 * @return {Object}               The destination object
 */
const merge = (destination, source) => {
  // Ensure that the destination value is an Object.
  const dest = isPlainObject(destination) ? destination : {};

  // Only merge source if it's an Object.
  if (!isPlainObject(source)) {
    return dest;
  }

  Object.keys(source).forEach((key) => {
    // Ignore null and undefined source values. `== null` covers both
    if (source[key] == null) {
      return;
    }

    // Is this an Object (but not something that inherits Object)?
    if (Object.getPrototypeOf(source[key]) === Object.prototype) {
      // Recursively merge source Object into destination
      dest[key] = merge(dest[key], source[key]);

      return;
    }

    dest[key] = source[key];
  });

  return dest;
};
/* eslint-enable eqeqeq */

/**
 * Recursively traverses a layer namespace and sets the value at the corresponding place in the object
 * @param {Object} destination The destination of the merge operation.
 * @param {Array<String>} namespaceArray An array of keys (namespaces) to traverse
 * @param {Object} source The source that properties are merged from
 * @return {Object}
 */
const recusiveNamespaceMerge = (destination, namespaceArray, source) => {
  const nextNamespace = namespaceArray.shift();
  const dest = isPlainObject(destination) ? destination : {};

  if (namespaceArray.length) {
    dest[nextNamespace] = recusiveNamespaceMerge(dest[nextNamespace] || {}, namespaceArray, source);

    return dest;
  }

  dest[nextNamespace] = merge(dest[nextNamespace], source);

  return dest;
};

/**
 * A Properties instance manages multiple statically configured layers,
 * and an active View instance.
 */
class Properties extends EventEmitter {
  /**
   * Constructor
   */
  constructor() {
    super();

    this.initialized = false;

    this.layers = [];
    this.properties = Immutable.Map();
    this.active = new View(this);
    this.tokendTransformer = new TokendTransformer();
  }

  /**
   * Concatenate layers' sources with the active view's sources
   *
   * @return {Array}
   */
  get sources() {
    return []

      // Get Dynamic layers' source instances
      .concat(this.layers.map((layer) => layer.source).filter((source) => !!source))

      // Add the active View's sources.
      //  NOTE: This is a shallow copy and only copies object references to a new array.
      //  DO NOT USE THIS GETTER TO PERFORM ANY MUTATING ACTIVITIES.
      .concat(this.active.sources.slice().reverse());
  }

  /**
   * Register a dynamic Source layer
   *
   * @param {Source}  source
   * @param {String}  namespace
   */
  dynamic(source, namespace) {
    this.layers.push(new Layer.Dynamic(source, namespace));
  }

  /**
   * Register a static layer
   *
   * @param {Object}  properties
   * @param {String}  namespace
   */
  static(properties, namespace) {
    this.layers.push(new Layer.Static(properties, namespace));
  }

  /**
   * Instantiate a new View
   *
   * @param {Array} sources An optional set of Sources to be passed to the new View
   * @return {View}
   */
  view(sources) {
    return new View(this, sources);
  }

  /**
   * Initialize persistent (Dynamic and Static) layers.
   *
   * @return {Promise<Properties>} resolves after a build has completed
   */
  initialize() {
    if (this.initialized) {
      return Promise.resolve(this);
    }
    this.initialized = true;

    return Promise.all(
      this.layers.concat(this.tokendTransformer).map((source) => source.initialize())
    ).then((sources) => {
      // Once initialized, watch for sources' update events
      sources.forEach((source) => {
        source.on('update', () => this.build());
      });

      return this.build();
    });
  }

  /**
   * Flatten layers and view's sources into one properties object
   *
   * @return {Promise<Properties>}
   */
  build() {
    // return after starting building timeout
    const built = new Promise((resolve) => this.once('build', () => resolve(this)));

    if (this._building) {
      return built;
    }

    // Block building for a hold-down period to let multiple updates propagate
    this._building = setTimeout(() => {
      // Merge layers into their own object. This can be consumed as an input by
      // template renderers.
      const persistent = this.layers.reduce((properties, layer) => {
        if (!layer.namespace) {
          return merge(properties, layer.properties);
        }

        let namespace = layer.namespace.split(':');
        const namespaceRoot = namespace.shift();

        if (namespace.length > 0) {
          properties[namespaceRoot] = recusiveNamespaceMerge(properties[namespaceRoot], namespace, layer.properties);
        } else {
          properties[namespaceRoot] = merge(properties[namespaceRoot], layer.properties);
        }

        return properties;
      }, {});

      const properties = merge(
        this.active.sources.reduce((properties, source) => merge(properties, source.properties), {}),
        persistent
      );

      this.tokendTransformer.transform(properties).then((transformedProperties) => {
        this.persistent = persistent;
        this.properties = Immutable.Map(properties).mergeDeep(transformedProperties).toJS();

        this.emit('build', this.properties);
        delete this._building;
      });
    }, Properties.BUILD_HOLD_DOWN);

    return built;
  }
}

// Build hold-down timeout
Properties.BUILD_HOLD_DOWN = 1000; // eslint-disable-line rapid7/static-magic-numbers

Properties.Layer = Layer;
Properties.View = View;
Properties.merge = merge;

module.exports = Properties;
<commit_msg>Removed setting the next destination as an empty object in favor of the ternary above setting the value on the next recursive call.<commit_after>'use strict';
const EventEmitter = require('events').EventEmitter;
const Layer = require('./properties/layer');
const View = require('./properties/view');
const TokendTransformer = require('./transformers/tokend');
const Immutable = require('immutable');
const isPlainObject = require('lodash.isplainobject');

/* eslint-disable eqeqeq */
/**
 * Deep-merge one Object into another. Do _not_ deep merge anything that isn't explicitly
 * a first-order instance of Object.
 *
 * @param  {Object} destination   The destination of the merge operation. This object is mutated
 * @param  {Object} source        The source that properties are merged from
 * @return {Object}               The destination object
 */
const merge = (destination, source) => {
  // Ensure that the destination value is an Object.
  const dest = isPlainObject(destination) ? destination : {};

  // Only merge source if it's an Object.
  if (!isPlainObject(source)) {
    return dest;
  }

  Object.keys(source).forEach((key) => {
    // Ignore null and undefined source values. `== null` covers both
    if (source[key] == null) {
      return;
    }

    // Is this an Object (but not something that inherits Object)?
    if (Object.getPrototypeOf(source[key]) === Object.prototype) {
      // Recursively merge source Object into destination
      dest[key] = merge(dest[key], source[key]);

      return;
    }

    dest[key] = source[key];
  });

  return dest;
};
/* eslint-enable eqeqeq */

/**
 * Recursively traverses a layer namespace and sets the value at the corresponding place in the object
 * @param {Object} destination The destination of the merge operation.
 * @param {Array<String>} namespaceArray An array of keys (namespaces) to traverse
 * @param {Object} source The source that properties are merged from
 * @return {Object}
 */
const recusiveNamespaceMerge = (destination, namespaceArray, source) => {
  const nextNamespace = namespaceArray.shift();
  const dest = isPlainObject(destination) ? destination : {};

  if (namespaceArray.length) {
    dest[nextNamespace] = recusiveNamespaceMerge(dest[nextNamespace], namespaceArray, source);

    return dest;
  }

  dest[nextNamespace] = merge(dest[nextNamespace], source);

  return dest;
};

/**
 * A Properties instance manages multiple statically configured layers,
 * and an active View instance.
 */
class Properties extends EventEmitter {
  /**
   * Constructor
   */
  constructor() {
    super();

    this.initialized = false;

    this.layers = [];
    this.properties = Immutable.Map();
    this.active = new View(this);
    this.tokendTransformer = new TokendTransformer();
  }

  /**
   * Concatenate layers' sources with the active view's sources
   *
   * @return {Array}
   */
  get sources() {
    return []

      // Get Dynamic layers' source instances
      .concat(this.layers.map((layer) => layer.source).filter((source) => !!source))

      // Add the active View's sources.
      //  NOTE: This is a shallow copy and only copies object references to a new array.
      //  DO NOT USE THIS GETTER TO PERFORM ANY MUTATING ACTIVITIES.
      .concat(this.active.sources.slice().reverse());
  }

  /**
   * Register a dynamic Source layer
   *
   * @param {Source}  source
   * @param {String}  namespace
   */
  dynamic(source, namespace) {
    this.layers.push(new Layer.Dynamic(source, namespace));
  }

  /**
   * Register a static layer
   *
   * @param {Object}  properties
   * @param {String}  namespace
   */
  static(properties, namespace) {
    this.layers.push(new Layer.Static(properties, namespace));
  }

  /**
   * Instantiate a new View
   *
   * @param {Array} sources An optional set of Sources to be passed to the new View
   * @return {View}
   */
  view(sources) {
    return new View(this, sources);
  }

  /**
   * Initialize persistent (Dynamic and Static) layers.
   *
   * @return {Promise<Properties>} resolves after a build has completed
   */
  initialize() {
    if (this.initialized) {
      return Promise.resolve(this);
    }
    this.initialized = true;

    return Promise.all(
      this.layers.concat(this.tokendTransformer).map((source) => source.initialize())
    ).then((sources) => {
      // Once initialized, watch for sources' update events
      sources.forEach((source) => {
        source.on('update', () => this.build());
      });

      return this.build();
    });
  }

  /**
   * Flatten layers and view's sources into one properties object
   *
   * @return {Promise<Properties>}
   */
  build() {
    // return after starting building timeout
    const built = new Promise((resolve) => this.once('build', () => resolve(this)));

    if (this._building) {
      return built;
    }

    // Block building for a hold-down period to let multiple updates propagate
    this._building = setTimeout(() => {
      // Merge layers into their own object. This can be consumed as an input by
      // template renderers.
      const persistent = this.layers.reduce((properties, layer) => {
        if (!layer.namespace) {
          return merge(properties, layer.properties);
        }

        let namespace = layer.namespace.split(':');
        const namespaceRoot = namespace.shift();

        if (namespace.length > 0) {
          properties[namespaceRoot] = recusiveNamespaceMerge(properties[namespaceRoot], namespace, layer.properties);
        } else {
          properties[namespaceRoot] = merge(properties[namespaceRoot], layer.properties);
        }

        return properties;
      }, {});

      const properties = merge(
        this.active.sources.reduce((properties, source) => merge(properties, source.properties), {}),
        persistent
      );

      this.tokendTransformer.transform(properties).then((transformedProperties) => {
        this.persistent = persistent;
        this.properties = Immutable.Map(properties).mergeDeep(transformedProperties).toJS();

        this.emit('build', this.properties);
        delete this._building;
      });
    }, Properties.BUILD_HOLD_DOWN);

    return built;
  }
}

// Build hold-down timeout
Properties.BUILD_HOLD_DOWN = 1000; // eslint-disable-line rapid7/static-magic-numbers

Properties.Layer = Layer;
Properties.View = View;
Properties.merge = merge;

module.exports = Properties;
<|endoftext|>


<commit_before>miqHttpInject(angular.module('containerDashboard', ['ui.bootstrap', 'patternfly', 'patternfly.charts', 'miq.card', 'miq.util']))
  .controller('containerDashboardController', ['$scope', 'dashboardUtilsFactory', 'chartsMixin', '$http', '$interval', '$window',
    function($scope, dashboardUtilsFactory, chartsMixin, $http, $interval, $window) {
      document.getElementById("center_div").className += " miq-body";

      // Obj-status cards init
      $scope.objectStatus = {
        providers:  dashboardUtilsFactory.createProvidersStatus(),
        nodes:      dashboardUtilsFactory.createNodesStatus(),
        containers: dashboardUtilsFactory.createContainersStatus(),
        registries: dashboardUtilsFactory.createRegistriesStatus(),
        projects:   dashboardUtilsFactory.createProjectsStatus(),
        pods:       dashboardUtilsFactory.createPodsStatus(),
        services:   dashboardUtilsFactory.createServicesStatus(),
        images:     dashboardUtilsFactory.createImagesStatus(),
        routes:     dashboardUtilsFactory.createRoutesStatus()
      };

      $scope.loadingDone = false;

      // Heatmaps init
      $scope.nodeCpuUsage = {
        title: __('CPU'),
        id: 'nodeCpuUsageMap',
        loadingDone: false
      };

      $scope.nodeMemoryUsage = {
        title: __('Memory'),
        id: 'nodeMemoryUsageMap',
        loadingDone: false
      };

      $scope.heatmaps = [$scope.nodeCpuUsage, $scope.nodeMemoryUsage];
      $scope.nodeHeatMapUsageLegendLabels = chartsMixin.nodeHeatMapUsageLegendLabels;
      $scope.dashboardHeatmapChartHeight = chartsMixin.dashboardHeatmapChartHeight;

      // Node Utilization
      $scope.cpuUsageConfig = chartsMixin.chartConfig.cpuUsageConfig;
      $scope.cpuUsageSparklineConfig = {
        tooltipFn : chartsMixin.dailyTimeTooltip,
        chartId: 'cpuSparklineChart'
      };
      $scope.cpuUsageDonutConfig = {
        chartId: 'cpuDonutChart',
        thresholds: {'warning':'60','error':'90'}
      };
      $scope.memoryUsageConfig = chartsMixin.chartConfig.memoryUsageConfig;
      $scope.memoryUsageSparklineConfig = {
        tooltipFn : chartsMixin.dailyTimeTooltip,
        chartId: 'memorySparklineChart'
      };
      $scope.memoryUsageDonutConfig = {
        chartId: 'memoryDonutChart',
        thresholds: {'warning':'60','error':'90'}
      };

      $scope.refresh = function() {
        var id;
        // get the pathname and remove trailing / if exist
        var pathname = $window.location.pathname.replace(/\/$/, '');
        if (pathname.match(/show$/)) {
          id = '';
        } else {
          // search for pattern ^/<controler>/<id>$ in the pathname
          id = '/' + (/^\/[^\/]+\/(\d+)$/.exec(pathname)[1]);
        }

        var url = '/container_dashboard/data'+id;
        $http.get(url).success(function(response) {
          'use strict';

          var data = response.data;

          // Obj-status (entity count row)
          var providers = data.providers;
          if (providers) {
            if (id) {
              $scope.providerTypeIconImage = data.providers[0].iconImage
              $scope.isSingleProvider = true
            } else {
              $scope.isSingleProvider = false
              $scope.objectStatus.providers.count = 0;
              $scope.objectStatus.providers.notifications = [];
              providers.forEach(function (item) {
                $scope.objectStatus.providers.count += item.count;
                $scope.objectStatus.providers.notifications.push({
                  iconImage: item.iconImage,
                  count: item.count
                })
              });
            }

            if ($scope.objectStatus.providers.count > 0) {
              $scope.objectStatus.providers.href = data.providers_link
            }
          }

          dashboardUtilsFactory.updateStatus($scope.objectStatus.nodes, data.status.nodes);
          dashboardUtilsFactory.updateStatus($scope.objectStatus.containers, data.status.containers);
          dashboardUtilsFactory.updateStatus($scope.objectStatus.registries, data.status.registries);
          dashboardUtilsFactory.updateStatus($scope.objectStatus.projects, data.status.projects);
          dashboardUtilsFactory.updateStatus($scope.objectStatus.pods, data.status.pods);
          dashboardUtilsFactory.updateStatus($scope.objectStatus.services, data.status.services);
          dashboardUtilsFactory.updateStatus($scope.objectStatus.images, data.status.images);
          dashboardUtilsFactory.updateStatus($scope.objectStatus.routes, data.status.routes);

          // Node utilization donut
          $scope.cpuUsageData = chartsMixin.processUtilizationData(data.ems_utilization.cpu,
                                                                   "dates",
                                                                   $scope.cpuUsageConfig.units);
          $scope.memoryUsageData = chartsMixin.processUtilizationData(data.ems_utilization.mem,
                                                                      "dates",
                                                                      $scope.memoryUsageConfig.units);

          // Heatmaps
          $scope.nodeCpuUsage = chartsMixin.processHeatmapData($scope.nodeCpuUsage, data.heatmaps.nodeCpuUsage);
          $scope.nodeCpuUsage.loadingDone = true;

          $scope.nodeMemoryUsage =
            chartsMixin.processHeatmapData($scope.nodeMemoryUsage, data.heatmaps.nodeMemoryUsage);
          $scope.nodeMemoryUsage.loadingDone = true;

          // Network metrics
          $scope.networkUtilizationDailyConfig = chartsMixin.chartConfig.dailyNetworkUsageConfig;

          $scope.dailyNetworkUtilization =
            chartsMixin.processUtilizationData(data.daily_network_metrics,
                                               "dates",
                                               $scope.networkUtilizationDailyConfig.units);

          // Pod metrics
          $scope.podEntityTrendDailyConfig = chartsMixin.chartConfig.dailyPodUsageConfig;

          $scope.dailyPodEntityTrend =
              chartsMixin.processPodUtilizationData(data.daily_pod_metrics,
                  "dates",
                  $scope.podEntityTrendDailyConfig.createdLabel,
                  $scope.podEntityTrendDailyConfig.deletedLabel);

          // Image metrics
          $scope.imageEntityTrendDailyConfig = chartsMixin.chartConfig.dailyImageUsageConfig;

          $scope.dailyImageEntityTrend =
              chartsMixin.processUtilizationData(data.daily_image_metrics,
                  "dates",
                  $scope.imageEntityTrendDailyConfig.createdLabel);

          // Trend lines data
          $scope.loadingDone = true;
        });
      };
      $scope.refresh();
      var promise = $interval($scope.refresh, 1000*60*3);

      $scope.$on('$destroy', function() {
        $interval.cancel(promise);
      });
    }]);
<commit_msg>container_dashboard_controller - whitespace cleanups after rebase (transferred from ManageIQ/manageiq@513a71b51d118c58b3cc119ef61a98b7b6e3d971)<commit_after>/* global miqHttpInject */

miqHttpInject(angular.module('containerDashboard', ['ui.bootstrap', 'patternfly', 'patternfly.charts', 'miq.card', 'miq.util']))
  .controller('containerDashboardController', ['$scope', 'dashboardUtilsFactory', 'chartsMixin', '$http', '$interval', '$window',
    function($scope, dashboardUtilsFactory, chartsMixin, $http, $interval, $window) {
      document.getElementById("center_div").className += " miq-body";

      // Obj-status cards init
      $scope.objectStatus = {
        providers:  dashboardUtilsFactory.createProvidersStatus(),
        nodes:      dashboardUtilsFactory.createNodesStatus(),
        containers: dashboardUtilsFactory.createContainersStatus(),
        registries: dashboardUtilsFactory.createRegistriesStatus(),
        projects:   dashboardUtilsFactory.createProjectsStatus(),
        pods:       dashboardUtilsFactory.createPodsStatus(),
        services:   dashboardUtilsFactory.createServicesStatus(),
        images:     dashboardUtilsFactory.createImagesStatus(),
        routes:     dashboardUtilsFactory.createRoutesStatus()
      };

      $scope.loadingDone = false;

      // Heatmaps init
      $scope.nodeCpuUsage = {
        title: __('CPU'),
        id: 'nodeCpuUsageMap',
        loadingDone: false
      };

      $scope.nodeMemoryUsage = {
        title: __('Memory'),
        id: 'nodeMemoryUsageMap',
        loadingDone: false
      };

      $scope.heatmaps = [$scope.nodeCpuUsage, $scope.nodeMemoryUsage];
      $scope.nodeHeatMapUsageLegendLabels = chartsMixin.nodeHeatMapUsageLegendLabels;
      $scope.dashboardHeatmapChartHeight = chartsMixin.dashboardHeatmapChartHeight;

      // Node Utilization
      $scope.cpuUsageConfig = chartsMixin.chartConfig.cpuUsageConfig;
      $scope.cpuUsageSparklineConfig = {
        tooltipFn: chartsMixin.dailyTimeTooltip,
        chartId: 'cpuSparklineChart'
      };
      $scope.cpuUsageDonutConfig = {
        chartId: 'cpuDonutChart',
        thresholds: { 'warning': '60', 'error': '90' },
      };
      $scope.memoryUsageConfig = chartsMixin.chartConfig.memoryUsageConfig;
      $scope.memoryUsageSparklineConfig = {
        tooltipFn: chartsMixin.dailyTimeTooltip,
        chartId: 'memorySparklineChart'
      };
      $scope.memoryUsageDonutConfig = {
        chartId: 'memoryDonutChart',
        thresholds: { 'warning': '60', 'error': '90' },
      };

      $scope.refresh = function() {
        var id;
        // get the pathname and remove trailing / if exist
        var pathname = $window.location.pathname.replace(/\/$/, '');
        if (pathname.match(/show$/)) {
          id = '';
        } else {
          // search for pattern ^/<controler>/<id>$ in the pathname
          id = '/' + (/^\/[^\/]+\/(\d+)$/.exec(pathname)[1]);
        }

        var url = '/container_dashboard/data' + id;
        $http.get(url).success(function(response) {
          'use strict';

          var data = response.data;

          // Obj-status (entity count row)
          var providers = data.providers;
          if (providers) {
            if (id) {
              $scope.providerTypeIconImage = data.providers[0].iconImage;
              $scope.isSingleProvider = true;
            } else {
              $scope.isSingleProvider = false;
              $scope.objectStatus.providers.count = 0;
              $scope.objectStatus.providers.notifications = [];
              providers.forEach(function (item) {
                $scope.objectStatus.providers.count += item.count;
                $scope.objectStatus.providers.notifications.push({
                  iconImage: item.iconImage,
                  count: item.count
                })
              });
            }

            if ($scope.objectStatus.providers.count > 0) {
              $scope.objectStatus.providers.href = data.providers_link;
            }
          }

          dashboardUtilsFactory.updateStatus($scope.objectStatus.nodes, data.status.nodes);
          dashboardUtilsFactory.updateStatus($scope.objectStatus.containers, data.status.containers);
          dashboardUtilsFactory.updateStatus($scope.objectStatus.registries, data.status.registries);
          dashboardUtilsFactory.updateStatus($scope.objectStatus.projects, data.status.projects);
          dashboardUtilsFactory.updateStatus($scope.objectStatus.pods, data.status.pods);
          dashboardUtilsFactory.updateStatus($scope.objectStatus.services, data.status.services);
          dashboardUtilsFactory.updateStatus($scope.objectStatus.images, data.status.images);
          dashboardUtilsFactory.updateStatus($scope.objectStatus.routes, data.status.routes);

          // Node utilization donut
          $scope.cpuUsageData = chartsMixin.processUtilizationData(data.ems_utilization.cpu,
                                                                   "dates",
                                                                   $scope.cpuUsageConfig.units);
          $scope.memoryUsageData = chartsMixin.processUtilizationData(data.ems_utilization.mem,
                                                                      "dates",
                                                                      $scope.memoryUsageConfig.units);

          // Heatmaps
          $scope.nodeCpuUsage = chartsMixin.processHeatmapData($scope.nodeCpuUsage, data.heatmaps.nodeCpuUsage);
          $scope.nodeCpuUsage.loadingDone = true;

          $scope.nodeMemoryUsage =
            chartsMixin.processHeatmapData($scope.nodeMemoryUsage, data.heatmaps.nodeMemoryUsage);
          $scope.nodeMemoryUsage.loadingDone = true;

          // Network metrics
          $scope.networkUtilizationDailyConfig = chartsMixin.chartConfig.dailyNetworkUsageConfig;

          $scope.dailyNetworkUtilization =
            chartsMixin.processUtilizationData(data.daily_network_metrics,
                                               "dates",
                                               $scope.networkUtilizationDailyConfig.units);

          // Pod metrics
          $scope.podEntityTrendDailyConfig = chartsMixin.chartConfig.dailyPodUsageConfig;

          $scope.dailyPodEntityTrend =
              chartsMixin.processPodUtilizationData(data.daily_pod_metrics,
                  "dates",
                  $scope.podEntityTrendDailyConfig.createdLabel,
                  $scope.podEntityTrendDailyConfig.deletedLabel);

          // Image metrics
          $scope.imageEntityTrendDailyConfig = chartsMixin.chartConfig.dailyImageUsageConfig;

          $scope.dailyImageEntityTrend =
              chartsMixin.processUtilizationData(data.daily_image_metrics,
                  "dates",
                  $scope.imageEntityTrendDailyConfig.createdLabel);

          // Trend lines data
          $scope.loadingDone = true;
        });
      };
      $scope.refresh();
      var promise = $interval($scope.refresh, 1000 * 60 * 3);

      $scope.$on('$destroy', function() {
        $interval.cancel(promise);
      });
    }]);
<|endoftext|>