<commit_before>'use strict';

const Wappalyzer = require('./wappalyzer');
const request = require('request');
const url = require('url');
const fs = require('fs');
const Browser = require('zombie');

const json = JSON.parse(fs.readFileSync(__dirname + '/apps.json'));

const extensions = /^([^.]+$|\.(asp|aspx|cgi|htm|html|jsp|php)$)/;

class Driver {
  constructor(pageUrl, options) {
    this.options = Object.assign({}, {
      chunkSize: 5,
      debug: false,
      delay: 500,
      maxDepth: 3,
      maxUrls: 10,
      maxWait: 5000,
      recursive: false,
      userAgent: 'Mozilla/5.0 (compatible; Wappalyzer)',
    }, options || {});

    this.options.debug = Boolean(this.options.debug);
    this.options.delay = this.options.recursive ? parseInt(this.options.delay, 10) : 0;
    this.options.maxDepth = parseInt(this.options.maxDepth, 10);
    this.options.maxUrls = parseInt(this.options.maxUrls, 10);
    this.options.maxWait = parseInt(this.options.maxWait, 10);
    this.options.recursive = Boolean(this.options.recursive);

    this.origPageUrl = url.parse(pageUrl);
    this.analyzedPageUrls = [];
    this.apps = [];
    this.meta = {};

    this.wappalyzer = new Wappalyzer();

    this.wappalyzer.apps = json.apps;
    this.wappalyzer.categories = json.categories;

    this.wappalyzer.parseJsPatterns();

    this.wappalyzer.driver.log = (message, source, type) => this.log(message, source, type);
    this.wappalyzer.driver.displayApps = (detected, meta, context) => this.displayApps(detected, meta, context);
  }

  analyze() {
    this.time = {
      start: new Date().getTime(),
      last: new Date().getTime(),
    }

    return this.crawl(this.origPageUrl);
  }

  log(message, source, type) {
    this.options.debug && console.log('[wappalyzer ' + type + ']', '[' + source + ']', message);
  }

  displayApps(detected, meta) {
    this.meta = meta;

    Object.keys(detected).forEach(appName => {
      const app = detected[appName];

      var categories = [];

      app.props.cats.forEach(id => {
        var category = {};

        category[id] = json.categories[id].name;

        categories.push(category)
      });

      if ( !this.apps.some(detectedApp => detectedApp.name === app.name) ) {
        this.apps.push({
          name: app.name,
          confidence: app.confidenceTotal.toString(),
          version: app.version,
          icon: app.props.icon || 'default.svg',
          website: app.props.website,
          categories
        });
      }
    });
  }

  fetch(pageUrl, index, depth) {
    // Return when the URL is a duplicate or maxUrls has been reached
    if ( this.analyzedPageUrls.indexOf(pageUrl.href) !== -1 || this.analyzedPageUrls.length >= this.options.maxUrls ) {
      return Promise.resolve();
    }

    this.analyzedPageUrls.push(pageUrl.href);

    const timerScope = {
      last: new Date().getTime()
    };

    this.timer('fetch; url: ' + pageUrl.href + '; depth: ' + depth + '; delay: ' + ( this.options.delay * index ) + 'ms', timerScope);

    return new Promise(resolve => this.sleep(this.options.delay * index).then(() => this.visit(pageUrl, timerScope, resolve)));
  }

  visit(pageUrl, timerScope, resolve) {
    const browser = new Browser({
      silent: true,
      userAgent: this.options.userAgent,
      waitDuration: this.options.maxWait,
    });

    this.timer('browser.visit start; url: ' + pageUrl.href, timerScope);

    browser.visit(pageUrl.href, () => {
      this.timer('browser.visit end; url: ' + pageUrl.href, timerScope);

      if ( !this.responseOk(browser, pageUrl) ) {
        return resolve();
      }

      const headers = this.getHeaders(browser);
      const html = this.getHtml(browser);
      const scripts = this.getScripts(browser);
      const js = this.getJs(browser);

      this.wappalyzer.analyze(pageUrl, {
        headers,
        html,
        scripts,
        js
      })
        .then(() => {
          const links = Array.from(browser.document.getElementsByTagName('a'))
            .filter(link => link.protocol === 'http:' || link.protocol === 'https:')
            .filter(link => link.hostname === this.origPageUrl.hostname)
            .filter(link => extensions.test(link.pathname))
            .map(link => { link.hash = ''; return url.parse(link.href) });

          return resolve(links);
        });
    });
  }

  responseOk(browser, pageUrl) {
    // Validate response
    const resource = browser.resources.length ? browser.resources.filter(resource => resource.response).shift() : null;

    if ( !resource ) {
      this.wappalyzer.log('No response from server; url: ' + pageUrl.href, 'driver', 'error');

      return false;
    }

    if ( resource.response.status !== 200 ) {
      this.wappalyzer.log('Response was not OK; status: ' + resource.response.status + ' ' + resource.response.statusText + '; url: ' + pageUrl.href, 'driver', 'error');

      return false;
    }

    const headers = this.getHeaders(browser);

    // Validate content type
    const contentType = headers.hasOwnProperty('content-type') ? headers['content-type'].shift() : null;

    if ( !contentType || !/\btext\/html\b/.test(contentType) ) {
      this.wappalyzer.log('Skipping; url: ' + pageUrl.href + '; content type: ' + contentType, 'driver');

      this.analyzedPageUrls.splice(this.analyzedPageUrls.indexOf(pageUrl.href), 1);

      return false;
    }

    // Validate document
    if ( !browser.document || !browser.document.documentElement ) {
      this.wappalyzer.log('No HTML document; url: ' + pageUrl.href, 'driver', 'error');

      return false;
    }

    return true;
  }

  getHeaders(browser) {
    const headers = {};

    const resource = browser.resources.length ? browser.resources.filter(resource => resource.response).shift() : null;

    if ( resource ) {
      resource.response.headers._headers.forEach(header => {
        if ( !headers[header[0]] ){
          headers[header[0]] = [];
        }

        headers[header[0]].push(header[1]);
      });
    }

    return headers;
  }

  getHtml(browser) {
    let html = '';

    try {
      html = browser.html();

      if ( html.length > 50000 ) {
        html = html.substring(0, 25000) + html.substring(html.length - 25000, html.length);
      }
    } catch ( error ) {
      this.wappalyzer.log(error.message, 'browser', 'error');
    }

    return html;
  }

  getScripts(browser) {
    if ( !browser.document || !browser.document.scripts ) {
      return [];
    }

    const scripts = Array.prototype.slice
      .apply(browser.document.scripts)
      .filter(script => script.src)
      .map(script => script.src);

    return scripts;
  }

  getJs(browser) {
    const patterns = this.wappalyzer.jsPatterns;
    const js = {};

    Object.keys(patterns).forEach(appName => {
      js[appName] = {};

      Object.keys(patterns[appName]).forEach(chain => {
        js[appName][chain] = {};

        patterns[appName][chain].forEach((pattern, index) => {
          const properties = chain.split('.');

          let value = properties.reduce((parent, property) => {
            return parent && parent.hasOwnProperty(property) ? parent[property] : null;
          }, browser.window);

          value = typeof value === 'string' || typeof value === 'number' ? value : !!value;

          if ( value ) {
            js[appName][chain][index] = value;
          }
        });
      });
    });

    return js;
  }

  crawl(pageUrl, index, depth = 1) {
    pageUrl.canonical = pageUrl.protocol + '//' + pageUrl.host + pageUrl.pathname;

    return new Promise(resolve => {
      this.fetch(pageUrl, index, depth)
        .catch(() => {})
        .then(links => {
          if ( links && Boolean(this.options.recursive) && depth < this.options.maxDepth ) {
            return this.chunk(links.slice(0, this.options.maxUrls), depth + 1);
          } else {
            return Promise.resolve();
          }
        })
        .then(() => {
          resolve({
            urls: this.analyzedPageUrls,
            applications: this.apps,
            meta: this.meta
          });
        });
    });
  }

  chunk(links, depth, chunk = 0) {
    if ( links.length === 0 ) {
      return Promise.resolve();
    }

    const chunked = links.splice(0, this.options.chunkSize);

    return new Promise(resolve => {
      Promise.all(chunked.map((link, index) => this.crawl(link, index, depth)))
        .then(() => this.chunk(links, depth, chunk + 1))
        .then(() => resolve());
    });
  }

  sleep(ms) {
    return ms ? new Promise(resolve => setTimeout(resolve, ms)) : Promise.resolve();
  }

  timer(message, scope) {
    const time = new Date().getTime();
    const sinceStart = ( Math.round(( time - this.time.start ) / 10) / 100) + 's';
    const sinceLast = ( Math.round(( time - scope.last ) / 10) / 100) + 's';

    this.wappalyzer.log('[timer] ' + message + '; lapsed: ' + sinceLast + ' / ' + sinceStart, 'driver');

    scope.last = time;
  }
};

