<commit_before>import Global from '../global';

var Render = {};

// TODO dynamic for list dont handle selected

Render.required = function (opt) {
	Global.batcher.read(function () {

		if (opt.element.required === opt.data) {
			opt.pending = false;
			return;
		}

		Global.batcher.write(function () {
			opt.element.required = Global.binder.modifyData(opt, opt.data);
			opt.pending = false;
		});
	});
};

Render.disable = function (opt) {
	Global.batcher.read(function () {

		if (opt.element.disabled === opt.data) {
			opt.pending = false;
			return;
		}

		Global.batcher.write(function () {
			opt.element.disabled = Global.binder.modifyData(opt, opt.data);
			opt.pending = false;
		});
	});
};

Render.enable = function (opt) {
	Global.batcher.read(function () {

		if (opt.element.disabled === !opt.data) {
			opt.pending = false;
			return;
		}

		Global.batcher.write(function () {
			opt.element.disabled = !Global.binder.modifyData(opt, opt.data);
			opt.pending = false;
		});
	});
};

Render.hide = function (opt) {
	Global.batcher.read(function () {

		if (opt.element.hidden === opt.data) {
			opt.pending = false;
			return;
		}

		Global.batcher.write(function () {
			opt.element.hidden = Global.binder.modifyData(opt, opt.data);
			opt.pending = false;
		});
	});
};

Render.show = function (opt) {
	Global.batcher.read(function () {

		if (opt.element.hidden === !opt.data) {
			opt.pending = false;
			return;
		}

		Global.batcher.write(function () {
			opt.element.hidden = !Global.binder.modifyData(opt, opt.data);
			opt.pending = false;
		});
	});
};

Render.read = function (opt) {
	Global.batcher.read(function () {

		if (opt.element.readOnly === opt.data) {
			opt.pending = false;
			return;
		}

		Global.batcher.write(function () {
			opt.element.readOnly = Global.binder.modifyData(opt, opt.data);
			opt.pending = false;
		});
	});
};

Render.write = function (opt) {
	Global.batcher.read(function () {

		if (opt.element.readOnly === !opt.data) {
			opt.pending = false;
			return;
		}

		Global.batcher.write(function () {
			opt.element.readOnly = !Global.binder.modifyData(opt, opt.data);
			opt.pending = false;
		});
	});
};

Render.html = function (opt) {
	Global.batcher.read(function () {

		if (opt.element.innerHTML === opt.data) {
			opt.pending = false;
			return;
		}

		Global.batcher.write(function () {
			opt.element.innerHTML = Global.binder.modifyData(opt, opt.data);
			opt.pending = false;
		});
	});
};

Render.class = function (opt) {
	Global.batcher.write(function () {
		var name = opt.names.slice(1).join('-');
		opt.element.classList.toggle(name, Global.binder.modifyData(opt, opt.data));
		opt.pending = false;
	});
};

Render.on = function (opt) {

	if (opt.cache) {
		opt.element.removeEventListener(opt.names[1], opt.cache);
	} else {
		opt.cache = Global.utility.getByPath(Global.methods.data, opt.scope + '.' + opt.path).bind(opt.container);
	}

	opt.element.addEventListener(opt.names[1], opt.cache);
	opt.pending = false;
};

Render.css = function (opt) {
	Global.batcher.read(function () {

		if (opt.element.style.cssText === opt.data) {
			opt.pending = false;
			return;
		}

		var data;

		if (opt.names.length > 1) {
			data = opt.names.slice(1).join('-') + ': ' +  data + ';';
		}

		Global.batcher.write(function () {
			opt.element.style.cssText = Global.binder.modifyData(opt, data);
			opt.pending = false;
		});
	});
};

Render.text = function (opt) {
	var data = opt.data === undefined || opt.data === null ? '' : opt.data;

	if (data && typeof data === 'object') {
		data = JSON.stringify(data);
	} else if (data && typeof data !== 'string') {
		data = String(data);
	}

	Global.batcher.write(function () {
		opt.element.innerText = Global.binder.modifyData(opt, data);
		opt.pending = false;
	});

};

Render.each = function (opt) {

	if (!opt.cache) {
		opt.cache = opt.element.removeChild(opt.element.firstElementChild);
	}

	if (!opt.data || typeof opt.data !== 'object' || opt.element.children.length === opt.data.length) {
		opt.pending = false;
		return;
	}

	Global.batcher.read(function () {

		var clone;
		var element = opt.element;
		var data = Global.binder.modifyData(opt, opt.data);

		var dLength = data.length;
		var eLength = element.children.length;

		Global.batcher.write(function () {

			while (eLength !== dLength) {

				if (eLength > dLength) {

					eLength--;
					element.removeChild(element.children[eLength]);

				} else if (eLength < dLength) {

					clone = opt.cache.cloneNode(true);
					Global.utility.replaceEachVariable(clone, opt.names[1], opt.path, eLength);
					element.appendChild(clone);
					eLength++;

				}

			}

			opt.pending = false;
		});
	});
};

Render.value = function (opt, caller) {

	Global.batcher.read(function () {

		var data, attribute, query;
		var i, l, element, elements;
		var type = opt.element.type;
		var name = opt.element.nodeName;

		if (caller === 'view') {

			if (name === 'SELECT') {
				data = opt.element.multiple ? [] : '';
				elements = opt.element.options;

				for (i = 0, l = elements.length; i < l; i++) {
					element = elements[i];

					if (element.selected) {
						if (opt.element.multiple) {
							data.push(element.value || element.innerText);
						} else {
							data = element.value || element.innerText;
							break;
						}
					}

				}

			} else if (type === 'radio') {
				query = 'input[type="radio"][o-value="' + opt.value + '"]';
				elements = opt.container.querySelectorAll(query);

				for (i = 0, l = elements.length; i < l; i++) {
					element = elements[i];

					if (opt.element === element) {
						data = i;
						break;
					}

				}

			} else if (type === 'file') {
				data = opt.element.files;
			} else if (type === 'checkbox') {
				data = opt.element.checked;
			} else {
				data = opt.element.value;
			}

			Global.model.set(opt.keys, data);
			opt.pending = false;

		} else {
			Global.batcher.write(function () {

				if (name === 'SELECT') {
					data = opt.data === undefined ? opt.element.multiple ? [] : '' : opt.data;

					for (i = 0, l = opt.element.options.length; i < l; i++) {
						if (!opt.element.options[i].disabled) {
							if (opt.element.options[i].selected) {
								if (opt.element.multiple) {
									data.push(opt.element.options[i].value || opt.element.options[i].innerText || '');
								} else {
									data = opt.element.options[i].value || opt.element.options[i].innerText || '';
									break;
								}
							} else if (i === l-1 && !opt.element.multiple) {
								data = opt.element.options[0].value || opt.element.options[0].innerText || '';
							}
						}
					}

					Global.model.set(opt.keys, data);
				} else if (type === 'radio') {
					data = opt.data === undefined ? Global.model.set(opt.keys, 0) : opt.data;
					query = 'input[type="radio"][o-value="' + opt.value + '"]';
					elements = opt.container.querySelectorAll(query);

					for (i = 0, l = elements.length; i < l; i++) {
						element = elements[i];
						element.checked = i === data;
					}

					elements[data].checked = true;
				} else if (type === 'file') {
					attribute = 'files';
					data = opt.data === undefined ? Global.model.set(opt.keys, []) : opt.data;
				} else if (type === 'checkbox') {
					attribute = 'checked';
					data = opt.data === undefined ? Global.model.set(opt.keys, false) : opt.data;
				} else {
					attribute = 'value';
					data = opt.data === undefined ? Global.model.set(opt.keys, '') : opt.data;
				}

				if (attribute) {
					opt.element[attribute] = data;
					opt.element[attribute] = Global.binder.modifyData(opt, data);
				}

				opt.pending = false;

			});
		}

	});

};

Render.default = function (opt) {
	Global.batcher.read(function () {

		if (opt.element[opt.type] === opt.data) {
			return;
		}

		Global.batcher.write(function () {
			opt.element[opt.type] = Global.binder.modifyData(opt, opt.data);
		});

	});
};

export default Render;
<commit_msg>fixed file handling<commit_after>import Global from '../global';

var Render = {};

// TODO dynamic for list dont handle selected

Render.required = function (opt) {
	Global.batcher.read(function () {

		if (opt.element.required === opt.data) {
			opt.pending = false;
			return;
		}

		Global.batcher.write(function () {
			opt.element.required = Global.binder.modifyData(opt, opt.data);
			opt.pending = false;
		});
	});
};

Render.disable = function (opt) {
	Global.batcher.read(function () {

		if (opt.element.disabled === opt.data) {
			opt.pending = false;
			return;
		}

		Global.batcher.write(function () {
			opt.element.disabled = Global.binder.modifyData(opt, opt.data);
			opt.pending = false;
		});
	});
};

Render.enable = function (opt) {
	Global.batcher.read(function () {

		if (opt.element.disabled === !opt.data) {
			opt.pending = false;
			return;
		}

		Global.batcher.write(function () {
			opt.element.disabled = !Global.binder.modifyData(opt, opt.data);
			opt.pending = false;
		});
	});
};

Render.hide = function (opt) {
	Global.batcher.read(function () {

		if (opt.element.hidden === opt.data) {
			opt.pending = false;
			return;
		}

		Global.batcher.write(function () {
			opt.element.hidden = Global.binder.modifyData(opt, opt.data);
			opt.pending = false;
		});
	});
};

Render.show = function (opt) {
	Global.batcher.read(function () {

		if (opt.element.hidden === !opt.data) {
			opt.pending = false;
			return;
		}

		Global.batcher.write(function () {
			opt.element.hidden = !Global.binder.modifyData(opt, opt.data);
			opt.pending = false;
		});
	});
};

Render.read = function (opt) {
	Global.batcher.read(function () {

		if (opt.element.readOnly === opt.data) {
			opt.pending = false;
			return;
		}

		Global.batcher.write(function () {
			opt.element.readOnly = Global.binder.modifyData(opt, opt.data);
			opt.pending = false;
		});
	});
};

Render.write = function (opt) {
	Global.batcher.read(function () {

		if (opt.element.readOnly === !opt.data) {
			opt.pending = false;
			return;
		}

		Global.batcher.write(function () {
			opt.element.readOnly = !Global.binder.modifyData(opt, opt.data);
			opt.pending = false;
		});
	});
};

Render.html = function (opt) {
	Global.batcher.read(function () {

		if (opt.element.innerHTML === opt.data) {
			opt.pending = false;
			return;
		}

		Global.batcher.write(function () {
			opt.element.innerHTML = Global.binder.modifyData(opt, opt.data);
			opt.pending = false;
		});
	});
};

