<commit_before>import Url from 'url';
import config from 'config';
import crypto from 'crypto';
import base64url from 'base64url';
import Promise from 'bluebird';
import debugLib from 'debug';
import pdf from 'html-pdf';
import fs from 'fs';
import path from 'path';
import handlebars from './handlebars';

const debug = debugLib('utils');

/**
 * Encrypt with resetPasswordSecret
 */
export const encrypt = (text) => {
  const cipher = crypto.createCipher('aes-256-cbc', config.keys.opencollective.resetPasswordSecret)
  let crypted = cipher.update(text, 'utf8', 'hex')
  crypted += cipher.final('hex');
  return crypted;
};

/**
 * Descript wih resetPasswordSecret
 */
export const decrypt = (text) => {
  const decipher = crypto.createDecipher('aes-256-cbc', config.keys.opencollective.resetPasswordSecret)
  let dec = decipher.update(text,'hex','utf8')
  dec += decipher.final('utf8');
  return dec;
};

/**
 * Generate a secured token that works inside URLs
 * http://stackoverflow.com/a/25690754
 */
export const generateURLSafeToken = size => base64url(crypto.randomBytes(size));

/**
 * Get current Url.
 */
export const getRequestedUrl = (req) => {
  return `${req.protocol}://${req.get('Host')}${req.url}`;
};

/**
 * Add parameters to an url.
 */
export const addParameterUrl = (url, parameters) => {
  const parsedUrl  = Url.parse(url, true);

  function removeTrailingChar(str, char) {
    if (str.substr(-1) === char) {
      return str.substr(0, str.length - 1);
    }

    return str;
  }

  parsedUrl.pathname = removeTrailingChar(parsedUrl.pathname, '/');

  delete parsedUrl.search; // Otherwise .search is used in place of .query
  delete parsedUrl.query.api_key; // make sure we don't surface the api_key publicly

  for (const p in parameters) {
    const param = parameters[p];
    parsedUrl.query[p] = param;
  }

  return Url.format(parsedUrl);
};

/**
 * Pagination: from (offset, limit) to (page, per_page).
 */
const paginatePage = (offset, limit) => {
  return {
    page: Math.floor(offset / limit + 1),
    perPage: limit
  }
};

/**
 * Get links for pagination.
 */
export const getLinks = (url, options) => {
  const page = options.page || paginatePage(options.offset, options.limit).page;
  const perPage = options.perPage || paginatePage(options.offset, options.limit).perPage;

  if (!page && !perPage)
    return null;

  const links = {
    next: addParameterUrl(url, {page: page + 1, per_page: perPage}),
    current: addParameterUrl(url, {page, per_page: perPage})
  };
  if (page > 1) {
    links.prev = addParameterUrl(url, {page: page - 1, per_page: perPage});
    links.first = addParameterUrl(url, {page: 1, per_page: perPage});
  }

  if (options.total) {
    const lastPage = Math.ceil(options.total / perPage);
    links.last = addParameterUrl(url, {page: lastPage, per_page: perPage});
    if (page >= lastPage)
      delete links.next;
  }

  return links;
};

/**
 * Get headers for pagination.
 */
export const getLinkHeader = (url, options) => {
  const links = getLinks(url, options);
  let header = '';
  let k = 0;
  for (const i in links) {
    header += ((k !== 0) ? ', ' : '') + '<' + links[i] + '>; rel="' + i + '"'; // eslint-disable-line
    k += 1;
  }

  return header;
};

/**
 * We can generate our own plan ids with stripe, we will use a simple one for
 * now until we decide to make more complex plans. We will only take into account
 * the currency, interval and amount. It will have the following format
 *
 * 'USD-MONTH-1000'
 */
export const planId = (plan) =>  {
  return [plan.currency, plan.interval, plan.amount].join('-').toUpperCase();
};

/**
 * Pagination offset: from (page,per_page) to (offset, limit).
 */
export const paginateOffset = (page, perPage) => {
  return {
    offset: (page - 1) * perPage,
    limit: perPage
  }
};

/**
 * Returns stats for each tier compared to previousMonth
 *
 * @PRE:
 *  - tiers: array of Tier: [ { name, interval, users: [ { id, totalDonations, firstDonation, lastDonation } ] } ]
 *  - startDate, endDate: boundaries for lastMonth
 *
 * @POST: { stats, tiers }
 *  - stats.backers.lastMonth: number of backers who were active by endDate
 *  - stats.backers.previousMonth: number of backers who were active by startDate
 *  - stats.backers.new: the number of backers whose first donation was after startDate
 *  - stats.backers.lost: the number of backers who were active before startDate, but stopped being active
 *  - tiers: tiers with users sorted by totalDonations
 */
export const getTiersStats = (tiers, startDate, endDate) => {

  const userids = {};
  const stats = { backers: {} };

  const rank = (user) => {
    if (user.isNew) return 1;
    if (user.isLost) return 2;
    return 3;
  };

  stats.backers.lastMonth = 0;
  stats.backers.previousMonth = 0;
  stats.backers.new = 0;
  stats.backers.lost = 0;

  // We only keep the tiers that have at least one user
  tiers = tiers.filter(tier => tier.users.length > 0 && tier.name != 'host' && tier.name != 'core contributor');

  // We sort tiers by number of users ASC
  tiers.sort((a,b) => b.range[0] - a.range[0]);

  tiers = tiers.map(tier => {

    let index = 0
    debug("> processing tier ", tier.name);

    // We sort users by total donations DESC
    tier.users.sort((a,b) => b.totalDonations - a.totalDonations );

    tier.users = Promise.filter(tier.users, u => {
      if (userids[u.id]) {
        debug(">>> user ", u.username, "is a duplicate");
        return false;
      }
      userids[u.id] = true;

      u.index = index++;

      return Promise.all([tier.isActive(u, endDate), tier.isActive(u, startDate)])
        .then(results => {
          u.activeLastMonth = results[0];
          u.activePreviousMonth = (u.firstDonation < startDate) && results[1];

          if (tier.name.match(/sponsor/i))
            u.isSponsor = true;
          if (u.firstDonation > startDate) {
            u.isNew = true;
            stats.backers.new++;
          }
          if (u.activePreviousMonth && !u.activeLastMonth) {
            u.isLost = true;
            stats.backers.lost++;
          }

          debug("----------- ", u.username, "----------");
          debug("firstDonation", u.firstDonation && u.firstDonation.toISOString().substr(0,10));
          debug("totalDonations", u.totalDonations/100);
          debug("active last month?", u.activeLastMonth);
          debug("active previous month?", u.activePreviousMonth);
          debug("is new?", u.isNew === true);
          debug("is lost?", u.isLost === true);
          if (u.activePreviousMonth)
            stats.backers.previousMonth++;
          if (u.activeLastMonth) {
            stats.backers.lastMonth++;
            return true;
          } else if (u.isLost) {
            return true;
          }
        });
    });

    tier.users.sort((a, b) => {
      if (rank(a) > rank(b)) return 1;
      if (rank(a) < rank(b)) return -1;
      return a.index - b.index; // make sure we keep the original order within a tier (typically totalDonations DESC)
    });

    return tier;
  });
  return { stats, tiers};
}

/**
 * export data to CSV
 * @param {*} data
 * @param {*} attributes
 * @param {*} getColumnName
 * @param {*} processValue
 */
export function exportToCSV(data, attributes, getColumnName = (attr) => attr, processValue = (attr, val) => val) {
  const lines = [];

  lines.push(`"${attributes.map(getColumnName).join('","')}"`); // Header

  const getLine = (row) => {
    const cols = [];
    attributes.map(attr => {
      cols.push(`${processValue(attr, row[attr])}`.replace(/\"/g,"\""));
    });
    return `"${cols.join('","')}"`;
  }

  data.map(row => {
    lines.push(getLine(row));
  });
  return lines.join('\n');
}

/**
 * export transactions to PDF
 */
export function exportToPDF(template, data, options) {

  options = options || {};
  options.paper = options.paper || 'Letter' // Letter for US or A4 for Europe

  let paperSize;

  switch (options.paper) {
    case 'A4':
      paperSize = {
        width: '210mm',
        height: '297mm',
        margin: {
          top: '10mm',
          left: '10mm'
        }
      }
      break;
    case 'Letter':
    default:
      paperSize = {
        width: '8.5in',
        height: '11in',
        margin: {
          top: '0.4in',
          left: '0.4in'
        }
      }
      break;
  }

  data.paperSize = paperSize;
  options.paperSize = paperSize;

  const templateFilepath = path.resolve(__dirname, `../../templates/pdf/${template}.hbs`);
  const source = fs.readFileSync(templateFilepath, 'utf8');
  const render = handlebars.compile(source);

  const html = render(data);

  if (options.format === 'html') return Promise.resolve(html);
  options.format = options.paper;

  return new Promise((resolve, reject) => {
    pdf.create(html, options).toBuffer((err, buffer) => {
      if (err) return reject(err);
      return resolve(buffer);
    });
  });
}

/**
 * Default host id, set this for new collectives created through Github
 */
export const defaultHostUser = (tag) => {
  if (process.env.NODE_ENV === 'production' || process.env.NODE_ENV  === 'staging') {
    if (tag === 'opensource') {
      return { id: 772, CollectiveId: 83 }; // Open Source Host Collective User
    } else {
      return { id: 7944, CollectiveId: 8674 }; // Open Source Host Collective User
    }
  }
  return { id: 1, CollectiveId: 1 };
};

/**
 * Demo host id, set this for new collectives created through the flow
 */
export const demoHostId = () => {
  if (process.env.NODE_ENV === 'production' || process.env.NODE_ENV  === 'staging') {
    return 254;
  }
  return 1;
};

export const isValidEmail = (email) => {
  if (typeof email !== 'string') return false;
  return email.match(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/);
};

/**
 * Check if this is an internal email address.
 * Useful for testing emails in localhost or staging
 */
export const isEmailInternal = (email) => {
  if (!email) return false;
  if (email.match(/(opencollective\.(com|org))$/i) !== -1 ) {
    return true;
  }
  return false;
};

export function capitalize(str) {
  if (!str) return '';
  return str[0].toUpperCase() + str.slice(1);
}

export function pluralize(str, count) {
  if (count <= 1) return str;
  return `${str}s`.replace(/s+$/,'s');
}

export function resizeImage(imageUrl, { width, height, query, defaultImage }) {
  if (!imageUrl) {
    if (defaultImage) {
      imageUrl = (defaultImage.substr(0,1) === '/') ? `${config.host.website}${defaultImage}` : defaultImage;
    } else {
      return null;
    }
  }

  if (imageUrl[0] === '/') imageUrl = `https://opencollective.com${imageUrl}`;

  let queryurl = '';
  if (query) {
    queryurl = `&query=${encodeURIComponent(query)}`;
  } else {
    if (width) queryurl += `&width=${width}`;
    if (height) queryurl += `&height=${height}`;
  }
  return `${config.host.website}/proxy/images/?src=${encodeURIComponent(imageUrl)}${queryurl}`;
}