module.exports = Driver;
<commit_msg>Using `reduce` to remove extra iterations (#2122)<commit_after>'use strict';

const Wappalyzer = require('./wappalyzer');
const request = require('request');
const url = require('url');
const fs = require('fs');
const Browser = require('zombie');

const json = JSON.parse(fs.readFileSync(__dirname + '/apps.json'));

const extensions = /^([^.]+$|\.(asp|aspx|cgi|htm|html|jsp|php)$)/;

class Driver {
  constructor(pageUrl, options) {
    this.options = Object.assign({}, {
      chunkSize: 5,
      debug: false,
      delay: 500,
      maxDepth: 3,
      maxUrls: 10,
      maxWait: 5000,
      recursive: false,
      userAgent: 'Mozilla/5.0 (compatible; Wappalyzer)',
    }, options || {});

    this.options.debug = Boolean(this.options.debug);
    this.options.delay = this.options.recursive ? parseInt(this.options.delay, 10) : 0;
    this.options.maxDepth = parseInt(this.options.maxDepth, 10);
    this.options.maxUrls = parseInt(this.options.maxUrls, 10);
    this.options.maxWait = parseInt(this.options.maxWait, 10);
    this.options.recursive = Boolean(this.options.recursive);

    this.origPageUrl = url.parse(pageUrl);
    this.analyzedPageUrls = [];
    this.apps = [];
    this.meta = {};

    this.wappalyzer = new Wappalyzer();

    this.wappalyzer.apps = json.apps;
    this.wappalyzer.categories = json.categories;

    this.wappalyzer.parseJsPatterns();

    this.wappalyzer.driver.log = (message, source, type) => this.log(message, source, type);
    this.wappalyzer.driver.displayApps = (detected, meta, context) => this.displayApps(detected, meta, context);
  }

  analyze() {
    this.time = {
      start: new Date().getTime(),
      last: new Date().getTime(),
    }

    return this.crawl(this.origPageUrl);
  }

  log(message, source, type) {
    this.options.debug && console.log('[wappalyzer ' + type + ']', '[' + source + ']', message);
  }

  displayApps(detected, meta) {
    this.meta = meta;

    Object.keys(detected).forEach(appName => {
      const app = detected[appName];

      var categories = [];

      app.props.cats.forEach(id => {
        var category = {};

        category[id] = json.categories[id].name;

        categories.push(category)
      });

      if ( !this.apps.some(detectedApp => detectedApp.name === app.name) ) {
        this.apps.push({
          name: app.name,
          confidence: app.confidenceTotal.toString(),
          version: app.version,
          icon: app.props.icon || 'default.svg',
          website: app.props.website,
          categories
        });
      }
    });
  }

  fetch(pageUrl, index, depth) {
    // Return when the URL is a duplicate or maxUrls has been reached
    if ( this.analyzedPageUrls.indexOf(pageUrl.href) !== -1 || this.analyzedPageUrls.length >= this.options.maxUrls ) {
      return Promise.resolve();
    }

    this.analyzedPageUrls.push(pageUrl.href);

    const timerScope = {
      last: new Date().getTime()
    };

    this.timer('fetch; url: ' + pageUrl.href + '; depth: ' + depth + '; delay: ' + ( this.options.delay * index ) + 'ms', timerScope);

    return new Promise(resolve => this.sleep(this.options.delay * index).then(() => this.visit(pageUrl, timerScope, resolve)));
  }

  visit(pageUrl, timerScope, resolve) {
    const browser = new Browser({
      silent: true,
      userAgent: this.options.userAgent,
      waitDuration: this.options.maxWait,
    });

    this.timer('browser.visit start; url: ' + pageUrl.href, timerScope);

    browser.visit(pageUrl.href, () => {
      this.timer('browser.visit end; url: ' + pageUrl.href, timerScope);

      if ( !this.responseOk(browser, pageUrl) ) {
        return resolve();
      }

      const headers = this.getHeaders(browser);
      const html = this.getHtml(browser);
      const scripts = this.getScripts(browser);
      const js = this.getJs(browser);

      this.wappalyzer.analyze(pageUrl, {
        headers,
        html,
        scripts,
        js
      })
        .then(() => {
          const links = Array.prototype.reduce.call(
            browser.document.getElementsByTagName('a'),
            (acc, link) => {
              if (link.protocol.match(/https?:/) || link.hostname === this.origPageUrl.hostname || extensions.test(link.pathname)) {
                link.hash = '';
                acc.push(url.parse(link.href));
              }
              return acc;
            },
            []
          );

          return resolve(links);
        });
    });
  }

  responseOk(browser, pageUrl) {
    // Validate response
    const resource = browser.resources.length ? browser.resources.filter(resource => resource.response).shift() : null;

    if ( !resource ) {
      this.wappalyzer.log('No response from server; url: ' + pageUrl.href, 'driver', 'error');

      return false;
    }

    if ( resource.response.status !== 200 ) {
      this.wappalyzer.log('Response was not OK; status: ' + resource.response.status + ' ' + resource.response.statusText + '; url: ' + pageUrl.href, 'driver', 'error');

      return false;
    }

    const headers = this.getHeaders(browser);

    // Validate content type
    const contentType = headers.hasOwnProperty('content-type') ? headers['content-type'].shift() : null;

    if ( !contentType || !/\btext\/html\b/.test(contentType) ) {
      this.wappalyzer.log('Skipping; url: ' + pageUrl.href + '; content type: ' + contentType, 'driver');

      this.analyzedPageUrls.splice(this.analyzedPageUrls.indexOf(pageUrl.href), 1);

      return false;
    }

    // Validate document
    if ( !browser.document || !browser.document.documentElement ) {
      this.wappalyzer.log('No HTML document; url: ' + pageUrl.href, 'driver', 'error');

      return false;
    }

    return true;
  }

  getHeaders(browser) {
    const headers = {};

    const resource = browser.resources.length ? browser.resources.filter(resource => resource.response).shift() : null;

    if ( resource ) {
      resource.response.headers._headers.forEach(header => {
        if ( !headers[header[0]] ){
          headers[header[0]] = [];
        }

        headers[header[0]].push(header[1]);
      });
    }

    return headers;
  }

  getHtml(browser) {
    let html = '';

    try {
      html = browser.html();

      if ( html.length > 50000 ) {
        html = html.substring(0, 25000) + html.substring(html.length - 25000, html.length);
      }
    } catch ( error ) {
      this.wappalyzer.log(error.message, 'browser', 'error');
    }

    return html;
  }

  getScripts(browser) {
    if ( !browser.document || !browser.document.scripts ) {
      return [];
    }

    const scripts = Array.prototype.slice
      .apply(browser.document.scripts)
      .filter(script => script.src)
      .map(script => script.src);

    return scripts;
  }

  getJs(browser) {
    const patterns = this.wappalyzer.jsPatterns;
    const js = {};

    Object.keys(patterns).forEach(appName => {
      js[appName] = {};

      Object.keys(patterns[appName]).forEach(chain => {
        js[appName][chain] = {};

        patterns[appName][chain].forEach((pattern, index) => {
          const properties = chain.split('.');

          let value = properties.reduce((parent, property) => {
            return parent && parent.hasOwnProperty(property) ? parent[property] : null;
          }, browser.window);

          value = typeof value === 'string' || typeof value === 'number' ? value : !!value;

          if ( value ) {
            js[appName][chain][index] = value;
          }
        });
      });
    });

    return js;
  }

  crawl(pageUrl, index, depth = 1) {
    pageUrl.canonical = pageUrl.protocol + '//' + pageUrl.host + pageUrl.pathname;

    return new Promise(resolve => {
      this.fetch(pageUrl, index, depth)
        .catch(() => {})
        .then(links => {
          if ( links && Boolean(this.options.recursive) && depth < this.options.maxDepth ) {
            return this.chunk(links.slice(0, this.options.maxUrls), depth + 1);
          } else {
            return Promise.resolve();
          }
        })
        .then(() => {
          resolve({
            urls: this.analyzedPageUrls,
            applications: this.apps,
            meta: this.meta
          });
        });
    });
  }

  chunk(links, depth, chunk = 0) {
    if ( links.length === 0 ) {
      return Promise.resolve();
    }

    const chunked = links.splice(0, this.options.chunkSize);

    return new Promise(resolve => {
      Promise.all(chunked.map((link, index) => this.crawl(link, index, depth)))
        .then(() => this.chunk(links, depth, chunk + 1))
        .then(() => resolve());
    });
  }

  sleep(ms) {
    return ms ? new Promise(resolve => setTimeout(resolve, ms)) : Promise.resolve();
  }

  timer(message, scope) {
    const time = new Date().getTime();
    const sinceStart = ( Math.round(( time - this.time.start ) / 10) / 100) + 's';
    const sinceLast = ( Math.round(( time - scope.last ) / 10) / 100) + 's';

    this.wappalyzer.log('[timer] ' + message + '; lapsed: ' + sinceLast + ' / ' + sinceStart, 'driver');

    scope.last = time;
  }
};

module.exports = Driver;
<|endoftext|>


<commit_before>const { TestRunnerTagger } = require('@integration/testing-tools');
const { ArtifactArchiver } = require('@serenity-js/core');
const { ConsoleReporter } = require('@serenity-js/console-reporter');
const { Photographer, TakePhotosOfFailures } = require('@serenity-js/web');
const { SerenityBDDReporter } = require('@serenity-js/serenity-bdd');
const { Actors } = require('./src/Actors');

const port = process.env.PORT || 8080;

exports.config = {

    baseUrl: `http://localhost:${port}`,

    SELENIUM_PROMISE_MANAGER: false,

    onPrepare: function () {
        return require('protractor').browser.waitForAngularEnabled(false);
    },

    allScriptsTimeout: 120_000,

    framework:      'custom',
    frameworkPath:  require.resolve('@serenity-js/protractor/adapter'),

    serenity: {
        actors: new Actors(),
        runner: 'mocha',
        crew: [
            new TestRunnerTagger('protractor'),
            ArtifactArchiver.storingArtifactsAt(`${ process.cwd() }/target/site/serenity`),
            // Photographer.whoWill(TakePhotosOfInteractions),
            Photographer.whoWill(TakePhotosOfFailures),
            new SerenityBDDReporter(),
            // ConsoleReporter.withDefaultColourSupport(),
        ]
    },

    specs: [
        './node_modules/@integration/web-specs/spec/**/*.spec.ts',
    ],

    mochaOpts: {
        timeout: 60_000,
        // ts-node is already loaded by nyc when protractor is executed via npm test
        require: [
            'ts-node/register',
        ],
        reporter: 'spec',
    },

    chromeDriver: require(`chromedriver`).path,
    directConnect: true,

    capabilities: {
        browserName: 'chrome',
        acceptInsecureCerts: true,

        loggingPrefs: {
            browser: 'INFO',
        },

        'goog:chromeOptions': {
            // As of version 75, ChromeDriver is W3C by default, which Protractor does not fully support.
            w3c: false,
            args: [
                '--disable-web-security',
                '--allow-file-access-from-files',
                '--allow-file-access',
                '--disable-infobars',
                '--headless',
                '--disable-gpu',
                '--window-size=1024x768',
            ],
        },
    },
};
<commit_msg>test(integration): enable console reporter for Protractor tests on CI<commit_after>const { TestRunnerTagger } = require('@integration/testing-tools');
const { ArtifactArchiver } = require('@serenity-js/core');
const { ConsoleReporter } = require('@serenity-js/console-reporter');
const { Photographer, TakePhotosOfFailures } = require('@serenity-js/web');
const { SerenityBDDReporter } = require('@serenity-js/serenity-bdd');
const { Actors } = require('./src/Actors');

const port = process.env.PORT || 8080;

exports.config = {

    baseUrl: `http://localhost:${port}`,

    SELENIUM_PROMISE_MANAGER: false,

    onPrepare: function () {
        return require('protractor').browser.waitForAngularEnabled(false);
    },

    allScriptsTimeout: 120_000,

    framework:      'custom',
    frameworkPath:  require.resolve('@serenity-js/protractor/adapter'),

    serenity: {
        actors: new Actors(),
        runner: 'mocha',
        crew: [
            new TestRunnerTagger('protractor'),
            ArtifactArchiver.storingArtifactsAt(`${ process.cwd() }/target/site/serenity`),
            // Photographer.whoWill(TakePhotosOfInteractions),
            Photographer.whoWill(TakePhotosOfFailures),
            new SerenityBDDReporter(),
        ]
        .concat(process.env.CI && ConsoleReporter.withDefaultColourSupport())
    },

    specs: [
        './node_modules/@integration/web-specs/spec/**/*.spec.ts',
    ],

    mochaOpts: {
        timeout: 60_000,
        // ts-node is already loaded by nyc when protractor is executed via npm test
        require: [
            'ts-node/register',
        ],
        reporter: 'spec',
    },

    chromeDriver: require(`chromedriver`).path,
    directConnect: true,

    capabilities: {
        browserName: 'chrome',
        acceptInsecureCerts: true,

        loggingPrefs: {
            browser: 'INFO',
        },

        'goog:chromeOptions': {
            // As of version 75, ChromeDriver is W3C by default, which Protractor does not fully support.
            w3c: false,
            args: [
                '--disable-web-security',
                '--allow-file-access-from-files',
                '--allow-file-access',
                '--disable-infobars',
                '--headless',
                '--disable-gpu',
                '--window-size=1024x768',
            ],
        },
    },
};
<|endoftext|>


<commit_before>import * as I  from 'immutable';
import * as fw from './freeWords';

const _relatorsByStartGen = relators => I.List(relators).map(I.List)
  .flatMap(fw.relatorPermutations)
  .groupBy(rel => rel.get(0))
  .map(I.Set);

const _inverseGen = g => fw.inverse([g]).first();

const _traceWord = (point, w, edge2word, action) => {
  let p = point;
  const trace = [];
  w.forEach(g => {
    trace.push(edge2word[p][g]);
    p = action(p, g);
  });

  return fw.product(trace);
};

const _closeRelations = (startEdge, wd, edge2word, relsByGen, action) => {
  const queue = [[startEdge, wd]];

  while (queue.length) {
    const [{ point, gen }, w] = queue.shift();

    if (edge2word[point] == null)
      edge2word[point] = {};
    edge2word[point][gen] = w;

    const pg = action(point, gen);
    if (edge2word[pg] == null)
      edge2word[pg] = {};
    edge2word[pg][_inverseGen(gen)] = fw.inverse(w);

    relsByGen.get(gen).forEach(r => {
      let cut = null;
      let w   = null;
      let x   = point;

      for (const i of r.keys()) {
        const h = r.get(i);
        if ((edge2word[x] || {})[h] == null) {
          if (cut == null) {
            cut = { point: x, gen: h };
            w   = fw.inverse(fw.rotated(r, i+1).slice(0, -1));
          }
          else {
            cut = null;
            break;
          }
        }
        x = action(x, h);
      };

      if (cut != null)
        queue.push([cut, _traceWord(cut.point, w, edge2word, action)]);
    });
  }
};

const _spanningTree = (basePoint, nrGens, action) => {
  const gens = I.Range(1, nrGens+1).flatMap(i => [i, -i]);

  const queue = [basePoint];
  const edges = [];
  const seen  = I.Set([basePoint]).asMutable();

  while (queue.length) {
    const point = queue.shift();

    gens.forEach(gen => {
      const p = action(point, gen);
      if (!seen.contains(p)) {
        queue.push(p);
        seen.add(p);
        edges.push({ point, gen });
      }
    });
  }

  return edges;
};

const _insertInOrderedSet = (elm, set, cmp) => {
  let i = 0;
  while (i < set.length && cmp(elm, set[i]) < 0)
    ++i;
  if (i >= set.length || cmp(elm, set[i]) != 0)
    set.splice(i, 0, elm);
};

export const stabilizer = (basePoint, nrGens, relators, domain, action) => {
  const relsByGen = _relatorsByStartGen(relators);
  const tree = _spanningTree(basePoint, nrGens, action);
  const id = fw.empty;

  const point2word = { [basePoint]: id };
  const edge2word = {};

  for (const edge of tree) {
    _closeRelations(edge, id, edge2word, relsByGen, action);
    point2word[action(edge.point, edge.gen)] =
      fw.product([point2word[edge.point], [edge.gen]]);
  }

  const generators = [];
  let lastGen = 0;

  for (const px of domain) {
    const wx = point2word[px];
    for (let i = 1; i <= nrGens; ++i) {
      for (const g of [i, -i]) {
        const edge = { point: px, gen: g };
        if (edge2word[px][g] == null) {
          const py = action(px, g);
          const wy = point2word[py];
          const h = ++lastGen;
          _closeRelations(edge, fw.word([h]), edge2word, relsByGen, action);
          generators.push(fw.product([wx, [g], fw.inverse(wy)]));
        }
      }
    }
  }

  const subrels = [];
  for (const p of domain) {
    for (const r of relators) {
      const w = fw.relatorRepresentative(_traceWord(p, r, edge2word, action));
      if (w && fw.compare(w, fw.empty))
        _insertInOrderedSet(w, subrels, fw.compare);
    }
  }

  return { generators, relators: subrels };
};

if (require.main == module) {
  const mapFn = map => (...args) => args.reduce((s, x) => s[x], map);

  console.log(stabilizer(
    'a',
    3,
    [[1,1],[2,2],[3,3],[1,2,1,2],[1,3,1,3],[2,3,2,3]],
    ['a', 'b', 'c', 'd'],
    mapFn({
      a: { '1': 'b', '2': 'c', '3': 'a', '-1': 'b', '-2': 'c', '-3': 'a' },
      b: { '1': 'a', '2': 'd', '3': 'b', '-1': 'a', '-2': 'd', '-3': 'b' },
      c: { '1': 'd', '2': 'a', '3': 'c', '-1': 'd', '-2': 'a', '-3': 'c' },
      d: { '1': 'c', '2': 'b', '3': 'd', '-1': 'c', '-2': 'b', '-3': 'd' }
    })
  ));

  console.log(stabilizer(
    'a',
    3,
    [[1,2,-1,-2],[1,3,-1,-3],[2,3,-2,-3]],
    ['a', 'b'],
    mapFn({
      a: { '1': 'b', '-1': 'b', '2': 'a', '-2': 'a', '3': 'a', '-3': 'a' },
      b: { '1': 'a', '-1': 'a', '2': 'b', '-2': 'b', '3': 'b', '-3': 'b' }
    })
  ));
}
<commit_msg>free fpgroup stabilizer code from immutable.js<commit_after>import * as fw from './freeWords';

const _insertInOrderedSet = (elm, set, cmp) => {
  let i = 0;
  while (i < set.length && cmp(elm, set[i]) < 0)
    ++i;
  if (i >= set.length || cmp(elm, set[i]) != 0)
    set.splice(i, 0, elm);
};

const _relatorsByStartGen = relators => {
  const result = {};
  for (const rel of relators) {
    for (const w of fw.relatorPermutations(rel)) {
      const g = w.first();
      if (result[g] == null)
        result[g] = [w];
      else
        _insertInOrderedSet(w, result[g], fw.compare);
    }
  }
  return result;
};

const _inverseGen = g => fw.inverse([g]).first();

const _traceWord = (point, w, edge2word, action) => {
  let p = point;
  const trace = [];
  w.forEach(g => {
    trace.push(edge2word[p][g]);
    p = action(p, g);
  });

  return fw.product(trace);
};

const _closeRelations = (startEdge, wd, edge2word, relsByGen, action) => {
  const queue = [[startEdge, wd]];

  while (queue.length) {
    const [{ point, gen }, w] = queue.shift();

    if (edge2word[point] == null)
      edge2word[point] = {};
    edge2word[point][gen] = w;

    const pg = action(point, gen);
    if (edge2word[pg] == null)
      edge2word[pg] = {};
    edge2word[pg][_inverseGen(gen)] = fw.inverse(w);

    relsByGen[gen].forEach(r => {
      let cut = null;
      let w   = null;
      let x   = point;

      for (const i of r.keys()) {
        const h = r.get(i);
        if ((edge2word[x] || {})[h] == null) {
          if (cut == null) {
            cut = { point: x, gen: h };
            w   = fw.inverse(fw.rotated(r, i+1).slice(0, -1));
          }
          else {
            cut = null;
            break;
          }
        }
        x = action(x, h);
      };

      if (cut != null)
        queue.push([cut, _traceWord(cut.point, w, edge2word, action)]);
    });
  }
};

const _spanningTree = (basePoint, nrGens, action) => {
  const queue = [basePoint];
  const edges = [];
  const seen  = { basePoint: true };

  while (queue.length) {
    const point = queue.shift();

    for (let i = 1; i <= nrGens; ++i) {
      for (const gen of [i, -i]) {
        const p = action(point, gen);
        if (!seen[p]) {
          queue.push(p);
          seen[p] = true;
          edges.push({ point, gen });
        }
      }
    }
  }

  return edges;
};

export const stabilizer = (basePoint, nrGens, relators, domain, action) => {
  const relsByGen = _relatorsByStartGen(relators);
  const tree = _spanningTree(basePoint, nrGens, action);
  const id = fw.empty;

  const point2word = { [basePoint]: id };
  const edge2word = {};

  for (const edge of tree) {
    _closeRelations(edge, id, edge2word, relsByGen, action);
    point2word[action(edge.point, edge.gen)] =
      fw.product([point2word[edge.point], [edge.gen]]);
  }

  const generators = [];
  let lastGen = 0;

  for (const px of domain) {
    const wx = point2word[px];
    for (let i = 1; i <= nrGens; ++i) {
      for (const g of [i, -i]) {
        const edge = { point: px, gen: g };
        if (edge2word[px][g] == null) {
          const py = action(px, g);
          const wy = point2word[py];
          const h = ++lastGen;
          _closeRelations(edge, fw.word([h]), edge2word, relsByGen, action);
          generators.push(fw.product([wx, [g], fw.inverse(wy)]));
        }
      }
    }
  }

  const subrels = [];
  for (const p of domain) {
    for (const r of relators) {
      const w = fw.relatorRepresentative(_traceWord(p, r, edge2word, action));
      if (w && fw.compare(w, fw.empty))
        _insertInOrderedSet(w, subrels, fw.compare);
    }
  }

  return { generators, relators: subrels };
};

if (require.main == module) {
  const mapFn = map => (...args) => args.reduce((s, x) => s[x], map);

  console.log(stabilizer(
    'a',
    3,
    [[1,1],[2,2],[3,3],[1,2,1,2],[1,3,1,3],[2,3,2,3]],
    ['a', 'b', 'c', 'd'],
    mapFn({
      a: { '1': 'b', '2': 'c', '3': 'a', '-1': 'b', '-2': 'c', '-3': 'a' },
      b: { '1': 'a', '2': 'd', '3': 'b', '-1': 'a', '-2': 'd', '-3': 'b' },
      c: { '1': 'd', '2': 'a', '3': 'c', '-1': 'd', '-2': 'a', '-3': 'c' },
      d: { '1': 'c', '2': 'b', '3': 'd', '-1': 'c', '-2': 'b', '-3': 'd' }
    })
  ));

  console.log(stabilizer(
    'a',
    3,
    [[1,2,-1,-2],[1,3,-1,-3],[2,3,-2,-3]],
    ['a', 'b'],
    mapFn({
      a: { '1': 'b', '-1': 'b', '2': 'a', '-2': 'a', '3': 'a', '-3': 'a' },
      b: { '1': 'a', '-1': 'a', '2': 'b', '-2': 'b', '3': 'b', '-3': 'b' }
    })
  ));
}
<|endoftext|>


<commit_before>'use strict';

var I = require('immutable');
var fw = require('./freeWords');

var _relatorsByStartGen = function _relatorsByStartGen(relators) {
  return I.List(relators).map(I.List)
    .flatMap(function(w) {
      return I.Range(0, w.size).flatMap(function(i) {
        var wx = fw.product([w.slice(i), w.slice(0, i)]);
        return [wx, fw.inverse(wx)];
      });
    })
    .groupBy(function(rel) { return rel.get(0); })
    .map(I.Set);
};

var Edge = I.Record({
  point: undefined,
  gen  : undefined
});

var _inverseGen = function _inverseGen(g) {
  return fw.inverse([g]).first();
};

var _reverseEdge = function _reverseEdge(edge, action) {
  return new Edge({
    point: action(edge.point, edge.gen),
    gen  : _inverseGen(edge.gen)
  });
};

var _closeRelations = function _closeRelations(
  startEdge,
  edge2word,
  relsByGen,
  action
) {
  var queue = I.List([startEdge]);

  while (!queue.isEmpty()) {
    var next = queue.first();
    queue = queue.rest();

    var p = next.point;
    var g = next.gen;

    relsByGen.get(g).forEach(function(r) {
      var x = p;
      var cuts = I.List();
      r.forEach(function(h, i) {
        var next = new Edge({ point: x, gen: h });
        if (edge2word.get(next) == null)
          cuts = cuts.push([i, next]);
        x = action(x, h);
      });

      if (cuts.size == 1) {
        var i = cuts.first()[0];
        var cut = cuts.first()[1];
        var x = cut.point;
        var g = cut.gen;
        var wx = fw.inverse(fw.product([r.slice(i+1), r.slice(0, i)]));

        var trace = fw.empty;
        wx.forEach(function(h) {
          var t = edge2word.get(new Edge({ point: x, gen: h }));
          trace = fw.product([trace, t]);
          x = action(x, h);
        });

        edge2word = edge2word
          .set(cut, trace)
          .set(_reverseEdge(cut, action), fw.inverse(trace));

        queue = queue.push(cut);
      }
    });
  }

  return edge2word;
};

var _spanningTree = function _spanningTree(basePoint, nrGens, action) {
  var queue = I.List([basePoint]);
  var seen = I.Set([basePoint]);
  var gens = I.Range(1, nrGens+1).flatMap(function(i) { return [i, -i]; });
  var edges = I.List();

  while (!queue.isEmpty()) {
    var point = queue.first();
    queue = queue.rest();

    gens.forEach(function(g) {
      var p = action(point, g);
      if (!seen.contains(p)) {
        queue = queue.push(p);
        seen = seen.add(p);
        edges = edges.push(new Edge({ point: point, gen: g }));
      }
    });
  }

  return edges;
};

var stabilizer = function stabilizer(
  basePoint, nrGens, relators, domain, action
) {
  var relsByGen = _relatorsByStartGen(relators);
  var tree = _spanningTree(basePoint, nrGens, action);
  var gens = I.Range(1, nrGens+1).flatMap(function(i) { return [i, -i]; });
  var id = fw.empty;

  var point2word = I.Map([[basePoint, id]]);
  var edge2word = I.Map();

  tree.forEach(function(edge) {
    edge2word = edge2word.set(edge, id).set(_reverseEdge(edge, action), id);
    edge2word = _closeRelations(edge, edge2word, relsByGen, action);
    point2word = point2word.set(
      action(edge.point, edge.gen),
      fw.product([point2word.get(edge.point), [edge.gen]]));
  });

  console.log('point2word = '+point2word);
  console.log('edge2word = '+edge2word);

  var lastGen = 0;
  var subgroupGens = I.List();

  domain.forEach(function(px) {
    var wx = point2word.get(px);
    gens.forEach(function(g) {
      var edge = new Edge({ point: px, gen: g });
      if (edge2word.get(edge) == null) {
        var py = action(px, g);
        var wy = point2word.get(py);
        var h = ++lastGen;
        var redge = _reverseEdge(edge, action);
        edge2word = edge2word
          .set(edge, h)
          .set(redge, _inverseGen(h));
        edge2word = _closeRelations(edge, edge2word, relsByGen, action);
        edge2word = _closeRelations(redge, edge2word, relsByGen, action);

        subgroupGens = subgroupGens.push(fw.product(wx, [g], fw.inverse(wy)));
      }
    });
  });

  console.log('edge2word = '+edge2word);
};

if (require.main == module) {
  var mapFn = function(map) {
    return function() {
      return map.getIn([].slice.apply(arguments));
    };
  };

  stabilizer(
    'a',
    2,
    [[1,1],[2,2],[1,2,1,2]],
    ['a', 'b', 'c', 'd'],
    mapFn(I.Map({
      a: I.Map([[1, 'b'], [2, 'c'], [-1, 'b'], [-2, 'c']]),
      b: I.Map([[1, 'a'], [2, 'd'], [-1, 'a'], [-2, 'd']]),
      c: I.Map([[1, 'd'], [2, 'a'], [-1, 'd'], [-2, 'a']]),
      d: I.Map([[1, 'c'], [2, 'b'], [-1, 'c'], [-2, 'b']]),
    }))
  );
}
<commit_msg>add another test example<commit_after>'use strict';

var I = require('immutable');
var fw = require('./freeWords');

var _relatorsByStartGen = function _relatorsByStartGen(relators) {
  return I.List(relators).map(I.List)
    .flatMap(function(w) {
      return I.Range(0, w.size).flatMap(function(i) {
        var wx = fw.product([w.slice(i), w.slice(0, i)]);
        return [wx, fw.inverse(wx)];
      });
    })
    .groupBy(function(rel) { return rel.get(0); })
    .map(I.Set);
};

var Edge = I.Record({
  point: undefined,
  gen  : undefined
});

var _inverseGen = function _inverseGen(g) {
  return fw.inverse([g]).first();
};

var _reverseEdge = function _reverseEdge(edge, action) {
  return new Edge({
    point: action(edge.point, edge.gen),
    gen  : _inverseGen(edge.gen)
  });
};

var _closeRelations = function _closeRelations(
  startEdge,
  edge2word,
  relsByGen,
  action
) {
  var queue = I.List([startEdge]);

  while (!queue.isEmpty()) {
    var next = queue.first();
    queue = queue.rest();

    var p = next.point;
    var g = next.gen;

    relsByGen.get(g).forEach(function(r) {
      var x = p;
      var cuts = I.List();
      r.forEach(function(h, i) {
        var next = new Edge({ point: x, gen: h });
        if (edge2word.get(next) == null)
          cuts = cuts.push([i, next]);
        x = action(x, h);
      });

      if (cuts.size == 1) {
        var i = cuts.first()[0];
        var cut = cuts.first()[1];
        var x = cut.point;
        var g = cut.gen;
        var wx = fw.inverse(fw.product([r.slice(i+1), r.slice(0, i)]));

        var trace = fw.empty;
        wx.forEach(function(h) {
          var t = edge2word.get(new Edge({ point: x, gen: h }));
          trace = fw.product([trace, t]);
          x = action(x, h);
        });

        edge2word = edge2word
          .set(cut, trace)
          .set(_reverseEdge(cut, action), fw.inverse(trace));

        queue = queue.push(cut);
      }
    });
  }

  return edge2word;
};

var _spanningTree = function _spanningTree(basePoint, nrGens, action) {
  var queue = I.List([basePoint]);
  var seen = I.Set([basePoint]);
  var gens = I.Range(1, nrGens+1).flatMap(function(i) { return [i, -i]; });
  var edges = I.List();

  while (!queue.isEmpty()) {
    var point = queue.first();
    queue = queue.rest();

    gens.forEach(function(g) {
      var p = action(point, g);
      if (!seen.contains(p)) {
        queue = queue.push(p);
        seen = seen.add(p);
        edges = edges.push(new Edge({ point: point, gen: g }));
      }
    });
  }

  return edges;
};

var stabilizer = function stabilizer(
  basePoint, nrGens, relators, domain, action
) {
  var relsByGen = _relatorsByStartGen(relators);
  var tree = _spanningTree(basePoint, nrGens, action);
  var gens = I.Range(1, nrGens+1).flatMap(function(i) { return [i, -i]; });
  var id = fw.empty;

  var point2word = I.Map([[basePoint, id]]);
  var edge2word = I.Map();

  tree.forEach(function(edge) {
    edge2word = edge2word.set(edge, id).set(_reverseEdge(edge, action), id);
    edge2word = _closeRelations(edge, edge2word, relsByGen, action);
    point2word = point2word.set(
      action(edge.point, edge.gen),
      fw.product([point2word.get(edge.point), [edge.gen]]));
  });

  console.log('point2word = '+point2word);
  console.log('edge2word = '+edge2word);

  var lastGen = 0;
  var subgroupGens = I.List();

  domain.forEach(function(px) {
    var wx = point2word.get(px);
    gens.forEach(function(g) {
      var edge = new Edge({ point: px, gen: g });
      if (edge2word.get(edge) == null) {
        var py = action(px, g);
        var wy = point2word.get(py);
        var h = ++lastGen;
        var redge = _reverseEdge(edge, action);
        edge2word = edge2word
          .set(edge, h)
          .set(redge, _inverseGen(h));
        edge2word = _closeRelations(edge, edge2word, relsByGen, action);
        edge2word = _closeRelations(redge, edge2word, relsByGen, action);

        subgroupGens = subgroupGens.push(fw.product(wx, [g], fw.inverse(wy)));
      }
    });
  });

  console.log('edge2word = '+edge2word);
  console.log();
};

if (require.main == module) {
  var mapFn = function(map) {
    return function() {
      return map.getIn([].slice.apply(arguments));
    };
  };

  stabilizer(
    'a',
    2,
    [[1,1],[2,2],[1,2,1,2]],
    ['a', 'b', 'c', 'd'],
    mapFn(I.Map({
      a: I.Map([[1, 'b'], [2, 'c'], [-1, 'b'], [-2, 'c']]),
      b: I.Map([[1, 'a'], [2, 'd'], [-1, 'a'], [-2, 'd']]),
      c: I.Map([[1, 'd'], [2, 'a'], [-1, 'd'], [-2, 'a']]),
      d: I.Map([[1, 'c'], [2, 'b'], [-1, 'c'], [-2, 'b']]),
    }))
  );

  stabilizer(
    'a',
    3,
    [[1,2,-1,-2],[1,3,-1,-3],[2,3,-2,-3]],
    ['a', 'b'],
    mapFn(I.Map({
      a: I.Map([[1, 'b'], [-1, 'b'], [2, 'a'], [-2, 'a'], [3, 'a'], [-3, 'a']]),
      b: I.Map([[1, 'a'], [-1, 'a'], [2, 'b'], [-2, 'b'], [3, 'b'], [-3, 'b']])
    }))
  );
}
<|endoftext|>


<commit_before>var gulp = require("gulp");
var runSeq = require("run-sequence");
var typescript = require("typescript");
var tsc = require("gulp-typescript");
var sourcemaps = require("gulp-sourcemaps");
var plumber = require("gulp-plumber");
var sass = require("gulp-sass");

var paths = require("../paths");

gulp.task("build", (cb) => {
	return runSeq(
		["compile:ts", "html", "copy:imgs"],
		cb);
});

gulp.task("rebuild", (cb) => {
	return runSeq(
		"clean",
		"build",
		cb);
});

// scripts
gulp.task("compile:ts", () => {
	var tsProject = getTscProject();
	var tsResult = gulp.src([paths.src.tsd, paths.src.ts])
		.pipe(plumber())
	//.pipe(changed(paths.output.dist, { extension: ".js" }))
		.pipe(sourcemaps.init())
		.pipe(tsc(tsProject));

	return tsResult.js
		.pipe(sourcemaps.write("."))
		.pipe(gulp.dest(`${paths.output.dist}`))
});

function getTscProject() {
	return tsc.createProject("tsconfig.json", {
		sortOutput: true,
		typescript: typescript
	});
}

// sass
gulp.task("compile:sass", () => {
	return gulp.src(paths.src.sass)
		.pipe(sass().on("error", sass.logError))
		.pipe(gulp.dest(`${paths.output.dist}/assets`))
});

// html
gulp.task("html", (cb) => {
	return runSeq(
		["compile:html", "compile:index-html"],
		cb);
});

gulp.task("compile:html", () => {
	return gulp.src(paths.src.html)
		.pipe(gulp.dest(`${paths.output.dist}/app`))
});

gulp.task("compile:index-html", () => {
	return gulp.src(paths.src.indexHtml)
		.pipe(gulp.dest(paths.output.root))
});

// images
gulp.task("copy:imgs", () => {
	return gulp.src(paths.src.imgs)
		.pipe(gulp.dest(`${paths.output.dist}/assets`))
});<commit_msg>fix(angular2-heroes): added sass build within task<commit_after>var gulp = require("gulp");
var runSeq = require("run-sequence");
var typescript = require("typescript");
var tsc = require("gulp-typescript");
var sourcemaps = require("gulp-sourcemaps");
var plumber = require("gulp-plumber");
var sass = require("gulp-sass");

var paths = require("../paths");

gulp.task("build", (cb) => {
	return runSeq(
		["compile:ts", "compile:sass", "html", "copy:imgs"],
		cb);
});

gulp.task("rebuild", (cb) => {
	return runSeq(
		"clean",
		"build",
		cb);
});

// scripts
gulp.task("compile:ts", () => {
	var tsProject = getTscProject();
	var tsResult = gulp.src([paths.src.tsd, paths.src.ts])
		.pipe(plumber())
	//.pipe(changed(paths.output.dist, { extension: ".js" }))
		.pipe(sourcemaps.init())
		.pipe(tsc(tsProject));

	return tsResult.js
		.pipe(sourcemaps.write("."))
		.pipe(gulp.dest(`${paths.output.dist}`))
});

function getTscProject() {
	return tsc.createProject("tsconfig.json", {
		sortOutput: true,
		typescript: typescript
	});
}

// sass
gulp.task("compile:sass", () => {
	return gulp.src(paths.src.sass)
		.pipe(sass().on("error", sass.logError))
		.pipe(gulp.dest(`${paths.output.dist}/assets`))
});

// html
gulp.task("html", (cb) => {
	return runSeq(
		["compile:html", "compile:index-html"],
		cb);
});

gulp.task("compile:html", () => {
	return gulp.src(paths.src.html)
		.pipe(gulp.dest(`${paths.output.dist}/app`))
});

gulp.task("compile:index-html", () => {
	return gulp.src(paths.src.indexHtml)
		.pipe(gulp.dest(paths.output.root))
});

// images
gulp.task("copy:imgs", () => {
	return gulp.src(paths.src.imgs)
		.pipe(gulp.dest(`${paths.output.dist}/assets`))
});<|endoftext|>


<commit_before>/*
Copyright 2019 New Vector Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import { MATRIXTO_URL_PATTERN } from '../linkify-matrix';
import { walkDOMDepthFirst } from "./dom";
import { checkBlockNode } from "../HtmlUtils";

const REGEX_MATRIXTO = new RegExp(MATRIXTO_URL_PATTERN);

function parseAtRoomMentions(text, partCreator) {
    const ATROOM = "@room";
    const parts = [];
    text.split(ATROOM).forEach((textPart, i, arr) => {
        if (textPart.length) {
            parts.push(partCreator.plain(textPart));
        }
        // it's safe to never append @room after the last textPart
        // as split will report an empty string at the end if
        // `text` ended in @room.
        const isLast = i === arr.length - 1;
        if (!isLast) {
            parts.push(partCreator.atRoomPill(ATROOM));
        }
    });
    return parts;
}

function parseLink(a, partCreator) {
    const {href} = a;
    const pillMatch = REGEX_MATRIXTO.exec(href) || [];
    const resourceId = pillMatch[1]; // The room/user ID
    const prefix = pillMatch[2]; // The first character of prefix
    switch (prefix) {
        case "@":
            return partCreator.userPill(a.textContent, resourceId);
        case "#":
            return partCreator.roomPill(resourceId);
        default: {
            if (href === a.textContent) {
                return partCreator.plain(a.textContent);
            } else {
                return partCreator.plain(`[${a.textContent}](${href})`);
            }
        }
    }
}

function parseCodeBlock(n, partCreator) {
    const parts = [];
    const preLines = ("```\n" + n.textContent + "```").split("\n");
    preLines.forEach((l, i) => {
        parts.push(partCreator.plain(l));
        if (i < preLines.length - 1) {
            parts.push(partCreator.newline());
        }
    });
    return parts;
}

function parseHeader(el, partCreator) {
    const depth = parseInt(el.nodeName.substr(1), 10);
    return partCreator.plain("#".repeat(depth) + " ");
}

function parseElement(n, partCreator, lastNode, state) {
    switch (n.nodeName) {
        case "H1":
        case "H2":
        case "H3":
        case "H4":
        case "H5":
        case "H6":
            return parseHeader(n, partCreator);
        case "A":
            return parseLink(n, partCreator);
        case "BR":
            return partCreator.newline();
        case "EM":
            return partCreator.plain(`_${n.textContent}_`);
        case "STRONG":
            return partCreator.plain(`**${n.textContent}**`);
        case "PRE":
            return parseCodeBlock(n, partCreator);
        case "CODE":
            return partCreator.plain(`\`${n.textContent}\``);
        case "DEL":
            return partCreator.plain(`<del>${n.textContent}</del>`);
        case "LI": {
            const indent = "  ".repeat(state.listDepth - 1);
            if (n.parentElement.nodeName === "OL") {
                return partCreator.plain(`${indent}1. `);
            } else {
                return partCreator.plain(`${indent}- `);
            }
        }
        case "P": {
            if (lastNode) {
                return partCreator.newline();
            }
            break;
        }
        case "OL":
        case "UL":
            state.listDepth = (state.listDepth || 0) + 1;
        // es-lint-disable-next-line no-fallthrough
        default:
            // don't textify block nodes we'll decend into
            if (!checkDecendInto(n)) {
                return partCreator.plain(n.textContent);
            }
    }
}

function checkDecendInto(node) {
    switch (node.nodeName) {
        case "PRE":
            // a code block is textified in parseCodeBlock
            // as we don't want to preserve markup in it,
            // so no need to decend into it
            return false;
        default:
            return checkBlockNode(node);
    }
}

function checkIgnored(n) {
    if (n.nodeType === Node.TEXT_NODE) {
        // riot adds \n text nodes in a lot of places,
        // which should be ignored
        return n.nodeValue === "\n";
    } else if (n.nodeType === Node.ELEMENT_NODE) {
        return n.nodeName === "MX-REPLY";
    }
    return true;
}

const QUOTE_LINE_PREFIX = "> ";
function prefixQuoteLines(isFirstNode, parts, partCreator) {
    // a newline (to append a > to) wouldn't be added to parts for the first line
    // if there was no content before the BLOCKQUOTE, so handle that
    if (isFirstNode) {
        parts.splice(0, 0, partCreator.plain(QUOTE_LINE_PREFIX));
    }
    for (let i = 0; i < parts.length; i += 1) {
        if (parts[i].type === "newline") {
            parts.splice(i + 1, 0, partCreator.plain(QUOTE_LINE_PREFIX));
            i += 1;
        }
    }
}

function parseHtmlMessage(html, partCreator, isQuotedMessage) {
    // no nodes from parsing here should be inserted in the document,
    // as scripts in event handlers, etc would be executed then.
    // we're only taking text, so that is fine
    const rootNode = new DOMParser().parseFromString(html, "text/html").body;
    const parts = [];
    let lastNode;
    let inQuote = isQuotedMessage;
    const state = {};

    function onNodeEnter(n) {
        if (checkIgnored(n)) {
            return false;
        }
        if (n.nodeName === "BLOCKQUOTE") {
            inQuote = true;
        }

        const newParts = [];
        if (lastNode && (checkBlockNode(lastNode) || checkBlockNode(n))) {
            newParts.push(partCreator.newline());
        }

        if (n.nodeType === Node.TEXT_NODE) {
            newParts.push(...parseAtRoomMentions(n.nodeValue, partCreator));
        } else if (n.nodeType === Node.ELEMENT_NODE) {
            const parseResult = parseElement(n, partCreator, lastNode, state);
            if (parseResult) {
                if (Array.isArray(parseResult)) {
                    newParts.push(...parseResult);
                } else {
                    newParts.push(parseResult);
                }
            }
        }

        if (newParts.length && inQuote) {
            const isFirstPart = parts.length === 0;
            prefixQuoteLines(isFirstPart, newParts, partCreator);
        }

        parts.push(...newParts);

        // extra newline after quote, only if there something behind it...
        if (lastNode && lastNode.nodeName === "BLOCKQUOTE") {
            parts.push(partCreator.newline());
        }
        const decend = checkDecendInto(n);
        // when not decending (like for PRE), onNodeLeave won't be called to set lastNode
        // so do that here.
        lastNode = decend ? null : n;
        return decend;
    }

    function onNodeLeave(n) {
        if (checkIgnored(n)) {
            return;
        }
        switch (n.nodeName) {
            case "BLOCKQUOTE":
                inQuote = false;
                break;
            case "OL":
            case "UL":
                state.listDepth -= 1;
                break;
        }
        lastNode = n;
    }

    walkDOMDepthFirst(rootNode, onNodeEnter, onNodeLeave);

    return parts;
}

export function parsePlainTextMessage(body, partCreator, isQuotedMessage) {
    const lines = body.split("\n");
    const parts = lines.reduce((parts, line, i) => {
        if (isQuotedMessage) {
            parts.push(partCreator.plain(QUOTE_LINE_PREFIX));
        }
        parts.push(...parseAtRoomMentions(line, partCreator));
        const isLast = i === lines.length - 1;
        if (!isLast) {
            parts.push(partCreator.newline());
        }
        return parts;
    }, []);
    return parts;
}

export function parseEvent(event, partCreator, {isQuotedMessage = false} = {}) {
    const content = event.getContent();
    let parts;
    if (content.format === "org.matrix.custom.html") {
        parts = parseHtmlMessage(content.formatted_body || "", partCreator, isQuotedMessage);
    } else {
        parts = parsePlainTextMessage(content.body || "", partCreator, isQuotedMessage);
    }
    if (content.msgtype === "m.emote") {
        parts.unshift(partCreator.plain("/me "));
    }
    return parts;
}
<commit_msg>don't append extra newline after blockquote anymore<commit_after>/*
Copyright 2019 New Vector Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import { MATRIXTO_URL_PATTERN } from '../linkify-matrix';
import { walkDOMDepthFirst } from "./dom";
import { checkBlockNode } from "../HtmlUtils";

const REGEX_MATRIXTO = new RegExp(MATRIXTO_URL_PATTERN);

function parseAtRoomMentions(text, partCreator) {
    const ATROOM = "@room";
    const parts = [];
    text.split(ATROOM).forEach((textPart, i, arr) => {
        if (textPart.length) {
            parts.push(partCreator.plain(textPart));
        }
        // it's safe to never append @room after the last textPart
        // as split will report an empty string at the end if
        // `text` ended in @room.
        const isLast = i === arr.length - 1;
        if (!isLast) {
            parts.push(partCreator.atRoomPill(ATROOM));
        }
    });
    return parts;
}

function parseLink(a, partCreator) {
    const {href} = a;
    const pillMatch = REGEX_MATRIXTO.exec(href) || [];
    const resourceId = pillMatch[1]; // The room/user ID
    const prefix = pillMatch[2]; // The first character of prefix
    switch (prefix) {
        case "@":
            return partCreator.userPill(a.textContent, resourceId);
        case "#":
            return partCreator.roomPill(resourceId);
        default: {
            if (href === a.textContent) {
                return partCreator.plain(a.textContent);
            } else {
                return partCreator.plain(`[${a.textContent}](${href})`);
            }
        }
    }
}

function parseCodeBlock(n, partCreator) {
    const parts = [];
    const preLines = ("```\n" + n.textContent + "```").split("\n");
    preLines.forEach((l, i) => {
        parts.push(partCreator.plain(l));
        if (i < preLines.length - 1) {
            parts.push(partCreator.newline());
        }
    });
    return parts;
}

function parseHeader(el, partCreator) {
    const depth = parseInt(el.nodeName.substr(1), 10);
    return partCreator.plain("#".repeat(depth) + " ");
}

function parseElement(n, partCreator, lastNode, state) {
    switch (n.nodeName) {
        case "H1":
        case "H2":
        case "H3":
        case "H4":
        case "H5":
        case "H6":
            return parseHeader(n, partCreator);
        case "A":
            return parseLink(n, partCreator);
        case "BR":
            return partCreator.newline();
        case "EM":
            return partCreator.plain(`_${n.textContent}_`);
        case "STRONG":
            return partCreator.plain(`**${n.textContent}**`);
        case "PRE":
            return parseCodeBlock(n, partCreator);
        case "CODE":
            return partCreator.plain(`\`${n.textContent}\``);
        case "DEL":
            return partCreator.plain(`<del>${n.textContent}</del>`);
        case "LI": {
            const indent = "  ".repeat(state.listDepth - 1);
            if (n.parentElement.nodeName === "OL") {
                return partCreator.plain(`${indent}1. `);
            } else {
                return partCreator.plain(`${indent}- `);
            }
        }
        case "P": {
            if (lastNode) {
                return partCreator.newline();
            }
            break;
        }
        case "OL":
        case "UL":
            state.listDepth = (state.listDepth || 0) + 1;
        // es-lint-disable-next-line no-fallthrough
        default:
            // don't textify block nodes we'll decend into
            if (!checkDecendInto(n)) {
                return partCreator.plain(n.textContent);
            }
    }
}

function checkDecendInto(node) {
    switch (node.nodeName) {
        case "PRE":
            // a code block is textified in parseCodeBlock
            // as we don't want to preserve markup in it,
            // so no need to decend into it
            return false;
        default:
            return checkBlockNode(node);
    }
}

function checkIgnored(n) {
    if (n.nodeType === Node.TEXT_NODE) {
        // riot adds \n text nodes in a lot of places,
        // which should be ignored
        return n.nodeValue === "\n";
    } else if (n.nodeType === Node.ELEMENT_NODE) {
        return n.nodeName === "MX-REPLY";
    }
    return true;
}

const QUOTE_LINE_PREFIX = "> ";
function prefixQuoteLines(isFirstNode, parts, partCreator) {
    // a newline (to append a > to) wouldn't be added to parts for the first line
    // if there was no content before the BLOCKQUOTE, so handle that
    if (isFirstNode) {
        parts.splice(0, 0, partCreator.plain(QUOTE_LINE_PREFIX));
    }
    for (let i = 0; i < parts.length; i += 1) {
        if (parts[i].type === "newline") {
            parts.splice(i + 1, 0, partCreator.plain(QUOTE_LINE_PREFIX));
            i += 1;
        }
    }
}

function parseHtmlMessage(html, partCreator, isQuotedMessage) {
    // no nodes from parsing here should be inserted in the document,
    // as scripts in event handlers, etc would be executed then.
    // we're only taking text, so that is fine
    const rootNode = new DOMParser().parseFromString(html, "text/html").body;
    const parts = [];
    let lastNode;
    let inQuote = isQuotedMessage;
    const state = {};

    function onNodeEnter(n) {
        if (checkIgnored(n)) {
            return false;
        }
        if (n.nodeName === "BLOCKQUOTE") {
            inQuote = true;
        }

        const newParts = [];
        if (lastNode && (checkBlockNode(lastNode) || checkBlockNode(n))) {
            newParts.push(partCreator.newline());
        }

        if (n.nodeType === Node.TEXT_NODE) {
            newParts.push(...parseAtRoomMentions(n.nodeValue, partCreator));
        } else if (n.nodeType === Node.ELEMENT_NODE) {
            const parseResult = parseElement(n, partCreator, lastNode, state);
            if (parseResult) {
                if (Array.isArray(parseResult)) {
                    newParts.push(...parseResult);
                } else {
                    newParts.push(parseResult);
                }
            }
        }

        if (newParts.length && inQuote) {
            const isFirstPart = parts.length === 0;
            prefixQuoteLines(isFirstPart, newParts, partCreator);
        }

        parts.push(...newParts);

        const decend = checkDecendInto(n);
        // when not decending (like for PRE), onNodeLeave won't be called to set lastNode
        // so do that here.
        lastNode = decend ? null : n;
        return decend;
    }

    function onNodeLeave(n) {
        if (checkIgnored(n)) {
            return;
        }
        switch (n.nodeName) {
            case "BLOCKQUOTE":
                inQuote = false;
                break;
            case "OL":
            case "UL":
                state.listDepth -= 1;
                break;
        }
        lastNode = n;
    }

    walkDOMDepthFirst(rootNode, onNodeEnter, onNodeLeave);

    return parts;
}

export function parsePlainTextMessage(body, partCreator, isQuotedMessage) {
    const lines = body.split("\n");
    const parts = lines.reduce((parts, line, i) => {
        if (isQuotedMessage) {
            parts.push(partCreator.plain(QUOTE_LINE_PREFIX));
        }
        parts.push(...parseAtRoomMentions(line, partCreator));
        const isLast = i === lines.length - 1;
        if (!isLast) {
            parts.push(partCreator.newline());
        }
        return parts;
    }, []);
    return parts;
}

export function parseEvent(event, partCreator, {isQuotedMessage = false} = {}) {
    const content = event.getContent();
    let parts;
    if (content.format === "org.matrix.custom.html") {
        parts = parseHtmlMessage(content.formatted_body || "", partCreator, isQuotedMessage);
    } else {
        parts = parsePlainTextMessage(content.body || "", partCreator, isQuotedMessage);
    }
    if (content.msgtype === "m.emote") {
        parts.unshift(partCreator.plain("/me "));
    }
    return parts;
}
<|endoftext|>


<commit_before>/**
 * ContactController
 *
 * @description :: Server-side logic for managing contacts
 * @help        :: See http://sailsjs.org/#!/documentation/concepts/Controllers
 */

module.exports = {

  login: function (req, res) {
    if (typeof req.param('nickname') === 'undefined' || typeof req.param('password') === 'undefined') {
      return res.json({errorMessage: "Les informations de connexion entrées en correspondent pas !"});
    } else {
      Contact.findOne({nickname: req.param('nickname')}).exec(function (user) {
        if (err) return res.badRequest(err);
        if (!user) return res.json({errorMessage: "Les informations de connexion entrées en correspondent pas !"});

        bcrypt.compare(req.param('password'), user.password, function (err, res) {
          if (err) return res.badRequest(err);
          if (!res) return res.json({errorMessage: "Les informations de connexion entrées en correspondent pas !"});
          return res.json(res);
        });
      });
    }
  },

  getContacts: function (req, res) {
    Contact.find().populate('phones').exec(function (err, contacts) {
      if (err) return res.badRequest(err);
      return res.json(contacts);
    });
  },

  getContactByNickname: function (req, res) {
    Contact.findOne({nickname: req.param('nickname')}).populate('phones').exec(function (err, contact) {
      if (err) return res.badRequest(err);
      return res.json(contact);
    });
  },

  createContact: function (req, res) {
    var phones = (typeof req.param('phones') !== 'undefined') ? JSON.parse(req.param('phones')) : '';

    Contact.create(
      req.allParams()
    ).exec(function (err, created) {
      if (err) return res.badRequest(err);
      Contact.find({id: created.id}).populate('phones').exec(function (e, r) {
        if (phones !== '') {
          if (Array.isArray(phones)) {
            phones.forEach(function (phone) {
              r[0].phones.add({
                label: phone.label,
                phone: phone.phone
              });
              r[0].save(function (err, result) {
                if (err) return res.badRequest(err);
                return res.json(created);
              });
            });
          }
        }
      });
    });
  },

  updateContact: function (req, res) {
    // Todo: To be implement !
    return res.json({info: "To be implement !"});
  },

  deleteContact: function (req, res) {
    Contact.destroy({id: req.param('id')}).exec(function (err) {
      if (err) return res.badRequest(err);
      return res.json({deleted: req.param('id')});
    });
  },

  getSMSByNickname: function (req, res) {
    Contact.findOne({nickname: req.param('nickname')}).populateAll().exec(function (err, contact) {
      if (err) return res.badRequest(err);
      var sms = {
        send: contact.smsSend,
        receipt: contact.smsReceipt
      }
      return res.json(sms);
    });
  }

};

<commit_msg>Add update contact<commit_after>/**
 * ContactController
 *
 * @description :: Server-side logic for managing contacts
 * @help        :: See http://sailsjs.org/#!/documentation/concepts/Controllers
 */

module.exports = {

  login: function (req, res) {
    if (typeof req.param('nickname') === 'undefined' || typeof req.param('password') === 'undefined') {
      return res.json({errorMessage: "Les informations de connexion entrées en correspondent pas !"});
    } else {
      Contact.findOne({nickname: req.param('nickname')}).exec(function (user) {
        if (err) return res.badRequest(err);
        if (!user) return res.json({errorMessage: "Les informations de connexion entrées en correspondent pas !"});

        bcrypt.compare(req.param('password'), user.password, function (err, res) {
          if (err) return res.badRequest(err);
          if (!res) return res.json({errorMessage: "Les informations de connexion entrées en correspondent pas !"});
          return res.json(res);
        });
      });
    }
  },

  getContacts: function (req, res) {
    Contact.find().populate('phones').exec(function (err, contacts) {
      if (err) return res.badRequest(err);
      return res.json(contacts);
    });
  },

  getContactByNickname: function (req, res) {
    Contact.findOne({nickname: req.param('nickname')}).populate('phones').exec(function (err, contact) {
      if (err) return res.badRequest(err);
      return res.json(contact);
    });
  },

  createContact: function (req, res) {
    var phones = (typeof req.param('phones') !== 'undefined') ? JSON.parse(req.param('phones')) : '';

    Contact.create(
      req.allParams()
    ).exec(function (err, created) {
      if (err) return res.badRequest(err);
      Contact.find({id: created.id}).populate('phones').exec(function (e, r) {
        if (phones !== '') {
          if (Array.isArray(phones)) {
            phones.forEach(function (phone) {
              r[0].phones.add({
                label: phone.label,
                phone: phone.phone
              });
              r[0].save(function (err, result) {
                if (err) return res.badRequest(err);
                return res.json(created);
              });
            });
          }
        }
      });
    });
  },

  updateContact: function (req, res) {
    Contact.update({nickname: req.param('nickname')}, req.allParams()).exec(function(contact) {
      if(err) return res.badRequest(res);
      return res.json(contact[0]);
    });
  },

  deleteContact: function (req, res) {
    Contact.destroy({id: req.param('id')}).exec(function (err) {
      if (err) return res.badRequest(err);
      return res.json({deleted: req.param('id')});
    });
  },

  getSMSByNickname: function (req, res) {
    Contact.findOne({nickname: req.param('nickname')}).populateAll().exec(function (err, contact) {
      if (err) return res.badRequest(err);
      var sms = {
        send: contact.smsSend,
        receipt: contact.smsReceipt
      }
      return res.json(sms);
    });
  }

};

<|endoftext|>


<commit_before>'use strict';

const getLernaPackages = require('./get-lerna-packages');
const getPackage = require('./get-package');

/**
 * @returns {Object} returns an object of available scripts as key and their packages as array
**/
function getScriptCommands({ diGetLernaPackages = getLernaPackages, diGetPackage = getPackage }) {
	const commands = {};

	diGetLernaPackages(packagePath => {
		const packageData = diGetPackage(packagePath);

		if (!packageData.scripts) {
			return;
		}

		Object.keys(packageData.scripts).forEach(scriptKey => {
			if (!commands[scriptKey]) {
				commands[scriptKey] = [];
			}
			commands[scriptKey].push(packagePath);
		});
	});

	return commands;
}

module.exports = getScriptCommands;
<commit_msg>fix(get-script-commands): Fix bug occurred because of dependeny injection<commit_after>'use strict';

const getLernaPackages = require('./get-lerna-packages');
const getPackage = require('./get-package');

/**
 * @param {Object|undefined} di - dependency injection for tests
 * @returns {Object} returns an object of available scripts as key and their packages as array
**/
function getScriptCommands(di) {
	const commands = {};

	const diGetLernaPackages = di ? di.diGetLernaPackages : getLernaPackages;
	const diGetPackage = di ? di.diGetPackage : getPackage;

	diGetLernaPackages(packagePath => {
		const packageData = diGetPackage(packagePath);

		if (!packageData.scripts) {
			return;
		}

		Object.keys(packageData.scripts).forEach(scriptKey => {
			if (!commands[scriptKey]) {
				commands[scriptKey] = [];
			}
			commands[scriptKey].push(packagePath);
		});
	});

	return commands;
}

module.exports = getScriptCommands;
<|endoftext|>


<commit_before>/*
 * grunt-raygun-deployment
 * https://raygun.io
 *
 * Copyright (c) 2015 Raygun.io
 * Licensed under the MIT license.
 */

'use strict';

var request = require('request');

module.exports = function (grunt) {

  grunt.registerTask('raygun_deployment', 'Grunt plugin for generating Deployment information for Raygun.io', function () {
    var finishedTask = this.async(), end, send, generate;

    var options = this.options({
      release: 'Release.yaml',
      raygunApiUri: 'https://app.raygun.io',
      useGit: true
    });

    if(!options.raygunApiKey && !process.env.RAYGUN_APIKEY){
      grunt.fatal('Required option raygunApiKey is missing');
      return;
    }
    if(!options.raygunAuthToken && !process.env.RAYGUN_AUTHTOKEN){
      grunt.fatal('Required option raygunAuthToken is missing');
      return;
    }

    var apiKey = options.raygunApiKey || process.env.RAYGUN_APIKEY;
    var authToken = options.raygunAuthToken || process.env.RAYGUN_AUTHTOKEN;

    generate = function(release, gitHash) {
      var deployment = {
        apiKey: apiKey,
        version: release.version,
        ownerName: release.ownerName,
        emailAddress: release.emailAddress,
        comment: release.notes,
        scmIdentifier: gitHash
      };
      send(deployment);
    };

    send = function(data) {
      request.post({
        uri: options.raygunApiUri + '/deployments',
        qs: { authToken: authToken },
        json: true,
        body: data
      }, end);
    };

    end = function(error, res, body) {
      if(error) {
        grunt.fatal(error);
      } else if (res.statusCode === 200) {
        grunt.log.writeln('Sent deployment info to Raygun.io');
        finishedTask();
      } else if(res.statusCode === 403) {
        grunt.fatal('Could not send deployment info to Raygun: your raygunApiKey is either wrong or you don\'t have access to that application');
      } else if(res.statusCode === 401) {
        grunt.fatal('Could not send deployment info to Raygun: your raygunAuthToken is wrong');
      } else {
        grunt.fatal('Could not send deployment info to Raygun: got a ' + res.statusCode + ' response code');
      }
    };

    var release = grunt.file.readYAML(options.release);

    if(options.useGit) {
      grunt.util.spawn({
        cmd: 'git',
        args: ['rev-parse', '--verify', 'HEAD'],
        grunt: false,
        fallback: ''
      }, function(error, result) {
        var gitHash = String(result);
        generate(release, gitHash);
      });
    } else {
      generate(release, '');
    }
  });

};
<commit_msg>feat: add support for provide release from options directly rather than through file.<commit_after>/*
 * grunt-raygun-deployment
 * https://raygun.io
 *
 * Copyright (c) 2015 Raygun.io
 * Licensed under the MIT license.
 */

'use strict';

var request = require('request');

module.exports = function (grunt) {

  grunt.registerTask('raygun_deployment', 'Grunt plugin for generating Deployment information for Raygun.io', function () {
    var finishedTask = this.async(), end, send, generate;

    var options = this.options({
      release: 'Release.yaml',
      raygunApiUri: 'https://app.raygun.io',
      useGit: true
    });

    if(!options.raygunApiKey && !process.env.RAYGUN_APIKEY){
      grunt.fatal('Required option raygunApiKey is missing');
      return;
    }
    if(!options.raygunAuthToken && !process.env.RAYGUN_AUTHTOKEN){
      grunt.fatal('Required option raygunAuthToken is missing');
      return;
    }

    var apiKey = options.raygunApiKey || process.env.RAYGUN_APIKEY;
    var authToken = options.raygunAuthToken || process.env.RAYGUN_AUTHTOKEN;

    generate = function(release, gitHash) {
      var deployment = {
        apiKey: apiKey,
        version: release.version,
        ownerName: release.ownerName,
        emailAddress: release.emailAddress,
        comment: release.notes,
        scmIdentifier: gitHash
      };
      send(deployment);
    };

    send = function(data) {
      request.post({
        uri: options.raygunApiUri + '/deployments',
        qs: { authToken: authToken },
        json: true,
        body: data
      }, end);
    };

    end = function(error, res, body) {
      if(error) {
        grunt.fatal(error);
      } else if (res.statusCode === 200) {
        grunt.log.writeln('Sent deployment info to Raygun.io');
        finishedTask();
      } else if(res.statusCode === 403) {
        grunt.fatal('Could not send deployment info to Raygun: your raygunApiKey is either wrong or you don\'t have access to that application');
      } else if(res.statusCode === 401) {
        grunt.fatal('Could not send deployment info to Raygun: your raygunAuthToken is wrong');
      } else {
        grunt.fatal('Could not send deployment info to Raygun: got a ' + res.statusCode + ' response code');
      }
    };

    var release = null;

    if(typeof options.release=="string"){
      grunt.file.readYAML(options.release);
    } else if(typeof options.release=="object"){
      release = options.release;
    }

    if(options.useGit) {
      grunt.util.spawn({
        cmd: 'git',
        args: ['rev-parse', '--verify', 'HEAD'],
        grunt: false,
        fallback: ''
      }, function(error, result) {
        var gitHash = String(result);
        generate(release, gitHash);
      });
    } else {
      generate(release, '');
    }
  });

};
<|endoftext|>


<commit_before>/*
 * validate-licenses
 * https://github.com/danielheth/validate-licenses
 *
 * Copyright (c) 2016 Daniel Moran
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {
  var cp = require('child_process'),
    f = require('util').format,
    _ = grunt.util._,
    log = grunt.log,
    path = require('path'),
    verbose = grunt.verbose;

  // Please see the Grunt documentation for more information regarding task
  // creation: http://gruntjs.com/creating-tasks

  grunt.registerMultiTask('validate_licenses', 'Validate licenses of npm modules and fail builds if unapproved licenses exist.', function() {
    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options({
      blacklist: [],
      whitelist: {}
    });

    var cmdPath = null;
    var binPath = path.resolve(__dirname + '../../.bin');
    if (!grunt.file.exist(binPath, '/.license-checker.cmd')) {
      binPath = path.resolve(__dirname + '../node_modules/.bin');
      if (!grunt.file.exist(binPath, '/.license-checker.cmd')) {
        log.error('Unable to find license-checker.cmd');
        return done(false);
      }
    }

    var localPath = path.resolve(__dirname + '../node_modules/.bin/');

    //1. generate licenses report based on project
    var data = {},
        outputReport = (this.target === 'out' && this.data !== undefined) ? this.data : '.licenses.json',
        execOptions = {},
        stdout = true,
        stderr = true,
        callback = function() {},
        exitCodes = [0],
        command = '"' + binPath + '/license-checker.cmd"' +
                  ' --production' +  //only show production dependencies.
                  ' --json ' +  //output in json format.
                  ' --out ' + outputReport,
        childProcess,
        args = [].slice.call(arguments, 0),
        done = this.async();

    data.cwd = execOptions.cwd;
    data.maxBuffer = execOptions.maxBuffer;

    if (_.isFunction(command)) {
      command = command.apply(grunt, args);
    }

    childProcess = cp.exec(command, execOptions, callback.bind(grunt));

    if (stdout) {
      childProcess.stdout.on('data', function (d) { log.write(d); });
    }
    if (stderr) {
      childProcess.stderr.on('data', function (d) { log.error(d); });
    }

    // Catches failing to execute the command at all (eg spawn ENOENT),
    // since in that case an 'exit' event will not be emitted.
    childProcess.on('error', function (err) {
      log.error(f('Failed to generate licenses report: %s', err));
      done(false);
    });

    childProcess.on('exit', function(code) {
      if (exitCodes.indexOf(code) < 0) {
        log.error(f('Exited with code: %d.', code));
        return done(false);
      }

      //2. process the report
      if (!grunt.file.exists(outputReport)) {
        grunt.fail.fatal('Missing licenses report file.');
      }
      var licenses = grunt.file.readJSON(outputReport);

      var hasFailures = false;
      for(var nodeModule in licenses) {
        var license = String(licenses[nodeModule].licenses);
        for (var i = 0; i < options.blacklist.length; i++) {
          if (license.match(options.blacklist[i])) {
            if (!options.whitelist.hasOwnProperty(nodeModule)) {
              hasFailures = true;
              log.error(nodeModule + ': ' + license);
            }
          }
        }
      }
      if (hasFailures) {
        grunt.fail.fatal('One or more licenses have failed our validation checks.');
      } else {
        log.ok('All licenses have passed our validation checks.');
      }
      done();
    });

  });
};
<commit_msg>adjusting pathing to bin<commit_after>/*
 * validate-licenses
 * https://github.com/danielheth/validate-licenses
 *
 * Copyright (c) 2016 Daniel Moran
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {
  var cp = require('child_process'),
    f = require('util').format,
    _ = grunt.util._,
    log = grunt.log,
    path = require('path'),
    verbose = grunt.verbose;

  // Please see the Grunt documentation for more information regarding task
  // creation: http://gruntjs.com/creating-tasks

  grunt.registerMultiTask('validate_licenses', 'Validate licenses of npm modules and fail builds if unapproved licenses exist.', function() {
    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options({
      blacklist: [],
      whitelist: {}
    });

    var cmdPath = null;
    var binPath = path.resolve(__dirname + '../../.bin');
    if (!grunt.file.exists(binPath, '/.license-checker.cmd')) {
      binPath = path.resolve(__dirname + '../node_modules/.bin');
      if (!grunt.file.exists(binPath, '/.license-checker.cmd')) {
        log.error('Unable to find license-checker.cmd');
        return done(false);
      }
    }

    var localPath = path.resolve(__dirname + '../node_modules/.bin/');

    //1. generate licenses report based on project
    var data = {},
        outputReport = (this.target === 'out' && this.data !== undefined) ? this.data : '.licenses.json',
        execOptions = {},
        stdout = true,
        stderr = true,
        callback = function() {},
        exitCodes = [0],
        command = '"' + binPath + '/license-checker.cmd"' +
                  ' --production' +  //only show production dependencies.
                  ' --json ' +  //output in json format.
                  ' --out ' + outputReport,
        childProcess,
        args = [].slice.call(arguments, 0),
        done = this.async();

    data.cwd = execOptions.cwd;
    data.maxBuffer = execOptions.maxBuffer;

    if (_.isFunction(command)) {
      command = command.apply(grunt, args);
    }

    childProcess = cp.exec(command, execOptions, callback.bind(grunt));

    if (stdout) {
      childProcess.stdout.on('data', function (d) { log.write(d); });
    }
    if (stderr) {
      childProcess.stderr.on('data', function (d) { log.error(d); });
    }

    // Catches failing to execute the command at all (eg spawn ENOENT),
    // since in that case an 'exit' event will not be emitted.
    childProcess.on('error', function (err) {
      log.error(f('Failed to generate licenses report: %s', err));
      done(false);
    });

    childProcess.on('exit', function(code) {
      if (exitCodes.indexOf(code) < 0) {
        log.error(f('Exited with code: %d.', code));
        return done(false);
      }

      //2. process the report
      if (!grunt.file.exists(outputReport)) {
        grunt.fail.fatal('Missing licenses report file.');
      }
      var licenses = grunt.file.readJSON(outputReport);

      var hasFailures = false;
      for(var nodeModule in licenses) {
        var license = String(licenses[nodeModule].licenses);
        for (var i = 0; i < options.blacklist.length; i++) {
          if (license.match(options.blacklist[i])) {
            if (!options.whitelist.hasOwnProperty(nodeModule)) {
              hasFailures = true;
              log.error(nodeModule + ': ' + license);
            }
          }
        }
      }
      if (hasFailures) {
        grunt.fail.fatal('One or more licenses have failed our validation checks.');
      } else {
        log.ok('All licenses have passed our validation checks.');
      }
      done();
    });

  });
};
<|endoftext|>


<commit_before>define(function() {
	"use strict";

	var StringUtil = {};

	StringUtil.endsWith = function(str, suffix) {
		return str.indexOf(suffix, str.length - suffix.length) !== -1;
	};

	StringUtil.startsWith = function(str, prefix) {
		return str.indexOf(prefix) === 0;
	};

	StringUtil.capitalize = function(str) {
		return str.charAt(0).toUpperCase() + str.substring(1);
	};

	StringUtil.uncapitalize = function(str) {
		return str.charAt(0).toLowerCase() + str.substring(1);
	};

	StringUtil.getIndexedName = function(base, takenNames, separator){
		if (!separator) {
			separator = '_';
		}

		var re = new RegExp(base+'(' + separator + '\\d+)?');
		var i;
		var index = 0;
		for (i in takenNames) {
			var name = takenNames[i];
			var m = re.exec(name);
			if (m) {
				if (m.length>1 && m[1]){
					var nidx = parseInt(m[1].substring(separator.length), 10);
					if (nidx>=index) {
						index = nidx+1;
					}
				}
				else {
					index = 1;
				}
			}
		}

		return base + separator + index;
	};

	StringUtil.getUniqueName = function(desiredName, takenNames, separator) {
		if (takenNames.indexOf(desiredName)===-1) {
			return desiredName;
		}

		return StringUtil.getIndexedName(desiredName, takenNames, separator);
	};

	StringUtil.toAscii = function (input) {
		return input.replace(/([^\x00-\x7F]|\s)*/g, '');
	};

	/*jshint bitwise: false */
	/**
	Js implementation of Java's hashcode (sort of). Somewhat useful for creating
	unique ideas that contain [A-Za-z0-9-_]
	*/
	StringUtil.hashCode = function(str){
		var hash = 0;
		if (str.length === 0) {
			return hash;
		}
		for (var i = 0; i < str.length; i++) {
			var character = str.charCodeAt(i);
			hash = ((hash<<5)-hash)+character;
			hash = hash & hash; // Convert to 32bit integer
		}
		return btoa(hash).replace('/', '_').replace('+', '-');
	};

	return StringUtil;
});
<commit_msg>Bugfix in stringutil<commit_after>define(function() {
	"use strict";

	var StringUtil = {};

	StringUtil.endsWith = function(str, suffix) {
		return str.indexOf(suffix, str.length - suffix.length) !== -1;
	};

	StringUtil.startsWith = function(str, prefix) {
		return str.indexOf(prefix) === 0;
	};

	StringUtil.capitalize = function(str) {
		return str.charAt(0).toUpperCase() + str.substring(1);
	};

	StringUtil.uncapitalize = function(str) {
		return str.charAt(0).toLowerCase() + str.substring(1);
	};

	StringUtil.getIndexedName = function(base, takenNames, separator){
		if (!separator) {
			separator = '_';
		}

		var re = new RegExp(base+'(' + separator + '\\d+)?');
		var i;
		var index = 0;
		for (i in takenNames) {
			var name = takenNames[i];
			var m = re.exec(name);
			if (m) {
				if (m.length>1 && m[1]){
					var nidx = parseInt(m[1].substring(separator.length), 10);
					if (nidx>=index) {
						index = nidx+1;
					}
				}
				else {
					index = 1;
				}
			}
		}

		return base + separator + index;
	};

	StringUtil.getUniqueName = function(desiredName, takenNames, separator) {
		if (takenNames.indexOf(desiredName)===-1) {
			return desiredName;
		}

		return StringUtil.getIndexedName(desiredName, takenNames, separator);
	};

	StringUtil.toAscii = function (input) {
		return input.replace(/([^\x00-\x7F])*/g, '');
	};

	/*jshint bitwise: false */
	/**
	Js implementation of Java's hashcode (sort of). Somewhat useful for creating
	unique ideas that contain [A-Za-z0-9-_]
	*/
	StringUtil.hashCode = function(str){
		var hash = 0;
		if (str.length === 0) {
			return hash;
		}
		for (var i = 0; i < str.length; i++) {
			var character = str.charCodeAt(i);
			hash = ((hash<<5)-hash)+character;
			hash = hash & hash; // Convert to 32bit integer
		}
		return btoa(hash).replace('/', '_').replace('+', '-');
	};

	return StringUtil;
});
<|endoftext|>