Render.class = function (opt) {
	Global.batcher.write(function () {
		var name = opt.names.slice(1).join('-');
		opt.element.classList.toggle(name, Global.binder.modifyData(opt, opt.data));
		opt.pending = false;
	});
};

Render.on = function (opt) {

	if (opt.cache) {
		opt.element.removeEventListener(opt.names[1], opt.cache);
	} else {
		opt.cache = Global.utility.getByPath(Global.methods.data, opt.scope + '.' + opt.path).bind(opt.container);
	}

	opt.element.addEventListener(opt.names[1], opt.cache);
	opt.pending = false;
};

Render.css = function (opt) {
	Global.batcher.read(function () {

		if (opt.element.style.cssText === opt.data) {
			opt.pending = false;
			return;
		}

		var data;

		if (opt.names.length > 1) {
			data = opt.names.slice(1).join('-') + ': ' +  data + ';';
		}

		Global.batcher.write(function () {
			opt.element.style.cssText = Global.binder.modifyData(opt, data);
			opt.pending = false;
		});
	});
};

Render.text = function (opt) {
	var data = opt.data === undefined || opt.data === null ? '' : opt.data;

	if (data && typeof data === 'object') {
		data = JSON.stringify(data);
	} else if (data && typeof data !== 'string') {
		data = String(data);
	}

	Global.batcher.write(function () {
		opt.element.innerText = Global.binder.modifyData(opt, data);
		opt.pending = false;
	});

};

Render.each = function (opt) {

	if (!opt.cache) {
		opt.cache = opt.element.removeChild(opt.element.firstElementChild);
	}

	if (!opt.data || typeof opt.data !== 'object' || opt.element.children.length === opt.data.length) {
		opt.pending = false;
		return;
	}

	Global.batcher.read(function () {

		var clone;
		var element = opt.element;
		var data = Global.binder.modifyData(opt, opt.data);

		var dLength = data.length;
		var eLength = element.children.length;

		Global.batcher.write(function () {

			while (eLength !== dLength) {

				if (eLength > dLength) {

					eLength--;
					element.removeChild(element.children[eLength]);

				} else if (eLength < dLength) {

					clone = opt.cache.cloneNode(true);
					Global.utility.replaceEachVariable(clone, opt.names[1], opt.path, eLength);
					element.appendChild(clone);
					eLength++;

				}

			}

			opt.pending = false;
		});
	});
};

Render.value = function (opt, caller) {

	Global.batcher.read(function () {

		var data, attribute, query;
		var i, l, element, elements;
		var type = opt.element.type;
		var name = opt.element.nodeName;

		if (caller === 'view') {

			if (name === 'SELECT') {
				data = opt.element.multiple ? [] : '';
				elements = opt.element.options;

				for (i = 0, l = elements.length; i < l; i++) {
					element = elements[i];

					if (element.selected) {
						if (opt.element.multiple) {
							data.push(element.value || element.innerText);
						} else {
							data = element.value || element.innerText;
							break;
						}
					}

				}

			} else if (type === 'radio') {
				query = 'input[type="radio"][o-value="' + opt.value + '"]';
				elements = opt.container.querySelectorAll(query);

				for (i = 0, l = elements.length; i < l; i++) {
					element = elements[i];

					if (opt.element === element) {
						data = i;
						break;
					}

				}

			} else if (type === 'file') {
				data = data || [];
				for (i = 0, l = opt.element.files.length; i < l; i++) {
					data[i] = opt.element.files[i];
				}
			} else if (type === 'checkbox') {
				data = opt.element.checked;
			} else {
				data = opt.element.value;
			}

			Global.model.set(opt.keys, data);
			opt.pending = false;

		} else {
			Global.batcher.write(function () {

				if (name === 'SELECT') {
					data = opt.data === undefined ? opt.element.multiple ? [] : '' : opt.data;

					for (i = 0, l = opt.element.options.length; i < l; i++) {
						if (!opt.element.options[i].disabled) {
							if (opt.element.options[i].selected) {
								if (opt.element.multiple) {
									data.push(opt.element.options[i].value || opt.element.options[i].innerText || '');
								} else {
									data = opt.element.options[i].value || opt.element.options[i].innerText || '';
									break;
								}
							} else if (i === l-1 && !opt.element.multiple) {
								data = opt.element.options[0].value || opt.element.options[0].innerText || '';
							}
						}
					}

					Global.model.set(opt.keys, data);
				} else if (type === 'radio') {
					data = opt.data === undefined ? Global.model.set(opt.keys, 0) : opt.data;
					query = 'input[type="radio"][o-value="' + opt.value + '"]';
					elements = opt.container.querySelectorAll(query);

					for (i = 0, l = elements.length; i < l; i++) {
						element = elements[i];
						element.checked = i === data;
					}

					elements[data].checked = true;
				} else if (type === 'file') {
					data = opt.data === undefined ? Global.model.set(opt.keys, []) : opt.data;
					for (i = 0, l = data.length; i < l; i++) {
						opt.element.files = data[i];
					}
				} else if (type === 'checkbox') {
					attribute = 'checked';
					data = opt.data === undefined ? Global.model.set(opt.keys, false) : opt.data;
				} else {
					attribute = 'value';
					data = opt.data === undefined ? Global.model.set(opt.keys, '') : opt.data;
				}

				if (attribute) {
					opt.element[attribute] = data;
					opt.element[attribute] = Global.binder.modifyData(opt, data);
				}

				opt.pending = false;

			});
		}

	});

};

Render.default = function (opt) {
	Global.batcher.read(function () {

		if (opt.element[opt.type] === opt.data) {
			return;
		}

		Global.batcher.write(function () {
			opt.element[opt.type] = Global.binder.modifyData(opt, opt.data);
		});

	});
};

export default Render;
<|endoftext|>


<commit_before>'use strict'
var hub = require('./hub')
var engine = require('./engine')
var logger = require('../utils/composrLogger')
var config = require('config')
var allowedVerbs = ['get', 'put', 'post', 'delete']
var phraseHooks = require('./phraseHooks')

/* *
 * [analyzePhrase description]
 * @param  {[type]} acc [description]
 * @return {[type]}     [description]
 */
function analyzePhrase (acc) {
  return function (phraseModel) {
    var domain = phraseModel.getDomain()

    allowedVerbs.forEach(function (verb) {
      if (phraseModel.canRun(verb)) {
        // Restify doesn't use delete it uses 'del' for storing the delete callback
        var restifyMappedVerb = verb === 'delete' ? 'del' : verb

        acc.push({
          restifyVerb: restifyMappedVerb,
          verb: verb,
          domain: domain,
          path: phraseModel.getUrl(),
          version: phraseModel.getVersion(),
          id: phraseModel.getId(),
          phrase: phraseModel
        })
      }
    })
  }
}

function doCheckCache (routeItem, response, path, authorization) {
  if (routeItem.phrase.json[routeItem.verb].middlewares && routeItem.phrase.json[routeItem.verb].middlewares.indexOf('cache') !== -1) {
    var options = routeItem.phrase.json[routeItem.verb].cache

    switch (routeItem.verb) {
      case 'get':
        hub.emit('cache-add', path, routeItem.verb, authorization, routeItem.phrase.getVersion(), response, options)
        break
      default:
        // Another request deletes the 'get' path cache
        hub.emit('cache-remove', path, 'get', authorization, routeItem.phrase.getVersion(), routeItem.domain, options)
    }
  }
}

/**
 * [executePhraseById description]
 * @param  {[type]}   req       [description]
 * @param  {[type]}   res       [description]
 * @param  {Function} next      [description]
 * @param  {[type]}   routeItem [description]
 * @return {[type]}             [description]
 */
function executePhraseById (req, res, next, routeItem) {
  var params = executionMode({
    corbelDriver: req.corbelDriver,
    req: req,
    res: res,
    next: next,
    browser: true,
    timeout: config.get('execution.timeout'),
    server: 'restify',
    userId: req.userId
  })

  hub.emit('phrase:execution:start', routeItem.domain, routeItem.id, routeItem.verb)

  return engine.composr.Phrase.runById(routeItem.id, routeItem.verb, params)
    .then(function (response) {
      enforceGC()
      hub.emit('phrase:execution:end', response.status, routeItem.domain, routeItem.id, routeItem.verb)
      doCheckCache(routeItem, response, req.getHref(), req.header('Authorization'))
      return next()
    })
    .catch(function (err) {
      if (err === 'phrase:cant:be:runned') {
        err = new engine.composr.ComposrError('endpoint:not:found', 'Endpoint not found', 404)
      }

      var parsedErr = engine.composr.parseToComposrError(err.body || err, 'internal:server:error:endpoint:execution')

      if (err.status || err.statusCode) {
        parsedErr.status = err.status || err.statusCode
        parsedErr.statusCode = parsedErr.status
      }

      logger.debug('[Router]', err)
      logger.error('[Router]', 'Failing executing Phrase', parsedErr.status, routeItem.domain, routeItem.id)
      // @TODO: log error in metrics

      hub.emit('phrase:execution:end', parsedErr.status, routeItem.domain, routeItem.id, routeItem.verb)

      if (res.headersSent) {
        return next()
      } else {
        // Shortcut for res.send if the phrase hasn't handled it
        return next(parsedErr)
      }
    })
}

/**
 * Set composr-core execution phrases with Node VM
 * @param  {Object} params execution configuration
 * @return {Object} modified execution params
 */
function executionMode (params) {
  if (config.get('execution.vm')) {
    params.browser = false
  }

  return params
}

/**
 * Enforce run Garbage Collector every phrase execution
 * @return {[type]} [description]
 */
function enforceGC () {
  if (config.get('execution.gc') && !!global.gc) {
    global.gc()
  }
}

/**
 * [createRoutes description]
 * @param  {[type]}   phrases [description]
 * @param  {Function} next    [description]
 * @return {[type]}           [description]
 */
function createRoutes (phrases, next) {
  var routeObjects = []
  phrases.forEach(analyzePhrase(routeObjects))
  next(routeObjects)
}

/**
 * Add End-Points to Restify Router
 * @param  {[type]} server       [description]
 * @param  {[type]} routeObjects [description]
 * @return {[type]}              [description]
 */
