<commit_before>
module.exports = function(fn) {
	var qs		= require('querystring'),
		html	= {};

	html.el = function (name, opts) {
		return  html.beginEl(name, opts) + html.endEl(name);
	};

	html.beginEl = function (name, opts) {
		opts = opts || {};

		var innerHTML = opts && typeof opts.val !== 'undefined' ? fn.e(opts.val) : ''; // escaped value
		delete opts.val;
		if (opts && typeof opts.html !== 'undefined') {
			innerHTML =  opts.html;
			delete opts.html;
		}
		return '<'+ name + fn.toAttr(opts) +'>'+ innerHTML;
	};

	html.endEl = function (name) {
		return '</'+ name +'>';
	};

	// meta charset
	html.charset = function (charset) {
		charset = charset || 'utf-8';
		return '<meta charset="'+ charset +'">';
	};

	html.css = function (href, opts) {
		return '<link'+ fn.toAttr(fn.mergeObject({ href: href, rel: 'stylesheet', type: 'text/css', media: 'all'}, opts)) +' />';
	};

	html.script = function (src, opts) {
		return '';
	};

	html.a = function(link, text, opts) {
		return ''+ text +'';
	};

	html.img = function (src, alt, opts) {
		return '';
	};

	html.imgText = function(text, opt) {
        opt = opt || {};
        var fgColor = opt.fgColor || 'EFEFEF';
        var bgColor = opt.bgColor || 'AAAAAA';
        var w = opt.w || 291;
        var h = opt.h || 170;
        text = text || 'nincs kép';
        // http://www.placehold.it/291x170/EFEFEF/AAAAAA&text=nincs+kép
        return '';
    };

    html.refresh = function (url, sec, opts) {
    	if (!sec)
    		sec = 5;
    	return '<meta'+ fn.toAttr(fn.mergeObject({ http: { equiv: 'refresh' }, content: sec +',URL='+ url }, opts)) +' />';
    };

	return html;
};<commit_msg>fix meta xhtml close<commit_after>
module.exports = function(fn) {
	var qs		= require('querystring'),
		html	= {};

	html.el = function (name, opts) {
		return  html.beginEl(name, opts) + html.endEl(name);
	};

	html.beginEl = function (name, opts) {
		opts = opts || {};

		var innerHTML = opts && typeof opts.val !== 'undefined' ? fn.e(opts.val) : ''; // escaped value
		delete opts.val;
		if (opts && typeof opts.html !== 'undefined') {
			innerHTML =  opts.html;
			delete opts.html;
		}
		return '<'+ name + fn.toAttr(opts) +'>'+ innerHTML;
	};

	html.endEl = function (name) {
		return '</'+ name +'>';
	};

	// meta charset
	html.charset = function (charset) {
		charset = charset || 'utf-8';
		return '<meta charset="'+ charset +'" />';
	};

	html.css = function (href, opts) {
		return '<link'+ fn.toAttr(fn.mergeObject({ href: href, rel: 'stylesheet', type: 'text/css', media: 'all'}, opts)) +' />';
	};

	html.script = function (src, opts) {
		return '';
	};

	html.a = function(link, text, opts) {
		return ''+ text +'';
	};

	html.img = function (src, alt, opts) {
		return '';
	};

	html.imgText = function(text, opt) {
        opt = opt || {};
        var fgColor = opt.fgColor || 'EFEFEF';
        var bgColor = opt.bgColor || 'AAAAAA';
        var w = opt.w || 291;
        var h = opt.h || 170;
        text = text || 'nincs kép';
        // http://www.placehold.it/291x170/EFEFEF/AAAAAA&text=nincs+kép
        return '';
    };

    html.refresh = function (url, sec, opts) {
    	if (!sec)
    		sec = 5;
    	return '<meta'+ fn.toAttr(fn.mergeObject({ http: { equiv: 'refresh' }, content: sec +',URL='+ url }, opts)) +' />';
    };

	return html;
};<|endoftext|>


<commit_before>/**
 * @file Guild events file.
 * @author Capuccino
 * @author Ovyerus
 */

/* eslint-env node */

module.exports = bot => {
    bot.on('guildCreate', g => {
        if (g.members.filter(m => m.bot).size / g.members.size >= 0.50) {
            logger.info(`Leaving bot collection '${g.name}' (${g.id})`);
            g.leave();
        } else {
            bot.editStatus('online', {name: `${bot.config.gameName || `${bot.config.mainPrefix}help for commands!`} | ${bot.guilds.size} ${bot.guilds.size === 1 ? 'server' : 'servers'}`, type: bot.config.gameURL ? 1 : 0, url: `${bot.config.gameURL || null}`});
            bot.postGuildCount();
        }
    });

    bot.on('guildDelete', g => {
        if (!(g.members.filter(m => m.bot).size/g.members.size >= 0.50)) {
            bot.editStatus('online', {name: `${bot.config.gameName || `${bot.config.mainPrefix}help for commands!`} | ${bot.guilds.size} ${bot.guilds.size === 1 ? 'server' : 'servers'}`, type: bot.config.gameURL ? 1 : 0, url: `${bot.config.gameURL || null}`});
            bot.postGuildCount();
        }
    });

    bot.on('guildMemberAdd', (g, m) => {
        bot.getGuildSettings(g.id).then(res => {
            if (!res || !res.greeting || !res.greeting.enabled || !res.greeting.channelID || !res.greeting.message) {
                return null;
            }
            let msg = res.greeting.message.replace(/\{\{user\}\}/g, m.mention).replace(/\{\{name\}\}/g, utils.formatUsername(m));
            return g.channels.get(res.greeting.channelID).createMessage(msg);
        });
    });

    bot.on('guildMemberDelete', (g, m) => {
        bot.guildSettings(g.id).then(res => {
            if (!res || !res.goodbyes || !res.goodbyes.enabled || !res.goodbyes.channelID || !res.goodbyes.message) {
                return null;
            }
            let msg = res.goodbyes.message.replace(/\{\user\}\}/g, m.mention).replace(/\{name\}\}/g, utils.formatUsername(m));
            return g.channels.get(res.greeting.channelID).createMessage(msg);
        });
    });
};
<commit_msg>Use Goodbye-specific Guild ID setting<commit_after>/**
 * @file Guild events file.
 * @author Capuccino
 * @author Ovyerus
 */

/* eslint-env node */

module.exports = bot => {
    bot.on('guildCreate', g => {
        if (g.members.filter(m => m.bot).size / g.members.size >= 0.50) {
            logger.info(`Leaving bot collection '${g.name}' (${g.id})`);
            g.leave();
        } else {
            bot.editStatus('online', {name: `${bot.config.gameName || `${bot.config.mainPrefix}help for commands!`} | ${bot.guilds.size} ${bot.guilds.size === 1 ? 'server' : 'servers'}`, type: bot.config.gameURL ? 1 : 0, url: `${bot.config.gameURL || null}`});
            bot.postGuildCount();
        }
    });

    bot.on('guildDelete', g => {
        if (!(g.members.filter(m => m.bot).size/g.members.size >= 0.50)) {
            bot.editStatus('online', {name: `${bot.config.gameName || `${bot.config.mainPrefix}help for commands!`} | ${bot.guilds.size} ${bot.guilds.size === 1 ? 'server' : 'servers'}`, type: bot.config.gameURL ? 1 : 0, url: `${bot.config.gameURL || null}`});
            bot.postGuildCount();
        }
    });

    bot.on('guildMemberAdd', (g, m) => {
        bot.getGuildSettings(g.id).then(res => {
            if (!res || !res.greeting || !res.greeting.enabled || !res.greeting.channelID || !res.greeting.message) {
                return null;
            }
            let msg = res.greeting.message.replace(/\{\{user\}\}/g, m.mention).replace(/\{\{name\}\}/g, utils.formatUsername(m));
            return g.channels.get(res.greeting.channelID).createMessage(msg);
        });
    });

    bot.on('guildMemberDelete', (g, m) => {
        bot.guildSettings(g.id).then(res => {
            if (!res || !res.goodbyes || !res.goodbyes.enabled || !res.goodbyes.channelID || !res.goodbyes.message) {
                return null;
            }
            let msg = res.goodbyes.message.replace(/\{\user\}\}/g, m.mention).replace(/\{name\}\}/g, utils.formatUsername(m));
            return g.channels.get(res.goodbyes.channelID).createMessage(msg);
        });
    });
};
<|endoftext|>


<commit_before>const urllib = require('url');
const querystring = require('querystring');
const sax = require('sax');
const miniget = require('miniget');
const util = require('./util');
const extras = require('./info-extras');
const sig = require('./sig');
const Cache = require('./cache');

const VIDEO_URL = 'https://www.youtube.com/watch?v=';
const EMBED_URL = 'https://www.youtube.com/embed/';
const VIDEO_EURL = 'https://youtube.googleapis.com/v/';
const INFO_HOST = 'www.youtube.com';
const INFO_PATH = '/get_video_info';

// Cached for storing basic/full info.
exports.cache = new Cache();
exports.cookieCache = new Cache(1000 * 60 * 60 * 24);

/**
 * Gets info from a video without getting additional formats.
 *
 * @param {string} id
 * @param {Object} options
 * @returns {Promise<Object>}
 */