<commit_before>// Attraction Constructor
function Attraction(id, name, url, attraction_type, destination){
  this.id = id;
  this.name = name;
  this.url = url;
  this.attraction_type = attraction_type;
  this.destination = destination;
}

Attraction.prototype.formatUrl = function(){
  var origUrl = this.url;
  if (origUrl.includes("http") == true){
    return origUrl;
  }
  else if (origUrl.includes("www.") == true){
    return "http://" + origUrl;
  }
  else {
    return "http://www." + origUrl;
  }
}<commit_msg>add use strict to attraction.js since it seems to be giving off errors in Heroku deployment<commit_after>// Attraction Constructor
'use strict'
function Attraction(id, name, url, attraction_type, destination){
  this.id = id;
  this.name = name;
  this.url = url;
  this.attraction_type = attraction_type;
  this.destination = destination;
}

Attraction.prototype.formatUrl = function() {
  var origUrl = this.url;
  if (origUrl.includes("http") == true){
    return origUrl;
  }
  else if (origUrl.includes("www.") == true){
    return "http://" + origUrl;
  }
  else {
    return "http://www." + origUrl;
  }
}<|endoftext|>


<commit_before>var map, mapbox, cartodb, markers = [];

function locationSuccess(position) {
  // do something with position.coords.latitude and position.coords.longitude
  // for example, re-center the embedded map on the user's position
}