export function formatArrayToString(arr) {
  return arr.join(', ').replace(/, ([^,]*)$/,' and $1');
}

export function formatCurrency(amount, currency, precision = 0) {
  amount = amount/100; // converting cents
  let locale;
  switch (currency) {
    case 'USD':
      locale = 'en-US';
      break;
    case 'EUR':
      locale = 'en-EU';
      break;
    default:
      locale = currency;
  }
  return amount.toLocaleString(locale, {
    style: 'currency',
    currencyDisplay: 'symbol',
    currency,
    minimumFractionDigits : precision,
    maximumFractionDigits : precision
  });
}

/**
 * @PRE: { USD: 1000, EUR: 6000 }
 * @POST: "$10 and €60"
 */
export function formatCurrencyObject(currencyObj, options = { precision: 0 }) {
  const array = [];
  for (const currency in currencyObj) {
    array.push(formatCurrency(currencyObj[currency], currency, options.precision));
  }
  return formatArrayToString(array);
}

export function isUUID(str) {
  return (str.length === 36 && str.match(/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i));
}<commit_msg>update host collective for open source (#982)<commit_after>import Url from 'url';
import config from 'config';
import crypto from 'crypto';
import base64url from 'base64url';
import Promise from 'bluebird';
import debugLib from 'debug';
import pdf from 'html-pdf';
import fs from 'fs';
import path from 'path';
import handlebars from './handlebars';

const debug = debugLib('utils');

/**
 * Encrypt with resetPasswordSecret
 */
export const encrypt = (text) => {
  const cipher = crypto.createCipher('aes-256-cbc', config.keys.opencollective.resetPasswordSecret)
  let crypted = cipher.update(text, 'utf8', 'hex')
  crypted += cipher.final('hex');
  return crypted;
};

/**
 * Descript wih resetPasswordSecret
 */
export const decrypt = (text) => {
  const decipher = crypto.createDecipher('aes-256-cbc', config.keys.opencollective.resetPasswordSecret)
  let dec = decipher.update(text,'hex','utf8')
  dec += decipher.final('utf8');
  return dec;
};

/**
 * Generate a secured token that works inside URLs
 * http://stackoverflow.com/a/25690754
 */
export const generateURLSafeToken = size => base64url(crypto.randomBytes(size));

/**
 * Get current Url.
 */
export const getRequestedUrl = (req) => {
  return `${req.protocol}://${req.get('Host')}${req.url}`;
};

/**
 * Add parameters to an url.
 */
export const addParameterUrl = (url, parameters) => {
  const parsedUrl  = Url.parse(url, true);

  function removeTrailingChar(str, char) {
    if (str.substr(-1) === char) {
      return str.substr(0, str.length - 1);
    }

    return str;
  }

  parsedUrl.pathname = removeTrailingChar(parsedUrl.pathname, '/');

  delete parsedUrl.search; // Otherwise .search is used in place of .query
  delete parsedUrl.query.api_key; // make sure we don't surface the api_key publicly

  for (const p in parameters) {
    const param = parameters[p];
    parsedUrl.query[p] = param;
  }

  return Url.format(parsedUrl);
};

/**
 * Pagination: from (offset, limit) to (page, per_page).
 */
const paginatePage = (offset, limit) => {
  return {
    page: Math.floor(offset / limit + 1),
    perPage: limit
  }
};

/**
 * Get links for pagination.
 */
export const getLinks = (url, options) => {
  const page = options.page || paginatePage(options.offset, options.limit).page;
  const perPage = options.perPage || paginatePage(options.offset, options.limit).perPage;

  if (!page && !perPage)
    return null;

  const links = {
    next: addParameterUrl(url, {page: page + 1, per_page: perPage}),
    current: addParameterUrl(url, {page, per_page: perPage})
  };
  if (page > 1) {
    links.prev = addParameterUrl(url, {page: page - 1, per_page: perPage});
    links.first = addParameterUrl(url, {page: 1, per_page: perPage});
  }

  if (options.total) {
    const lastPage = Math.ceil(options.total / perPage);
    links.last = addParameterUrl(url, {page: lastPage, per_page: perPage});
    if (page >= lastPage)
      delete links.next;
  }

  return links;
};

/**
 * Get headers for pagination.
 */
export const getLinkHeader = (url, options) => {
  const links = getLinks(url, options);
  let header = '';
  let k = 0;
  for (const i in links) {
    header += ((k !== 0) ? ', ' : '') + '<' + links[i] + '>; rel="' + i + '"'; // eslint-disable-line
    k += 1;
  }

  return header;
};

/**
 * We can generate our own plan ids with stripe, we will use a simple one for
 * now until we decide to make more complex plans. We will only take into account
 * the currency, interval and amount. It will have the following format
 *
 * 'USD-MONTH-1000'
 */
export const planId = (plan) =>  {
  return [plan.currency, plan.interval, plan.amount].join('-').toUpperCase();
};

/**
 * Pagination offset: from (page,per_page) to (offset, limit).
 */
export const paginateOffset = (page, perPage) => {
  return {
    offset: (page - 1) * perPage,
    limit: perPage
  }
};

/**
 * Returns stats for each tier compared to previousMonth
 *
 * @PRE:
 *  - tiers: array of Tier: [ { name, interval, users: [ { id, totalDonations, firstDonation, lastDonation } ] } ]
 *  - startDate, endDate: boundaries for lastMonth
 *
 * @POST: { stats, tiers }
 *  - stats.backers.lastMonth: number of backers who were active by endDate
 *  - stats.backers.previousMonth: number of backers who were active by startDate
 *  - stats.backers.new: the number of backers whose first donation was after startDate
 *  - stats.backers.lost: the number of backers who were active before startDate, but stopped being active
 *  - tiers: tiers with users sorted by totalDonations
 */
export const getTiersStats = (tiers, startDate, endDate) => {

  const userids = {};
  const stats = { backers: {} };

  const rank = (user) => {
    if (user.isNew) return 1;
    if (user.isLost) return 2;
    return 3;
  };

  stats.backers.lastMonth = 0;
  stats.backers.previousMonth = 0;
  stats.backers.new = 0;
  stats.backers.lost = 0;

  // We only keep the tiers that have at least one user
  tiers = tiers.filter(tier => tier.users.length > 0 && tier.name != 'host' && tier.name != 'core contributor');

  // We sort tiers by number of users ASC
  tiers.sort((a,b) => b.range[0] - a.range[0]);

  tiers = tiers.map(tier => {

    let index = 0
    debug("> processing tier ", tier.name);

    // We sort users by total donations DESC
    tier.users.sort((a,b) => b.totalDonations - a.totalDonations );

    tier.users = Promise.filter(tier.users, u => {
      if (userids[u.id]) {
        debug(">>> user ", u.username, "is a duplicate");
        return false;
      }
      userids[u.id] = true;

      u.index = index++;

      return Promise.all([tier.isActive(u, endDate), tier.isActive(u, startDate)])
        .then(results => {
          u.activeLastMonth = results[0];
          u.activePreviousMonth = (u.firstDonation < startDate) && results[1];

          if (tier.name.match(/sponsor/i))
            u.isSponsor = true;
          if (u.firstDonation > startDate) {
            u.isNew = true;
            stats.backers.new++;
          }
          if (u.activePreviousMonth && !u.activeLastMonth) {
            u.isLost = true;
            stats.backers.lost++;
          }

          debug("----------- ", u.username, "----------");
          debug("firstDonation", u.firstDonation && u.firstDonation.toISOString().substr(0,10));
          debug("totalDonations", u.totalDonations/100);
          debug("active last month?", u.activeLastMonth);
          debug("active previous month?", u.activePreviousMonth);
          debug("is new?", u.isNew === true);
          debug("is lost?", u.isLost === true);
          if (u.activePreviousMonth)
            stats.backers.previousMonth++;
          if (u.activeLastMonth) {
            stats.backers.lastMonth++;
            return true;
          } else if (u.isLost) {
            return true;
          }
        });
    });

    tier.users.sort((a, b) => {
      if (rank(a) > rank(b)) return 1;
      if (rank(a) < rank(b)) return -1;
      return a.index - b.index; // make sure we keep the original order within a tier (typically totalDonations DESC)
    });

    return tier;
  });
  return { stats, tiers};
}

/**
 * export data to CSV
 * @param {*} data
 * @param {*} attributes
 * @param {*} getColumnName
 * @param {*} processValue
 */
export function exportToCSV(data, attributes, getColumnName = (attr) => attr, processValue = (attr, val) => val) {
  const lines = [];

  lines.push(`"${attributes.map(getColumnName).join('","')}"`); // Header

  const getLine = (row) => {
    const cols = [];
    attributes.map(attr => {
      cols.push(`${processValue(attr, row[attr])}`.replace(/\"/g,"\""));
    });
    return `"${cols.join('","')}"`;
  }

  data.map(row => {
    lines.push(getLine(row));
  });
  return lines.join('\n');
}

/**
 * export transactions to PDF
 */
export function exportToPDF(template, data, options) {

  options = options || {};
  options.paper = options.paper || 'Letter' // Letter for US or A4 for Europe

  let paperSize;

  switch (options.paper) {
    case 'A4':
      paperSize = {
        width: '210mm',
        height: '297mm',
        margin: {
          top: '10mm',
          left: '10mm'
        }
      }
      break;
    case 'Letter':
    default:
      paperSize = {
        width: '8.5in',
        height: '11in',
        margin: {
          top: '0.4in',
          left: '0.4in'
        }
      }
      break;
  }

  data.paperSize = paperSize;
  options.paperSize = paperSize;

  const templateFilepath = path.resolve(__dirname, `../../templates/pdf/${template}.hbs`);
  const source = fs.readFileSync(templateFilepath, 'utf8');
  const render = handlebars.compile(source);

  const html = render(data);

  if (options.format === 'html') return Promise.resolve(html);
  options.format = options.paper;

  return new Promise((resolve, reject) => {
    pdf.create(html, options).toBuffer((err, buffer) => {
      if (err) return reject(err);
      return resolve(buffer);
    });
  });
}

/**
 * Default host id, set this for new collectives created through Github
 */
export const defaultHostUser = (tag) => {
  if (process.env.NODE_ENV === 'production' || process.env.NODE_ENV  === 'staging') {
    if (tag === 'opensource') {
      return { id: 772, CollectiveId: 9805 }; // Open Source Host Collective
    } else {
      return { id: 7944, CollectiveId: 8674 }; // Open Collective Host Collective
    }
  }
  return { id: 1, CollectiveId: 1 };
};

/**
 * Demo host id, set this for new collectives created through the flow
 */
export const demoHostId = () => {
  if (process.env.NODE_ENV === 'production' || process.env.NODE_ENV  === 'staging') {
    return 254;
  }
  return 1;
};

export const isValidEmail = (email) => {
  if (typeof email !== 'string') return false;
  return email.match(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/);
};

/**
 * Check if this is an internal email address.
 * Useful for testing emails in localhost or staging
 */
export const isEmailInternal = (email) => {
  if (!email) return false;
  if (email.match(/(opencollective\.(com|org))$/i) !== -1 ) {
    return true;
  }
  return false;
};

export function capitalize(str) {
  if (!str) return '';
  return str[0].toUpperCase() + str.slice(1);
}

export function pluralize(str, count) {
  if (count <= 1) return str;
  return `${str}s`.replace(/s+$/,'s');
}

export function resizeImage(imageUrl, { width, height, query, defaultImage }) {
  if (!imageUrl) {
    if (defaultImage) {
      imageUrl = (defaultImage.substr(0,1) === '/') ? `${config.host.website}${defaultImage}` : defaultImage;
    } else {
      return null;
    }
  }

  if (imageUrl[0] === '/') imageUrl = `https://opencollective.com${imageUrl}`;

  let queryurl = '';
  if (query) {
    queryurl = `&query=${encodeURIComponent(query)}`;
  } else {
    if (width) queryurl += `&width=${width}`;
    if (height) queryurl += `&height=${height}`;
  }
  return `${config.host.website}/proxy/images/?src=${encodeURIComponent(imageUrl)}${queryurl}`;
}

export function formatArrayToString(arr) {
  return arr.join(', ').replace(/, ([^,]*)$/,' and $1');
}

export function formatCurrency(amount, currency, precision = 0) {
  amount = amount/100; // converting cents
  let locale;
  switch (currency) {
    case 'USD':
      locale = 'en-US';
      break;
    case 'EUR':
      locale = 'en-EU';
      break;
    default:
      locale = currency;
  }
  return amount.toLocaleString(locale, {
    style: 'currency',
    currencyDisplay: 'symbol',
    currency,
    minimumFractionDigits : precision,
    maximumFractionDigits : precision
  });
}

/**
 * @PRE: { USD: 1000, EUR: 6000 }
 * @POST: "$10 and €60"
 */
export function formatCurrencyObject(currencyObj, options = { precision: 0 }) {
  const array = [];
  for (const currency in currencyObj) {
    array.push(formatCurrency(currencyObj[currency], currency, options.precision));
  }
  return formatArrayToString(array);
}

export function isUUID(str) {
  return (str.length === 36 && str.match(/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i));
}<|endoftext|>


<commit_before>var input    = require('./digits.js');
var exercise = {};

exercise.one = function(){
    //-------------------
    //---- Your Code ----
    //-------------------
    return 'Error: 1st function not implemented 2234';
};

exercise.two = function(data){
    //-------------------
    //---- Your Code ----
    //-------------------
    return 'Error: 2nd function not implemented';
};

exercise.three = function(data){
    //-------------------
    //---- Your Code ----
    //-------------------
    return 'Error: 3rd function not implemented';
};

exercise.four = function(data){
    //-------------------
    //---- Your Code ----
    //-------------------
    return 'Error: 4th function not implemented';
};

exercise.five = function(data){
    //-------------------
    //---- Your Code ----
    //-------------------
    return 'Error: 5th function not implemented';
};

module.exports = exercise;
<commit_msg>Update exercise.js<commit_after>var input    = require('./digits.js');
var exercise = {};

exercise.one = function(){
    //-------------------
    //---- Your Code ----
    //-------------------
    return 'Error: 1st function not implemented 2237';
};

exercise.two = function(data){
    //-------------------
    //---- Your Code ----
    //-------------------
    return 'Error: 2nd function not implemented';
};

exercise.three = function(data){
    //-------------------
    //---- Your Code ----
    //-------------------
    return 'Error: 3rd function not implemented';
};

exercise.four = function(data){
    //-------------------
    //---- Your Code ----
    //-------------------
    return 'Error: 4th function not implemented';
};

exercise.five = function(data){
    //-------------------
    //---- Your Code ----
    //-------------------
    return 'Error: 5th function not implemented';
};

module.exports = exercise;
<|endoftext|>


<commit_before>"use strict";

var http        = require('http');

module.exports = exports = {
  // NEED API KEY in api_config.js
  key: process.env.ECHO_API || api_keys.echo_api_key,

  optionBuilder: function(type, data) {
    // declare general option/query parameters
    var query = { api_key: exports.key };
    var options = {
      port: '80',
      hostname: 'developer.echonest.com',
      method: type,
      path: '/api/v4/track/'
    };
    // assign specific parameters based on request type
    if (type === 'GET') {
      options.path  = options.path + 'profile';
      query.format = 'json';
      query.md5 = data;
      query.bucket = 'audio_summary';
    } else if (type === 'POST') {
      options.path = options.path + 'upload';
      query.filetype = 'mp3';
      options.headers = {
        'Content-Type': 'application/octet-stream',
        'Content-Length': data.length
      };
    }
    // merge query results into a string
    var queryURL = [];
    for (var key in query) {
      queryURL.push(key + '=' + query[key]);
    }

    options.path = options.path + '?' + queryURL.join('&');
    return options;
  },

  get: function(md5, cb) {
    // build echo nest requesst
    var options = exports.optionBuilder('GET', md5);
    // make the http request
    http.request(options, function(response) {
      var str = '';
      response.on('data', function(chunk){
        if (chunk) {
          str+=chunk;
        }
      });
      response.on('end', function() {
        str = JSON.parse(str);
        console.log(str);
        cb(str);
      });
    })
    .end();
  },

  postBuffer: function(buffer, callback) {
    // build echo nest request
    var options = exports.optionBuilder('POST', buffer);
    // Set up the request
    var post_req = http.request(options, function(res) {
        res.setEncoding('utf8');
        res.on('data', function (chunk) {
            console.log('Response:' + chunk);
            callback(null, chunk);
        });
    });
    // post the data
    post_req.write(buffer);
    post_req.end();
  }
 };
<commit_msg>Update for deployment. Removes api_config file and demoinit file<commit_after>"use strict";

var http        = require('http'),

module.exports = exports = {
  // NEED API KEY in api_config.js
  key: process.env.ECHO_API,

  optionBuilder: function(type, data) {
    // declare general option/query parameters
    var query = { api_key: exports.key };
    var options = {
      port: '80',
      hostname: 'developer.echonest.com',
      method: type,
      path: '/api/v4/track/'
    };
    // assign specific parameters based on request type
    if (type === 'GET') {
      options.path  = options.path + 'profile';
      query.format = 'json';
      query.md5 = data;
      query.bucket = 'audio_summary';
    } else if (type === 'POST') {
      options.path = options.path + 'upload';
      query.filetype = 'mp3';
      options.headers = {
        'Content-Type': 'application/octet-stream',
        'Content-Length': data.length
      };
    }
    // merge query results into a string
    var queryURL = [];
    for (var key in query) {
      queryURL.push(key + '=' + query[key]);
    }

    options.path = options.path + '?' + queryURL.join('&');
    return options;
  },

  get: function(md5, cb) {
    // build echo nest requesst
    var options = exports.optionBuilder('GET', md5);
    // make the http request

    http.request(options, function(response) {
      var str = '';
      response.on('data', function(chunk){
        if (chunk) {
          str+=chunk;
        }
      });
      response.on('end', function() {
        str = JSON.parse(str);
        console.log(str);
        cb(str);
      });
    })
    .end();
  },

  postBuffer: function(buffer, callback) {
    // build echo nest request
    var options = exports.optionBuilder('POST', buffer);
    // Set up the request
    var post_req = http.request(options, function(res) {
        res.setEncoding('utf8');
        res.on('data', function (chunk) {
            console.log('Response:' + chunk);
            callback(null, chunk);
        });
    });
    // post the data
    post_req.write(buffer);
    post_req.end();
  }
 };
<|endoftext|>


<commit_before>//
// Authentication with MakerPass
//
var passport = require('passport')
var MakerpassStrategy = require('passport-makerpass').Strategy
var Promise    = require('knex/node_modules/bluebird')
var User       = require('./models/user')
var Group      = require('./models/group')
var Membership = require('./models/membership')
var School     = require('./models/school')

exports.mount = function (app, host) {

  if (! process.env.MAKERPASS_CLIENT_ID || ! process.env.MAKERPASS_CLIENT_SECRET) {
    throw new Error("Please set MAKERPASS_CLIENT_ID and MAKERPASS_CLIENT_SECRET")
  }

  passport.use(new MakerpassStrategy({
      clientID: process.env.MAKERPASS_CLIENT_ID,
      clientSecret: process.env.MAKERPASS_CLIENT_SECRET,
      callbackURL: host + '/auth/makerpass/callback'
    },
    function(accessToken, refreshToken, profile, done) {
      importAuthData(profile).then(done.papp(null))
    }
  ))

  app.use(passport.initialize())
  app.use(passport.session())

  passport.serializeUser(function(user, done) {
    done(null, user.uid)
  })

  passport.deserializeUser(function(id, done) {
    User.find(id)
      .then(done.papp(null))
      .catch(function (err) {
        if (err.message === 'not_found') {
          done(null, null)
        }
        else {
          done(err)
        }
      })
  })

  app.get('/auth/makerpass',
    passport.authenticate('makerpass'))

  app.get('/auth/makerpass/callback',
    passport.authenticate('makerpass', { failureRedirect: '/' }),
    function(req, res) {
      // Successful authentication, redirect home.sj
      res.redirect('/me')
    })

  app.get('/me', function (req, res) {
    res.send({ user: req.user})
  })

  app.get('/users', function(req, res){
    var users = User.retrieve(function(x){res.send({users: x})
    })
  })

  app.post('/signout', function (req, res) {
    req.session = null
    res.send({})
  })

}

var importAuthData = module.exports.importAuthData = function (mks) {

  // These two can run in parallel
  var userPromise = importUser(mks)
  var schoolPromises = mks.schools.map(School.updateOrCreate)

  return Promise.all(schoolPromises).then(function() {
    return Promise.all( mks.memberships.map( getProp('group') ).map(Group.updateOrCreate) )
  })
  .then(function() {
    return userPromise
  })
}

function importUser (mks) {
  return User.updateOrCreate({
    uid: mks.id,
    name: mks.name,
    email: mks.email,
    avatar_url: mks.avatar_url
  })
}
<commit_msg>(feat)updatedAPIkeys<commit_after>//
// Authentication with MakerPass
//
var passport = require('passport')
var MakerpassStrategy = require('passport-makerpass').Strategy
var Promise    = require('knex/node_modules/bluebird')
var User       = require('./models/user')
var Group      = require('./models/group')
var Membership = require('./models/membership')
var School     = require('./models/school')

exports.mount = function (app, host) {

  passport.use(new MakerpassStrategy({
      clientID: process.env.MAKERPASS_CLIENT_ID || 'eae6795ed5d6fe1fb29497641a083edb2c4fe242a233fc98138f7224177581e9',
      clientSecret: process.env.MAKERPASS_CLIENT_SECRET || 'c92309a053636df7b24e1672ce6190ef9c76bca9e5aebf1cb8847e70607b534f',
      callbackURL: host + '/auth/makerpass/callback'
    },
    function(accessToken, refreshToken, profile, done) {
      importAuthData(profile).then(done.papp(null))
    }
  ))

  app.use(passport.initialize())
  app.use(passport.session())

  passport.serializeUser(function(user, done) {
    done(null, user.uid)
  })

  passport.deserializeUser(function(id, done) {
    User.find(id)
      .then(done.papp(null))
      .catch(function (err) {
        if (err.message === 'not_found') {
          done(null, null)
        }
        else {
          done(err)
        }
      })
  })

  app.get('/auth/makerpass',
    passport.authenticate('makerpass'))

  app.get('/auth/makerpass/callback',
    passport.authenticate('makerpass', { failureRedirect: '/' }),
    function(req, res) {
      // Successful authentication, redirect home.sj
      res.redirect('/me')
    })

  app.get('/me', function (req, res) {
    res.send({ user: req.user})
  })

  app.get('/users', function(req, res){
    var users = User.retrieve(function(x){res.send({users: x})
    })
  })

  app.post('/signout', function (req, res) {
    req.session = null
    res.send({})
  })

}

var importAuthData = module.exports.importAuthData = function (mks) {

  // These two can run in parallel
  var userPromise = importUser(mks)
  var schoolPromises = mks.schools.map(School.updateOrCreate)

  return Promise.all(schoolPromises).then(function() {
    return Promise.all( mks.memberships.map( getProp('group') ).map(Group.updateOrCreate) )
  })
  .then(function() {
    return userPromise
  })
}

function importUser (mks) {
  return User.updateOrCreate({
    uid: mks.id,
    name: mks.name,
    email: mks.email,
    avatar_url: mks.avatar_url
  })
}
<|endoftext|>


<commit_before>/* Copyright Théo Zimmermann 2014
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

define(["app/dom", "app/i18n", "app/utils", "diff_match_patch"], function($, i18n, utils) {

    "use strict";

    // mode can take values "reading", "reading_modification" and "commenting"
    var mode = "reading";
    // if mode is "reading_modification", currently_showing stores id of comment
    var currently_showing;

    // there must be only one <article> on the page
    var article = $("article");
    // but there can be many blocks in an article
    var blocks = $(".block", article, false);
    // in the case there is no block, current_block will always represent the full article
    var current_block = article;

    var original_content, new_content;

    // button to show the original version
    var original_button = $.htmlify('<button type="button">' + i18n.translate("show-original") + '</button>');

    // make a diff_match_patch object once and for all
    var dmp = new diff_match_patch();

    // remember some of the DOM elements
    var cancel_button, comment_field;

    // FUNCTION WHICH ENABLE COMMENTING AND EDITING

    var init = function(comment_postbox) {
        comment_field = $(".textarea", comment_postbox);
        // let's curry!
        return function() {
            show_original();
            if (mode === "reading" && comment_field.innerHTML !== "") {
                mode = "commenting";
                original_content = utils.clean_html(current_block.innerHTML);
                new_content = null;
                current_block.setAttribute("contenteditable", true);
                // first time : create cancel button and associate event
                if (!cancel_button) {
                    cancel_button = $(".post-action", comment_postbox).prepend(
                      '<input type="reset" value="' + i18n.translate("postbox-cancel") + '"></input>');
                    cancel_button.on("click", function(e) {
                        if (new_content === null ||
                            confirm(i18n.translate("postbox-confirm-cancel"))) {
                            comment_field.innerHTML = "";
                            cancel();
                        }
                    });
                }
                else {
                  cancel_button.style.display = "inline";
                }
            }
            else if (mode === "commenting" && comment_field.innerHTML === ""
                                           && new_article === null) {
                cancel();
            }
        };
    };

    var maybe_article_just_changed = function() {
        var current = utils.clean_html(current_block.innerHTML);
        if (current !== original_content) {
            new_content = current;
        }
        else {
            new_content = null;
            if (comment_field.innerHTML === "") {
                cancel();
            }
        }
    };

    var cancel = function() {
        if (mode === "commenting") {
            current_block.setAttribute("contenteditable", false);
            if (new_content !== null) {
                current_block.innerHTML = original_content;
                new_content = null;
            }
            cancel_button.hide();
            mode = "reading";
        }
    };

    // FUNCTIONS TO SHOW COMMENTS / EDITS

    var show_block_comments = function() {
        // when showing an edit or commenting, the current block is locked
        if (mode == "reading") {
            // current block = block in the middle
            var center = window.pageYOffset + window.innerHeight/2;
            var i = 0;
            while (i < blocks.length && blocks[i].offsetTop <= center) { i++; }
            current_block = blocks[i - 1];
            for (var i = 0; i < blocks.length; i++) {
                blocks[i].style.background = "transparent";
            }
            current_block.style.background = "#D8D8D8";
        }
    };

    var show_edit = function(el, comment) {
        // let's curry!
        return function() {
            if (mode === "reading" || mode === "reading_modification") {
                if (currently_showing === comment.id) {
                    show_original();
                }
                else {
                    // print diffs
                    var array = JSON.parse(utils.tags_from_text(comment.edit));
                    var html = dmp.diff_prettyHtml(array);
                    current_block.innerHTML = html;

                    // add button to go back to standard reading mode
                    original_button.style.visibility = "visible";

                    // display selected comment in green and all others are set back to default
                    var comments = $(".isso-comment", null, false);
                    for (var i = 0; i < comments.length; i++) {
                        comments[i].style.background = "transparent";
                    }
                    el.style.background = "#e6ffe6";

                    // scroll to first change
                    $("#edit").scrollIntoView();

                    mode = "reading_modification";
                    currently_showing = comment.id;
                }
            }
        };
    };

    var show_original = function() {
        if (mode === "reading_modification") {
            // restore original display
            current_block.innerHTML = original_content;
            original_button.style.visibility = "hidden";
            var comments = $(".isso-comment", null, false);
            for (var i = 0; i < comments.length; i++) {
                comments[i].style.background = "transparent";
            }
            mode = "reading";
            currently_showing = null;
            // now show the current block like if we had just scrolled
            show_block_comments();
        }
    };

    // DEFINE EVENTS

    original_button.on("click", show_original);

    article.on("keyup", maybe_article_just_changed);
    document.addEventListener("keydown", function(e) {
        if (e.keyCode === 27) {
            show_original();
        }
    });

    window.addEventListener("scroll", show_block_comments);

    // ADD HTML ELEMENTS
    original_button.style.visibility = "hidden";
    $("#isso-thread").prepend(original_button);

    // FIRST CALLS
    show_block_comments();

    // PUBLIC METHODS

    return {
        init: init,
        new_article: function() {
            if (new_content === null) {
                return null;
            }
            // otherwise we apply some pre-treatment before returning
            var new_text = utils.tags_from_text(new_content);
            var diffs = dmp.diff_main(original_content, new_text);
            dmp.diff_cleanupSemantic(diffs);
            return JSON.stringify(diffs);
        },
        cancel: cancel,
        show: show_edit
    };
});

<commit_msg>semi transparent background for current block<commit_after>/* Copyright Théo Zimmermann 2014
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

define(["app/dom", "app/i18n", "app/utils", "diff_match_patch"], function($, i18n, utils) {

    "use strict";

    // mode can take values "reading", "reading_modification" and "commenting"
    var mode = "reading";
    // if mode is "reading_modification", currently_showing stores id of comment
    var currently_showing;

    // there must be only one <article> on the page
    var article = $("article");
    // but there can be many blocks in an article
    var blocks = $(".block", article, false);
    // in the case there is no block, current_block will always represent the full article
    var current_block = article;

    var original_content, new_content;

    // button to show the original version
    var original_button = $.htmlify('<button type="button">' + i18n.translate("show-original") + '</button>');

    // make a diff_match_patch object once and for all
    var dmp = new diff_match_patch();

    // remember some of the DOM elements
    var cancel_button, comment_field;

    // FUNCTION WHICH ENABLE COMMENTING AND EDITING

    var init = function(comment_postbox) {
        comment_field = $(".textarea", comment_postbox);
        // let's curry!
        return function() {
            show_original();
            if (mode === "reading" && comment_field.innerHTML !== "") {
                mode = "commenting";
                original_content = utils.clean_html(current_block.innerHTML);
                new_content = null;
                current_block.setAttribute("contenteditable", true);
                // first time : create cancel button and associate event
                if (!cancel_button) {
                    cancel_button = $(".post-action", comment_postbox).prepend(
                      '<input type="reset" value="' + i18n.translate("postbox-cancel") + '"></input>');
                    cancel_button.on("click", function(e) {
                        if (new_content === null ||
                            confirm(i18n.translate("postbox-confirm-cancel"))) {
                            comment_field.innerHTML = "";
                            cancel();
                        }
                    });
                }
                else {
                  cancel_button.style.display = "inline";
                }
            }
            else if (mode === "commenting" && comment_field.innerHTML === ""
                                           && new_article === null) {
                cancel();
            }
        };
    };

    var maybe_article_just_changed = function() {
        var current = utils.clean_html(current_block.innerHTML);
        if (current !== original_content) {
            new_content = current;
        }
        else {
            new_content = null;
            if (comment_field.innerHTML === "") {
                cancel();
            }
        }
    };

    var cancel = function() {
        if (mode === "commenting") {
            current_block.setAttribute("contenteditable", false);
            if (new_content !== null) {
                current_block.innerHTML = original_content;
                new_content = null;
            }
            cancel_button.hide();
            mode = "reading";
        }
    };

    // FUNCTIONS TO SHOW COMMENTS / EDITS

    var show_block_comments = function() {
        // when showing an edit or commenting, the current block is locked
        if (mode == "reading") {
            // current block = block in the middle
            var center = window.pageYOffset + window.innerHeight/2;
            var i = 0;
            while (i < blocks.length && blocks[i].offsetTop <= center) { i++; }
            current_block = blocks[i - 1];
            for (var i = 0; i < blocks.length; i++) {
                blocks[i].style.background = "transparent";
            }
            current_block.style.background = "rgba(211,211,211,0.5)";
        }
    };

    var show_edit = function(el, comment) {
        // let's curry!
        return function() {
            if (mode === "reading" || mode === "reading_modification") {
                if (currently_showing === comment.id) {
                    show_original();
                }
                else {
                    // print diffs
                    var array = JSON.parse(utils.tags_from_text(comment.edit));
                    var html = dmp.diff_prettyHtml(array);
                    current_block.innerHTML = html;

                    // add button to go back to standard reading mode
                    original_button.style.visibility = "visible";

                    // display selected comment in green and all others are set back to default
                    var comments = $(".isso-comment", null, false);
                    for (var i = 0; i < comments.length; i++) {
                        comments[i].style.background = "transparent";
                    }
                    el.style.background = "#e6ffe6";

                    // scroll to first change
                    $("#edit").scrollIntoView();

                    mode = "reading_modification";
                    currently_showing = comment.id;
                }
            }
        };
    };

    var show_original = function() {
        if (mode === "reading_modification") {
            // restore original display
            current_block.innerHTML = original_content;
            original_button.style.visibility = "hidden";
            var comments = $(".isso-comment", null, false);
            for (var i = 0; i < comments.length; i++) {
                comments[i].style.background = "transparent";
            }
            mode = "reading";
            currently_showing = null;
            // now show the current block like if we had just scrolled
            show_block_comments();
        }
    };

    // DEFINE EVENTS

    original_button.on("click", show_original);

    article.on("keyup", maybe_article_just_changed);
    document.addEventListener("keydown", function(e) {
        if (e.keyCode === 27) {
            show_original();
        }
    });

    window.addEventListener("scroll", show_block_comments);

    // ADD HTML ELEMENTS
    original_button.style.visibility = "hidden";
    $("#isso-thread").prepend(original_button);

    // FIRST CALLS
    show_block_comments();

    // PUBLIC METHODS

    return {
        init: init,
        new_article: function() {
            if (new_content === null) {
                return null;
            }
            // otherwise we apply some pre-treatment before returning
            var new_text = utils.tags_from_text(new_content);
            var diffs = dmp.diff_main(original_content, new_text);
            dmp.diff_cleanupSemantic(diffs);
            return JSON.stringify(diffs);
        },
        cancel: cancel,
        show: show_edit
    };
});

<|endoftext|>


<commit_before>require('dotenv').config()
import http from 'http';
import https from 'https';
import Koa from 'koa';
import Io from 'socket.io';
import KoaBody from 'koa-body';
import cors from 'kcors';
import Router from 'koa-router';
import bluebird from 'bluebird';
import Redis from 'redis';
import socketRedis from 'socket.io-redis';
import Socket from './socket';
import crypto from 'crypto'
import mailer from './utils/mailer';
import koaStatic from 'koa-static';
import koaSend from 'koa-send';

bluebird.promisifyAll(Redis.RedisClient.prototype);
bluebird.promisifyAll(Redis.Multi.prototype);

const redis = Redis.createClient(process.env.REDIS_URL)

export const getRedis = () => redis

const env = process.env.NODE_ENV || 'development';

const app = new Koa();
const PORT = process.env.PORT || 3001;

const router = new Router();
const koaBody = new KoaBody();

app.use(cors({
  credentials: true,
}));

router.post('/handshake', koaBody, async (ctx) => {
  const { body } = ctx.request;
  const { roomId } = body;

  const roomIdHash = getRoomIdHash(roomId)

  let roomExists = await redis.hgetAsync('rooms', roomIdHash)
  if (roomExists) {
    roomExists = JSON.parse(roomExists)
  }

  ctx.body = {
    id: roomId,
    ready: true,
    isLocked: Boolean(roomExists && roomExists.isLocked),
    size: ((roomExists && roomExists.users.length) || 0) + 1,
  };
});

router.post('/abuse/:roomId', koaBody, async (ctx) => {
  let { roomId } = ctx.params;

  roomId = roomId.trim();

  if (process.env.ABUSE_FROM_EMAIL_ADDRESS && process.env.ABUSE_TO_EMAIL_ADDRESS) {
    const abuseForRoomExists = await redis.hgetAsync('abuse', roomId);
    if (!abuseForRoomExists) {
      mailer.send({
        from: process.env.ABUSE_FROM_EMAIL_ADDRESS,
        to: process.env.ABUSE_TO_EMAIL_ADDRESS,
        subject: 'Darkwire Abuse Notification',
        text: `Room ID: ${roomId}`
      });
    }
  }

  await redis.hincrbyAsync('abuse', roomId, 1);

  ctx.status = 200;
});

app.use(router.routes());

const clientDistDirectory = process.env.CLIENT_DIST_DIRECTORY;
if (clientDistDirectory) {
  app.use(koaStatic(clientDistDirectory));

  app.use(async (ctx) => {
    await koaSend(ctx, 'index.html', { root: clientDistDirectory });
  })
} else {
  app.use(async ctx => {
    ctx.body = { ready: true };
  });
}

const protocol = (process.env.PROTOCOL || 'http') === 'http' ? http : https;

const server = protocol.createServer(app.callback());
const io = Io(server);
io.adapter(socketRedis(process.env.REDIS_URL));

const roomHashSecret = process.env.ROOM_HASH_SECRET;

const getRoomIdHash = (id) => {
  if (env === 'development') {
    return id
  }

  if (roomHashSecret) {
    return crypto
      .createHmac('sha256', roomHashSecret)
      .update(id)
      .digest('hex')
  }

  return crypto.createHash('sha256').update(id).digest('hex');
}

export const getIO = () => io

io.on('connection', async (socket) => {
  const roomId = socket.handshake.query.roomId

  const roomIdHash = getRoomIdHash(roomId)

  let room = await redis.hgetAsync('rooms', roomIdHash)
  room = JSON.parse(room || '{}')

  new Socket({
    roomId: roomIdHash,
    socket,
    room,
  })
})

const init = async () => {
  server.listen(PORT, () => {
    console.log(`Darkwire is online at port ${PORT}`);
  })
}

init()

<commit_msg>Security headers (#67)<commit_after>require('dotenv').config()
import http from 'http';
import https from 'https';
import Koa from 'koa';
import Io from 'socket.io';
import KoaBody from 'koa-body';
import cors from 'kcors';
import Router from 'koa-router';
import bluebird from 'bluebird';
import Redis from 'redis';
import socketRedis from 'socket.io-redis';
import Socket from './socket';
import crypto from 'crypto'
import mailer from './utils/mailer';
import koaStatic from 'koa-static';
import koaSend from 'koa-send';

bluebird.promisifyAll(Redis.RedisClient.prototype);
bluebird.promisifyAll(Redis.Multi.prototype);

const redis = Redis.createClient(process.env.REDIS_URL)

export const getRedis = () => redis

const env = process.env.NODE_ENV || 'development';

const app = new Koa();
const PORT = process.env.PORT || 3001;

const router = new Router();
const koaBody = new KoaBody();

app.use(cors({
  credentials: true,
}));

router.post('/handshake', koaBody, async (ctx) => {
  const { body } = ctx.request;
  const { roomId } = body;

  const roomIdHash = getRoomIdHash(roomId)

  let roomExists = await redis.hgetAsync('rooms', roomIdHash)
  if (roomExists) {
    roomExists = JSON.parse(roomExists)
  }

  ctx.body = {
    id: roomId,
    ready: true,
    isLocked: Boolean(roomExists && roomExists.isLocked),
    size: ((roomExists && roomExists.users.length) || 0) + 1,
  };
});

router.post('/abuse/:roomId', koaBody, async (ctx) => {
  let { roomId } = ctx.params;

  roomId = roomId.trim();

  if (process.env.ABUSE_FROM_EMAIL_ADDRESS && process.env.ABUSE_TO_EMAIL_ADDRESS) {
    const abuseForRoomExists = await redis.hgetAsync('abuse', roomId);
    if (!abuseForRoomExists) {
      mailer.send({
        from: process.env.ABUSE_FROM_EMAIL_ADDRESS,
        to: process.env.ABUSE_TO_EMAIL_ADDRESS,
        subject: 'Darkwire Abuse Notification',
        text: `Room ID: ${roomId}`
      });
    }
  }

  await redis.hincrbyAsync('abuse', roomId, 1);

  ctx.status = 200;
});

app.use(router.routes());

const cspDefaultSrc = `'self'${process.env.API_HOST ? ` https://${process.env.API_HOST} wss://${process.env.API_HOST}` : ''}`

function setStaticFileHeaders(ctx) {
  ctx.set({
    'strict-transport-security': 'max-age=31536000',
    'Content-Security-Policy': `default-src ${cspDefaultSrc} 'unsafe-inline'; img-src 'self' data:;`,
    'X-Frame-Options': 'deny',
    'X-XSS-Protection': '1; mode=block',
    'X-Content-Type-Options': 'nosniff',
    'Referrer-Policy': 'no-referrer',
    'Feature-Policy': "geolocation 'none'; vr 'none'; payment 'none'; microphone 'none'",
  });
}

const clientDistDirectory = process.env.CLIENT_DIST_DIRECTORY;
if (clientDistDirectory) {
  app.use(async (ctx, next) => {
    setStaticFileHeaders(ctx);
    await koaStatic(clientDistDirectory)(ctx, next);
  });

  app.use(async (ctx) => {
    setStaticFileHeaders(ctx);
    await koaSend(ctx, 'index.html', { root: clientDistDirectory });
  })
} else {
  app.use(async ctx => {
    ctx.body = { ready: true };
  });
}

const protocol = (process.env.PROTOCOL || 'http') === 'http' ? http : https;

const server = protocol.createServer(app.callback());
const io = Io(server);
io.adapter(socketRedis(process.env.REDIS_URL));

const roomHashSecret = process.env.ROOM_HASH_SECRET;

const getRoomIdHash = (id) => {
  if (env === 'development') {
    return id
  }

  if (roomHashSecret) {
    return crypto
      .createHmac('sha256', roomHashSecret)
      .update(id)
      .digest('hex')
  }

  return crypto.createHash('sha256').update(id).digest('hex');
}

export const getIO = () => io

io.on('connection', async (socket) => {
  const roomId = socket.handshake.query.roomId

  const roomIdHash = getRoomIdHash(roomId)

  let room = await redis.hgetAsync('rooms', roomIdHash)
  room = JSON.parse(room || '{}')

  new Socket({
    roomId: roomIdHash,
    socket,
    room,
  })
})

const init = async () => {
  server.listen(PORT, () => {
    console.log(`Darkwire is online at port ${PORT}`);
  })
}

init()

<|endoftext|>


<commit_before>'use strict';

/**
 * @type {hashmap}
 * @public
 */
var thumbChecks = {};

/**
 * Handle the 'onload' event of our XHR request. The responseText of the event
 * should be an HTML document. Once this is parsed into a DOMElement, we
 * search it for the source of the demanded image, and then download the image.
 *
 * @param {ProgressEvent} e The XHR ProgressEvent.
 * @public
 */
var handleLoad = function(e) {
  var documentBuffer = document.createElement('body');
  documentBuffer.innerHTML = e.target.responseText;

  // Try to find a well-formed url.
  var image = document.evaluate('//img[@id][@style]', documentBuffer, null, 9, null).singleNodeValue;
  var src = (image ? image.getAttribute('src') : null);

  if ( !image || !src ) {
    image = documentBuffer.querySelectorAll('#img')[0];
    src = (image ? image.src : null);
  }

  if ( !image || !src ) {
    image = documentBuffer.querySelectorAll('#thepic')[0];
    src = (image ? image.src : null);
  }

  if (!src) return;
  if ( src.indexOf('chrome-extension') >= 0 ) {
    var baseURL = e.target.responseURL.match(/^.+?[^\/:](?=[?\/]|$)/);
    src = src.replace(/chrome-extension:\/\/.*\/views\//, '')
    src = baseURL + '/' + src;
  }

  chrome.downloads.download({url: src});
};

/**
 * Update the relevant fields with the new data.
 *
 * @param {hashmap} domInfo
 * @public
 */
var handleDOMInfo = function(domInfo) {
  var thumbsList = document.getElementById('thumbs');
  while (thumbsList.children.length > 1) {
    thumbsList.removeChild(thumbsList.children[thumbsList.children.length - 1])
  }

  for (var i = 0; i < domInfo.length; i++) {
    var checkbox = document.createElement('input');
    checkbox.type = 'checkbox';
    checkbox.checked = false;

    var thumb = document.createElement('img');
    thumb.src = domInfo[i].src;
    thumb.alt = domInfo[i].url;
    thumb.onclick = function() {
      var sibling = this.previousSibling;
      sibling.checked = !sibling.checked;
      thumbChecks[this.src]['download'] = sibling.checked;
    }

    var listItem = document.createElement('li');
    listItem.appendChild(checkbox);
    listItem.appendChild(thumb);
    thumbsList.appendChild(listItem);

    thumbChecks[ domInfo[i].src ] = {};
    thumbChecks[ domInfo[i].src ]['download'] = false;
    thumbChecks[ domInfo[i].src ]['url'] = domInfo[i].url;
  }
};

/* Once the document's DOM is ready, send a message to the content. */
document.addEventListener('DOMContentLoaded', function() {
  chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
    chrome.tabs.sendMessage(
      tabs[0].id,
      {from: 'popup', subject: 'DOMInfo'},
      handleDOMInfo);
  });
});