exports.getBasicInfo = async(id, options) => {
  // Try getting config from the video page first.
  const params = `hl=${options.lang || 'en'}`;
  const watchPageURL = `${VIDEO_URL + id}&${params}&bpctr=${Math.ceil(Date.now() / 1000)}`;
  const jsonEndpointURL = `${watchPageURL}&pbj=1`;

  const reqOptions = Object.assign({ headers: {} }, options.requestOptions);
  let cookie = reqOptions.headers.Cookie || reqOptions.headers.cookie;
  reqOptions.headers = Object.assign({}, {
    'x-youtube-client-name': '1',
    'x-youtube-client-version': '2.20200701.03.01',
    'x-youtube-identity-token': exports.cookieCache.get(cookie || 'browser') || '',
  }, reqOptions.headers);

  const setIdentityToken = async key => {
    let token = await exports.cookieCache.getOrSet(key, async() => {
      let watchPageBody = await miniget(watchPageURL, reqOptions).text();
      let match = watchPageBody.match(/(["'])ID_TOKEN\1[:,]\s?"([^"]+)"/);
      if (!match) {
        throw Error('Cookie header used in request, but unable to find YouTube identity token');
      }
      return match[2];
    });
    reqOptions.headers['x-youtube-identity-token'] = token;
  };

  if (cookie && !reqOptions.headers['x-youtube-identity-token']) {
    await setIdentityToken(cookie);
  }

  let body = await miniget(jsonEndpointURL, reqOptions).text();
  let info;
  try {
    let parsedBody = JSON.parse(body);
    if (parsedBody.reload === 'now' && !reqOptions.headers['x-youtube-identity-token']) {
      await setIdentityToken('browser');
      body = await miniget(jsonEndpointURL, reqOptions).text();
      parsedBody = JSON.parse(body);
    }
    if (!Array.isArray(parsedBody)) {
      throw Error('Cookie header used in request, but unable to retrieve video metadata');
    }
    info = parsedBody.reduce((part, curr) => Object.assign(curr, part), {});
  } catch (err) {
    throw Error(`Error parsing info: ${err.message}`);
  }

  let playErr = util.playError(info, 'ERROR');
  if (playErr) {
    throw playErr;
  }

  if (!info.player) {
    // If the video page doesn't work, maybe because it has mature content.
    // and requires an account logged in to view, try the embed page.
    let embedUrl = `${EMBED_URL + id}?${params}`;
    body = await miniget(embedUrl, options.requestOptions).text();
    let jsonStr = util.between(body, 't.setConfig({\'PLAYER_CONFIG\': ', '</script>');
    let config;
    if (!jsonStr) {
      throw Error('Could not find player config');
    }
    try {
      config = JSON.parse(util.cutAfterJSON(jsonStr));
    } catch (err) {
      throw Error(`Error parsing config: ${err.message}`);
    }
    playErr = util.playError(info, 'LOGIN_REQUIRED');
    if (!config.args.player_response && !config.args.embedded_player_response && playErr) {
      throw playErr;
    }
    info.player = config;
  }
  return gotConfig(id, options, info, body);
};

/**
 * @param {Object} info
 * @returns {Array.<Object>}
 */
const parseFormats = info => {
  let formats = [];
  if (info.player_response.streamingData) {
    if (info.player_response.streamingData.formats) {
      formats = formats.concat(info.player_response.streamingData.formats);
    }
    if (info.player_response.streamingData.adaptiveFormats) {
      formats = formats.concat(info.player_response.streamingData.adaptiveFormats);
    }
  }
  return formats;
};

/**
 * @param {Object} id
 * @param {Object} options
 * @param {Object} info
 * @param {string} body
 * @returns {Promise<Object>}
 */
const gotConfig = async(id, options, info, body) => {
  let player_response =
    info.player && info.player.args && info.player.args.player_response;

  if (!player_response) {
    const url = urllib.format({
      protocol: 'https',
      host: INFO_HOST,
      pathname: INFO_PATH,
      query: {
        video_id: id,
        eurl: VIDEO_EURL + id,
        ps: 'default',
        gl: 'US',
        hl: options.lang || 'en',
        sts: info.sts,
      },
    });
    let morebody = await miniget(url, options.requestOptions).text();
    let moreinfo = querystring.parse(morebody);
    player_response = moreinfo.player_response || info.playerResponse;
  }

  if (typeof player_response === 'object') {
    info.player_response = player_response;
  } else {
    try {
      info.player_response = JSON.parse(player_response);
    } catch (err) {
      throw Error(`Error parsing \`player_response\`: ${err.message}`);
    }
  }

  info.formats = parseFormats(info);

  // Add additional properties to info.
  let additional = {
    author: extras.getAuthor(info),
    media: extras.getMedia(info),
    likes: extras.getLikes(body),
    dislikes: extras.getDislikes(body),
    age_restricted: !!(info.player.args && info.player.args.is_embed),

    // Give the standard link to the video.
    video_url: VIDEO_URL + id,
  };

  info.videoDetails = Object.assign({},
    info.player_response.microformat.playerMicroformatRenderer,
    info.player_response.videoDetails, additional);
  info.related_videos = extras.getRelatedVideos(info);
  info.html5player = info.player && info.player.assets && info.player.assets.js;

  // TODO: Remove these warnings later and remove the properties.
  // Remember to remove from typings too.
  for (let [prop, value] of Object.entries(additional)) {
    util.deprecate(info, prop, value, `info.${prop}`, `info.videoDetails.${prop}`);
  }
  util.deprecate(info, 'published', info.player_response.microformat.playerMicroformatRenderer.publishDate,
    'info.published', 'info.videoDetails.publishDate');
  let props = {
    description: 'shortDescription',
    video_id: 'videoId',
    title: 'title',
    length_seconds: 'lengthSeconds',
  };
  for (let [oldProp, newProp] of Object.entries(props)) {
    util.deprecate(info, oldProp, info.videoDetails[newProp],
      `info.${oldProp}`, `info.videoDetails.${newProp}`);
  }

  return info;
};

/**
 * Gets info from a video additional formats and deciphered URLs.
 *
 * @param {string} id
 * @param {Object} options
 * @returns {Promise<Object>}
 */
exports.getInfo = async(id, options) => {
  let info = await exports.getBasicInfo(id, options);
  const hasManifest =
    info.player_response && info.player_response.streamingData && (
      info.player_response.streamingData.dashManifestUrl ||
      info.player_response.streamingData.hlsManifestUrl
    );
  let funcs = [];
  if (info.formats.length) {
    const html5player = urllib.resolve(VIDEO_URL, info.html5player);
    funcs.push(sig.decipherFormats(info.formats, html5player, options));
  }
  if (hasManifest && info.player_response.streamingData.dashManifestUrl) {
    let url = info.player_response.streamingData.dashManifestUrl;
    funcs.push(getDashManifest(url, options));
  }
  if (hasManifest && info.player_response.streamingData.hlsManifestUrl) {
    let url = info.player_response.streamingData.hlsManifestUrl;
    funcs.push(getM3U8(url, options));
  }

  let results = await Promise.all(funcs);
  info.formats = Object.values(Object.assign({}, ...results));
  info.formats = info.formats.map(util.addFormatMeta);
  info.formats.sort(util.sortFormats);
  info.full = true;
  return info;
};

/**
 * Gets additional DASH formats.
 *
 * @param {string} url
 * @param {Object} options
 * @returns {Promise<Array.<Object>>}
 */
const getDashManifest = (url, options) => new Promise((resolve, reject) => {
  let formats = {};
  const parser = sax.parser(false);
  parser.onerror = reject;
  parser.onopentag = node => {
    if (node.name === 'REPRESENTATION') {
      const itag = parseInt(node.attributes.ID);
      formats[itag] = { itag, url };
    }
  };
  parser.onend = () => { resolve(formats); };
  const req = miniget(urllib.resolve(VIDEO_URL, url), options.requestOptions);
  req.setEncoding('utf8');
  req.on('error', reject);
  req.on('data', chunk => { parser.write(chunk); });
  req.on('end', parser.close.bind(parser));
});

/**
 * Gets additional formats.
 *
 * @param {string} url
 * @param {Object} options
 * @returns {Promise<Array.<Object>>}
 */
const getM3U8 = async(url, options) => {
  url = urllib.resolve(VIDEO_URL, url);
  let body = await miniget(url, options.requestOptions).text();
  let formats = {};
  body
    .split('\n')
    .filter(line => /https?:\/\//.test(line))
    .forEach(line => {
      const itag = parseInt(line.match(/\/itag\/(\d+)\//)[1]);
      formats[itag] = { itag: itag, url: line };
    });
  return formats;
};

// Cache get info functions.
// In case a user wants to get a video's info before downloading.
for (let fnName of ['getBasicInfo', 'getInfo']) {
  /**
   * @param {string} link
   * @param {Object} options
   * @param {Function(Error, Object)} callback
   * @returns {Promise<Object>}
   */
  const fn = exports[fnName];
  exports[fnName] = (link, options, callback) => {
    if (typeof options === 'function') {
      callback = options;
      options = {};
    } else if (!options) {
      options = {};
    }

    if (callback) {
      // TODO: Fully remove callback support in a future release.
      // eslint-disable-next-line no-console
      console.warn(
        `Calling \`ytdl.${fnName}\` with a callback will be removed in a near future release. ` +
        `Use async/await.`);
      return exports[fnName](link, options)
        .then(info => callback(null, info), callback);
    }

    let id = util.getVideoID(link);
    const key = [fnName, id, options.lang].join('-');
    return exports.cache.getOrSet(key, () => fn(id, options));
  };
}

// Export a few helpers.
exports.validateID = util.validateID;
exports.validateURL = util.validateURL;
exports.getURLVideoID = util.getURLVideoID;
exports.getVideoID = util.getVideoID;
<commit_msg>fix: fix "Could not find player config" error in age restricted videos<commit_after>const urllib = require('url');
const querystring = require('querystring');
const sax = require('sax');
const miniget = require('miniget');
const util = require('./util');
const extras = require('./info-extras');
const sig = require('./sig');
const Cache = require('./cache');

const VIDEO_URL = 'https://www.youtube.com/watch?v=';
const EMBED_URL = 'https://www.youtube.com/embed/';
const VIDEO_EURL = 'https://youtube.googleapis.com/v/';
const INFO_HOST = 'www.youtube.com';
const INFO_PATH = '/get_video_info';

// Cached for storing basic/full info.
exports.cache = new Cache();
exports.cookieCache = new Cache(1000 * 60 * 60 * 24);

/**
 * Gets info from a video without getting additional formats.
 *
 * @param {string} id
 * @param {Object} options
 * @returns {Promise<Object>}
 */
exports.getBasicInfo = async(id, options) => {
  // Try getting config from the video page first.
  const params = `hl=${options.lang || 'en'}`;
  const watchPageURL = `${VIDEO_URL + id}&${params}&bpctr=${Math.ceil(Date.now() / 1000)}`;
  const jsonEndpointURL = `${watchPageURL}&pbj=1`;

  const reqOptions = Object.assign({ headers: {} }, options.requestOptions);
  let cookie = reqOptions.headers.Cookie || reqOptions.headers.cookie;
  reqOptions.headers = Object.assign({}, {
    'x-youtube-client-name': '1',
    'x-youtube-client-version': '2.20200701.03.01',
    'x-youtube-identity-token': exports.cookieCache.get(cookie || 'browser') || '',
  }, reqOptions.headers);

  const setIdentityToken = async key => {
    let token = await exports.cookieCache.getOrSet(key, async() => {
      let watchPageBody = await miniget(watchPageURL, reqOptions).text();
      let match = watchPageBody.match(/(["'])ID_TOKEN\1[:,]\s?"([^"]+)"/);
      if (!match) {
        throw Error('Cookie header used in request, but unable to find YouTube identity token');
      }
      return match[2];
    });
    reqOptions.headers['x-youtube-identity-token'] = token;
  };

  if (cookie && !reqOptions.headers['x-youtube-identity-token']) {
    await setIdentityToken(cookie);
  }

  let body = await miniget(jsonEndpointURL, reqOptions).text();
  let info;
  try {
    let parsedBody = JSON.parse(body);
    if (parsedBody.reload === 'now' && !reqOptions.headers['x-youtube-identity-token']) {
      await setIdentityToken('browser');
      body = await miniget(jsonEndpointURL, reqOptions).text();
      parsedBody = JSON.parse(body);
    }
    if (!Array.isArray(parsedBody)) {
      throw Error('Cookie header used in request, but unable to retrieve video metadata');
    }
    info = parsedBody.reduce((part, curr) => Object.assign(curr, part), {});
  } catch (err) {
    throw Error(`Error parsing info: ${err.message}`);
  }

  let playErr = util.playError(info, 'ERROR');
  if (playErr) {
    throw playErr;
  }

  if (!info.player) {
    // If the video page doesn't work, maybe because it has mature content.
    // and requires an account logged in to view, try the embed page.
    let embedUrl = `${EMBED_URL + id}?${params}`;
    body = await miniget(embedUrl, options.requestOptions).text();
    let jsonStr = util.between(body, '\'PLAYER_CONFIG\': ', '</script>');
    let config;
    if (!jsonStr) {
      throw Error('Could not find player config');
    }
    try {
      config = JSON.parse(util.cutAfterJSON(jsonStr));
    } catch (err) {
      throw Error(`Error parsing config: ${err.message}`);
    }
    playErr = util.playError(info, 'LOGIN_REQUIRED');
    if (!config.args.player_response && !config.args.embedded_player_response && playErr) {
      throw playErr;
    }
    info.player = config;
  }
  return gotConfig(id, options, info, body);
};

/**
 * @param {Object} info
 * @returns {Array.<Object>}
 */
const parseFormats = info => {
  let formats = [];
  if (info.player_response.streamingData) {
    if (info.player_response.streamingData.formats) {
      formats = formats.concat(info.player_response.streamingData.formats);
    }
    if (info.player_response.streamingData.adaptiveFormats) {
      formats = formats.concat(info.player_response.streamingData.adaptiveFormats);
    }
  }
  return formats;
};

/**
 * @param {Object} id
 * @param {Object} options
 * @param {Object} info
 * @param {string} body
 * @returns {Promise<Object>}
 */
const gotConfig = async(id, options, info, body) => {
  let player_response =
    info.player && info.player.args && info.player.args.player_response;

  if (!player_response) {
    const url = urllib.format({
      protocol: 'https',
      host: INFO_HOST,
      pathname: INFO_PATH,
      query: {
        video_id: id,
        eurl: VIDEO_EURL + id,
        ps: 'default',
        gl: 'US',
        hl: options.lang || 'en',
        sts: info.sts,
      },
    });
    let morebody = await miniget(url, options.requestOptions).text();
    let moreinfo = querystring.parse(morebody);
    player_response = moreinfo.player_response || info.playerResponse;
  }

  if (typeof player_response === 'object') {
    info.player_response = player_response;
  } else {
    try {
      info.player_response = JSON.parse(player_response);
    } catch (err) {
      throw Error(`Error parsing \`player_response\`: ${err.message}`);
    }
  }

  info.formats = parseFormats(info);

  // Add additional properties to info.
  let additional = {
    author: extras.getAuthor(info),
    media: extras.getMedia(info),
    likes: extras.getLikes(body),
    dislikes: extras.getDislikes(body),
    age_restricted: !!(info.player.args && info.player.args.is_embed),

    // Give the standard link to the video.
    video_url: VIDEO_URL + id,
  };

  info.videoDetails = Object.assign({},
    info.player_response.microformat.playerMicroformatRenderer,
    info.player_response.videoDetails, additional);
  info.related_videos = extras.getRelatedVideos(info);
  info.html5player = info.player && info.player.assets && info.player.assets.js;

  // TODO: Remove these warnings later and remove the properties.
  // Remember to remove from typings too.
  for (let [prop, value] of Object.entries(additional)) {
    util.deprecate(info, prop, value, `info.${prop}`, `info.videoDetails.${prop}`);
  }
  util.deprecate(info, 'published', info.player_response.microformat.playerMicroformatRenderer.publishDate,
    'info.published', 'info.videoDetails.publishDate');
  let props = {
    description: 'shortDescription',
    video_id: 'videoId',
    title: 'title',
    length_seconds: 'lengthSeconds',
  };
  for (let [oldProp, newProp] of Object.entries(props)) {
    util.deprecate(info, oldProp, info.videoDetails[newProp],
      `info.${oldProp}`, `info.videoDetails.${newProp}`);
  }

  return info;
};

/**
 * Gets info from a video additional formats and deciphered URLs.
 *
 * @param {string} id
 * @param {Object} options
 * @returns {Promise<Object>}
 */
exports.getInfo = async(id, options) => {
  let info = await exports.getBasicInfo(id, options);
  const hasManifest =
    info.player_response && info.player_response.streamingData && (
      info.player_response.streamingData.dashManifestUrl ||
      info.player_response.streamingData.hlsManifestUrl
    );
  let funcs = [];
  if (info.formats.length) {
    const html5player = urllib.resolve(VIDEO_URL, info.html5player);
    funcs.push(sig.decipherFormats(info.formats, html5player, options));
  }
  if (hasManifest && info.player_response.streamingData.dashManifestUrl) {
    let url = info.player_response.streamingData.dashManifestUrl;
    funcs.push(getDashManifest(url, options));
  }
  if (hasManifest && info.player_response.streamingData.hlsManifestUrl) {
    let url = info.player_response.streamingData.hlsManifestUrl;
    funcs.push(getM3U8(url, options));
  }

  let results = await Promise.all(funcs);
  info.formats = Object.values(Object.assign({}, ...results));
  info.formats = info.formats.map(util.addFormatMeta);
  info.formats.sort(util.sortFormats);
  info.full = true;
  return info;
};

/**
 * Gets additional DASH formats.
 *
 * @param {string} url
 * @param {Object} options
 * @returns {Promise<Array.<Object>>}
 */
const getDashManifest = (url, options) => new Promise((resolve, reject) => {
  let formats = {};
  const parser = sax.parser(false);
  parser.onerror = reject;
  parser.onopentag = node => {
    if (node.name === 'REPRESENTATION') {
      const itag = parseInt(node.attributes.ID);
      formats[itag] = { itag, url };
    }
  };
  parser.onend = () => { resolve(formats); };
  const req = miniget(urllib.resolve(VIDEO_URL, url), options.requestOptions);
  req.setEncoding('utf8');
  req.on('error', reject);
  req.on('data', chunk => { parser.write(chunk); });
  req.on('end', parser.close.bind(parser));
});

/**
 * Gets additional formats.
 *
 * @param {string} url
 * @param {Object} options
 * @returns {Promise<Array.<Object>>}
 */
const getM3U8 = async(url, options) => {
  url = urllib.resolve(VIDEO_URL, url);
  let body = await miniget(url, options.requestOptions).text();
  let formats = {};
  body
    .split('\n')
    .filter(line => /https?:\/\//.test(line))
    .forEach(line => {
      const itag = parseInt(line.match(/\/itag\/(\d+)\//)[1]);
      formats[itag] = { itag: itag, url: line };
    });
  return formats;
};

// Cache get info functions.
// In case a user wants to get a video's info before downloading.
for (let fnName of ['getBasicInfo', 'getInfo']) {
  /**
   * @param {string} link
   * @param {Object} options
   * @param {Function(Error, Object)} callback
   * @returns {Promise<Object>}
   */
  const fn = exports[fnName];
  exports[fnName] = (link, options, callback) => {
    if (typeof options === 'function') {
      callback = options;
      options = {};
    } else if (!options) {
      options = {};
    }

    if (callback) {
      // TODO: Fully remove callback support in a future release.
      // eslint-disable-next-line no-console
      console.warn(
        `Calling \`ytdl.${fnName}\` with a callback will be removed in a near future release. ` +
        `Use async/await.`);
      return exports[fnName](link, options)
        .then(info => callback(null, info), callback);
    }

    let id = util.getVideoID(link);
    const key = [fnName, id, options.lang].join('-');
    return exports.cache.getOrSet(key, () => fn(id, options));
  };
}

// Export a few helpers.
exports.validateID = util.validateID;
exports.validateURL = util.validateURL;
exports.getURLVideoID = util.getURLVideoID;
exports.getVideoID = util.getVideoID;
<|endoftext|>


<commit_before>#!/usr/bin/node

var co = require('co');
var db = require('./db');

co(function * () {
	yield db.createTables();
})
.then(() => process.exit(0))
.catch(err => {
	console.error(err);
	process.exit(1);
});
<commit_msg>Reset schema<commit_after>#!/usr/bin/node

var co = require('co');
var db = require('./db');

co(function * () {
	yield db.reset();
	yield db.createTables();
})
.then(() => process.exit(0))
.catch(err => {
	console.error(err);
	process.exit(1);
});
<|endoftext|>


<commit_before>/* globals d3, $, _ */

$(window).ready(function () {
  var shas = window.location.hash.substr(1).split('..');
  var $gets = [];

  //var params = val.params;
  //var results = val.results;
  var testsDiv = d3.select("#tests");
  var data = {};
  var dataPerSha = [];

  // Generate XHR promises for each SHA
  $.each(shas, function (i, sha) {
    $gets.push($.getJSON(sha + '.json'));
  });

  // populate graphs with data when it's all loaded
  $.when.apply($.when, $gets).done(function () {
    if (shas.length === 1) {
      dataPerSha.push({
        sha: shas[0],
        color: 0,
        tests: arguments[0]
      });
    } else {
      for (var i = 0 ; i < arguments.length ; i += 1) {
        dataPerSha.push({
          sha: shas[i],
          color: i,
          tests: arguments[i][0]
        });
        $('#colors').append($('<div >').text(shas[i]).addClass(
          'color_' + i));
      }
    }
    for (var i = 0; i < dataPerSha.length ; i += 1) {
      var d = dataPerSha[i];
      $.each(d.tests, function (key, test) {
        if (!_.has(data, key)) {
          data[key] = {
            params: test.params,
            results: [],
          };
        }
        for (var j = 0; j < test.results.length ; j += 1) {
          var r = test.results[j];
          r.sha = d.sha;
          r.color = d.color,
          data[key].results.push(r);
        }
      });
    }

    data = _.map(data, function (val, key) {
      return {
        testName: key,
        params: val.params,
        results: val.results
      };
    });

    var svgWidth = 150;
    var svgHeight = 150;

    var chartEnter = testsDiv.data(data).enter()
                             .append('div')
                             .attr('class', 'chart');

    var legend = chartEnter.append('div').attr('class', 'legend')
                           .text(function (d) {
                             return d.params.api_method + ', ' +
                                 d.params.geom_complexity + ', ' +
                                 d.params.geom + ', ' +
                                 d.params.normalization + ', ' +
                                 d.params.boundary;
                           });
    var svgEnter = chartEnter.append("svg")
                             .attr("width", svgWidth)
                             .attr("height", svgHeight);

    var x = d3.local();
    var y = d3.local();
    var margin = {top: 20, right: 20, bottom: 30, left: 40},
        width = +svgWidth - margin.left - margin.right,
        height = +svgHeight - margin.top - margin.bottom;

    var svg = testsDiv.selectAll('svg')
                      .data(function (d) {
                        return d.results;
                      });

    var g = svgEnter.append("g")
        .each(function (d) {
          x.set(this, d3.scaleBand().rangeRound([0, width]).padding(0.1))
                        .domain(_.pluck(d.results, 'rows'));
          y.set(this, d3.scaleLinear().rangeRound([height, 0]))
                        .domain([0, d3.max(d.results, function (d) {
                          return d.qps; })]);
        })
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    g.append("g")
        .attr("class", "axis axis--x")
        .attr("transform", "translate(0," + height + ")")
        .each(function () {
          d3.axisBottom(x.get(this))(d3.select(this));
        });

    g.append("g")
        .attr("class", "axis axis--y")
        .each(function () {
          d3.axisLeft(y.get(this)).ticks(4)(d3.select(this));
        })
        .append("text")
        .attr("transform", "rotate(-90)")
        .attr("y", 6)
        .attr("dy", "0.71em")
        .attr("text-anchor", "end")
        .text("QPS");

    g.selectAll(".bar")
      .data(function (d) {
        return d.results;
      })
      .enter()
      .append("rect")
      .attr("class", function (d) {
        return 'bar color_' + d.color;
      })
      .attr("x", function(d) {
        return x.get(this)(d.rows) +
          ((x.get(this).bandwidth() / dataPerSha.length) * d.color);
      })
      .attr("y", function(d) {
        return y.get(this)(d.qps);
      })
      .attr("width", function () {
        return x.get(this).bandwidth() / dataPerSha.length;
      }).attr("height", function(d) {
        return height - y.get(this)(d.qps);
      });

  });
});
<commit_msg>fix width of svg<commit_after>/* globals d3, $, _ */

$(window).ready(function () {
  var shas = window.location.hash.substr(1).split('..');
  var $gets = [];

  //var params = val.params;
  //var results = val.results;
  var testsDiv = d3.select("#tests");
  var data = {};
  var dataPerSha = [];

  // Generate XHR promises for each SHA
  $.each(shas, function (i, sha) {
    $gets.push($.getJSON(sha + '.json'));
  });

  // populate graphs with data when it's all loaded
  $.when.apply($.when, $gets).done(function () {
    if (shas.length === 1) {
      dataPerSha.push({
        sha: shas[0],
        color: 0,
        tests: arguments[0]
      });
    } else {
      for (var i = 0 ; i < arguments.length ; i += 1) {
        dataPerSha.push({
          sha: shas[i],
          color: i,
          tests: arguments[i][0]
        });
        $('#colors').append($('<div >').text(shas[i]).addClass(
          'color_' + i));
      }
    }
    for (var i = 0; i < dataPerSha.length ; i += 1) {
      var d = dataPerSha[i];
      $.each(d.tests, function (key, test) {
        if (!_.has(data, key)) {
          data[key] = {
            params: test.params,
            results: [],
          };
        }
        for (var j = 0; j < test.results.length ; j += 1) {
          var r = test.results[j];
          r.sha = d.sha;
          r.color = d.color,
          data[key].results.push(r);
        }
      });
    }

    data = _.map(data, function (val, key) {
      return {
        testName: key,
        params: val.params,
        results: val.results
      };
    });

    var svgWidth = 250;
    var svgHeight = 150;

    var chartEnter = testsDiv.data(data).enter()
                             .append('div')
                             .attr('class', 'chart');

    var legend = chartEnter.append('div').attr('class', 'legend')
                           .text(function (d) {
                             return d.params.api_method + ', ' +
                                 d.params.geom_complexity + ', ' +
                                 d.params.geom + ', ' +
                                 d.params.normalization + ', ' +
                                 d.params.boundary;
                           });
    var svgEnter = chartEnter.append("svg")
                             .attr("width", svgWidth)
                             .attr("height", svgHeight);

    var x = d3.local();
    var y = d3.local();
    var margin = {top: 20, right: 20, bottom: 30, left: 40},
        width = +svgWidth - margin.left - margin.right,
        height = +svgHeight - margin.top - margin.bottom;

    var svg = testsDiv.selectAll('svg')
                      .data(function (d) {
                        return d.results;
                      });

    var g = svgEnter.append("g")
        .each(function (d) {
          x.set(this, d3.scaleBand().rangeRound([0, width]).padding(0.1))
                        .domain(_.pluck(d.results, 'rows'));
          y.set(this, d3.scaleLinear().rangeRound([height, 0]))
                        .domain([0, d3.max(d.results, function (d) {
                          return d.qps; })]);
        })
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    g.append("g")
        .attr("class", "axis axis--x")
        .attr("transform", "translate(0," + height + ")")
        .each(function () {
          d3.axisBottom(x.get(this))(d3.select(this));
        });

    g.append("g")
        .attr("class", "axis axis--y")
        .each(function () {
          d3.axisLeft(y.get(this)).ticks(4)(d3.select(this));
        })
        .append("text")
        .attr("transform", "rotate(-90)")
        .attr("y", 6)
        .attr("dy", "0.71em")
        .attr("text-anchor", "end")
        .text("QPS");

    g.selectAll(".bar")
      .data(function (d) {
        return d.results;
      })
      .enter()
      .append("rect")
      .attr("class", function (d) {
        return 'bar color_' + d.color;
      })
      .attr("x", function(d) {
        return x.get(this)(d.rows) +
          ((x.get(this).bandwidth() / dataPerSha.length) * d.color);
      })
      .attr("y", function(d) {
        return y.get(this)(d.qps);
      })
      .attr("width", function () {
        return x.get(this).bandwidth() / dataPerSha.length;
      }).attr("height", function(d) {
        return height - y.get(this)(d.qps);
      });

  });
});
<|endoftext|>


<commit_before>/*!
 * Jade
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var Parser = require('./parser')
  , Lexer = require('./lexer')
  , Compiler = require('./compiler')
  , runtime = require('./runtime')
// if node
  , fs = require('fs');
// end

/**
 * Library version.
 */

exports.version = '0.28.2';

/**
 * Expose self closing tags.
 */

exports.selfClosing = require('./self-closing');

/**
 * Default supported doctypes.
 */

exports.doctypes = require('./doctypes');

/**
 * Text filters.
 */

exports.filters = require('./filters');

/**
 * Utilities.
 */

exports.utils = require('./utils');

/**
 * Expose `Compiler`.
 */

exports.Compiler = Compiler;

/**
 * Expose `Parser`.
 */

exports.Parser = Parser;

/**
 * Expose `Lexer`.
 */

exports.Lexer = Lexer;

/**
 * Nodes.
 */

exports.nodes = require('./nodes');

/**
 * Jade runtime helpers.
 */

exports.runtime = runtime;

/**
 * Template function cache.
 */

exports.cache = {};

/**
 * Parse the given `str` of jade and return a function body.
 *
 * @param {String} str
 * @param {Object} options
 * @return {String}
 * @api private
 */

function parse(str, options){
  try {
    // Parse
    var parser = new Parser(str, options.filename, options);

    // Compile
    var compiler = new (options.compiler || Compiler)(parser.parse(), options)
      , js = compiler.compile();

    // Debug compiler
    if (options.debug) {
      console.error('\nCompiled Function:\n\n\033[90m%s\033[0m', js.replace(/^/gm, '  '));
    }

    if (options.coffee) {
      return ''
        + 'buf = []\n'
        + (options.inline ? js
          : options.self ? 'self = locals || {}\n' + js
          : '`with (locals || {}) {`\n' + js + '\n`}`')
        + '\n'
        + "return buf.join('')";
    } else {
      return ''
        + 'var buf = [];\n'
        + (options.inline ? js
          : options.self ? 'var self = locals || {};\n' + js
          : 'with (locals || {}) {\n' + js + '\n}')
        + '\n'
        + "return buf.join('');";
    }
  } catch (err) {
    parser = parser.context();
    runtime.rethrow(err, parser.filename, parser.lexer.lineno, str);
  }
}

/**
 * Strip any UTF-8 BOM off of the start of `str`, if it exists.
 *
 * @param {String} str
 * @return {String}
 * @api private
 */

function stripBOM(str){
  return 0xFEFF == str.charCodeAt(0)
    ? str.substring(1)
    : str;
}

/**
 * Compile a `Function` representation of the given jade `str`.
 *
 * Options:
 *
 *   - `compileDebug` when `false` debugging code is stripped from the compiled template
 *   - `client` when `true` the helper functions `escape()` etc will reference `jade.escape()`
 *      for use with the Jade client-side runtime.js
 *
 * @param {String} str
 * @param {Options} options
 * @return {Function}
 * @api public
 */

exports.compile = function(str, options){
  var options = options || {}
    , client = options.client
    , filename = options.filename
      ? JSON.stringify(options.filename)
      : 'undefined'
    , fn;

  str = stripBOM(String(str));

  if (options.compileDebug !== false) {
    if (options.coffee) {
      fn = [
          '__jade = [{ lineno: 1, filename: ' + filename + ' }];'
        , 'try'
        , parse(str, options).replace(/^/gm, '  ')
        , 'catch (err)'
        , '  rethrow(err, __jade[0].filename, __jade[0].lineno);'
        , ''
      ].join('\n');
    } else {
      fn = [
          'var __jade = [{ lineno: 1, filename: ' + filename + ' }];'
        , 'try {'
        , parse(str, options)
        , '} catch (err) {'
        , '  rethrow(err, __jade[0].filename, __jade[0].lineno);'
        , '}'
      ].join('\n');
    }
  } else {
    fn = parse(str, options);
  }

  if (client) {
    if (options.coffee) {
      fn = 'attrs ||= jade.attrs; escape ||= jade.escape; rethrow ||= jade.rethrow; merge ||= jade.merge\n' + fn;
    } else {
      fn = 'attrs = attrs || jade.attrs; escape = escape || jade.escape; rethrow = rethrow || jade.rethrow; merge = merge || jade.merge;\n' + fn;
    }
  }

  if (options.coffee) {
    return [
      '((locals, attrs, escape, rethrow, merge)->',
      fn.replace(/^/gm, '  '),
      ')'
    ].join('\n');
    // Coffee mode can't be run directly, only returned as a string
  } else {
    fn = new Function('locals, attrs, escape, rethrow, merge', fn);
    if (client) return fn;
    return function(locals){
      return fn(locals, runtime.attrs, runtime.escape, runtime.rethrow, runtime.merge);
    };
  }
};

/**
 * Render the given `str` of jade and invoke
 * the callback `fn(err, str)`.
 *
 * Options:
 *
 *   - `cache` enable template caching
 *   - `filename` filename required for `include` / `extends` and caching
 *
 * @param {String} str
 * @param {Object|Function} options or fn
 * @param {Function} fn
 * @api public
 */

exports.render = function(str, options, fn){
  // swap args
  if ('function' == typeof options) {
    fn = options, options = {};
  }

  // cache requires .filename
  if (options.cache && !options.filename) {
    return fn(new Error('the "filename" option is required for caching'));
  }

  try {
    var path = options.filename;
    var tmpl = options.cache
      ? exports.cache[path] || (exports.cache[path] = exports.compile(str, options))
      : exports.compile(str, options);
    fn(null, tmpl(options));
  } catch (err) {
    fn(err);
  }
};

/**
 * Render a Jade file at the given `path` and callback `fn(err, str)`.
 *
 * @param {String} path
 * @param {Object|Function} options or callback
 * @param {Function} fn
 * @api public
 */

exports.renderFile = function(path, options, fn){
  var key = path + ':string';

  if ('function' == typeof options) {
    fn = options, options = {};
  }

  try {
    options.filename = path;
    var str = options.cache
      ? exports.cache[key] || (exports.cache[key] = fs.readFileSync(path, 'utf8'))
      : fs.readFileSync(path, 'utf8');
    exports.render(str, options, fn);
  } catch (err) {
    fn(err);
  }
};

/**
 * Express support.
 */

exports.__express = exports.renderFile;
<commit_msg>bugfix: Coffee syntax is 'catch e', NOT 'catch (e)'<commit_after>/*!
 * Jade
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var Parser = require('./parser')
  , Lexer = require('./lexer')
  , Compiler = require('./compiler')
  , runtime = require('./runtime')
// if node
  , fs = require('fs');
// end

/**
 * Library version.
 */

exports.version = '0.28.2';

/**
 * Expose self closing tags.
 */

exports.selfClosing = require('./self-closing');

/**
 * Default supported doctypes.
 */

exports.doctypes = require('./doctypes');

/**
 * Text filters.
 */

exports.filters = require('./filters');

/**
 * Utilities.
 */

exports.utils = require('./utils');

/**
 * Expose `Compiler`.
 */

exports.Compiler = Compiler;

/**
 * Expose `Parser`.
 */

exports.Parser = Parser;

/**
 * Expose `Lexer`.
 */

exports.Lexer = Lexer;

/**
 * Nodes.
 */

exports.nodes = require('./nodes');

/**
 * Jade runtime helpers.
 */

exports.runtime = runtime;

/**
 * Template function cache.
 */

exports.cache = {};

/**
 * Parse the given `str` of jade and return a function body.
 *
 * @param {String} str
 * @param {Object} options
 * @return {String}
 * @api private
 */

function parse(str, options){
  try {
    // Parse
    var parser = new Parser(str, options.filename, options);

    // Compile
    var compiler = new (options.compiler || Compiler)(parser.parse(), options)
      , js = compiler.compile();

    // Debug compiler
    if (options.debug) {
      console.error('\nCompiled Function:\n\n\033[90m%s\033[0m', js.replace(/^/gm, '  '));
    }

    if (options.coffee) {
      return ''
        + 'buf = []\n'
        + (options.inline ? js
          : options.self ? 'self = locals || {}\n' + js
          : '`with (locals || {}) {`\n' + js + '\n`}`')
        + '\n'
        + "return buf.join('')";
    } else {
      return ''
        + 'var buf = [];\n'
        + (options.inline ? js
          : options.self ? 'var self = locals || {};\n' + js
          : 'with (locals || {}) {\n' + js + '\n}')
        + '\n'
        + "return buf.join('');";
    }
  } catch (err) {
    parser = parser.context();
    runtime.rethrow(err, parser.filename, parser.lexer.lineno, str);
  }
}

/**
 * Strip any UTF-8 BOM off of the start of `str`, if it exists.
 *
 * @param {String} str
 * @return {String}
 * @api private
 */

function stripBOM(str){
  return 0xFEFF == str.charCodeAt(0)
    ? str.substring(1)
    : str;
}

/**
 * Compile a `Function` representation of the given jade `str`.
 *
 * Options:
 *
 *   - `compileDebug` when `false` debugging code is stripped from the compiled template
 *   - `client` when `true` the helper functions `escape()` etc will reference `jade.escape()`
 *      for use with the Jade client-side runtime.js
 *
 * @param {String} str
 * @param {Options} options
 * @return {Function}
 * @api public
 */

exports.compile = function(str, options){
  var options = options || {}
    , client = options.client
    , filename = options.filename
      ? JSON.stringify(options.filename)
      : 'undefined'
    , fn;

  str = stripBOM(String(str));

  if (options.compileDebug !== false) {
    if (options.coffee) {
      fn = [
          '__jade = [{ lineno: 1, filename: ' + filename + ' }];'
        , 'try'
        , parse(str, options).replace(/^/gm, '  ')
        , 'catch err'
        , '  rethrow(err, __jade[0].filename, __jade[0].lineno);'
        , ''
      ].join('\n');
    } else {
      fn = [
          'var __jade = [{ lineno: 1, filename: ' + filename + ' }];'
        , 'try {'
        , parse(str, options)
        , '} catch (err) {'
        , '  rethrow(err, __jade[0].filename, __jade[0].lineno);'
        , '}'
      ].join('\n');
    }
  } else {
    fn = parse(str, options);
  }

  if (client) {
    if (options.coffee) {
      fn = 'attrs ||= jade.attrs; escape ||= jade.escape; rethrow ||= jade.rethrow; merge ||= jade.merge\n' + fn;
    } else {
      fn = 'attrs = attrs || jade.attrs; escape = escape || jade.escape; rethrow = rethrow || jade.rethrow; merge = merge || jade.merge;\n' + fn;
    }
  }

  if (options.coffee) {
    return [
      '((locals, attrs, escape, rethrow, merge)->',
      fn.replace(/^/gm, '  '),
      ')'
    ].join('\n');
    // Coffee mode can't be run directly, only returned as a string
  } else {
    fn = new Function('locals, attrs, escape, rethrow, merge', fn);
    if (client) return fn;
    return function(locals){
      return fn(locals, runtime.attrs, runtime.escape, runtime.rethrow, runtime.merge);
    };
  }
};

/**
 * Render the given `str` of jade and invoke
 * the callback `fn(err, str)`.
 *
 * Options:
 *
 *   - `cache` enable template caching
 *   - `filename` filename required for `include` / `extends` and caching
 *
 * @param {String} str
 * @param {Object|Function} options or fn
 * @param {Function} fn
 * @api public
 */

exports.render = function(str, options, fn){
  // swap args
  if ('function' == typeof options) {
    fn = options, options = {};
  }

  // cache requires .filename
  if (options.cache && !options.filename) {
    return fn(new Error('the "filename" option is required for caching'));
  }

  try {
    var path = options.filename;
    var tmpl = options.cache
      ? exports.cache[path] || (exports.cache[path] = exports.compile(str, options))
      : exports.compile(str, options);
    fn(null, tmpl(options));
  } catch (err) {
    fn(err);
  }
};

/**
 * Render a Jade file at the given `path` and callback `fn(err, str)`.
 *
 * @param {String} path
 * @param {Object|Function} options or callback
 * @param {Function} fn
 * @api public
 */

exports.renderFile = function(path, options, fn){
  var key = path + ':string';

  if ('function' == typeof options) {
    fn = options, options = {};
  }

  try {
    options.filename = path;
    var str = options.cache
      ? exports.cache[key] || (exports.cache[key] = fs.readFileSync(path, 'utf8'))
      : fs.readFileSync(path, 'utf8');
    exports.render(str, options, fn);
  } catch (err) {
    fn(err);
  }
};

/**
 * Express support.
 */

exports.__express = exports.renderFile;
<|endoftext|>


<commit_before>'use strict';

const expect = require('chai').expect;
const lookupCommand = require('../../../lib/cli/lookup-command');
const Command = require('../../../lib/models/command');
const Project = require('../../../lib/models/project');
const MockUI = require('console-ui/mock');
const AddonCommand = require('../../fixtures/addon/commands/addon-command');
const OtherCommand = require('../../fixtures/addon/commands/other-addon-command');
const ClassCommand = require('../../fixtures/addon/commands/addon-command-class');
const OverrideCommand = require('../../fixtures/addon/commands/addon-override-intentional');

let commands = {
  serve: Command.extend({
    name: 'serve',
    aliases: ['s'],
    works: 'everywhere',
    availableOptions: [{ name: 'port', key: 'port', type: Number, default: 4200, required: true }],
    run() {},
  }),
};

function AddonServeCommand() {
  this.name = 'FakeAddon';
  return this;
}
AddonServeCommand.prototype.includedCommands = function () {
  return {
    Serve: {
      name: 'serve',
      description: 'overrides the serve command',
    },
  };
};

describe('cli/lookup-command.js', function () {
  let ui;
  let project = {
    isEmberCLIProject() {
      return true;
    },
    initializeAddons() {
      this.addons = [new AddonCommand(), new OtherCommand(), new ClassCommand()];
    },
    addonCommands: Project.prototype.addonCommands,
    eachAddonCommand: Project.prototype.eachAddonCommand,
  };

  before(function () {
    ui = new MockUI();
  });

  it('lookupCommand() should find commands by name and aliases.', function () {
    // Valid commands

    expect(lookupCommand(commands, 'serve')).to.exist;
    expect(lookupCommand(commands, 's')).to.exist;
  });

  it('lookupCommand() should find commands that addons add by name and aliases.', function () {
    let command, Command;

    Command = lookupCommand(commands, 'addon-command', [], {
      project,
      ui,
    });
    command = new Command({
      ui,
      project,
    });

    expect(command.name).to.equal('addon-command');

    Command = lookupCommand(commands, 'ac', [], {
      project,
      ui,
    });

    command = new Command({
      ui,
      project,
    });

    expect(command.name).to.equal('addon-command');

    Command = lookupCommand(commands, 'other-addon-command', [], {
      project,
      ui,
    });

    command = new Command({
      ui,
      project,
    });

    expect(command.name).to.equal('other-addon-command');

    Command = lookupCommand(commands, 'oac', [], {
      project,
      ui,
    });

    command = new Command({
      ui,
      project,
    });

    expect(command.name).to.equal('other-addon-command');

    Command = lookupCommand(commands, 'class-addon-command', [], {
      project,
      ui,
    });

    command = new Command({
      ui,
      project,
    });

    expect(command.name).to.equal('class-addon-command');
  });

  it('lookupCommand() should write out a warning when overriding a core command', function () {
    project = {
      isEmberCLIProject() {
        return true;
      },
      initializeAddons() {
        this.addons = [new AddonServeCommand()];
      },
      addonCommands: Project.prototype.addonCommands,
      eachAddonCommand: Project.prototype.eachAddonCommand,
    };

    lookupCommand(commands, 'serve', [], {
      project,
      ui,
    });

    let re = new RegExp(
      `WARNING: An ember-addon \\(${project.addons[0].name}\\) has attempted to override the core command "serve"\\. The core command will be used.*`
    );
    expect(ui.output).to.match(re);
  });

  it('lookupCommand() should write out a warning when overriding a core command and allow it if intentional', function () {
    project = {
      isEmberCLIProject() {
        return true;
      },
      initializeAddons() {
        this.addons = [new OverrideCommand()];
      },
      addonCommands: Project.prototype.addonCommands,
      eachAddonCommand: Project.prototype.eachAddonCommand,
    };

    lookupCommand(commands, 'serve', [], {
      project,
      ui,
    });

    let re = new RegExp(
      `WARNING: An ember-addon \\(${project.addons[0].name}\\) has attempted to override the core command "serve"\\. The addon command will be used as the overridding was explicit.*`
    );
    expect(ui.output).to.match(re);
  });

  it('lookupCommand() should return UnknownCommand object when command name is not present.', function () {
    let Command = lookupCommand(commands, 'something-else', [], {
      project,
      ui,
    });
    let command = new Command({
      ui,
      project,
    });

    expect(command.name).to.equal('something-else');

    expect(() => {
      command.validateAndRun([]);
    }).to.throw(/command.*something-else.*is invalid/);
  });
});
<commit_msg>updated tests to search for explicit addon name when expecting message, rather than expression<commit_after>'use strict';

const expect = require('chai').expect;
const lookupCommand = require('../../../lib/cli/lookup-command');
const Command = require('../../../lib/models/command');
const Project = require('../../../lib/models/project');
const MockUI = require('console-ui/mock');
const AddonCommand = require('../../fixtures/addon/commands/addon-command');
const OtherCommand = require('../../fixtures/addon/commands/other-addon-command');
const ClassCommand = require('../../fixtures/addon/commands/addon-command-class');
const OverrideCommand = require('../../fixtures/addon/commands/addon-override-intentional');

let commands = {
  serve: Command.extend({
    name: 'serve',
    aliases: ['s'],
    works: 'everywhere',
    availableOptions: [{ name: 'port', key: 'port', type: Number, default: 4200, required: true }],
    run() {},
  }),
};

function AddonServeCommand() {
  this.name = 'FakeAddon';
  return this;
}
AddonServeCommand.prototype.includedCommands = function () {
  return {
    Serve: {
      name: 'serve',
      description: 'overrides the serve command',
    },
  };
};

describe('cli/lookup-command.js', function () {
  let ui;
  let project = {
    isEmberCLIProject() {
      return true;
    },
    initializeAddons() {
      this.addons = [new AddonCommand(), new OtherCommand(), new ClassCommand()];
    },
    addonCommands: Project.prototype.addonCommands,
    eachAddonCommand: Project.prototype.eachAddonCommand,
  };

  before(function () {
    ui = new MockUI();
  });

  it('lookupCommand() should find commands by name and aliases.', function () {
    // Valid commands

    expect(lookupCommand(commands, 'serve')).to.exist;
    expect(lookupCommand(commands, 's')).to.exist;
  });

  it('lookupCommand() should find commands that addons add by name and aliases.', function () {
    let command, Command;

    Command = lookupCommand(commands, 'addon-command', [], {
      project,
      ui,
    });
    command = new Command({
      ui,
      project,
    });

    expect(command.name).to.equal('addon-command');

    Command = lookupCommand(commands, 'ac', [], {
      project,
      ui,
    });

    command = new Command({
      ui,
      project,
    });

    expect(command.name).to.equal('addon-command');

    Command = lookupCommand(commands, 'other-addon-command', [], {
      project,
      ui,
    });

    command = new Command({
      ui,
      project,
    });

    expect(command.name).to.equal('other-addon-command');

    Command = lookupCommand(commands, 'oac', [], {
      project,
      ui,
    });

    command = new Command({
      ui,
      project,
    });

    expect(command.name).to.equal('other-addon-command');

    Command = lookupCommand(commands, 'class-addon-command', [], {
      project,
      ui,
    });

    command = new Command({
      ui,
      project,
    });

    expect(command.name).to.equal('class-addon-command');
  });

  it('lookupCommand() should write out a warning when overriding a core command', function () {
    project = {
      isEmberCLIProject() {
        return true;
      },
      initializeAddons() {
        this.addons = [new AddonServeCommand()];
      },
      addonCommands: Project.prototype.addonCommands,
      eachAddonCommand: Project.prototype.eachAddonCommand,
    };

    lookupCommand(commands, 'serve', [], {
      project,
      ui,
    });

    let re = new RegExp(
      `WARNING: An ember-addon \\(FakeAddon\\) has attempted to override the core command "serve"\\. The core command will be used`
    );
    expect(ui.output).to.match(re);
  });

  it('lookupCommand() should write out a warning when overriding a core command and allow it if intentional', function () {
    project = {
      isEmberCLIProject() {
        return true;
      },
      initializeAddons() {
        this.addons = [new OverrideCommand()];
      },
      addonCommands: Project.prototype.addonCommands,
      eachAddonCommand: Project.prototype.eachAddonCommand,
    };

    lookupCommand(commands, 'serve', [], {
      project,
      ui,
    });

    let re = new RegExp(
      `WARNING: An ember-addon \\(Other Ember CLI Addon Command To Test Intentional Core Command Override\\) has attempted to override the core command "serve"\\. The addon command will be used as the overridding was explicit.*`
    );
    expect(ui.output).to.match(re);
  });

  it('lookupCommand() should return UnknownCommand object when command name is not present.', function () {
    let Command = lookupCommand(commands, 'something-else', [], {
      project,
      ui,
    });
    let command = new Command({
      ui,
      project,
    });

    expect(command.name).to.equal('something-else');

    expect(() => {
      command.validateAndRun([]);
    }).to.throw(/command.*something-else.*is invalid/);
  });
});
<|endoftext|>


<commit_before>import { moduleFor, test } from 'ember-qunit';
import Ember from 'ember';

//Stub panelActions service
const panelActionsStub = Ember.Service.extend({
    open() {
        return;
    }
});

moduleFor('controller:submit', 'Unit | Controller | submit', {
  // Specify the other units that are required for this test.
  // needs: ['controller:foo']
    needs: [
        'validator:presence',
        'validator:length',
        'validator:format',
        'service:metrics',
        'service:panel-actions'
    ],
    beforeEach: function () {
       this.register('service:panel-actions', panelActionsStub);
       this.inject.service('panel-actions', { as: 'panelActions' });
   }

});

test('editLicense sets basicsLicense and licenseValid', function(assert) {
    const ctrl = this.subject();
    assert.equal(ctrl.get('basicsLicense.copyrightHolders'), null);
    assert.equal(ctrl.get('basicsLicense.licenseType'), null);
    assert.equal(ctrl.get('basicsLicense.year'), null);
    assert.equal(ctrl.get('licenseValid'), false);
    // Trigger controller action
    ctrl.send('editLicense', 'license', true);

    assert.equal(ctrl.get('basicsLicense'), 'license');
    assert.equal(ctrl.get('licenseValid'), true);
});

test('applyLicenseToggle toggles applyLicense', function(assert) {
    const ctrl = this.subject();
    assert.equal(ctrl.get('applyLicense'), false);
    ctrl.send('applyLicenseToggle', true);
    assert.equal(ctrl.get('applyLicense'), true);
});

test('next opens next panel and flashes changes saved', function(assert) {
    const ctrl = this.subject();
    const currentPanelName = 'Discipline';
    assert.equal('Basics', ctrl.get(`_names.${ctrl.get('_names').indexOf(currentPanelName) + 1}`));
    // Test breaking down before Ember.run.later complete
    // ctrl.send('next', currentPanelName);

});
<commit_msg>Add placeholders for some controller action tests.<commit_after>import { moduleFor, test } from 'ember-qunit';
import Ember from 'ember';
import DS from 'ember-data';

//Stub panelActions service
const panelActionsStub = Ember.Service.extend({
    open() {
        return;
    },
    toggle(name) {
        const panel = panels[name];
        return panel.get('isOpen') ? panel.set('isOpen', false) : panel.set('isOpen', true);
    }
});

let panels = Ember.Object.create({
    'Discipline': Ember.Object.create({'isOpen': true}), 'Basics': Ember.Object.create({'isOpen': false})
});

moduleFor('controller:submit', 'Unit | Controller | submit', {
  // Specify the other units that are required for this test.
  // needs: ['controller:foo']
    needs: [
        'validator:presence',
        'validator:length',
        'validator:format',
        'service:metrics',
        'service:panel-actions'
    ],
    beforeEach: function () {
       this.register('service:panel-actions', panelActionsStub);
       this.inject.service('panel-actions', { as: 'panelActions' });
   }

});

test('editLicense sets basicsLicense and licenseValid', function(assert) {
    const ctrl = this.subject();
    assert.equal(ctrl.get('basicsLicense.copyrightHolders'), null);
    assert.equal(ctrl.get('basicsLicense.licenseType'), null);
    assert.equal(ctrl.get('basicsLicense.year'), null);
    assert.equal(ctrl.get('licenseValid'), false);
    // Trigger controller action
    ctrl.send('editLicense', 'license', true);

    assert.equal(ctrl.get('basicsLicense'), 'license');
    assert.equal(ctrl.get('licenseValid'), true);
});

test('applyLicenseToggle toggles applyLicense', function(assert) {
    const ctrl = this.subject();
    assert.equal(ctrl.get('applyLicense'), false);
    ctrl.send('applyLicenseToggle', true);
    assert.equal(ctrl.get('applyLicense'), true);
});

test('next opens next panel and flashes changes saved', function(assert) {
    const ctrl = this.subject();
    const currentPanelName = 'Discipline';
    assert.equal('Basics', ctrl.get(`_names.${ctrl.get('_names').indexOf(currentPanelName) + 1}`));
    // Test breaking down before Ember.run.later complete
    // ctrl.send('next', currentPanelName);
});

test('next opens next panel and flashes changes saved', function(assert) {
    const ctrl = this.subject();
    const currentPanelName = 'Discipline';
    assert.equal('Basics', ctrl.get(`_names.${ctrl.get('_names').indexOf(currentPanelName) + 1}`));
    // TODO Test breaking down before setTimeout  complete
    // ctrl.send('next', currentPanelName);
});

test('nextUploadSection closes current panel and opens next panel', function(assert) {
    // TODO not really testing anything except the stub
    const ctrl = this.subject();
    panels = Ember.Object.create({
        'Discipline': Ember.Object.create({'isOpen': true}), 'Basics': Ember.Object.create({'isOpen': false})
    });
    ctrl.send('nextUploadSection', 'Discipline', 'Basics');
    assert.equal(panels.get('Discipline.isOpen'), false);
    assert.equal(panels.get('Basics.isOpen'), true);

});

// test('changesSaved temporarily changes currentPanelSaveState to true', function(assert) {
//     // TODO
// });

// test('error', function(assert) {
//     //TODO
// })

// test('changeInitialState', function(assert) {
//     //TODO
// })

test('lockNode', function(assert) {
    const ctrl = this.subject();
    assert.equal(ctrl.get('nodeLocked'), false);
    ctrl.send('lockNode');
    assert.equal(ctrl.get('nodeLocked'), true);
});

// test('finishUpload', function(assert) {
//     //TODO
// })

// test('existingNodeExistingFile', function(assert) {
//     //TODO
// })

// test('createComponentCopyFile', function(assert) {
//     //TODO
// })

// test('resumeAbandonedPreprint', function(assert) {
//     //TODO
// })

// test('startPreprint', function(assert) {
//     //TODO
// })

test('selectExistingFile', function(assert) {
    const ctrl = this.subject();
    assert.equal(ctrl.get('selectedFile'), null);
    ctrl.send('selectExistingFile', 'my-file.jpg');
    assert.equal(ctrl.get('selectedFile'), 'my-file.jpg');
});

test('discardUploadChanges', function(assert) {
    this.inject.service('store');
    let store = this.store;
    Ember.run(() => {
        store.createRecord('file', {
            'id': '12345'
        });
    });

    const ctrl = this.subject();
    var file = store.modelFor('file');
    assert.equal(ctrl.get('file'), null);
    assert.equal(ctrl.get('selectedFile'), null);
    assert.equal(ctrl.get('nodeTitle'), null);
    assert.equal(ctrl.get('titleValid'), null);
    ctrl.send('discardUploadChanges');

});
<|endoftext|>


<commit_before>'use strict';

var func = require('./func.js'),
    type = require('./type.js'),
    equal = require('./equal.js'),
    unique = require('./unique.js'),
    strings = require('./strings.js'),
    SchemaResolver = require('./resolver.js'),
    formats = require('./formats.js'),
    types = {},
    keywords = {};

types.null = function (path) {
    return path + ' === null';
};

types.boolean = function (path) {
    return 'typeof ' + path + ' === "boolean"';
};

types.string = function (path) {
    return 'typeof ' + path + ' === "string"';
};

types.number = function (path) {
    return 'typeof ' + path + ' === "number"';
};

types.integer = function (path) {
    return 'typeof ' + path + ' === "number" && !(' + path + ' % 1)';
};

types.array = function (path) {
    return 'Array.isArray(' + path + ')';
};

types.object = function (path) {
    return 'typeof ' + path + ' === "object" && ' + path + ' && !Array.isArray(' + path + ')';
};

keywords.type = function (context) {
    if (!context.schema.type) {
        return;
    }

    var specified = Array.isArray(context.schema.type) ? context.schema.type : [context.schema.type],
        src = specified.map(function mapType(type) {
            return types[type](context.path) || 'true';
        }).join(' || ');

    if (src) {
        context.code('ok = ok && (' + src + ')');
    }
};

keywords.enum = function (context) {
    var arr = context.schema.enum,
        clauses = [],
        value, enumType, i;

    if (!Array.isArray(arr)) {
        return;
    }

    for (i = 0; i < arr.length; i++) {
        value = arr[i];
        enumType = typeof value;

        if (value === null || ['boolean', 'number', 'string'].indexOf(enumType) > -1) {
            // simple equality check for simple data types
            if (enumType === 'string') {
                clauses.push(context.path + ' === "' + value + '"');
            }
            else {
                clauses.push(context.path + ' === ' + value);
            }
        }
        else {
            // deep equality check for complex types or regexes
            clauses.push('equal(' + context.path + ', ' + JSON.stringify(value) + ')');
        }
    }

    context.code('ok = ok && (' + clauses.join(' || ') + ')');
};

keywords.minimum = function (context) {
    if (typeof context.schema.minimum === 'number') {
        context.code('ok = ok && (!(' + types.number(context.path) + ') || ' + context.path + ' >= ' + context.schema.minimum + ')');
    }
};

keywords.exclusiveMinimum = function (context) {
    if (context.schema.exclusiveMinimum === true && typeof context.schema.minimum === 'number') {
        context.code('ok = ok && ' + context.path + ' !== ' + context.schema.minimum);
    }
};

keywords.maximum = function (context) {
    if (typeof context.schema.maximum === 'number') {
        context.code('ok = ok && (!(' + types.number(context.path) + ') || ' + context.path + ' <= ' + context.schema.maximum + ')');
    }
};

keywords.exclusiveMaximum = function (context) {
    if (context.schema.exclusiveMaximum === true && typeof context.schema.maximum === 'number') {
        context.code('ok = ok && ' + context.path + ' !== ' + context.schema.maximum);
    }
};

keywords.multipleOf = function (context) {
    if (typeof context.schema.multipleOf === 'number') {
        var mul = context.schema.multipleOf,
            decimals = mul.toString().length - mul.toFixed(0).length - 1,
            pow = decimals > 0 ? Math.pow(10, decimals) : 1,
            path = context.path;

        if (decimals > 0) {
            context.code('ok = ok && (!(' + types.number(path) + ') || (+(Math.round((' + path + ' * ' + pow + ') + "e+" + ' + decimals + ') + "e-" + ' + decimals + ') % ' + (mul * pow) + ') === 0)');
        } else {
            context.code('ok = ok && (!(' + types.number(path) + ') || ((' + path + ' * ' + pow + ') % ' + (mul * pow) + ') === 0)');
        }
    }
};

keywords.minLength = function (context) {
    if (type.isInteger(context.schema.minLength)) {
        context.code('ok = ok && (!(' + types.string(context.path) + ') || ' + context.path + '.length >= ' + context.schema.minLength + ')');
    }
};

keywords.maxLength = function (context) {
    if (type.isInteger(context.schema.maxLength)) {
        context.code('ok = ok && (!(' + types.string(context.path) + ') || ' + context.path + '.length <= ' + context.schema.maxLength + ')');
    }
};

keywords.pattern = function (context) {
    var regex = typeof context.schema.pattern === 'string' ?
        new RegExp(context.schema.pattern) :
        context.schema.pattern;

    if (type.isRegExp(regex)) {
        context.code('ok = ok && (!(' + types.string(context.path) + ') || (' + regex.toString() + ').test(' + context.path + '))');
    }
};

keywords.format = function (context) {
    if (typeof context.schema.format !== 'string' || !formats[context.schema.format]) {
        return;
    }

    context.code('ok = ok && (!(' + types.string(context.path) + ') || (' + formats[context.schema.format].toString() + ').test(' + context.path + '))');
};

keywords.minItems = function (context) {
    if (type.isInteger(context.schema.minItems)) {
        context.code('ok = ok && (!(' + types.array(context.path) + ') || ' + context.path + '.length >= ' + context.schema.minItems + ')');
    }
};

keywords.maxItems = function (context) {
    if (type.isInteger(context.schema.maxItems)) {
        context.code('ok = ok && (!(' + types.array(context.path) + ') || ' + context.path + '.length <= ' + context.schema.maxItems + ')');
    }
};

keywords.uniqueItems = function (context) {
    if (context.schema.uniqueItems) {
        context.code('ok = ok && (!(' + types.array(context.path) + ') || unique(' + context.path + ').length === ' + context.path + '.length)');
    }
};

keywords.items = function (context) {
    var index = context.declare(0),
        i = 0;

    context.code('if (ok && ' + types.array(context.path) + ') {');

    if (type(context.schema.items) === 'object') {
        context.code('for (' + index + '; ' + index + ' < ' + context.path + '.length; ' + index + '++) {');

        context.validate(context.path + '[' + index + ']', context.schema.items);

        context.code('if (!ok) {')
            ('break')
        ('}');

        context.code('}');
    }
    else if (Array.isArray(context.schema.items)) {
        for (; i < context.schema.items.length; i++) {
            context.code('if (' + context.path + '.length - 1 >= ' + i + ') {');

            context.validate(context.path + '[' + i + ']', context.schema.items[i]);

            context.code('}');
        }

        if (type.isObject(context.schema.additionalItems)) {
            context.code('for (' + index + ' = ' + i + '; ' + index + ' < ' + context.path + '.length; ' + index + '++) {');

            context.validate(context.path + '[' + index + ']', context.schema.additionalItems);

            context.code('if (!ok) {')
                ('break')
            ('}')

            ('}');
        }
    }

    context.code('}');
};

keywords.additionalItems = function (context) {
    if (context.schema.additionalItems === false && Array.isArray(context.schema.items)) {
        context.code('ok = ok && !(' + types.array(context.path) + ') || ' + context.path + '.length <= ' + context.schema.items.length);
    }
};

keywords.maxProperties = function (context) {
    if (type.isInteger(context.schema.maxProperties)) {
        context.code('ok = ok && !(' + types.object(context.path) + ') || Object.keys(' + context.path + ').length <= ' + context.schema.maxProperties);
    }
};

keywords.minProperties = function (context) {
    if (type.isInteger(context.schema.minProperties)) {
        context.code('ok = ok && !(' + types.object(context.path) + ') || Object.keys(' + context.path + ').length >= ' + context.schema.minProperties);
    }
};

keywords.required = function (context) {
    if (!Array.isArray(context.schema.required)) {
        return;
    }

    context.code('if (ok && ' + types.object(context.path) + ') {');

    for (var i = 0; i < context.schema.required.length; i++) {
        context.code('ok = ok && ' + context.path + '.' + context.schema.required[i] + ' !== undefined');
    }

    context.code('}');
};

keywords.properties = function (context) {
    var props = context.schema.properties,
        prop;

    if (!type.isObject(props)) {
        return;
    }

    context.code('if (ok && ' + types.object(context.path) + ') {');

    for (prop in props) {
        context.code('if (' + context.path + '.' + prop + ' !== undefined) {');

        context.validate(context.path + '.' + prop, props[prop]);

        context.code('}');
    }

    context.code('}');
};

keywords.$ref = function (context) {
    if (!context.schema.$ref) {
        return;
    }

    var compiled = context.compile(context.schema);

    context.code('ok = ok && ' + compiled + '(' + context.path + ')');
};

// TODO: Object validators / multi validators

function jsen(schema) {
    if (!type.isObject(schema)) {
        throw new Error(strings.invalidSchema);
    }

    var resolver = new SchemaResolver(schema),
        counter = 0,
        id = function () { return 'i' + (counter++); },
        funcache = {},
        refs = {},
        scope = {
            equal: equal,
            unique: unique,
            refs: refs
        };

    function cacheCompile(schema) {
        var deref = resolver.resolve(schema),
            ref = schema.$ref,
            cached = funcache[ref],
            func;

        if (!cached) {
            cached = funcache[ref] = {
                key: id(),
                func: function (data) {
                    return func(data);
                }
            };

            func = compile(deref);

            refs[cached.key] = cached.func;
        }

        return 'refs.' + cached.key;
    }

    function compile(schema) {
        function declare(def) {
            var variname = id();

            source.def(variname, def);

            return variname;
        }

        function validate(path, schema) {
            var context = {
                    path: path,
                    schema: schema,
                    code: source,
                    declare: declare,
                    compile: cacheCompile,
                    validate: validate
                },
                keys = Object.keys(schema),
                generator, i;

            for (i = 0; i < keys.length; i++) {
                generator = keywords[keys[i]];

                if (generator) {
                    generator(context);
                }
            }
        }

        var source = func('data')
            ('var ok = true');

        validate('data', schema);

        source('return ok');

        return source.compile(scope);
    }

    // return resolve(schema, compile);
    return compile(schema);
}

module.exports = jsen;<commit_msg>Add property validation<commit_after>'use strict';

var func = require('./func.js'),
    type = require('./type.js'),
    equal = require('./equal.js'),
    unique = require('./unique.js'),
    strings = require('./strings.js'),
    SchemaResolver = require('./resolver.js'),
    formats = require('./formats.js'),
    types = {},
    keywords = {};

types.null = function (path) {
    return path + ' === null';
};

types.boolean = function (path) {
    return 'typeof ' + path + ' === "boolean"';
};

types.string = function (path) {
    return 'typeof ' + path + ' === "string"';
};

types.number = function (path) {
    return 'typeof ' + path + ' === "number"';
};

types.integer = function (path) {
    return 'typeof ' + path + ' === "number" && !(' + path + ' % 1)';
};

types.array = function (path) {
    return 'Array.isArray(' + path + ')';
};

types.object = function (path) {
    return 'typeof ' + path + ' === "object" && ' + path + ' && !Array.isArray(' + path + ')';
};

keywords.type = function (context) {
    if (!context.schema.type) {
        return;
    }

    var specified = Array.isArray(context.schema.type) ? context.schema.type : [context.schema.type],
        src = specified.map(function mapType(type) {
            return types[type](context.path) || 'true';
        }).join(' || ');

    if (src) {
        context.code('ok = ok && (' + src + ')');
    }
};

keywords.enum = function (context) {
    var arr = context.schema.enum,
        clauses = [],
        value, enumType, i;

    if (!Array.isArray(arr)) {
        return;
    }

    for (i = 0; i < arr.length; i++) {
        value = arr[i];
        enumType = typeof value;

        if (value === null || ['boolean', 'number', 'string'].indexOf(enumType) > -1) {
            // simple equality check for simple data types
            if (enumType === 'string') {
                clauses.push(context.path + ' === "' + value + '"');
            }
            else {
                clauses.push(context.path + ' === ' + value);
            }
        }
        else {
            // deep equality check for complex types or regexes
            clauses.push('equal(' + context.path + ', ' + JSON.stringify(value) + ')');
        }
    }

    context.code('ok = ok && (' + clauses.join(' || ') + ')');
};

keywords.minimum = function (context) {
    if (typeof context.schema.minimum === 'number') {
        context.code('ok = ok && (!(' + types.number(context.path) + ') || ' + context.path + ' >= ' + context.schema.minimum + ')');
    }
};

keywords.exclusiveMinimum = function (context) {
    if (context.schema.exclusiveMinimum === true && typeof context.schema.minimum === 'number') {
        context.code('ok = ok && ' + context.path + ' !== ' + context.schema.minimum);
    }
};

keywords.maximum = function (context) {
    if (typeof context.schema.maximum === 'number') {
        context.code('ok = ok && (!(' + types.number(context.path) + ') || ' + context.path + ' <= ' + context.schema.maximum + ')');
    }
};

keywords.exclusiveMaximum = function (context) {
    if (context.schema.exclusiveMaximum === true && typeof context.schema.maximum === 'number') {
        context.code('ok = ok && ' + context.path + ' !== ' + context.schema.maximum);
    }
};

keywords.multipleOf = function (context) {
    if (typeof context.schema.multipleOf === 'number') {
        var mul = context.schema.multipleOf,
            decimals = mul.toString().length - mul.toFixed(0).length - 1,
            pow = decimals > 0 ? Math.pow(10, decimals) : 1,
            path = context.path;

        if (decimals > 0) {
            context.code('ok = ok && (!(' + types.number(path) + ') || (+(Math.round((' + path + ' * ' + pow + ') + "e+" + ' + decimals + ') + "e-" + ' + decimals + ') % ' + (mul * pow) + ') === 0)');
        } else {
            context.code('ok = ok && (!(' + types.number(path) + ') || ((' + path + ' * ' + pow + ') % ' + (mul * pow) + ') === 0)');
        }
    }
};

keywords.minLength = function (context) {
    if (type.isInteger(context.schema.minLength)) {
        context.code('ok = ok && (!(' + types.string(context.path) + ') || ' + context.path + '.length >= ' + context.schema.minLength + ')');
    }
};

keywords.maxLength = function (context) {
    if (type.isInteger(context.schema.maxLength)) {
        context.code('ok = ok && (!(' + types.string(context.path) + ') || ' + context.path + '.length <= ' + context.schema.maxLength + ')');
    }
};

keywords.pattern = function (context) {
    var regex = typeof context.schema.pattern === 'string' ?
        new RegExp(context.schema.pattern) :
        context.schema.pattern;

    if (type.isRegExp(regex)) {
        context.code('ok = ok && (!(' + types.string(context.path) + ') || (' + regex.toString() + ').test(' + context.path + '))');
    }
};

keywords.format = function (context) {
    if (typeof context.schema.format !== 'string' || !formats[context.schema.format]) {
        return;
    }

    context.code('ok = ok && (!(' + types.string(context.path) + ') || (' + formats[context.schema.format].toString() + ').test(' + context.path + '))');
};

keywords.minItems = function (context) {
    if (type.isInteger(context.schema.minItems)) {
        context.code('ok = ok && (!(' + types.array(context.path) + ') || ' + context.path + '.length >= ' + context.schema.minItems + ')');
    }
};

keywords.maxItems = function (context) {
    if (type.isInteger(context.schema.maxItems)) {
        context.code('ok = ok && (!(' + types.array(context.path) + ') || ' + context.path + '.length <= ' + context.schema.maxItems + ')');
    }
};

keywords.additionalItems = function (context) {
    if (context.schema.additionalItems === false && Array.isArray(context.schema.items)) {
        context.code('ok = ok && !(' + types.array(context.path) + ') || ' + context.path + '.length <= ' + context.schema.items.length);
    }
};

keywords.uniqueItems = function (context) {
    if (context.schema.uniqueItems) {
        context.code('ok = ok && (!(' + types.array(context.path) + ') || unique(' + context.path + ').length === ' + context.path + '.length)');
    }
};

keywords.items = function (context) {
    var index = context.declare(0),
        i = 0;

    context.code('if (ok && ' + types.array(context.path) + ') {');

    if (type(context.schema.items) === 'object') {
        context.code('for (' + index + '; ' + index + ' < ' + context.path + '.length; ' + index + '++) {');

        context.validate(context.path + '[' + index + ']', context.schema.items);

        context.code('if (!ok) {')
            ('break')
        ('}');

        context.code('}');
    }
    else if (Array.isArray(context.schema.items)) {
        for (; i < context.schema.items.length; i++) {
            context.code('if (' + context.path + '.length - 1 >= ' + i + ') {');

            context.validate(context.path + '[' + i + ']', context.schema.items[i]);

            context.code('}');
        }

        if (type.isObject(context.schema.additionalItems)) {
            context.code('for (' + index + ' = ' + i + '; ' + index + ' < ' + context.path + '.length; ' + index + '++) {');

            context.validate(context.path + '[' + index + ']', context.schema.additionalItems);

            context.code('if (!ok) {')
                ('break')
            ('}')

            ('}');
        }
    }

    context.code('}');
};

keywords.maxProperties = function (context) {
    if (type.isInteger(context.schema.maxProperties)) {
        context.code('ok = ok && !(' + types.object(context.path) + ') || Object.keys(' + context.path + ').length <= ' + context.schema.maxProperties);
    }
};

keywords.minProperties = function (context) {
    if (type.isInteger(context.schema.minProperties)) {
        context.code('ok = ok && !(' + types.object(context.path) + ') || Object.keys(' + context.path + ').length >= ' + context.schema.minProperties);
    }
};

keywords.required = function (context) {
    if (!Array.isArray(context.schema.required)) {
        return;
    }

    context.code('if (ok && ' + types.object(context.path) + ') {');

    for (var i = 0; i < context.schema.required.length; i++) {
        context.code('ok = ok && ' + context.path + '.' + context.schema.required[i] + ' !== undefined');
    }

    context.code('}');
};

keywords.properties =
keywords.patternProperties =
keywords.additionalProperties = function (context) {
    if (context.validatedProperties) {
        // prevent multiple generations of this function
        return;
    }

    var props = context.schema.properties,
        propKeys = type(props) === 'object' ? Object.keys(props) : [],
        patProps = context.schema.patternProperties,
        patterns = type(patProps) === 'object' ? Object.keys(patProps) : [],
        addProps = context.schema.additionalProperties,
        addPropsCheck = addProps === false || type(addProps) === 'object',
        key, found,
        propKey, pattern, i;

    if (!propKeys.length && !patterns.length && !addPropsCheck) {
        return;
    }

    key = context.declare('""');

    if (addPropsCheck) {
        found = context.declare(false);
    }

    context.code('if (ok && ' + types.object(context.path) + ') {')
        ('for (' + key + ' in ' + context.path + ') {');

    if (addPropsCheck) {
        context.code(found + ' = false');
    }

    // validate regular properties
    for (i = 0; i < propKeys.length; i++) {
        propKey = propKeys[i];

        context.code('if (ok && ' + key + ' === "' + propKey + '") {');

        if (addPropsCheck) {
            context.code(found + ' = true');
        }

        context.validate(context.path + '[' + key + ']', props[propKey]);

        context.code('}');
    }

    // validate pattern properties
    for (i = 0; i < patterns.length; i++) {
        pattern = patterns[i];

        context.code('if (ok && (' + new RegExp(pattern).toString() + ').test(' + key + ')) {');

        if (addPropsCheck) {
            context.code(found + ' = true');
        }

        context.validate(context.path + '[' + key + ']', patProps[pattern]);

        context.code('}');
    }

    // validate additional properties
    if (addPropsCheck) {
        context.code('if (ok && !' + found + ') {');

        if (addProps === false) {
            // do not allow additional properties
            context.code('ok = false');
        }
        else {
            // validate additional properties
            context.validate(context.path + '[' + key + ']', addProps);
        }

        context.code('}');
    }

    context.code('if (!ok) {')
        ('break')
    ('}');

    context.code('}')
    ('}');

    context.validatedProperties = true;
};

keywords.dependencies = function (context) {
    if (type(context.schema.dependencies) !== 'object') {
        return;
    }

    var key, dep, i = 0;

    context.code('if (ok && ' + types.object(context.path) + ') {');

    for (key in context.schema.dependencies) {
        dep = context.schema.dependencies[key];

        context.code('if (ok && ' + context.path + '["' + key + '"] !== undefined) {');

        if (type(dep) === 'object') {
            //schema dependency
            context.validate(context.path, dep);
        }
        else {
            // property dependency
            for (i; i < dep.length; i++) {
                context.code('ok = ok && ' + context.path + '["' + dep[i] + '"] !== undefined');
            }
        }

        context.code('}');
    }

    context.code('}');
};

keywords.$ref = function (context) {
    if (!context.schema.$ref) {
        return;
    }

    var compiled = context.compile(context.schema);

    context.code('ok = ok && ' + compiled + '(' + context.path + ')');
};

function jsen(schema) {
    if (!type.isObject(schema)) {
        throw new Error(strings.invalidSchema);
    }

    var resolver = new SchemaResolver(schema),
        counter = 0,
        id = function () { return 'i' + (counter++); },
        funcache = {},
        refs = {},
        scope = {
            equal: equal,
            unique: unique,
            refs: refs
        };

    function cacheCompile(schema) {
        var deref = resolver.resolve(schema),
            ref = schema.$ref,
            cached = funcache[ref],
            func;

        if (!cached) {
            cached = funcache[ref] = {
                key: id(),
                func: function (data) {
                    return func(data);
                }
            };

            func = compile(deref);

            refs[cached.key] = cached.func;
        }

        return 'refs.' + cached.key;
    }

    function compile(schema) {
        function declare(def) {
            var variname = id();

            source.def(variname, def);

            return variname;
        }

        function validate(path, schema) {
            var context = {
                    path: path,
                    schema: schema,
                    code: source,
                    declare: declare,
                    compile: cacheCompile,
                    validate: validate
                },
                keys = Object.keys(schema),
                generator, i;

            for (i = 0; i < keys.length; i++) {
                generator = keywords[keys[i]];

                if (generator) {
                    generator(context);
                }
            }
        }

        var source = func('data')
            ('var ok = true');

        validate('data', schema);

        source('return ok');

        return source.compile(scope);
    }

    return compile(schema);
}

module.exports = jsen;<|endoftext|>


<commit_before>'use strict';

var isGitRepo = require('is-git-url');
var expect    = require('chai').expect;

describe('cleanBaseURL()', function() {
  it('recognizes git-style urls in various formats', function() {
    expect(isGitRepo('https://github.com/trek/app-blueprint-test.git')).to.be.ok;
    expect(isGitRepo('git@github.com:trek/app-blueprint-test.git')).to.be.ok;
    expect(isGitRepo('git+ssh://user@server/project.git')).to.be.ok;
    expect(isGitRepo('git+https://user@server/project.git')).to.be.ok;
  });
});
<commit_msg>tests/utilities/git-repo: Fix test suite name<commit_after>'use strict';

var isGitRepo = require('is-git-url');
var expect    = require('chai').expect;

describe('is-git-url', function() {
  it('recognizes git-style urls in various formats', function() {
    expect(isGitRepo('https://github.com/trek/app-blueprint-test.git')).to.be.ok;
    expect(isGitRepo('git@github.com:trek/app-blueprint-test.git')).to.be.ok;
    expect(isGitRepo('git+ssh://user@server/project.git')).to.be.ok;
    expect(isGitRepo('git+https://user@server/project.git')).to.be.ok;
  });
});
<|endoftext|>