function locationError(msg) {
  // if the user can't be found . . .
}

function initialize() {
  map = new L.Map('map-canvas').setView(new L.LatLng(40.675573,-73.96212), 11);
  var mapboxUrl = 'http://{s}.tiles.mapbox.com/v3/csabuilder.map-m2jqpyy8/{z}/{x}/{y}.png',
      mapbox = new L.TileLayer(mapboxUrl, {maxZoom: 17});
  map.addLayer(mapbox,true);

  cartodb = new L.CartoDBLayer({
    map_canvas: 'map_canvas',
    map: map,
    user_name:'csabuilder',
    table_name: 'user_locations',
    query: "SELECT cartodb_id,user_id,ST_Transform(ST_Buffer(the_geom_webmercator,300),3857) as the_geom_webmercator FROM user_locations",
    tile_style:"#user_locations {polygon-fill:#FF1A00;polygon-opacity: 0.4;line-opacity:0;line-color: #FFFFFF;}",
    infowindow: false,
    auto_bound: false,
    debug: true
  });

  $(".marker-container").click(function() {
  	addMarker($(this).attr("data-key"));

  });

  if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(locationSuccess, locationError);
  }

}

function addMarker(type) {

	var Icon = L.Icon.extend({
	    iconUrl: '/assets/' + type + '-basic.png',
	    iconSize: new L.Point(32, 37),
	    iconAnchor: new L.Point(22, 94),
	    popupAnchor: new L.Point(-3, -76)
	});

	var markerIcon = new Icon();

	var marker = new L.Marker(map.getCenter(), { icon: markerIcon, draggable: true });
	map.addLayer(marker);
	markers.push(marker);

}<commit_msg>Center map if we get user's geolocation<commit_after>var map, mapbox, cartodb, markers = [];