function bindRoutes (server, routeObjects) {
  for (var i = routeObjects.length - 1; i >= 0; i--) {
    (function (item) {
      var url = '/' + item.domain + '/' + item.path

      // Mandatory hooks
      var corbelDriverSetupHook = phraseHooks.get('corbel-driver-setup')
      var metricsHook = phraseHooks.get('metrics')
      // User-defined hooks
      var hooks = phraseHooks.getHooks(item.phrase, item.verb)

      var args = [{
        path: url,
        version: item.version
      }]

      if (hooks) {
        args = args.concat(hooks)
      }
      args = args.concat(corbelDriverSetupHook)
      args = args.concat(metricsHook)
      args = args.concat(function bindRoute (req, res, next) {
        executePhraseById(req, res, next, item)
      })

      server[item.restifyVerb].apply(server, args)
    })(routeObjects[i])
  }
}

/**
 * List All End-points registered in
 * Restify Router.
 * @param  {[type]} server [description]
 * @return {[type]}        [description]
 */
function listAllRoutes (server) {
  logger.debug('[Router]', 'GET paths:')
  server.router.routes.GET.forEach(
    function (value) {
      logger.info(value.spec.path)
    }
  )
  logger.debug('[Router]', 'PUT paths:')
  server.router.routes.PUT.forEach(
    function (value) {
      logger.info(value.spec.path)
    }
  )
  logger.debug('[Router]', 'POST paths:')
  server.router.routes.POST.forEach(
    function (value) {
      logger.info(value.spec.path)
    }
  )
}

module.exports = function (server) {
  hub.on('create:routes', function (phrases) {
    logger.debug('[Router]', 'Creting or updating endpoints...')

    if (!Array.isArray(phrases)) {
      phrases = [phrases]
    }

    createRoutes(phrases, function (routeObjects) {
      bindRoutes(server, routeObjects)
    })
  })

  hub.once('create:staticRoutes', function (server) {
    logger.info('[Router]', 'Creating static routes...')
    require('../routes')(server)
  })

  hub.on('remove:route', function (url) {
    logger.debug('[Router]', 'Remove route:', url)
    // Restify doesn't support removing routes on the fly, instead return a 404
    listAllRoutes()
  })
}
<commit_msg>fix weird traces logs<commit_after>'use strict'
var hub = require('./hub')
var engine = require('./engine')
var logger = require('../utils/composrLogger')
var config = require('config')
var allowedVerbs = ['get', 'put', 'post', 'delete']
var phraseHooks = require('./phraseHooks')
var _ = require('lodash')

/* *
 * [analyzePhrase description]
 * @param  {[type]} acc [description]
 * @return {[type]}     [description]
 */
function analyzePhrase (acc) {
  return function (phraseModel) {
    var domain = phraseModel.getDomain()

    allowedVerbs.forEach(function (verb) {
      if (phraseModel.canRun(verb)) {
        // Restify doesn't use delete it uses 'del' for storing the delete callback
        var restifyMappedVerb = verb === 'delete' ? 'del' : verb

        acc.push({
          restifyVerb: restifyMappedVerb,
          verb: verb,
          domain: domain,
          path: phraseModel.getUrl(),
          version: phraseModel.getVersion(),
          id: phraseModel.getId(),
          phrase: phraseModel
        })
      }
    })
  }
}

function doCheckCache (routeItem, response, path, authorization) {
  if (routeItem.phrase.json[routeItem.verb].middlewares && routeItem.phrase.json[routeItem.verb].middlewares.indexOf('cache') !== -1) {
    var options = routeItem.phrase.json[routeItem.verb].cache

    switch (routeItem.verb) {
      case 'get':
        hub.emit('cache-add', path, routeItem.verb, authorization, routeItem.phrase.getVersion(), response, options)
        break
      default:
        // Another request deletes the 'get' path cache
        hub.emit('cache-remove', path, 'get', authorization, routeItem.phrase.getVersion(), routeItem.domain, options)
    }
  }
}

/**
 * [executePhraseById description]
 * @param  {[type]}   req       [description]
 * @param  {[type]}   res       [description]
 * @param  {Function} next      [description]
 * @param  {[type]}   routeItem [description]
 * @return {[type]}             [description]
 */
function executePhraseById (req, res, next, routeItem) {
  var params = executionMode({
    corbelDriver: req.corbelDriver,
    req: req,
    res: res,
    next: next,
    browser: true,
    timeout: config.get('execution.timeout'),
    server: 'restify',
    userId: req.userId
  })

  hub.emit('phrase:execution:start', routeItem.domain, routeItem.id, routeItem.verb)

  return engine.composr.Phrase.runById(routeItem.id, routeItem.verb, params)
    .then(function (response) {
      enforceGC()
      hub.emit('phrase:execution:end', response.status, routeItem.domain, routeItem.id, routeItem.verb)
      doCheckCache(routeItem, response, req.getHref(), req.header('Authorization'))
      return next()
    })
    .catch(function (err) {
      if (err === 'phrase:cant:be:runned') {
        err = new engine.composr.ComposrError('endpoint:not:found', 'Endpoint not found', 404)
      }

      var parsedErr = engine.composr.parseToComposrError(err.body || err, 'internal:server:error:endpoint:execution')

      if (err.status || err.statusCode) {
        parsedErr.status = err.status || err.statusCode
        parsedErr.statusCode = parsedErr.status
      }

      logger.debug('[Router]', _.pick(err, ['status', 'data']))
      logger.error('[Router]', 'Failing executing Phrase', parsedErr.status, routeItem.domain, req.getHref())
      // @TODO: log error in metrics

      hub.emit('phrase:execution:end', parsedErr.status, routeItem.domain, routeItem.id, routeItem.verb)

      if (res.headersSent) {
        return next()
      } else {
        // Shortcut for res.send if the phrase hasn't handled it
        return next(parsedErr)
      }
    })
}

/**
 * Set composr-core execution phrases with Node VM
 * @param  {Object} params execution configuration
 * @return {Object} modified execution params
 */
function executionMode (params) {
  if (config.get('execution.vm')) {
    params.browser = false
  }

  return params
}

/**
 * Enforce run Garbage Collector every phrase execution
 * @return {[type]} [description]
 */
function enforceGC () {
  if (config.get('execution.gc') && !!global.gc) {
    global.gc()
  }
}

/**
 * [createRoutes description]
 * @param  {[type]}   phrases [description]
 * @param  {Function} next    [description]
 * @return {[type]}           [description]
 */
function createRoutes (phrases, next) {
  var routeObjects = []
  phrases.forEach(analyzePhrase(routeObjects))
  next(routeObjects)
}

/**
 * Add End-Points to Restify Router
 * @param  {[type]} server       [description]
 * @param  {[type]} routeObjects [description]
 * @return {[type]}              [description]
 */
function bindRoutes (server, routeObjects) {
  for (var i = routeObjects.length - 1; i >= 0; i--) {
    (function (item) {
      var url = '/' + item.domain + '/' + item.path

      // Mandatory hooks
      var corbelDriverSetupHook = phraseHooks.get('corbel-driver-setup')
      var metricsHook = phraseHooks.get('metrics')
      // User-defined hooks
      var hooks = phraseHooks.getHooks(item.phrase, item.verb)

      var args = [{
        path: url,
        version: item.version
      }]

      if (hooks) {
        args = args.concat(hooks)
      }
      args = args.concat(corbelDriverSetupHook)
      args = args.concat(metricsHook)
      args = args.concat(function bindRoute (req, res, next) {
        executePhraseById(req, res, next, item)
      })

      server[item.restifyVerb].apply(server, args)
    })(routeObjects[i])
  }
}

/**
 * List All End-points registered in
 * Restify Router.
 * @param  {[type]} server [description]
 * @return {[type]}        [description]
 */
function listAllRoutes (server) {
  logger.debug('[Router]', 'GET paths:')
  server.router.routes.GET.forEach(
    function (value) {
      logger.info(value.spec.path)
    }
  )
  logger.debug('[Router]', 'PUT paths:')
  server.router.routes.PUT.forEach(
    function (value) {
      logger.info(value.spec.path)
    }
  )
  logger.debug('[Router]', 'POST paths:')
  server.router.routes.POST.forEach(
    function (value) {
      logger.info(value.spec.path)
    }
  )
}

module.exports = function (server) {
  hub.on('create:routes', function (phrases) {
    logger.debug('[Router]', 'Creting or updating endpoints...')

    if (!Array.isArray(phrases)) {
      phrases = [phrases]
    }

    createRoutes(phrases, function (routeObjects) {
      bindRoutes(server, routeObjects)
    })
  })

  hub.once('create:staticRoutes', function (server) {
    logger.info('[Router]', 'Creating static routes...')
    require('../routes')(server)
  })

  hub.on('remove:route', function (url) {
    logger.debug('[Router]', 'Remove route:', url)
    // Restify doesn't support removing routes on the fly, instead return a 404
    listAllRoutes()
  })
}
<|endoftext|>