document.addEventListener('click', function() {
  var numSelected = 0;
  for (var i in thumbChecks) {
    if (thumbChecks[i]['download']) numSelected++;
  }
  document.getElementById('num-selected').innerHTML = 'selected: ' + numSelected;
});

window.onload = function() {
  document.getElementById('download').onclick = function() {
    for (var i in thumbChecks) {
      if (thumbChecks[i]['download']) {
        var request = new XMLHttpRequest();
        request.open('GET', thumbChecks[i]['url'], true);
        request.onload = handleLoad;
        request.send(null);
      }
    }
  };

  document.getElementById('select-all').onclick = function() {
    var inputs = document.getElementsByTagName('input');
    for (var i = 0; i < inputs.length; i++) {
      inputs[i].checked = true;
      var sibling = inputs[i].nextSibling;
      thumbChecks[sibling.src]['download'] = true;
    }
  };

  document.getElementById('select-none').onclick = function() {
    var inputs = document.getElementsByTagName('input');
    for (var i = 0; i < inputs.length; i++) {
      inputs[i].checked = false;
      var sibling = inputs[i].nextSibling;
      thumbChecks[sibling.src]['download'] = false;
    }
  };
};
<commit_msg>Fixed some document querying<commit_after>'use strict';

/**
 * @type {hashmap}
 * @public
 */