function locationSuccess(position) {

	map.setView(new L.LatLng(position.coords.latitude, position.coords.longitude), 12);
  // do something with position.coords.latitude and position.coords.longitude
  // for example, re-center the embedded map on the user's position
}

function locationError(msg) {
  // if the user can't be found . . .
}

function initialize() {
  map = new L.Map('map-canvas').setView(new L.LatLng(40.675573,-73.96212), 12);
  var mapboxUrl = 'http://{s}.tiles.mapbox.com/v3/csabuilder.map-m2jqpyy8/{z}/{x}/{y}.png',
      mapbox = new L.TileLayer(mapboxUrl, {maxZoom: 17});
  map.addLayer(mapbox,true);

  cartodb = new L.CartoDBLayer({
    map_canvas: 'map_canvas',
    map: map,
    user_name:'csabuilder',
    table_name: 'user_locations',
    query: "SELECT cartodb_id,user_id,ST_Transform(ST_Buffer(the_geom_webmercator,300),3857) as the_geom_webmercator FROM user_locations",
    tile_style:"#user_locations {polygon-fill:#FF1A00;polygon-opacity: 0.4;line-opacity:0;line-color: #FFFFFF;}",
    infowindow: false,
    auto_bound: false,
    debug: true
  });

  $(".marker-container").click(function() {
  	addMarker($(this).attr("data-key"));

  });

  if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(locationSuccess, locationError);
  }

}

function addMarker(type) {

	var Icon = L.Icon.extend({
	    iconUrl: '/assets/' + type + '-basic.png',
	    iconSize: new L.Point(32, 37),
	    iconAnchor: new L.Point(22, 94),
	    popupAnchor: new L.Point(-3, -76)
	});

	var markerIcon = new Icon();

	var marker = new L.Marker(map.getCenter(), { icon: markerIcon, draggable: true });
	map.addLayer(marker);
	markers.push(marker);

}<|endoftext|>


<commit_before>$(function() {
  $('[data-scroll]').click(function() {
    var $target = $($(this).attr('data-target'));

    $('html, body').animate({ scrollTop: $target.offset().top }, 500);

    setTimeout(function() { $target.focus(); }, 500);

    return false;
  });
});
<commit_msg>Fix the scroll button now that we inject that after page load<commit_after>$(function() {
  $('body').delegate('[data-scroll]', 'click', function() {
    var $target = $($(this).attr('data-target'));

    $('html, body').animate({ scrollTop: $target.offset().top }, 500);
    setTimeout(function() { $target.focus(); }, 500);

    return false;
  });
});
<|endoftext|>