<commit_before>(function () {
  'use strict';

  KC3StrategyTabs.logger = new KC3StrategyTab('logger');

  KC3StrategyTabs.logger.definition = {
    ITEMS_PER_PAGE: 20,
    VISIBLE_PAGES: 9,

    filterState: {
      logTypes: {
        log: true,
        info: true,
        warn: true,
        error: true,
      },
      contexts: {
        Background: true,
        'Strategy Room': true,
        Devtools: true,
        'Content Script': true,
      },
      logSearch: '',
    },

    filterFuncs: {
      logTypes({ type }) {
        const { logTypes: isVisible } = KC3StrategyTabs.logger.definition.filterState;
        return isVisible[type];
      },
      contexts({ context }) {
        const { contexts: isVisible } = KC3StrategyTabs.logger.definition.filterState;
        return isVisible[context];
      },
      logSearch({ message, data, stack }) {
        const { logSearch } = KC3StrategyTabs.logger.definition.filterState;
        const { getCallsite } = KC3StrategyTabs.logger.definition;
        const searchString = logSearch.toLowerCase();
        const targets = message ? [message.concat(data)] : data;
        if (stack) {
          targets.push(getCallsite(stack).full);
        }
        return targets.some((target) => { return target.toLowerCase().includes(searchString); });
      },
    },

    /* INIT: mandatory
    Prepares initial static data needed.
    ---------------------------------*/
    init() {},

    /* EXECUTE: mandatory
    Places data onto the interface from scratch.
    ---------------------------------*/
    execute() {
      const { initStackToggle, initLogClearButton, initFilter, initPagination, logError,
        initSearchBox } = KC3StrategyTabs.logger.definition;
      return Promise.resolve()
        .then(initStackToggle)
        .then(initSearchBox)
        .then(initLogClearButton)
        .then(initFilter.bind(null, 'logTypes'))
        .then(initFilter.bind(null, 'contexts'))
        .then(initPagination)
        .catch(logError);
    },

    // --------------------------------------------------------------------- //
    // ------------------------[ INTERNAL METHODS ]------------------------- //
    // --------------------------------------------------------------------- //

    // -----------------------[ TOGGLE STACK TRACE ]------------------------ //

    initStackToggle() {
      $('.log_list').on('click', '.log_entry .summary', ({ currentTarget }) => {
        if ($(currentTarget).hasClass('hover')) {
          $(currentTarget).parent().children('.data').slideToggle(50);
          $(currentTarget).parent().children('.stack').slideToggle(50);
        }
      });
    },

    // ---------------------------[ SEARCH BOX ]---------------------------- //

    initSearchBox() {
      const { filterState, initPagination } = KC3StrategyTabs.logger.definition;
      const form = $('.tab_logger form#log_search');
      $('input', form).val(filterState.logSearch)
        .on('focus', () => {
          $('input', form).select();
        });
      form.submit(() => {
        // record search string
        filterState.logSearch = $('input', form).val();

        // reload log list
        initPagination();

        return false;
      });
    },

    // ------------------------[ CLEAR LOGS BUTTON ]------------------------ //

    initLogClearButton() {
      const { clearLogs, initPagination } = KC3StrategyTabs.logger.definition;
      $('.clear_logs').on('click', () => {
        clearLogs().then(initPagination);
      });
    },

    // ------------------------[ FILTER RENDERING ]------------------------- //

    initFilter(filterType) {
      const { renderFilter, initFilterStateListener, filterState } =
        KC3StrategyTabs.logger.definition;
      Object.keys(filterState[filterType]).forEach((key) => {
        renderFilter({ filterType, filterLabel: key, isVisible: filterState[filterType][key] });
      });
      initFilterStateListener(filterType);
    },

    renderFilter({ filterType, filterLabel, isVisible }) {
      const filter = $('.tab_logger .factory .entry_filter').clone();

      filter.children('.filter_label').html(filterLabel);
      filter.children('input').attr('checked', isVisible).attr('name', filterLabel);

      $(`.tab_logger [data-filter-type="${filterType}"`).append(filter);
    },

    initFilterStateListener(filterType) {
      const { initPagination, filterState } = KC3StrategyTabs.logger.definition;
      $(`.tab_logger [data-filter-type="${filterType}"] .entry_filter input:checkbox`).change(function () {
        // update filter state
        filterState[filterType][this.name] = this.checked;

        // reload log list
        initPagination();
      });
    },

    // ---------------------------[ PAGINATION ]---------------------------- //

    initPagination() {
      const { getEntryCount, ITEMS_PER_PAGE, showPagination } = KC3StrategyTabs.logger.definition;
      return getEntryCount()
        .then((entryCount) => {
          const pageCount = Math.ceil(entryCount / ITEMS_PER_PAGE);
          return showPagination(pageCount > 0 ? pageCount : 1);
        });
    },

    showPagination(pageCount) {
      const { VISIBLE_PAGES, renderPage } = KC3StrategyTabs.logger.definition;
      const element = $('.tab_logger .pagination');
      element.twbsPagination('destroy');
      element.twbsPagination({
        totalPages: pageCount,
        visiblePages: VISIBLE_PAGES,
        onPageClick(event, page) { renderPage(page); },
      });
    },

    renderPage(pageNum) {
      const { clearEntries, getLogEntries, splitByDate, renderElement } =
        KC3StrategyTabs.logger.definition;
      return Promise.resolve()
        .then(getLogEntries.bind(null, pageNum))
        .then(splitByDate)
        .then((elements) => {
          clearEntries();
          elements.forEach(renderElement);
        });
    },

    // ----------------------------[ DATABASE ]----------------------------- //

    getEntryCount() {
      const { composeFilters } = KC3StrategyTabs.logger.definition;
      return KC3Database.count_log_entries(composeFilters());
    },

    getLogEntries(pageNumber) {
      const { ITEMS_PER_PAGE, composeFilters } = KC3StrategyTabs.logger.definition;
      return KC3Database.get_log_entries({
        pageNumber,
        itemsPerPage: ITEMS_PER_PAGE,
        filters: composeFilters(),
      });
    },

    clearLogs() {
      return KC3Database.delete_log_entries();
    },

    composeFilters() {
      const { filterFuncs } = KC3StrategyTabs.logger.definition;
      return Object.keys(filterFuncs).map(key => filterFuncs[key]);
    },

    // -------------------------[ SPLIT BY DATES ]-------------------------- //

    splitByDate(logEntries) {
      if (!logEntries || logEntries.length === 0) { return []; }
      const { isDateSplit, createDateSeparator } = KC3StrategyTabs.logger.definition;

      return logEntries.reduce((result, entry, index) => {
        if (index > 0 && isDateSplit(logEntries[index - 1], entry)) {
          result.push(createDateSeparator(entry));
        }

        result.push(entry);

        return result;
      }, [createDateSeparator(logEntries[0])]);
    },

    isDateSplit({ timestamp: t1 }, { timestamp: t2 }) {
      const d1 = new Date(t1);
      const d2 = new Date(t2);
      return d1.getDate() !== d2.getDate();
    },

    createDateSeparator({ timestamp }) {
      return {
        type: 'dateSeparator',
        timestamp,
      };
    },

    // --------------------------[ RENDERING ]------------------------------ //

    renderElement(element = {}) {
      const { elementFactory } = KC3StrategyTabs.logger.definition;
      const { type } = element;
      if (!elementFactory[type]) {
        throw new Error(`Bad log entry: ${JSON.stringify(element)}`);
      }
      elementFactory[type].create(element);
    },

    elementFactory: {
      error: {
        create(spec) {
          const { renderLogEntry, defineEntryStack, formatStack } =
            KC3StrategyTabs.logger.definition;
          const entry = renderLogEntry(spec);
          defineEntryStack(entry, formatStack(spec.stack));
        },
      },
      warn: {
        create(spec) {
          const { renderLogEntry, defineEntryStack, formatStack } =
            KC3StrategyTabs.logger.definition;
          const entry = renderLogEntry(spec);
          defineEntryStack(entry, formatStack(spec.stack));
        },
      },
      info: {
        create(spec) {
          const { renderLogEntry } = KC3StrategyTabs.logger.definition;
          renderLogEntry(spec);
        },
      },
      log: {
        create(spec) {
          const { renderLogEntry } = KC3StrategyTabs.logger.definition;
          renderLogEntry(spec);
        },
      },
      dateSeparator: {
        create({ timestamp }) {
          const { createEntry, defineEntryProps } = KC3StrategyTabs.logger.definition;

          const entry = createEntry('date_separator');
          defineEntryProps(entry, { date: new Date(timestamp).format('isoDate') });
        },
      },
    },

    renderLogEntry({ type, timestamp, message, data, context, stack }) {
      const { createEntry, setEntryBackground, defineEntryProps, defineEntryDataArray,
        defineEntrySource, getCallsite } = KC3StrategyTabs.logger.definition;

      const entry = createEntry('log_entry');
      setEntryBackground(entry, type);
      defineEntryProps(entry, {
        message,
        context,
        timestamp: new Date(timestamp).format('isoTime'),
        dataline: data.join(' ').substr(0, 72),
      });
      defineEntryDataArray(entry, data);
      defineEntrySource(entry, getCallsite(stack));

      return entry;
    },

    createEntry(classId) {
      const result = $(`.tab_logger .factory .${classId}`).clone();
      $('.tab_logger .log_list').append(result);
      return result;
    },

    setEntryBackground(entry, logLevel) {
      switch (logLevel) {
        case 'error':
          entry.addClass('bg-danger');
          break;
        case 'warn':
          entry.addClass('bg-warning');
          break;
        case 'info':
          entry.addClass('bg-info');
          break;
        case 'log':
          entry.addClass('bg-success');
          break;
        default:
          /* do nothing */
      }
    },

    defineEntryProps(entry, props) {
      Object.keys(props).forEach((key) => {
        $(`.${key}`, entry).text(props[key]);
      });
    },

    defineEntryDataArray(entry, data) {
      const dataAnchor = $('.data', entry);
      data.forEach((d, index) => {
        if (index !== 0) {
          dataAnchor.append('<hr />');
        }
        $(document.createElement('div')).text(d).appendTo(dataAnchor);
      });
      $('.summary', dataAnchor.parent()).toggleClass('hover', data.length > 0);
    },

    defineEntrySource(entry, { short, full }) {
      $('.source', entry).text(short || 'n/a').attr('title', full);
    },

    defineEntryStack(entry, stack) {
      const stackAnchor = $('.stack', entry);
      $(document.createElement('div')).text(stack).appendTo(stackAnchor);
      $('.summary', stackAnchor.parent()).addClass('hover');
    },

    clearEntries() {
      $('.tab_logger .log_list').empty();
    },

    // ----------------------[ STRING FORMATTING ]-------------------------- //

    getCallsite(stack) {
      const { formatStack } = KC3StrategyTabs.logger.definition;

      const top = formatStack(stack).split(/\r?\n/)[1];
      if (!top) { return { full: '?', short: '?' }; }

      const full = top.indexOf(' (') > -1 ?
        // named func
        top.split(' (')[1].trimRight().slice(0, -1) :
        // anonymous func
        top.split('at ')[1];
      return {
        full,
        short: full.substring(full.lastIndexOf('/') + 1, ((full.lastIndexOf(':') + 1) || (full.length + 1)) - 1),
      };
    },

    // Remove the chrome-extension prefix from the stack trace to save space
    formatStack(stack) {
      return (stack || '')
        .replace(/chrome-extension:\/\/[^/]+\//g, 'src/');
    },

    logError(error) {
      KC3Log.console.error(error, error.stack);
    },
  };
}());

<commit_msg>Revert logger page hash param try<commit_after>(function () {
  'use strict';

  KC3StrategyTabs.logger = new KC3StrategyTab('logger');

  KC3StrategyTabs.logger.definition = {
    ITEMS_PER_PAGE: 20,
    VISIBLE_PAGES: 9,

    filterState: {
      logTypes: {
        log: true,
        info: true,
        warn: true,
        error: true,
      },
      contexts: {
        'Background': true,
        'Strategy Room': true,
        'Devtools': true,
        'Content Script': true,
      },
      logSearch: '',
    },

    filterFuncs: {
      logTypes({ type }) {
        const { logTypes: isVisible } = KC3StrategyTabs.logger.definition.filterState;
        return isVisible[type];
      },
      contexts({ context }) {
        const { contexts: isVisible } = KC3StrategyTabs.logger.definition.filterState;
        return isVisible[context];
      },
      logSearch({ message, data, stack }) {
        const { logSearch } = KC3StrategyTabs.logger.definition.filterState;
        const { getCallsite } = KC3StrategyTabs.logger.definition;
        const searchString = logSearch.toLowerCase();
        const targets = message ? [message.concat(data)] : data;
        if (stack) {
          targets.push(getCallsite(stack).full);
        }
        return targets.some((target) => { return target.toLowerCase().includes(searchString); });
      },
    },

    /* INIT: mandatory
    Prepares initial static data needed.
    ---------------------------------*/
    init() {},

    /* EXECUTE: mandatory
    Places data onto the interface from scratch.
    ---------------------------------*/
    execute() {
      const { initStackToggle, initLogClearButton, initFilter, initPagination, logError,
        initSearchBox } = KC3StrategyTabs.logger.definition;
      return Promise.resolve()
        .then(initStackToggle)
        .then(initSearchBox)
        .then(initLogClearButton)
        .then(initFilter.bind(this, 'logTypes'))
        .then(initFilter.bind(this, 'contexts'))
        .then(initPagination)
        .catch(logError);
    },

    // --------------------------------------------------------------------- //
    // ------------------------[ INTERNAL METHODS ]------------------------- //
    // --------------------------------------------------------------------- //

    // -----------------------[ TOGGLE STACK TRACE ]------------------------ //

    initStackToggle() {
      $('.log_list').on('click', '.log_entry .summary', ({ currentTarget }) => {
        if ($(currentTarget).hasClass('hover')) {
          $(currentTarget).parent().children('.data').slideToggle(50);
          $(currentTarget).parent().children('.stack').slideToggle(50);
        }
      });
    },

    // ---------------------------[ SEARCH BOX ]---------------------------- //

    initSearchBox() {
      const { filterState, initPagination } = KC3StrategyTabs.logger.definition;
      const form = $('.tab_logger form#log_search');
      $('input', form).val(filterState.logSearch)
        .on('focus', () => {
          $('input', form).select();
        });
      form.submit(() => {
        // record search string
        filterState.logSearch = $('input', form).val();

        // reload log list
        initPagination();

        return false;
      });
    },

    // ------------------------[ CLEAR LOGS BUTTON ]------------------------ //

    initLogClearButton() {
      const { clearLogs, initPagination } = KC3StrategyTabs.logger.definition;
      $('.clear_logs').on('click', () => {
        clearLogs().then(initPagination);
      });
    },

    // ------------------------[ FILTER RENDERING ]------------------------- //

    initFilter(filterType) {
      const { renderFilter, initFilterStateListener, filterState } =
        KC3StrategyTabs.logger.definition;
      Object.keys(filterState[filterType]).forEach((key) => {
        renderFilter({ filterType, filterLabel: key, isVisible: filterState[filterType][key] });
      });
      initFilterStateListener(filterType);
    },

    renderFilter({ filterType, filterLabel, isVisible }) {
      const filter = $('.tab_logger .factory .entry_filter').clone();

      filter.children('.filter_label').html(filterLabel);
      filter.children('input').attr('checked', isVisible).attr('name', filterLabel);

      $(`.tab_logger [data-filter-type="${filterType}"`).append(filter);
    },

    initFilterStateListener(filterType) {
      const { initPagination, filterState } = KC3StrategyTabs.logger.definition;
      $(`.tab_logger [data-filter-type="${filterType}"] .entry_filter input:checkbox`).change(function () {
        // update filter state
        filterState[filterType][this.name] = this.checked;

        // reload log list
        initPagination();
      });
    },

    // ---------------------------[ PAGINATION ]---------------------------- //

    initPagination() {
      const { getEntryCount, ITEMS_PER_PAGE, showPagination } = KC3StrategyTabs.logger.definition;
      return getEntryCount()
        .then((entryCount) => {
          const pageCount = Math.ceil(entryCount / ITEMS_PER_PAGE);
          return showPagination(pageCount > 0 ? pageCount : 1);
        });
    },

    showPagination(pageCount) {
      const { VISIBLE_PAGES, renderPage } = KC3StrategyTabs.logger.definition;
      const element = $('.tab_logger .pagination');
      element.twbsPagination('destroy');
      element.twbsPagination({
        totalPages: pageCount,
        visiblePages: VISIBLE_PAGES,
        onPageClick(event, page) {
          renderPage(page);
        },
      });
    },

    renderPage(pageNum) {
      const { clearEntries, getLogEntries, splitByDate, renderElement } =
        KC3StrategyTabs.logger.definition;
      return Promise.resolve()
        .then(getLogEntries.bind(this, pageNum))
        .then(splitByDate)
        .then((elements) => {
          clearEntries();
          elements.forEach(renderElement);
        });
    },

    // ----------------------------[ DATABASE ]----------------------------- //

    getEntryCount() {
      const { composeFilters } = KC3StrategyTabs.logger.definition;
      return KC3Database.count_log_entries(composeFilters());
    },

    getLogEntries(pageNumber) {
      const { ITEMS_PER_PAGE, composeFilters } = KC3StrategyTabs.logger.definition;
      return KC3Database.get_log_entries({
        pageNumber,
        itemsPerPage: ITEMS_PER_PAGE,
        filters: composeFilters(),
      });
    },

    clearLogs() {
      return KC3Database.delete_log_entries();
    },

    composeFilters() {
      const { filterFuncs } = KC3StrategyTabs.logger.definition;
      return Object.keys(filterFuncs).map(key => filterFuncs[key]);
    },

    // -------------------------[ SPLIT BY DATES ]-------------------------- //

    splitByDate(logEntries) {
      if (!logEntries || logEntries.length === 0) { return []; }
      const { isDateSplit, createDateSeparator } = KC3StrategyTabs.logger.definition;

      return logEntries.reduce((result, entry, index) => {
        if (index > 0 && isDateSplit(logEntries[index - 1], entry)) {
          result.push(createDateSeparator(entry));
        }

        result.push(entry);

        return result;
      }, [createDateSeparator(logEntries[0])]);
    },

    isDateSplit({ timestamp: t1 }, { timestamp: t2 }) {
      const d1 = new Date(t1);
      const d2 = new Date(t2);
      return d1.getDate() !== d2.getDate();
    },

    createDateSeparator({ timestamp }) {
      return {
        type: 'dateSeparator',
        timestamp,
      };
    },

    // --------------------------[ RENDERING ]------------------------------ //

    renderElement(element = {}) {
      const { elementFactory } = KC3StrategyTabs.logger.definition;
      const { type } = element;
      if (!elementFactory[type]) {
        throw new Error(`Bad log entry: ${JSON.stringify(element)}`);
      }
      elementFactory[type].create(element);
    },

    elementFactory: {
      error: {
        create(spec) {
          const { renderLogEntry, defineEntryStack, formatStack } =
            KC3StrategyTabs.logger.definition;
          const entry = renderLogEntry(spec);
          defineEntryStack(entry, formatStack(spec.stack));
        },
      },
      warn: {
        create(spec) {
          const { renderLogEntry, defineEntryStack, formatStack } =
            KC3StrategyTabs.logger.definition;
          const entry = renderLogEntry(spec);
          defineEntryStack(entry, formatStack(spec.stack));
        },
      },
      info: {
        create(spec) {
          const { renderLogEntry } = KC3StrategyTabs.logger.definition;
          renderLogEntry(spec);
        },
      },
      log: {
        create(spec) {
          const { renderLogEntry } = KC3StrategyTabs.logger.definition;
          renderLogEntry(spec);
        },
      },
      dateSeparator: {
        create({ timestamp }) {
          const { createEntry, defineEntryProps } = KC3StrategyTabs.logger.definition;

          const entry = createEntry('date_separator');
          defineEntryProps(entry, { date: new Date(timestamp).format('isoDate') });
        },
      },
    },

    renderLogEntry({ type, timestamp, message, data, context, stack }) {
      const { createEntry, setEntryBackground, defineEntryProps, defineEntryDataArray,
        defineEntrySource, getCallsite } = KC3StrategyTabs.logger.definition;

      const entry = createEntry('log_entry');
      setEntryBackground(entry, type);
      defineEntryProps(entry, {
        message,
        context,
        timestamp: new Date(timestamp).format('isoTime'),
        dataline: data.join(' ').substr(0, 72),
      });
      defineEntryDataArray(entry, data);
      defineEntrySource(entry, getCallsite(stack));

      return entry;
    },

    createEntry(classId) {
      const result = $(`.tab_logger .factory .${classId}`).clone();
      $('.tab_logger .log_list').append(result);
      return result;
    },

    setEntryBackground(entry, logLevel) {
      switch (logLevel) {
        case 'error':
          entry.addClass('bg-danger');
          break;
        case 'warn':
          entry.addClass('bg-warning');
          break;
        case 'info':
          entry.addClass('bg-info');
          break;
        case 'log':
          entry.addClass('bg-success');
          break;
        default:
          /* do nothing */
      }
    },

    defineEntryProps(entry, props) {
      Object.keys(props).forEach((key) => {
        $(`.${key}`, entry).text(props[key]);
      });
    },

    defineEntryDataArray(entry, data) {
      const dataAnchor = $('.data', entry);
      data.forEach((d, index) => {
        if (index !== 0) {
          dataAnchor.append('<hr />');
        }
        $(document.createElement('div')).text(d).appendTo(dataAnchor);
      });
      $('.summary', dataAnchor.parent()).toggleClass('hover', data.length > 0);
    },

    defineEntrySource(entry, { short, full }) {
      $('.source', entry).text(short || 'n/a').attr('title', full);
    },

    defineEntryStack(entry, stack) {
      const stackAnchor = $('.stack', entry);
      $(document.createElement('div')).text(stack).appendTo(stackAnchor);
      $('.summary', stackAnchor.parent()).addClass('hover');
    },

    clearEntries() {
      $('.tab_logger .log_list').empty();
    },

    // ----------------------[ STRING FORMATTING ]-------------------------- //

    getCallsite(stack) {
      const { formatStack } = KC3StrategyTabs.logger.definition;

      const top = formatStack(stack).split(/\r?\n/)[1];
      if (!top) { return { full: '?', short: '?' }; }

      const full = top.indexOf(' (') > -1 ?
        // named func
        top.split(' (')[1].trimRight().slice(0, -1) :
        // anonymous func
        top.split('at ')[1];
      return {
        full,
        short: full.substring(full.lastIndexOf('/') + 1, ((full.lastIndexOf(':') + 1) || (full.length + 1)) - 1),
      };
    },

    // Remove the chrome-extension prefix from the stack trace to save space
    formatStack(stack) {
      return (stack || '')
        .replace(/chrome-extension:\/\/[^/]+\//g, 'src/');
    },

    logError(error) {
      KC3Log.console.error(error, error.stack);
    },

  };
}());

<|endoftext|>


<commit_before>/**
## # Line Chart [Concrete] < [Stackable Chart](#stackable-chart) < [CoordinateGrid Chart](#coordinate-grid-chart)
Concrete line/area chart implementation.

Examples:
* [Nasdaq 100 Index](http://nickqizhu.github.com/dc.js/)
* [Canadian City Crime Stats](http://nickqizhu.github.com/dc.js/crime/index.html)

#### dc.lineChart(parent[, chartGroup])
Create a line chart instance and attach it to the given parent element.

Parameters:

* parent : string|compositeChart - any valid d3 single selector representing typically a dom block element such
   as a div, or if this line chart is a sub-chart in a [Composite Chart](#composite-chart) then pass in the parent composite chart instance.
* chartGroup : string (optional) - name of the chart group this chart instance should be placed in. Once a chart is placed
   in a certain chart group then any interaction with such instance will only trigger events and redraw within the same
   chart group.

Return:
A newly created line chart instance

```js
// create a line chart under #chart-container1 element using the default global chart group
var chart1 = dc.lineChart("#chart-container1");
// create a line chart under #chart-container2 element using chart group A
var chart2 = dc.lineChart("#chart-container2", "chartGroupA");
// create a sub-chart under a composite parent chart
var chart3 = dc.lineChart(compositeChart);
```

**/
dc.lineChart = function (parent, chartGroup) {
    var DEFAULT_DOT_RADIUS = 5;
    var TOOLTIP_G_CLASS = "dc-tooltip";
    var DOT_CIRCLE_CLASS = "dot";
    var Y_AXIS_REF_LINE_CLASS = "yRef";
    var X_AXIS_REF_LINE_CLASS = "xRef";
    var DEFAULT_DOT_OPACITY = 1e-6;

    var _chart = dc.stackableChart(dc.coordinateGridChart({}));
    var _renderArea = false;
    var _dotRadius = DEFAULT_DOT_RADIUS;
    var _dataPointRadius = null;
    var _dataPointFillOpacity = DEFAULT_DOT_OPACITY;
    var _dataPointStrokeOpacity = DEFAULT_DOT_OPACITY;
    var _interpolate = 'linear';
    var _tension = 0.7;
    var _defined;
    var _dashStyle = [];

    _chart.transitionDuration(500);

    _chart.plotData = function () {
        var chartBody = _chart.chartBodyG();
        var layersList = chartBody.selectAll("g.stack-list");

        if (layersList.empty()) layersList = chartBody.append("g").attr("class", "stack-list");

        var layers = layersList.selectAll("g.stack").data(_chart.stackLayers());

        var layersEnter = layers
            .enter()
            .append("g")
            .attr("class", function (d, i) {
                return "stack " + "_" + i;
            });

        drawLine(layersEnter, layers);

        drawArea(layersEnter, layers);

        drawDots(chartBody, layers);

        _chart.stackLayers(null);
    };

    _chart.interpolate = function(_){
        if (!arguments.length) return _interpolate;
        _interpolate = _;
        return _chart;
    };

    _chart.tension = function(_){
        if (!arguments.length) return _tension;
        _tension = _;
        return _chart;
    };

    _chart.defined = function(_){
        if (!arguments.length) return _defined;
        _defined = _;
        return _chart;
    };
    /**
    #### .dashStyle([array])
    Set the line's d3 dashstyle. This value becomes "stroke-dasharray" of line. Defaults to empty array (solid line).
     ```js
     // create a Dash Dot Dot Dot
     chart.dashStyle([3,1,1,1]);
     ```
    **/
    _chart.dashStyle = function (_) {
        if (!arguments.length) return _dashStyle;
        _dashStyle = _;
        return _chart;
    };

    /**
    #### .renderArea([boolean])
    Get or set render area flag. If the flag is set to true then the chart will render the area beneath each line and effectively
    becomes an area chart.

    **/
    _chart.renderArea = function (_) {
        if (!arguments.length) return _renderArea;
        _renderArea = _;
        return _chart;
    };

    function drawLine(layersEnter, layers) {
        var line = d3.svg.line()
            .x(function (d) {
                return _chart.x()(d.x);
            })
            .y(function (d) {
                return _chart.y()(d.y + d.y0);
            })
            .interpolate(_interpolate)
            .tension(_tension);
        if (_defined)
            line.defined(_defined);

        layersEnter.append("path")
            .attr("class", "line")
            .attr("stroke", _chart.getColor)
            .attr("fill", _chart.getColor)
            .attr("stroke-dasharray", _dashStyle);

        dc.transition(layers.select("path.line"), _chart.transitionDuration())
            .attr("d", function (d) {
                return safeD(line(d.points));
            });
    }

    function drawArea(layersEnter, layers) {
        if (_renderArea) {
            var area = d3.svg.area()
                .x(function (d) {
                    return _chart.x()(d.x);
                })
                .y(function (d) {
                    return _chart.y()(d.y + d.y0);
                })
                .y0(function (d) {
                    return _chart.y()(d.y0);
                })
                .interpolate(_interpolate)
                .tension(_tension);
            if (_defined)
                area.defined(_defined);

            layersEnter.append("path")
                .attr("class", "area")
                .attr("fill", _chart.getColor)
                .attr("d", function (d) {
                    return safeD(area(d.points));
                });

            dc.transition(layers.select("path.area"), _chart.transitionDuration())
                .attr("d", function (d) {
                    return safeD(area(d.points));
                });
        }
    }

    function safeD(d){
        return (!d || d.indexOf("NaN") >= 0) ? "M0,0" : d;
    }

    function drawDots(chartBody, layers) {
        if (!_chart.brushOn()) {

            var tooltipListClass = TOOLTIP_G_CLASS + "-list";
            var tooltips = chartBody.select("g." + tooltipListClass);

            if (tooltips.empty()) tooltips = chartBody.append("g").attr("class", tooltipListClass);

            layers.each(function (d, layerIndex) {
                var layer = d3.select(this);
                var points = layer.datum().points;
                if (_defined) points = points.filter(_defined);

                var g = tooltips.select("g." + TOOLTIP_G_CLASS + "._" + layerIndex);
                if (g.empty()) g = tooltips.append("g").attr("class", TOOLTIP_G_CLASS + " _" + layerIndex);

                createRefLines(g);

                var dots = g.selectAll("circle." + DOT_CIRCLE_CLASS).data(points);

                dots.enter()
                    .append("circle")
                    .attr("class", DOT_CIRCLE_CLASS)
                    .attr("r", _dataPointRadius || _dotRadius)
                    .attr("fill", _chart.getColor) //function() {return _chart.colorCalculator()(layerIndex);})
                    .style("fill-opacity", _dataPointFillOpacity)
                    .style("stroke-opacity", _dataPointStrokeOpacity)
                    .on("mousemove", function (d) {
                        var dot = d3.select(this);
                        showDot(dot);
                        showRefLines(dot, g);
                    })
                    .on("mouseout", function (d) {
                        var dot = d3.select(this);
                        hideDot(dot);
                        hideRefLines(g);
                    })
                    .append("title").text(dc.pluck('data', _chart.getTitleByIndex(layerIndex)));

                dots.attr("cx", function (d) {
                        return dc.utils.safeNumber(_chart.x()(d.x));
                    })
                    .attr("cy", function (d) {
                        return dc.utils.safeNumber(_chart.y()(d.y + d.y0));
                    })
                    .select("title").text(dc.pluck('data', _chart.getTitleByIndex(layerIndex)));

                dots.exit().remove();
            });
        }
    }

    function createRefLines(g) {
        var yRefLine = g.select("path." + Y_AXIS_REF_LINE_CLASS).empty() ? g.append("path").attr("class", Y_AXIS_REF_LINE_CLASS) : g.select("path." + Y_AXIS_REF_LINE_CLASS);
        yRefLine.style("display", "none").attr("stroke-dasharray", "5,5");

        var xRefLine = g.select("path." + X_AXIS_REF_LINE_CLASS).empty() ? g.append("path").attr("class", X_AXIS_REF_LINE_CLASS) : g.select("path." + X_AXIS_REF_LINE_CLASS);
        xRefLine.style("display", "none").attr("stroke-dasharray", "5,5");
    }

    function showDot(dot) {
        dot.style("fill-opacity", 0.8);
        dot.style("stroke-opacity", 0.8);
        dot.attr("r", _dotRadius);
        return dot;
    }

    function showRefLines(dot, g) {
        var x = dot.attr("cx");
        var y = dot.attr("cy");
        g.select("path." + Y_AXIS_REF_LINE_CLASS).style("display", "").attr("d", "M0 " + y + "L" + (x) + " " + (y));
        g.select("path." + X_AXIS_REF_LINE_CLASS).style("display", "").attr("d", "M" + x + " " + _chart.yAxisHeight() + "L" + x + " " + y);
    }

    function hideDot(dot) {
        dot.style("fill-opacity", _dataPointFillOpacity)
            .style("stroke-opacity", _dataPointStrokeOpacity)
            .attr("r", _dataPointRadius);
    }

    function hideRefLines(g) {
        g.select("path." + Y_AXIS_REF_LINE_CLASS).style("display", "none");
        g.select("path." + X_AXIS_REF_LINE_CLASS).style("display", "none");
    }

    /**
    #### .dotRadius([dotRadius])
    Get or set the radius (in px) for data points. Default dot radius is 5.
    **/
    _chart.dotRadius = function (_) {
        if (!arguments.length) return _dotRadius;
        _dotRadius = _;
        return _chart;
    };

    /**
    #### .renderDataPoints([options])
    Always show individual dots for each datapoint.

    Options, if given, is an object that can contain the following:

    * fillOpacity (default 0.8)
    * strokeOpacity (default 0.8)
    * radius (default 2)

    If `options` is falsy, it disable data point rendering.

    If no `options` are provded, the current `options` values are instead returned

    Example:
    ```
    chart.renderDataPoints([{radius: 2, fillOpacity: 0.8, strokeOpacity: 0.8}])
    ```
    **/
    _chart.renderDataPoints = function (options) {
        if (!arguments.length) {
            return {
                fillOpacity: _dataPointFillOpacity,
                strokeOpacity: _dataPointStrokeOpacity,
                radius: _dataPointRadius
            };
        } else if (!options) {
            _dataPointFillOpacity = DEFAULT_DOT_OPACITY;
            _dataPointStrokeOpacity = DEFAULT_DOT_OPACITY;
            _dataPointRadius = null;
        } else {
            _dataPointFillOpacity = options.fillOpacity || 0.8;
            _dataPointStrokeOpacity = options.strokeOpacity || 0.8;
            _dataPointRadius = options.radius || 2;
        }
        return _chart;
    };

    _chart.legendHighlight = function (d) {
        _chart.selectAll('.chart-body').selectAll('path').filter(function () {
            return d3.select(this).attr('fill') == d.color;
        }).classed('highlight', true);
        _chart.selectAll('.chart-body').selectAll('path').filter(function () {
            return d3.select(this).attr('fill') != d.color;
        }).classed('fadeout', true);
    };

    _chart.legendReset = function (d) {
        _chart.selectAll('.chart-body').selectAll('path').filter(function () {
            return d3.select(this).attr('fill') == d.color;
        }).classed('highlight', false);
        _chart.selectAll('.chart-body').selectAll('path').filter(function () {
            return d3.select(this).attr('fill') != d.color;
        }).classed('fadeout', false);
    };

    return _chart.anchor(parent, chartGroup);
};
<commit_msg>fix to dots color on line chart<commit_after>/**
## # Line Chart [Concrete] < [Stackable Chart](#stackable-chart) < [CoordinateGrid Chart](#coordinate-grid-chart)
Concrete line/area chart implementation.

Examples:
* [Nasdaq 100 Index](http://nickqizhu.github.com/dc.js/)
* [Canadian City Crime Stats](http://nickqizhu.github.com/dc.js/crime/index.html)

#### dc.lineChart(parent[, chartGroup])
Create a line chart instance and attach it to the given parent element.

Parameters:

* parent : string|compositeChart - any valid d3 single selector representing typically a dom block element such
   as a div, or if this line chart is a sub-chart in a [Composite Chart](#composite-chart) then pass in the parent composite chart instance.
* chartGroup : string (optional) - name of the chart group this chart instance should be placed in. Once a chart is placed
   in a certain chart group then any interaction with such instance will only trigger events and redraw within the same
   chart group.

Return:
A newly created line chart instance

```js
// create a line chart under #chart-container1 element using the default global chart group
var chart1 = dc.lineChart("#chart-container1");
// create a line chart under #chart-container2 element using chart group A
var chart2 = dc.lineChart("#chart-container2", "chartGroupA");
// create a sub-chart under a composite parent chart
var chart3 = dc.lineChart(compositeChart);
```

**/
dc.lineChart = function (parent, chartGroup) {
    var DEFAULT_DOT_RADIUS = 5;
    var TOOLTIP_G_CLASS = "dc-tooltip";
    var DOT_CIRCLE_CLASS = "dot";
    var Y_AXIS_REF_LINE_CLASS = "yRef";
    var X_AXIS_REF_LINE_CLASS = "xRef";
    var DEFAULT_DOT_OPACITY = 1e-6;

    var _chart = dc.stackableChart(dc.coordinateGridChart({}));
    var _renderArea = false;
    var _dotRadius = DEFAULT_DOT_RADIUS;
    var _dataPointRadius = null;
    var _dataPointFillOpacity = DEFAULT_DOT_OPACITY;
    var _dataPointStrokeOpacity = DEFAULT_DOT_OPACITY;
    var _interpolate = 'linear';
    var _tension = 0.7;
    var _defined;
    var _dashStyle = [];

    _chart.transitionDuration(500);

    _chart.plotData = function () {
        var chartBody = _chart.chartBodyG();
        var layersList = chartBody.selectAll("g.stack-list");

        if (layersList.empty()) layersList = chartBody.append("g").attr("class", "stack-list");

        var layers = layersList.selectAll("g.stack").data(_chart.stackLayers());

        var layersEnter = layers
            .enter()
            .append("g")
            .attr("class", function (d, i) {
                return "stack " + "_" + i;
            });

        drawLine(layersEnter, layers);

        drawArea(layersEnter, layers);

        drawDots(chartBody, layers);

        _chart.stackLayers(null);
    };

    _chart.interpolate = function(_){
        if (!arguments.length) return _interpolate;
        _interpolate = _;
        return _chart;
    };

    _chart.tension = function(_){
        if (!arguments.length) return _tension;
        _tension = _;
        return _chart;
    };

    _chart.defined = function(_){
        if (!arguments.length) return _defined;
        _defined = _;
        return _chart;
    };
    /**
    #### .dashStyle([array])
    Set the line's d3 dashstyle. This value becomes "stroke-dasharray" of line. Defaults to empty array (solid line).
     ```js
     // create a Dash Dot Dot Dot
     chart.dashStyle([3,1,1,1]);
     ```
    **/
    _chart.dashStyle = function (_) {
        if (!arguments.length) return _dashStyle;
        _dashStyle = _;
        return _chart;
    };

    /**
    #### .renderArea([boolean])
    Get or set render area flag. If the flag is set to true then the chart will render the area beneath each line and effectively
    becomes an area chart.

    **/
    _chart.renderArea = function (_) {
        if (!arguments.length) return _renderArea;
        _renderArea = _;
        return _chart;
    };

    function drawLine(layersEnter, layers) {
        var line = d3.svg.line()
            .x(function (d) {
                return _chart.x()(d.x);
            })
            .y(function (d) {
                return _chart.y()(d.y + d.y0);
            })
            .interpolate(_interpolate)
            .tension(_tension);
        if (_defined)
            line.defined(_defined);

        layersEnter.append("path")
            .attr("class", "line")
            .attr("stroke", _chart.getColor)
            .attr("fill", _chart.getColor)
            .attr("stroke-dasharray", _dashStyle);

        dc.transition(layers.select("path.line"), _chart.transitionDuration())
            .attr("d", function (d) {
                return safeD(line(d.points));
            });
    }

    function drawArea(layersEnter, layers) {
        if (_renderArea) {
            var area = d3.svg.area()
                .x(function (d) {
                    return _chart.x()(d.x);
                })
                .y(function (d) {
                    return _chart.y()(d.y + d.y0);
                })
                .y0(function (d) {
                    return _chart.y()(d.y0);
                })
                .interpolate(_interpolate)
                .tension(_tension);
            if (_defined)
                area.defined(_defined);

            layersEnter.append("path")
                .attr("class", "area")
                .attr("fill", _chart.getColor)
                .attr("d", function (d) {
                    return safeD(area(d.points));
                });

            dc.transition(layers.select("path.area"), _chart.transitionDuration())
                .attr("d", function (d) {
                    return safeD(area(d.points));
                });
        }
    }

    function safeD(d){
        return (!d || d.indexOf("NaN") >= 0) ? "M0,0" : d;
    }

    function drawDots(chartBody, layers) {
        if (!_chart.brushOn()) {

            var tooltipListClass = TOOLTIP_G_CLASS + "-list";
            var tooltips = chartBody.select("g." + tooltipListClass);

            if (tooltips.empty()) tooltips = chartBody.append("g").attr("class", tooltipListClass);

            layers.each(function (d, layerIndex) {
                var layer = d3.select(this);
                var points = layer.datum().points;
                if (_defined) points = points.filter(_defined);

                var g = tooltips.select("g." + TOOLTIP_G_CLASS + "._" + layerIndex);
                if (g.empty()) g = tooltips.append("g").attr("class", TOOLTIP_G_CLASS + " _" + layerIndex);

                createRefLines(g);

                var dots = g.selectAll("circle." + DOT_CIRCLE_CLASS).data(points);

                dots.enter()
                    .append("circle")
                    .attr("class", DOT_CIRCLE_CLASS)
                    .attr("r", _dataPointRadius || _dotRadius)
                    .attr("fill", _chart.getColor)
                    .style("fill-opacity", _dataPointFillOpacity)
                    .style("stroke-opacity", _dataPointStrokeOpacity)
                    .on("mousemove", function (d) {
                        var dot = d3.select(this);
                        showDot(dot);
                        showRefLines(dot, g);
                    })
                    .on("mouseout", function (d) {
                        var dot = d3.select(this);
                        hideDot(dot);
                        hideRefLines(g);
                    })
                    .append("title").text(dc.pluck('data', _chart.getTitleByIndex(layerIndex)));

                dots.attr("cx", function (d) {
                        return dc.utils.safeNumber(_chart.x()(d.x));
                    })
                    .attr("cy", function (d) {
                        return dc.utils.safeNumber(_chart.y()(d.y + d.y0));
                    })
                    .select("title").text(dc.pluck('data', _chart.getTitleByIndex(layerIndex)));

                dots.exit().remove();
            });
        }
    }

    function createRefLines(g) {
        var yRefLine = g.select("path." + Y_AXIS_REF_LINE_CLASS).empty() ? g.append("path").attr("class", Y_AXIS_REF_LINE_CLASS) : g.select("path." + Y_AXIS_REF_LINE_CLASS);
        yRefLine.style("display", "none").attr("stroke-dasharray", "5,5");

        var xRefLine = g.select("path." + X_AXIS_REF_LINE_CLASS).empty() ? g.append("path").attr("class", X_AXIS_REF_LINE_CLASS) : g.select("path." + X_AXIS_REF_LINE_CLASS);
        xRefLine.style("display", "none").attr("stroke-dasharray", "5,5");
    }

    function showDot(dot) {
        dot.style("fill-opacity", 0.8);
        dot.style("stroke-opacity", 0.8);
        dot.attr("r", _dotRadius);
        return dot;
    }

    function showRefLines(dot, g) {
        var x = dot.attr("cx");
        var y = dot.attr("cy");
        g.select("path." + Y_AXIS_REF_LINE_CLASS).style("display", "").attr("d", "M0 " + y + "L" + (x) + " " + (y));
        g.select("path." + X_AXIS_REF_LINE_CLASS).style("display", "").attr("d", "M" + x + " " + _chart.yAxisHeight() + "L" + x + " " + y);
    }

    function hideDot(dot) {
        dot.style("fill-opacity", _dataPointFillOpacity)
            .style("stroke-opacity", _dataPointStrokeOpacity)
            .attr("r", _dataPointRadius);
    }

    function hideRefLines(g) {
        g.select("path." + Y_AXIS_REF_LINE_CLASS).style("display", "none");
        g.select("path." + X_AXIS_REF_LINE_CLASS).style("display", "none");
    }

    /**
    #### .dotRadius([dotRadius])
    Get or set the radius (in px) for data points. Default dot radius is 5.
    **/
    _chart.dotRadius = function (_) {
        if (!arguments.length) return _dotRadius;
        _dotRadius = _;
        return _chart;
    };

    /**
    #### .renderDataPoints([options])
    Always show individual dots for each datapoint.

    Options, if given, is an object that can contain the following:

    * fillOpacity (default 0.8)
    * strokeOpacity (default 0.8)
    * radius (default 2)

    If `options` is falsy, it disable data point rendering.

    If no `options` are provded, the current `options` values are instead returned

    Example:
    ```
    chart.renderDataPoints([{radius: 2, fillOpacity: 0.8, strokeOpacity: 0.8}])
    ```
    **/
    _chart.renderDataPoints = function (options) {
        if (!arguments.length) {
            return {
                fillOpacity: _dataPointFillOpacity,
                strokeOpacity: _dataPointStrokeOpacity,
                radius: _dataPointRadius
            };
        } else if (!options) {
            _dataPointFillOpacity = DEFAULT_DOT_OPACITY;
            _dataPointStrokeOpacity = DEFAULT_DOT_OPACITY;
            _dataPointRadius = null;
        } else {
            _dataPointFillOpacity = options.fillOpacity || 0.8;
            _dataPointStrokeOpacity = options.strokeOpacity || 0.8;
            _dataPointRadius = options.radius || 2;
        }
        return _chart;
    };

    _chart.legendHighlight = function (d) {
        _chart.selectAll('.chart-body').selectAll('path').filter(function () {
            return d3.select(this).attr('fill') == d.color;
        }).classed('highlight', true);
        _chart.selectAll('.chart-body').selectAll('path').filter(function () {
            return d3.select(this).attr('fill') != d.color;
        }).classed('fadeout', true);
    };

    _chart.legendReset = function (d) {
        _chart.selectAll('.chart-body').selectAll('path').filter(function () {
            return d3.select(this).attr('fill') == d.color;
        }).classed('highlight', false);
        _chart.selectAll('.chart-body').selectAll('path').filter(function () {
            return d3.select(this).attr('fill') != d.color;
        }).classed('fadeout', false);
    };

    return _chart.anchor(parent, chartGroup);
};
<|endoftext|>


<commit_before>// Lite Modal https://github.com/DarylPinto/lite-modal
// -----------
// The light-weight vanilla JS modal script
// @author Daryl Pinto https://github.com/DarylPinto

(function(g){

//Decrease character count with some handy aliases
var d = document;
var wait = g.setTimeout;
function qs(selector){
	return d.querySelector(selector);
}

//run callback on every element matched by selector
function qsaEach(selector, callback){
	[].slice.call(d.querySelectorAll(selector)).forEach(function(el){callback.call(el)});
}

//Apply object of CSS declarations to an element
function applyCSS(el, css_obj){
	for (var prop in css_obj){
		el.style[prop] = css_obj[prop];
	}
}

//On content load
d.addEventListener('DOMContentLoaded', function(){

	//Create modal background
	var bg = d.createElement('div');
	bg.id = 'modal-bg';

	var bg_css = {
		backgroundColor : 'rgba(0,0,0,0.5)',
		position        : 'fixed',
		top             : '0',
		left            : '0',
		transition      : '0.3s opacity',
		height          : '100vh',
		width           : '100vw',
		opacity         : '0',
		zIndex          : '100',
		display         : 'none'
	}

	applyCSS(bg, bg_css);

	d.body.appendChild(bg);

	//Move modals into modal background
	qsaEach('.lite-modal', function(){
		this.style.display = 'none';
		bg.appendChild(this);
	});

	//Center modal
	qsaEach('.lite-modal', function(){
		var el_css = {
			position        : 'absolute',
			top             : '50%',
			left            : '50%',
			'-ms-transform' : 'translate(-50%, -50%)',
			transform       : 'translate(-50%, -50%)'
		}

		applyCSS(this, el_css);
	});

	//Clicking modal background closes modal
	bg.addEventListener('click', function(){
		liteModal.close();
	});

	//Escape key closes modal
	d.addEventListener('keydown', function(e) {
		if (e.keyCode == 27) liteModal.close();
	});

	//Prevent event bubbling (clicking within modal shouldn't close it)
	qsaEach('.lite-modal', function(){
		this.addEventListener('click', function(e){
			e.stopPropagation();
		});
	});

});

//Modal open/close functions
g.liteModal = {
	open: function(selector){
		qsaEach('.lite-modal', function(){
			this.style.display = 'none';
		});
		qs(selector).style.display = 'block';
		qs('#modal-bg').style.display = 'block';
		wait(function(){
			qs('#modal-bg').style.opacity = '1';
		}, 20);
	},

	close: function(){
		qs('#modal-bg').style.opacity = '0';
		wait(function(){
			qs('#modal-bg').style.display = 'none';
			//If there are are any media elements in the modal, pause them
			qsaEach('.lite-modal, .lite-modal *', function(){
				if(typeof this.pause == 'function') this.pause();
			});
		}, 310);
	}

}

})(window);<commit_msg>Fix comment typo<commit_after>// Lite Modal https://github.com/DarylPinto/lite-modal
// -----------
// The light-weight vanilla JS modal script
// @author Daryl Pinto https://github.com/DarylPinto

(function(g){

//Decrease character count with some handy aliases
var d = document;
var wait = g.setTimeout;
function qs(selector){
	return d.querySelector(selector);
}

//run callback on every element matched by selector
function qsaEach(selector, callback){
	[].slice.call(d.querySelectorAll(selector)).forEach(function(el){callback.call(el)});
}

//Apply object of CSS declarations to an element
function applyCSS(el, css_obj){
	for (var prop in css_obj){
		el.style[prop] = css_obj[prop];
	}
}

//On content load
d.addEventListener('DOMContentLoaded', function(){

	//Create modal background
	var bg = d.createElement('div');
	bg.id = 'modal-bg';

	var bg_css = {
		backgroundColor : 'rgba(0,0,0,0.5)',
		position        : 'fixed',
		top             : '0',
		left            : '0',
		transition      : '0.3s opacity',
		height          : '100vh',
		width           : '100vw',
		opacity         : '0',
		zIndex          : '100',
		display         : 'none'
	}

	applyCSS(bg, bg_css);

	d.body.appendChild(bg);

	//Move modals into modal background
	qsaEach('.lite-modal', function(){
		this.style.display = 'none';
		bg.appendChild(this);
	});

	//Center modal
	qsaEach('.lite-modal', function(){
		var el_css = {
			position        : 'absolute',
			top             : '50%',
			left            : '50%',
			'-ms-transform' : 'translate(-50%, -50%)',
			transform       : 'translate(-50%, -50%)'
		}

		applyCSS(this, el_css);
	});

	//Clicking modal background closes modal
	bg.addEventListener('click', function(){
		liteModal.close();
	});

	//Escape key closes modal
	d.addEventListener('keydown', function(e) {
		if (e.keyCode == 27) liteModal.close();
	});

	//Prevent event bubbling (clicking within modal shouldn't close it)
	qsaEach('.lite-modal', function(){
		this.addEventListener('click', function(e){
			e.stopPropagation();
		});
	});

});

//Modal open/close functions
g.liteModal = {
	open: function(selector){
		qsaEach('.lite-modal', function(){
			this.style.display = 'none';
		});
		qs(selector).style.display = 'block';
		qs('#modal-bg').style.display = 'block';
		wait(function(){
			qs('#modal-bg').style.opacity = '1';
		}, 20);
	},

	close: function(){
		qs('#modal-bg').style.opacity = '0';
		wait(function(){
			qs('#modal-bg').style.display = 'none';
			//If there are any media elements in the modal, pause them
			qsaEach('.lite-modal, .lite-modal *', function(){
				if(typeof this.pause == 'function') this.pause();
			});
		}, 310);
	}

}

})(window);<|endoftext|>


<commit_before>/* jshint noarg:false */
var util = require('../utility.js');
var CALLSTACK_MAX_DEPTH = 10;
var FN_NAME_REGEX = /function ([\w\d\-_]+)\s*\(/;

function getName(f) {
    return f.name || (FN_NAME_REGEX.test(f.toString()) ? RegExp.$1 : '{anonymous}');
}

function makeLogFn (out, name) {
    return function (level) {
        return function (objOrMsg) {
            if (typeof objOrMsg === 'string') {
                objOrMsg = {msg: objOrMsg};
            }
            out( util.extend({
                level: level,
                name: name,
                time: new Date().getTime()
            }, objOrMsg) );
        };
    };
}

function retrieveErrorData (evt, caller) {
    var output = {
        msg: evt.message,
        url: evt.filename,
        line: evt.lineno,
        stack: []
    };
    try {
        var i = CALLSTACK_MAX_DEPTH;
        while (caller && i--) {
            output.stack.push(getName(caller));
            caller = caller.caller;
        }
    } catch (e) {}
    return output;
}

function create(name, strLevel, out) {
	var level = parseInt(strLevel || '0', 10);
    var log = makeLogFn(out, name);
    var noop = function () {};
    var logInstance = {
        level: level,
        error:  (level >= 1 ? log(1) : noop),
        warn:   (level >= 2 ? log(2) : noop),
        info:   (level >= 3 ? log(3) : noop),
        debug:  (level >= 4 ? log(4) : noop),
    };

    if (level > 0) {
        util.on('error', window, function (e) {
            var caller = arguments.callee && arguments.callee.caller;
            logInstance.error( retrieveErrorData(e, caller) );
        });
    }

    return logInstance;
}

module.exports = {
	create: create
};<commit_msg>Deleted extend methods from utility and use util-extend instead<commit_after>/* jshint noarg:false */
var util = require('../utility.js');
var extend = require('util-extend');
var CALLSTACK_MAX_DEPTH = 10;
var FN_NAME_REGEX = /function ([\w\d\-_]+)\s*\(/;

function getName(f) {
    return f.name || (FN_NAME_REGEX.test(f.toString()) ? RegExp.$1 : '{anonymous}');
}

function makeLogFn (out, name) {
    return function (level) {
        return function (objOrMsg) {
            if (typeof objOrMsg === 'string') {
                objOrMsg = {msg: objOrMsg};
            }
            out( extend({
                level: level,
                name: name,
                time: new Date().getTime()
            }, objOrMsg) );
        };
    };
}

function retrieveErrorData (evt, caller) {
    var output = {
        msg: evt.message,
        url: evt.filename,
        line: evt.lineno,
        stack: []
    };
    try {
        var i = CALLSTACK_MAX_DEPTH;
        while (caller && i--) {
            output.stack.push(getName(caller));
            caller = caller.caller;
        }
    } catch (e) {}
    return output;
}

function create(name, strLevel, out) {
	var level = parseInt(strLevel || '0', 10);
    var log = makeLogFn(out, name);
    var noop = function () {};
    var logInstance = {
        level: level,
        error:  (level >= 1 ? log(1) : noop),
        warn:   (level >= 2 ? log(2) : noop),
        info:   (level >= 3 ? log(3) : noop),
        debug:  (level >= 4 ? log(4) : noop),
    };

    if (level > 0) {
        util.on('error', window, function (e) {
            var caller = arguments.callee && arguments.callee.caller;
            logInstance.error( retrieveErrorData(e, caller) );
        });
    }

    return logInstance;
}

module.exports = {
	create: create
};<|endoftext|>