var thumbChecks = {};

/**
 * Handle the 'onload' event of our XHR request. The responseText of the event
 * should be an HTML document. Once this is parsed into a DOMElement, we
 * search it for the source of the demanded image, and then download the image.
 *
 * @param {ProgressEvent} e The XHR ProgressEvent.
 * @public
 */
var handleLoad = function(e) {
  var documentBuffer = document.createElement('body');
  documentBuffer.innerHTML = e.target.responseText;

  /* Try to find a well-formed url. */
  var image = document.evaluate('//img[@id][@style]', documentBuffer, null, 9, null).singleNodeValue;
  var src = (image ? image.getAttribute('src') : null);

  if ( !image || !src ) {
    image = documentBuffer.querySelectorAll('.image')[0];
    src = (image ? image.src : null);
  }

  if ( !image || !src ) {
    image = documentBuffer.querySelectorAll('#img')[0];
    src = (image ? image.src : null);
  }

  if ( !image || !src ) {
    image = documentBuffer.querySelectorAll('#thepic')[0];
    src = (image ? image.src : null);
  }

  if (!src) {
    console.log("Unable to find image for" + documentBuffer.innerHTML);
    return;
  }

  if ( src.indexOf('chrome-extension') >= 0 ) {
    var baseURL = e.target.responseURL.match(/^.+?[^\/:](?=[?\/]|$)/);
    src = src.replace(/chrome-extension:\/\/.*\/views\//, '')
    src = baseURL + '/' + src;
  }

  chrome.downloads.download({url: src});
};

/**
 * Update the relevant fields with the new data.
 *
 * @param {hashmap} domInfo
 * @public
 */
var handleDOMInfo = function(domInfo) {
  var thumbsList = document.getElementById('thumbs');
  while (thumbsList.children.length > 1) {
    thumbsList.removeChild(thumbsList.children[thumbsList.children.length - 1])
  }

  for (var i = 0; i < domInfo.length; i++) {
    var checkbox = document.createElement('input');
    checkbox.type = 'checkbox';
    checkbox.checked = false;

    var thumb = document.createElement('img');
    thumb.src = domInfo[i].src;
    thumb.alt = domInfo[i].url;
    thumb.onclick = function() {
      var sibling = this.previousSibling;
      sibling.checked = !sibling.checked;
      thumbChecks[this.src]['download'] = sibling.checked;
    }

    var listItem = document.createElement('li');
    listItem.appendChild(checkbox);
    listItem.appendChild(thumb);
    thumbsList.appendChild(listItem);

    thumbChecks[ domInfo[i].src ] = {};
    thumbChecks[ domInfo[i].src ]['download'] = false;
    thumbChecks[ domInfo[i].src ]['url'] = domInfo[i].url;
  }
};

/* Once the document's DOM is ready, send a message to the content. */
document.addEventListener('DOMContentLoaded', function() {
  chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
    chrome.tabs.sendMessage(
      tabs[0].id,
      {from: 'popup', subject: 'DOMInfo'},
      handleDOMInfo);
  });
});

document.addEventListener('click', function() {
  var numSelected = 0;
  for (var i in thumbChecks) {
    if (thumbChecks[i]['download']) numSelected++;
  }
  document.getElementById('num-selected').innerHTML = 'selected: ' + numSelected;
});

window.onload = function() {
  document.getElementById('download').onclick = function() {
    for (var i in thumbChecks) {
      if (thumbChecks[i]['download']) {
        var request = new XMLHttpRequest();
        request.open('GET', thumbChecks[i]['url'], true);
        request.onload = handleLoad;
        request.send(null);
      }
    }
  };

  document.getElementById('select-all').onclick = function() {
    var inputs = document.getElementsByTagName('input');
    for (var i = 0; i < inputs.length; i++) {
      inputs[i].checked = true;
      var sibling = inputs[i].nextSibling;
      thumbChecks[sibling.src]['download'] = true;
    }
  };

  document.getElementById('select-none').onclick = function() {
    var inputs = document.getElementsByTagName('input');
    for (var i = 0; i < inputs.length; i++) {
      inputs[i].checked = false;
      var sibling = inputs[i].nextSibling;
      thumbChecks[sibling.src]['download'] = false;
    }
  };
};
<|endoftext|>


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

/***
          Filter server
***/

var express = require('express'),
    cluster = require('cluster'),
    fs = require('fs'),
    cv = require('../../opencv-node'),
    serverutils = require('../common/descr/server-util.js'),
    images = require('../common/descr/image-library.js').Images;

var getGray,
    getGauss;

if (cluster.isMaster) {
  require('os').cpus().forEach(function() {
    cluster.fork();
  });
} else {

  /***    create server    ***/

  var app = exports.server = express(),
      port = process.env.PORT || 9003,
      host = process.env.PORT || '127.0.0.1';

  /***    configure server    ***/

  app.use(express.methodOverride());
  app.use(express.errorHandler());

  /***    start server    ***/

  app.listen(port);
  console.log('onlyjs server running on http://' + host + ':' + port);

  /***    handlers    ***/

  getGray = function(req, res, next) {
    var img = images.get(req.params[0]);
    if (img) {
      // read png
      var src = cv.imread(img.fileName);
      var gray = new cv.Mat();
      cv.cvtColor(src, gray, cv.CV_BGR2GRAY);
      var buf = cv.imencode('.png', gray);
      res.header('Content-Type', images.exts_getconttype(img.extension));
      res.send(buf);
    }
    else {
      res.header('Link','</grays>; rel="index"');
      res.send('', 404);
    }
  };

  getGauss = function(req, res, next) {
    var img = images.get(req.params[0]);
    if (img) {
      // read png
      var src = cv.imread(img.fileName);
      var gauss = new cv.Mat(src.size, src.type);
      cv.GaussianBlur(src, gauss, {width: 7, height: 7}, 0);
      var buf = cv.imencode('.png', gauss);
      res.header('Content-Type', images.exts_getconttype(img.extension));
      res.send(buf);
    }
    else {
      res.header('Link','</grays>; rel="index"');
      res.send('', 404);
    }
  };

  /***    routing    ***/

  app.get(/^\/grays\/(\d+)$/, getGray);
  app.get(/^\/gauss\/(\d+)$/, getGauss);
}
<commit_msg>bindings read url<commit_after>#!/usr/bin/env node

/***
          Native add-on server
***/

var express = require('express'),
    cluster = require('cluster'),
    http = require('http'),
    fs = require('fs'),
    cv = require('../../opencv-node');

var getGray,
    getGauss;

if (cluster.isMaster) {
  require('os').cpus().forEach(function() {
    cluster.fork();
  });
} else {

  /***    create server    ***/

  var app = exports.server = express(),
      port = process.env.PORT || 9003,
      host = process.env.HOST || '127.0.0.1';

  /***    configure server    ***/

  app.use(express.methodOverride());
  app.use(express.errorHandler());

  /***    start server    ***/

  app.listen(port);
  console.log('Native add-on server running on http://' + host + ':' + port);

  /***    handlers    ***/

  getGray = function(req, res, next) {
    var img = req.params[0];
    // get png
    http.get('http://127.0.0.1:9000/' + img + '.png', function(serverres) {
      var rawdata = [];
      serverres.on('data',function(chunk){
        for (var i = 0; i < chunk.length; ++i)
        {
          rawdata.push(chunk[i]);;
        }
      });
      serverres.on('end', function(){
        var src = cv.imdecode(rawdata,1);
        var gray = new cv.Mat();
        cv.cvtColor(src, gray, cv.CV_BGR2GRAY);
        var buf = cv.imencode('.png', gray);
        res.header('Content-Type', 'image/png');
        res.send(buf);
      });
    });
  };

  getGauss = function(req, res, next) {
    var img = req.params[0];
    // get png
    http.get('http://127.0.0.1:9000/' + img + '.png', function(serverres) {
      var rawdata = [];
      serverres.on('data',function(chunk){
        for (var i = 0; i < chunk.length; ++i)
        {
          rawdata.push(chunk[i]);;
        }
      });
      serverres.on('end', function(){
        var src = cv.imdecode(rawdata,1);
        var gauss = new cv.Mat(src.size, src.type);
        cv.GaussianBlur(src, gauss, {width: 7, height: 7}, 0);
        var buf = cv.imencode('.png', gauss);
        res.header('Content-Type', 'image/png');
        res.send(buf);
      });
    });
  };

  /***    routing    ***/

  app.get(/^\/grays\/(\d+)$/, getGray);
  app.get(/^\/gauss\/(\d+)$/, getGauss);
}
<|endoftext|>


<commit_before>var {users, messages} = require('./database');
var {makeUser}        = require('../models/user');
var {makeMessage}     = require('../models/message');

var io;

function onChatMessage(msg) {

    var socketId = this.id;
    users.findOne({socketId}, function (error, user) {

        if(user){
            messages.insert(makeMessage(msg, user), function (error, message) {
                if(!error){
                    user.messages.push(message._id);
                    users.update({_id : user._id}, user, function (error) {
                        if(!error)
                            io.emit('chat message', {message, user});
                        else
                            console.log(`Error updating user ${user.username} from address ${address}: ${error}`);
                    });
                }
                else {
                    console.log(`Error saving message "${msg}": ${error}`);
                }
            });
        }
        else {
            console.log(`User with id ${socketId} not found!`);
        }

    });
}

function onChangeUsername(username){
    var socketId = this.id;
    users.findOne({socketId}, function (error, user) {

        if(user){

            // If user exists, update it's username
            users.update({_id : user._id}, { $set : { username } }, function (error) {
                if(error) console.log(`Error updating user ${user.username} from address ${address}: ${error}`);
            });

        }
        else {
            console.log(`User with id ${socketId} not found!`);
        }

    });
}

function onChangeColor(color) {

    var socketId = this.id;
    users.findOne({socketId}, function (error, user) {

        if(user){

            // If user exists, update it's username
            users.update({_id : user._id}, { $set : { color } }, function (error) {
                if(error) console.log(`Error updating user ${user.username} from address ${address}: ${error}`);
            });

        }
        else {
            console.log(`User with id ${socketId} not found!`);
        }

    });

}

function onDisconnection() {
    //TODO
}

function onConnection(socket) {

    // Get the ip address of the connected user
    var address = socket.handshake.address;

    // Create the user if it doesn't exist
    users.findOne({address}, function (err, user) {
        if(user){

            // If user exists, update it's socket id
            users.update({_id : user._id}, { $set : { socketId : socket.id } }, function (error) {
                if(error) console.log(`Error updating user from address ${address}: ${error}`);
            });
        }
        else {

            // If user doesn't exist, insert it
            users.insert(makeUser(address, socket.id), function (error) {
                if(error) console.log(`Error saving user from address ${address}: ${error}`);
            });
        }
    });

    //Load up all messages and send them to connected socket for visualization
    messages.find({}, function (error, messages) {

        Promise.all(messages.map(function (message) {
            return new Promise(function (resolve, reject) {
                users.findOne({_id : message.userId}, function (error, user) {

                    if(!error){

                        message.user = user;

                        resolve(message);

                    }
                    else reject(error);

                });
            });
        })).then(function (filledMessages) {
            socket.emit('messages loaded', filledMessages);
        });

    });

    socket.on('chat message', onChatMessage.bind(socket));

    socket.on('change username', onChangeUsername.bind(socket));

    socket.on('change color', onChangeColor.bind(socket));

    socket.on('disconnection', onDisconnection.bind(socket));

}

function sockets (server){

    io = require('socket.io')(server);

    // Handle a user connecting to the server
    io.on('connection', onConnection);

    exports.io = io;
}

exports.sockets = sockets;<commit_msg>Fixes message history sorting bug<commit_after>var {users, messages} = require('./database');
var {makeUser}        = require('../models/user');
var {makeMessage}     = require('../models/message');

var io;

function onChatMessage(msg) {

    var socketId = this.id;
    users.findOne({socketId}, function (error, user) {

        if(user){
            messages.insert(makeMessage(msg, user), function (error, message) {
                if(!error){
                    user.messages.push(message._id);
                    users.update({_id : user._id}, user, function (error) {
                        if(!error)
                            io.emit('chat message', {message, user});
                        else
                            console.log(`Error updating user ${user.username} from address ${address}: ${error}`);
                    });
                }
                else {
                    console.log(`Error saving message "${msg}": ${error}`);
                }
            });
        }
        else {
            console.log(`User with id ${socketId} not found!`);
        }

    });
}

function onChangeUsername(username){
    var socketId = this.id;
    users.findOne({socketId}, function (error, user) {

        if(user){

            // If user exists, update it's username
            users.update({_id : user._id}, { $set : { username } }, function (error) {
                if(error) console.log(`Error updating user ${user.username} from address ${address}: ${error}`);
            });

        }
        else {
            console.log(`User with id ${socketId} not found!`);
        }

    });
}

function onChangeColor(color) {

    var socketId = this.id;
    users.findOne({socketId}, function (error, user) {

        if(user){

            // If user exists, update it's username
            users.update({_id : user._id}, { $set : { color } }, function (error) {
                if(error) console.log(`Error updating user ${user.username} from address ${address}: ${error}`);
            });

        }
        else {
            console.log(`User with id ${socketId} not found!`);
        }

    });

}

function onDisconnection() {
    //TODO
}

function onConnection(socket) {

    // Get the ip address of the connected user
    var address = socket.handshake.address;

    // Create the user if it doesn't exist
    users.findOne({address}, function (err, user) {
        if(user){

            // If user exists, update it's socket id
            users.update({_id : user._id}, { $set : { socketId : socket.id } }, function (error) {
                if(error) console.log(`Error updating user from address ${address}: ${error}`);
            });
        }
        else {

            // If user doesn't exist, insert it
            users.insert(makeUser(address, socket.id), function (error) {
                if(error) console.log(`Error saving user from address ${address}: ${error}`);
            });
        }
    });

    //Load up all messages and send them to connected socket for visualization
    messages.find({}).sort({timestamp : 1}).exec(function(error, messages){
        Promise.all(messages.map(function (message) {
            return new Promise(function (resolve, reject) {
                users.findOne({_id : message.userId}, function (error, user) {

                    if(!error){

                        message.user = user;

                        resolve(message);

                    }
                    else reject(error);

                });
            });
        })).then(function (filledMessages) {
            socket.emit('messages loaded', filledMessages);
        });

    });

    socket.on('chat message', onChatMessage.bind(socket));

    socket.on('change username', onChangeUsername.bind(socket));

    socket.on('change color', onChangeColor.bind(socket));

    socket.on('disconnection', onDisconnection.bind(socket));

}

function sockets (server){

    io = require('socket.io')(server);

    // Handle a user connecting to the server
    io.on('connection', onConnection);

    exports.io = io;
}

exports.sockets = sockets;<|endoftext|>


<commit_before>function checkSet(setid) {
    var set = sets.findOne({_id: setid});
    if (!set) {
        throw new Meteor.Error('set-not-found', "Can't find a set with id: " + setid);
    }

    return set;
}

Meteor.methods({
    setNew: function () {
        sets.insert({
            title: 'New Set',
            stage: null,
            active: null
        });
    },

    setDelete: function (setid) {
        var set = checkSet(setid);
        sets.remove(set);
        actions.remove({set: setid});
    },

    setTitle: function (setid, newtitle) {
        var set = checkSet(setid);
        sets.update(set, {$set: {title: newtitle}});
    },

    setStage: function (setid, stageid) {
        var set = checkSet(setid);
        sets.update(set, {$set: {stage: stageid}});
    },

    actionAdd: function (action) {
        actions.insert(action);
    },

    actionRemove: function (actionid) {
        var index = actions.findOne(actionid).order;
        actions.remove(actionid);
        actions.update({order: {$gte: index}}, {$inc: {order: -1}}, {multi: true});
    },

    actionTitle: function (actionid, title) {
        actions.update(actionid, {$set: {title: title}});
    },

    actionMove: function (actionid, index) {
        var action = actions.findOne(actionid);
        var setid = action.set;

        var max = actions.find({set: setid}).count() - 1;
        if (index < 0) index = 0;
        if (index > max) index = max;

        if (action.order > index) actions.update({set: setid, order: {$gte: index, $lt: action.order}}, {$inc: {order: 1}}, {multi: true});
        else if (action.order < index) actions.update({set: setid, order: {$lte: index, $gt: action.order}}, {$inc: {order: -1}}, {multi: true});
        actions.update({_id: actionid}, {$set: {order: index}});
    },

    setActivate: function (setid, actionid) {
        var set = checkSet(setid);
        var action = actions.findOne(actionid);
        var triggers = actions.find({actionid: action._id}).fetch();

        var set_actions = [action].concat(triggers);

        sets.update(set, {$set: {active: actionid}});

        for (var i in set_actions) {
            var action = set_actions[i];
            console.log(action);
            if (action.type == 'media') {
                Meteor.call('mediaActionActivate', action);
            }

            else if (action.type == 'lightscene') {
                Meteor.call('sceneActionActivate', action);
            }
        }
    },

    setDeactivate: function (setid) {
        var set = checkSet(setid);
        if (set.active !== null) {
            var action = actions.findOne(set.active);
            sets.update(set, {$set: {active: null}});

            if (action.type == 'media') {
                if (action['minions'] && action.minions.length > 0) {
                    var targets = action.minions;
                } else {
                    var targets = minions.find({stage: set.stage, roles: {$all: [action.role]}}).fetch();
                }

                targets.forEach(function (minion) {
                    minions.update(minion._id, {$set: {actions: []}});
                });
            }
        }
    }
});
<commit_msg>Fixed set delete to remove trigger actions<commit_after>function checkSet(setid) {
    var set = sets.findOne({_id: setid});
    if (!set) {
        throw new Meteor.Error('set-not-found', "Can't find a set with id: " + setid);
    }

    return set;
}

Meteor.methods({
    setNew: function () {
        sets.insert({
            title: 'New Set',
            stage: null,
            active: null
        });
    },

    setDelete: function (setid) {
        var set = checkSet(setid);

        var actionids = actions.find({set: setid}, {_id: 1});
        for (var i in actionids) actionids[i] = actionids[i]._id;
        actions.remove({action: {$in: actionids}});

        actions.remove({set: setid});
        sets.remove(set);
    },

    setTitle: function (setid, newtitle) {
        var set = checkSet(setid);
        sets.update(set, {$set: {title: newtitle}});
    },

    setStage: function (setid, stageid) {
        var set = checkSet(setid);
        sets.update(set, {$set: {stage: stageid}});
    },

    actionAdd: function (action) {
        actions.insert(action);
    },

    actionRemove: function (actionid) {
        var index = actions.findOne(actionid).order;
        actions.remove(actionid);
        actions.update({order: {$gte: index}}, {$inc: {order: -1}}, {multi: true});
    },

    actionTitle: function (actionid, title) {
        actions.update(actionid, {$set: {title: title}});
    },

    actionMove: function (actionid, index) {
        var action = actions.findOne(actionid);
        var setid = action.set;

        var max = actions.find({set: setid}).count() - 1;
        if (index < 0) index = 0;
        if (index > max) index = max;

        if (action.order > index) actions.update({set: setid, order: {$gte: index, $lt: action.order}}, {$inc: {order: 1}}, {multi: true});
        else if (action.order < index) actions.update({set: setid, order: {$lte: index, $gt: action.order}}, {$inc: {order: -1}}, {multi: true});
        actions.update({_id: actionid}, {$set: {order: index}});
    },

    setActivate: function (setid, actionid) {
        var set = checkSet(setid);
        var action = actions.findOne(actionid);
        var triggers = actions.find({actionid: action._id}).fetch();

        var set_actions = [action].concat(triggers);

        sets.update(set, {$set: {active: actionid}});

        for (var i in set_actions) {
            var action = set_actions[i];
            console.log(action);
            if (action.type == 'media') {
                Meteor.call('mediaActionActivate', action);
            }

            else if (action.type == 'lightscene') {
                Meteor.call('sceneActionActivate', action);
            }
        }
    },

    setDeactivate: function (setid) {
        var set = checkSet(setid);
        if (set.active !== null) {
            var action = actions.findOne(set.active);
            sets.update(set, {$set: {active: null}});

            if (action.type == 'media') {
                if (action['minions'] && action.minions.length > 0) {
                    var targets = action.minions;
                } else {
                    var targets = minions.find({stage: set.stage, roles: {$all: [action.role]}}).fetch();
                }

                targets.forEach(function (minion) {
                    minions.update(minion._id, {$set: {actions: []}});
                });
            }
        }
    }
});
<|endoftext|>


<commit_before>var fs = require("fs");
var path = require('path');

//
// setup DOM-like sandbox
//

var window = {};
var loader;

var script = function(inPath) {
	eval(fs.readFileSync(inPath, "utf8"));
};

var chunks = [];

var pushChunkFile = function(inType, inFile) {
	var chunk = chunks.slice(-1)[0];
	if (!chunk || !chunk[inType]) {
		chunk = { sheets:[], scripts:[] };
		chunks.push(chunk);
	}
	chunk[inType].push(inFile);
};

module.exports = {
	init: function(inEnyoPath, inLibPath, inMapFrom, inMapTo) {
		// Always use the Enyo loader that comes with _this_ walker
		script(path.join(__dirname, "..", "..", "..", "..", "enyo", "loader.js"));
		enyo.path.addPaths({
			enyo: inEnyoPath,
			lib: inLibPath
		});
		loader = new enyo.loaderFactory({
			script: function(inScript) {
				pushChunkFile("scripts", inScript);
			},
			sheet: function(inSheet) {
				pushChunkFile("sheets", inSheet);
			}
		});
		loader.loadPackage = function(inScript) {
			if (inMapFrom) {
				var pkgDir = path.dirname(path.relative(process.cwd(), inScript));
				var mapIdx = inMapFrom.indexOf(pkgDir);
				if (mapIdx >= 0) {
					chunks.push(inMapTo[mapIdx]);
					loader.more.apply(loader);
					return;
				}
			}
			script(inScript);
		};
		enyo.depends = function() {
			//console.log(arguments);
			loader.load.apply(loader, arguments);
		};
	},
	walk: function(inScript, inCallback) {
		//console.log("walking: ", inScript);
		loader.finish = function() {
			inCallback(loader, chunks);
		};
		script(enyo.path.rewrite(inScript));
	}
}<commit_msg>GF-7829: Keep package name in re-mapped sources, to allow deploying multiple CSS themes in the same library. Enyo-DCO-1.1-Signed-off-by: Kevin Schaaf <kevin.schaaf@lge.com><commit_after>var fs = require("fs");
var path = require('path');

//
// setup DOM-like sandbox
//

var window = {};
var loader;

var script = function(inPath) {
	eval(fs.readFileSync(inPath, "utf8"));
};

var chunks = [];

var pushChunkFile = function(inType, inFile) {
	var chunk = chunks.slice(-1)[0];
	if (!chunk || !chunk[inType]) {
		chunk = { sheets:[], scripts:[] };
		chunks.push(chunk);
	}
	chunk[inType].push(inFile);
};

module.exports = {
	init: function(inEnyoPath, inLibPath, inMapFrom, inMapTo) {
		// Always use the Enyo loader that comes with _this_ walker
		script(path.join(__dirname, "..", "..", "..", "..", "enyo", "loader.js"));
		enyo.path.addPaths({
			enyo: inEnyoPath,
			lib: inLibPath
		});
		loader = new enyo.loaderFactory({
			script: function(inScript) {
				pushChunkFile("scripts", inScript);
			},
			sheet: function(inSheet) {
				pushChunkFile("sheets", inSheet);
			}
		});
		loader.loadPackage = function(inScript) {
			if (inMapFrom) {
				var pkg = path.relative(process.cwd(), inScript);
				var pkgDir = path.dirname(pkg);
				var mapIdx = inMapFrom.indexOf(pkgDir);
				if (mapIdx >= 0) {
					chunks.push(inMapTo[mapIdx] + pkg.substring(pkgDir.length));
					loader.more.apply(loader);
					return;
				}
			}
			script(inScript);
		};
		enyo.depends = function() {
			//console.log(arguments);
			loader.load.apply(loader, arguments);
		};
	},
	walk: function(inScript, inCallback) {
		//console.log("walking: ", inScript);
		loader.finish = function() {
			inCallback(loader, chunks);
		};
		script(enyo.path.rewrite(inScript));
	}
}<|endoftext|>


<commit_before>require(['../brief.js/src/brief.js'], function(b) {
  var resultBox = b('#resultBox').get(0);
    var listener1 = function(event) {
      event.preventDefault();
      resultBox.innerHTML = 'this event was triggered by hovering or leaving an anchor tag, but the listener is actually on the body which is delegating it to the anchor tag.
' + resultBox.innerHTML;
    };
    var listener2 = function(event) {
      event.preventDefault();
      resultBox.innerHTML = 'this event was triggered by clicking on the element with the #test id.
' + resultBox.innerHTML;
    };
    var listener3 = function(event) {
      event.preventDefault();
      resultBox.innerHTML = 'this event was triggered by clicking on an element with the .test class.
' + resultBox.innerHTML;
    };
    var listener4 = function(event) {
      resultBox.innerHTML = event.type + ' on the body
' + resultBox.innerHTML;
    };
    b('body').on('mouseenter mouseleave', listener1, 'a');
    b('#test').on('click', listener2);
    b('.test').on('click', listener3);
    b('body').on('mouseenter mouseleave', listener4);
    b('body').once('mouseleave', function(event) {
      resultBox.innerHTML = 'oh no! you moved your mouse off the body for the first time!!!
' + resultBox.innerHTML;
    });
    b('#removeEventListeners').on('click', function() {
      b('body').off('mouseenter mouseleave', listener1, 'a');
      b('#test').off('click', listener2);
      b('.test').off('click', listener3);
      b('body').off('mouseenter mouseleave', listener4);
    });
});<commit_msg>fix demo for brief.js<commit_after>require(['https://rawgithub.com/jeffshaver/brief.js/master/src/brief.min.js'], function(b) {
  var resultBox = b('#resultBox').get(0);
    var listener1 = function(event) {
      event.preventDefault();
      resultBox.innerHTML = 'this event was triggered by hovering or leaving an anchor tag, but the listener is actually on the body which is delegating it to the anchor tag.
' + resultBox.innerHTML;
    };
    var listener2 = function(event) {
      event.preventDefault();
      resultBox.innerHTML = 'this event was triggered by clicking on the element with the #test id.
' + resultBox.innerHTML;
    };
    var listener3 = function(event) {
      event.preventDefault();
      resultBox.innerHTML = 'this event was triggered by clicking on an element with the .test class.
' + resultBox.innerHTML;
    };
    var listener4 = function(event) {
      resultBox.innerHTML = event.type + ' on the body
' + resultBox.innerHTML;
    };
    b('body').on('mouseenter mouseleave', listener1, 'a');
    b('#test').on('click', listener2);
    b('.test').on('click', listener3);
    b('body').on('mouseenter mouseleave', listener4);
    b('body').once('mouseleave', function(event) {
      resultBox.innerHTML = 'oh no! you moved your mouse off the body for the first time!!!
' + resultBox.innerHTML;
    });
    b('#removeEventListeners').on('click', function() {
      b('body').off('mouseenter mouseleave', listener1, 'a');
      b('#test').off('click', listener2);
      b('.test').off('click', listener3);
      b('body').off('mouseenter mouseleave', listener4);
    });
});<|endoftext|>