<commit_before>/**
 * Wappalyzer v5
 *
 * Created by Elbert Alias <elbert@alias.io>
 *
 * License: GPLv3 http://www.gnu.org/licenses/gpl-3.0.txt
 */

'use strict';

const validation = {
  hostname: /(www.)?((.+?)\.(([a-z]{2,3}\.)?[a-z]{2,6}))$/,
  hostnameBlacklist: /((local|dev(elopment)?|stag(e|ing)?|test(ing)?|demo(shop)?|admin|google|cache)\.|\/admin|\.local)/
};

class Wappalyzer {
  constructor() {
    this.apps = {};
    this.categories = {};
    this.driver = {};
    this.jsPatterns = {};

    this.detected = {};
    this.hostnameCache = {};
    this.adCache = [];

    this.config = {
      websiteURL: 'https://www.wappalyzer.com/',
      twitterURL: 'https://twitter.com/Wappalyzer',
      githubURL: 'https://github.com/AliasIO/Wappalyzer',
    };
  }

  /**
   * Log messages to console
   */
  log(message, source, type) {
    this.driver.log(message, source || '', type || 'debug');
  }

  analyze(url, data, context) {
    var apps = {};

    if ( typeof data.html !== 'string' ) {
      data.html = '';
    }

    if ( this.detected[url.canonical] === undefined ) {
      this.detected[url.canonical] = {};
    }

    // Additional information
    const matches = data.html.match(/<html[^>]*[: ]lang="([a-z]{2}((-|_)[A-Z]{2})?)"/i);

    const language = matches && matches.length ? matches[1] : null;

    Object.keys(this.apps).forEach(appName => {
      apps[appName] = this.detected[url.canonical] && this.detected[url.canonical][appName] ? this.detected[url.canonical][appName] : new Application(appName, this.apps[appName]);

      var app = apps[appName];

      this.analyzeUrl(app, url);

      if ( data.html ) {
        this.analyzeHtml(app, data.html);
        this.analyzeMeta(app, data.html);
      }

      if ( data.scripts ) {
        this.analyzeScripts(app, data.scripts);
      }

      if ( data.headers ) {
        this.analyzeHeaders(app, data.headers);
      }

      if ( data.env ) {
        this.analyzeEnv(app, data.env);
      }

      if ( data.robotsTxt ) {
        this.analyzeRobotsTxt(app, data.robotsTxt);
      }
    })

    if ( data.js ) {
      Object.keys(data.js).forEach(appName => {
        this.analyzeJs(apps[appName], data.js[appName]);
      });
    }

    Object.keys(apps).forEach(appName => {
      var app = apps[appName];

      if ( !app.detected || !app.getConfidence() ) {
        delete apps[app.name];
      }
    });

    this.resolveExcludes(apps);
    this.resolveImplies(apps, url.canonical);

    this.cacheDetectedApps(apps, url.canonical);
    this.trackDetectedApps(apps, url, language);

    if ( Object.keys(apps).length ) {
      this.log(Object.keys(apps).length + ' apps detected: ' + Object.keys(apps).join(', ') + ' on ' + url.canonical, 'core');
    }

    this.driver.displayApps(this.detected[url.canonical], { language }, context);
  }

  /**
   * Cache detected ads
   */
  cacheDetectedAds(ad) {
    this.adCache.push(ad);
  }

  /**
   *
   */
  robotsTxtAllows(url) {
    return new Promise((resolve, reject) => {
      var parsed = this.parseUrl(url);

      if ( parsed.protocol !== 'http:' && parsed.protocol !== 'https:' ) {
        return reject();
      }

      this.driver.getRobotsTxt(parsed.host, parsed.protocol === 'https:')
        .then(robotsTxt => {
          if (robotsTxt.some(disallowedPath => parsed.pathname.indexOf(disallowedPath) === 0)) {
            return reject();
          } else {
            return resolve();
          }
        });
    });
  };

  /**
   * Parse a URL
   */
  parseUrl(url) {
    var a = this.driver.document.createElement('a');

    a.href = url;

    a.canonical = a.protocol + '//' + a.host + a.pathname;

    return a;
  }

  /**
   *
   */
  parseRobotsTxt(robotsTxt) {
    var userAgent;
    var disallow = [];

    robotsTxt.split('\n').forEach(line => {
      var matches = /^User-agent:\s*(.+)$/i.exec(line);

      if ( matches ) {
        userAgent = matches[1].toLowerCase();
      } else {
        if ( userAgent === '*' || userAgent === 'wappalyzer' ) {
          matches = /^Disallow:\s*(.+)$/i.exec(line);

          if ( matches ) {
            disallow.push(matches[1]);
          }
        }
      }
    });

    return disallow;
  }

  /**
   *
   */
  ping() {
    if ( Object.keys(this.hostnameCache).length + this.adCache.length > 50 ) {
      this.driver.ping(this.hostnameCache, this.adCache);

      this.hostnameCache = {};
      this.adCache = [];
    }
  }

  /**
   * Enclose string in array
   */
  asArray(value) {
    return value instanceof Array ? value : [ value ];
  }

  /**
   * Parse apps.json patterns
   */
  parsePatterns(patterns) {
    if ( !patterns ) {
      return [];
    }

    var parsed = {};

    // Convert string to object containing array containing string
    if ( typeof patterns === 'string' || patterns instanceof Array ) {
      patterns = {
        main: this.asArray(patterns)
      };
    }

    Object.keys(patterns).forEach(key => {
      parsed[key] = [];

      this.asArray(patterns[key]).forEach(pattern => {
        var attrs = {};

        pattern.split('\\;').forEach((attr, i) => {
          if ( i ) {
            // Key value pairs
            attr = attr.split(':');

            if ( attr.length > 1 ) {
              attrs[attr.shift()] = attr.join(':');
            }
          } else {
            attrs.string = attr;

            try {
              attrs.regex = new RegExp(attr.replace('/', '\/'), 'i'); // Escape slashes in regular expression
            } catch (e) {
              attrs.regex = new RegExp();

              this.log(e + ': ' + attr, 'error', 'core');
            }
          }
        });

        parsed[key].push(attrs);
      });
    });

    // Convert back to array if the original pattern list was an array (or string)
    if ( 'main' in parsed ) {
      parsed = parsed.main;
    }

    return parsed;
  }

  /**
   * Parse JavaScript patterns
   */
  parseJsPatterns() {
    Object.keys(this.apps).forEach(appName => {
      if ( this.apps[appName].js ) {
        this.jsPatterns[appName] = this.parsePatterns(this.apps[appName].js);
      }
    });
  }

  resolveExcludes(apps) {
    var excludes = [];

    // Exclude app in detected apps only
    Object.keys(apps).forEach(appName => {
      var app = apps[appName];

      if ( app.props.excludes ) {
        this.asArray(app.props.excludes).forEach(excluded => {
          excludes.push(excluded);
        });
      }
    })

    // Remove excluded applications
    Object.keys(apps).forEach(appName => {
      if ( excludes.indexOf(appName) !== -1 ) {
        delete apps[appName];
      }
    })
  }

  resolveImplies(apps, url) {
    var checkImplies = true;

    // Implied applications
    // Run several passes as implied apps may imply other apps
    while ( checkImplies ) {
      checkImplies = false;

      Object.keys(apps).forEach(appName => {
        var app = apps[appName];

        if ( app && app.props.implies ) {
          this.asArray(app.props.implies).forEach(implied => {
            implied = this.parsePatterns(implied)[0];

            if ( !this.apps[implied.string] ) {
              this.log('Implied application ' + implied.string + ' does not exist', 'core', 'warn');

              return;
            }

            if ( !( implied.string in apps ) ) {
              apps[implied.string] = this.detected[url] && this.detected[url][implied.string] ? this.detected[url][implied.string] : new Application(implied.string, this.apps[implied.string], true);

              checkImplies = true;
            }

            // Apply app confidence to implied app
            Object.keys(app.confidence).forEach(id => {
              apps[implied.string].confidence[id + ' implied by ' + appName] = app.confidence[id] * ( implied.confidence ? implied.confidence / 100 : 1 );
            });
          });
        }
      });
    }
  }

  /**
   * Cache detected applications
   */
  cacheDetectedApps(apps, url) {
    Object.keys(apps).forEach(appName => {
      var app = apps[appName];

      // Per URL
      this.detected[url][appName] = app;

      Object.keys(app.confidence).forEach(id => {
        this.detected[url][appName].confidence[id] = app.confidence[id];
      });
    })

    if ( this.driver.ping instanceof Function ) {
      this.ping();
    }
  }

  /**
   * Track detected applications
   */
  trackDetectedApps(apps, url, language) {
    if ( !( this.driver.ping instanceof Function ) ) {
      return;
    }

    const hostname = url.protocol + '//' + url.hostname;

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

      if ( this.detected[url.canonical][appName].getConfidence() >= 100 ) {
        if ( validation.hostname.test(url.hostname) && !validation.hostnameBlacklist.test(url.hostname) ) {
          if ( !( hostname in this.hostnameCache ) ) {
            this.hostnameCache[hostname] = {
              applications: {},
              meta: {}
            };
          }

          if ( !( appName in this.hostnameCache[hostname].applications ) ) {
            this.hostnameCache[hostname].applications[appName] = {
              hits: 0
            };
          }

          this.hostnameCache[hostname].applications[appName].hits ++;

          if ( apps[appName].version ) {
            this.hostnameCache[hostname].applications[appName].version = app.version;
          }
        }
      }
    });

    if ( hostname in this.hostnameCache ) {
      this.hostnameCache[hostname].meta['language'] = language;
    }

    this.ping();
  }

  /**
   * Analyze URL
   */
  analyzeUrl(app, url) {
    var patterns = this.parsePatterns(app.props.url);

    if ( patterns.length ) {
      patterns.forEach(pattern => {
        if ( pattern.regex.test(url.canonical) ) {
          this.addDetected(app, pattern, 'url', url.canonical);
        }
      });
    }
  }

  /**
   * Analyze HTML
   */
  analyzeHtml(app, html) {
    var patterns = this.parsePatterns(app.props.html);

    if ( patterns.length ) {
      patterns.forEach(pattern => {
        if ( pattern.regex.test(html) ) {
          this.addDetected(app, pattern, 'html', html);
        }
      });
    }
  }

  /**
   * Analyze script tag
   */
  analyzeScripts(app, scripts) {
    var patterns = this.parsePatterns(app.props.script);

    if ( patterns.length ) {
      patterns.forEach(pattern => {
        var match;

        scripts.forEach(uri => {
          if ( pattern.regex.test(uri) ) {
            this.addDetected(app, pattern, 'script', uri);
          }
        });
      });
    }
  }

  /**
   * Analyze meta tag
   */
  analyzeMeta(app, html) {
    var regex = /<meta[^>]+>/ig;
    var patterns = this.parsePatterns(app.props.meta);
    var content = '';
    var matches = [];

    while ( patterns && ( matches = regex.exec(html) ) ) {
      for ( var meta in patterns ) {

        const r = new RegExp('(?:name|property)=["\']' + meta + '["\']', 'i');

        if ( new RegExp('(?:name|property)=["\']' + meta + '["\']', 'i').test(matches[0]) ) {
          content = matches[0].match(/content=("|')([^"']+)("|')/i);

          patterns[meta].forEach(pattern => {
            if ( content && content.length === 4 && pattern.regex.test(content[2]) ) {
              this.addDetected(app, pattern, 'meta', content[2], meta);
            }
          });
        }
      }
    }
  }

  /**
   * analyze response headers
   */
  analyzeHeaders(app, headers) {
    var patterns = this.parsePatterns(app.props.headers);

    if ( headers ) {
      Object.keys(patterns).forEach(headerName => {
        patterns[headerName].forEach(pattern => {
          headerName = headerName.toLowerCase();

          if ( headerName in headers ) {
            headers[headerName].forEach(headerValue => {
              if ( pattern.regex.test(headerValue) ) {
                this.addDetected(app, pattern, 'headers', headerValue, headerName);
              }
            });
          }
        });
      });
    }
  }

  /**
   * Analyze environment variables
   */
  analyzeEnv(app, envs) {
    var patterns = this.parsePatterns(app.props.env);

    if ( patterns.length ) {
      patterns.forEach(pattern => {
        Object.keys(envs).forEach(env => {
          if ( pattern.regex.test(envs[env]) ) {
            this.addDetected(app, pattern, 'env', envs[env]);
          }
        })
      });
    }
  }

  /**
   * Analyze JavaScript variables
   */
  analyzeJs(app, results) {
    Object.keys(results).forEach(string => {
      Object.keys(results[string]).forEach(index => {
        const pattern = this.jsPatterns[app.name][string][index];
        const value = results[string][index];

        if ( pattern.regex.test(value) ) {
          this.addDetected(app, pattern, 'js', value);
        }
      });
    });
  }

  /**
   * Analyze robots.txt
   */
  analyzeRobotsTxt(app, robotsTxt) {
    var patterns = this.parsePatterns(app.props.robotsTxt);

    if ( patterns.length ) {
      patterns.forEach(pattern => {
        if ( pattern.regex.test(robotsTxt) ) {
          this.addDetected(app, pattern, 'robotsTxt', robotsTxt);
        }
      });
    }
  }

  /**
   * Mark application as detected, set confidence and version
   */
  addDetected(app, pattern, type, value, key) {
    app.detected = true;

    // Set confidence level
    app.confidence[type + ' ' + ( key ? key + ' ' : '' ) + pattern.regex] = pattern.confidence || 100;

    // Detect version number
    if ( pattern.version ) {
      var versions = [];
      var version  = pattern.version;
      var matches  = pattern.regex.exec(value);

      if ( matches ) {
        matches.forEach((match, i) => {
          // Parse ternary operator
          var ternary = new RegExp('\\\\' + i + '\\?([^:]+):(.*)$').exec(version);

          if ( ternary && ternary.length === 3 ) {
            version = version.replace(ternary[0], match ? ternary[1] : ternary[2]);
          }

          // Replace back references
          version = version.replace(new RegExp('\\\\' + i, 'g'), match || '');
        });

        if ( version && versions.indexOf(version) === -1 ) {
          versions.push(version);
        }

        if ( versions.length ) {
          // Use the longest detected version number
          app.version = versions.reduce((a, b) => a.length > b.length ? a : b);
        }
      }
    }
  }
}

/**
 * Application class
 */
class Application {
  constructor(name, props, detected) {
    this.confidence      = {};
    this.confidenceTotal = 0;
    this.detected        = Boolean(detected);
    this.excludes        = [];
    this.name            = name;
    this.props           = props;
    this.version         = '';
  }

  /**
   * Calculate confidence total
   */
  getConfidence() {
    var total = 0;

    for ( var id in this.confidence ) {
      total += this.confidence[id];
    }

    return this.confidenceTotal = Math.min(total, 100);
  }
}

if ( typeof module === 'object' ) {
  module.exports = Wappalyzer;
}
<commit_msg>fix analyzeMeta duplicate line (#2096)<commit_after>/**
 * Wappalyzer v5
 *
 * Created by Elbert Alias <elbert@alias.io>
 *
 * License: GPLv3 http://www.gnu.org/licenses/gpl-3.0.txt
 */

'use strict';

const validation = {
  hostname: /(www.)?((.+?)\.(([a-z]{2,3}\.)?[a-z]{2,6}))$/,
  hostnameBlacklist: /((local|dev(elopment)?|stag(e|ing)?|test(ing)?|demo(shop)?|admin|google|cache)\.|\/admin|\.local)/
};

class Wappalyzer {
  constructor() {
    this.apps = {};
    this.categories = {};
    this.driver = {};
    this.jsPatterns = {};

    this.detected = {};
    this.hostnameCache = {};
    this.adCache = [];

    this.config = {
      websiteURL: 'https://www.wappalyzer.com/',
      twitterURL: 'https://twitter.com/Wappalyzer',
      githubURL: 'https://github.com/AliasIO/Wappalyzer',
    };
  }

  /**
   * Log messages to console
   */
  log(message, source, type) {
    this.driver.log(message, source || '', type || 'debug');
  }

  analyze(url, data, context) {
    var apps = {};

    if ( typeof data.html !== 'string' ) {
      data.html = '';
    }

    if ( this.detected[url.canonical] === undefined ) {
      this.detected[url.canonical] = {};
    }

    // Additional information
    const matches = data.html.match(/<html[^>]*[: ]lang="([a-z]{2}((-|_)[A-Z]{2})?)"/i);

    const language = matches && matches.length ? matches[1] : null;

    Object.keys(this.apps).forEach(appName => {
      apps[appName] = this.detected[url.canonical] && this.detected[url.canonical][appName] ? this.detected[url.canonical][appName] : new Application(appName, this.apps[appName]);

      var app = apps[appName];

      this.analyzeUrl(app, url);

      if ( data.html ) {
        this.analyzeHtml(app, data.html);
        this.analyzeMeta(app, data.html);
      }

      if ( data.scripts ) {
        this.analyzeScripts(app, data.scripts);
      }

      if ( data.headers ) {
        this.analyzeHeaders(app, data.headers);
      }

      if ( data.env ) {
        this.analyzeEnv(app, data.env);
      }

      if ( data.robotsTxt ) {
        this.analyzeRobotsTxt(app, data.robotsTxt);
      }
    })

    if ( data.js ) {
      Object.keys(data.js).forEach(appName => {
        this.analyzeJs(apps[appName], data.js[appName]);
      });
    }

    Object.keys(apps).forEach(appName => {
      var app = apps[appName];

      if ( !app.detected || !app.getConfidence() ) {
        delete apps[app.name];
      }
    });

    this.resolveExcludes(apps);
    this.resolveImplies(apps, url.canonical);

    this.cacheDetectedApps(apps, url.canonical);
    this.trackDetectedApps(apps, url, language);

    if ( Object.keys(apps).length ) {
      this.log(Object.keys(apps).length + ' apps detected: ' + Object.keys(apps).join(', ') + ' on ' + url.canonical, 'core');
    }

    this.driver.displayApps(this.detected[url.canonical], { language }, context);
  }

  /**
   * Cache detected ads
   */
  cacheDetectedAds(ad) {
    this.adCache.push(ad);
  }

  /**
   *
   */
  robotsTxtAllows(url) {
    return new Promise((resolve, reject) => {
      var parsed = this.parseUrl(url);

      if ( parsed.protocol !== 'http:' && parsed.protocol !== 'https:' ) {
        return reject();
      }

      this.driver.getRobotsTxt(parsed.host, parsed.protocol === 'https:')
        .then(robotsTxt => {
          if (robotsTxt.some(disallowedPath => parsed.pathname.indexOf(disallowedPath) === 0)) {
            return reject();
          } else {
            return resolve();
          }
        });
    });
  };

  /**
   * Parse a URL
   */
  parseUrl(url) {
    var a = this.driver.document.createElement('a');

    a.href = url;

    a.canonical = a.protocol + '//' + a.host + a.pathname;

    return a;
  }

  /**
   *
   */
  parseRobotsTxt(robotsTxt) {
    var userAgent;
    var disallow = [];

    robotsTxt.split('\n').forEach(line => {
      var matches = /^User-agent:\s*(.+)$/i.exec(line);

      if ( matches ) {
        userAgent = matches[1].toLowerCase();
      } else {
        if ( userAgent === '*' || userAgent === 'wappalyzer' ) {
          matches = /^Disallow:\s*(.+)$/i.exec(line);

          if ( matches ) {
            disallow.push(matches[1]);
          }
        }
      }
    });

    return disallow;
  }

  /**
   *
   */
  ping() {
    if ( Object.keys(this.hostnameCache).length + this.adCache.length > 50 ) {
      this.driver.ping(this.hostnameCache, this.adCache);

      this.hostnameCache = {};
      this.adCache = [];
    }
  }

  /**
   * Enclose string in array
   */
  asArray(value) {
    return value instanceof Array ? value : [ value ];
  }

  /**
   * Parse apps.json patterns
   */
  parsePatterns(patterns) {
    if ( !patterns ) {
      return [];
    }

    var parsed = {};

    // Convert string to object containing array containing string
    if ( typeof patterns === 'string' || patterns instanceof Array ) {
      patterns = {
        main: this.asArray(patterns)
      };
    }

    Object.keys(patterns).forEach(key => {
      parsed[key] = [];

      this.asArray(patterns[key]).forEach(pattern => {
        var attrs = {};

        pattern.split('\\;').forEach((attr, i) => {
          if ( i ) {
            // Key value pairs
            attr = attr.split(':');

            if ( attr.length > 1 ) {
              attrs[attr.shift()] = attr.join(':');
            }
          } else {
            attrs.string = attr;

            try {
              attrs.regex = new RegExp(attr.replace('/', '\/'), 'i'); // Escape slashes in regular expression
            } catch (e) {
              attrs.regex = new RegExp();

              this.log(e + ': ' + attr, 'error', 'core');
            }
          }
        });

        parsed[key].push(attrs);
      });
    });

    // Convert back to array if the original pattern list was an array (or string)
    if ( 'main' in parsed ) {
      parsed = parsed.main;
    }

    return parsed;
  }

  /**
   * Parse JavaScript patterns
   */
  parseJsPatterns() {
    Object.keys(this.apps).forEach(appName => {
      if ( this.apps[appName].js ) {
        this.jsPatterns[appName] = this.parsePatterns(this.apps[appName].js);
      }
    });
  }

  resolveExcludes(apps) {
    var excludes = [];

    // Exclude app in detected apps only
    Object.keys(apps).forEach(appName => {
      var app = apps[appName];

      if ( app.props.excludes ) {
        this.asArray(app.props.excludes).forEach(excluded => {
          excludes.push(excluded);
        });
      }
    })

    // Remove excluded applications
    Object.keys(apps).forEach(appName => {
      if ( excludes.indexOf(appName) !== -1 ) {
        delete apps[appName];
      }
    })
  }

  resolveImplies(apps, url) {
    var checkImplies = true;

    // Implied applications
    // Run several passes as implied apps may imply other apps
    while ( checkImplies ) {
      checkImplies = false;

      Object.keys(apps).forEach(appName => {
        var app = apps[appName];

        if ( app && app.props.implies ) {
          this.asArray(app.props.implies).forEach(implied => {
            implied = this.parsePatterns(implied)[0];

            if ( !this.apps[implied.string] ) {
              this.log('Implied application ' + implied.string + ' does not exist', 'core', 'warn');

              return;
            }

            if ( !( implied.string in apps ) ) {
              apps[implied.string] = this.detected[url] && this.detected[url][implied.string] ? this.detected[url][implied.string] : new Application(implied.string, this.apps[implied.string], true);

              checkImplies = true;
            }

            // Apply app confidence to implied app
            Object.keys(app.confidence).forEach(id => {
              apps[implied.string].confidence[id + ' implied by ' + appName] = app.confidence[id] * ( implied.confidence ? implied.confidence / 100 : 1 );
            });
          });
        }
      });
    }
  }

  /**
   * Cache detected applications
   */
  cacheDetectedApps(apps, url) {
    Object.keys(apps).forEach(appName => {
      var app = apps[appName];

      // Per URL
      this.detected[url][appName] = app;

      Object.keys(app.confidence).forEach(id => {
        this.detected[url][appName].confidence[id] = app.confidence[id];
      });
    })

    if ( this.driver.ping instanceof Function ) {
      this.ping();
    }
  }

  /**
   * Track detected applications
   */
  trackDetectedApps(apps, url, language) {
    if ( !( this.driver.ping instanceof Function ) ) {
      return;
    }

    const hostname = url.protocol + '//' + url.hostname;

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

      if ( this.detected[url.canonical][appName].getConfidence() >= 100 ) {
        if ( validation.hostname.test(url.hostname) && !validation.hostnameBlacklist.test(url.hostname) ) {
          if ( !( hostname in this.hostnameCache ) ) {
            this.hostnameCache[hostname] = {
              applications: {},
              meta: {}
            };
          }

          if ( !( appName in this.hostnameCache[hostname].applications ) ) {
            this.hostnameCache[hostname].applications[appName] = {
              hits: 0
            };
          }

          this.hostnameCache[hostname].applications[appName].hits ++;

          if ( apps[appName].version ) {
            this.hostnameCache[hostname].applications[appName].version = app.version;
          }
        }
      }
    });

    if ( hostname in this.hostnameCache ) {
      this.hostnameCache[hostname].meta['language'] = language;
    }

    this.ping();
  }

  /**
   * Analyze URL
   */
  analyzeUrl(app, url) {
    var patterns = this.parsePatterns(app.props.url);

    if ( patterns.length ) {
      patterns.forEach(pattern => {
        if ( pattern.regex.test(url.canonical) ) {
          this.addDetected(app, pattern, 'url', url.canonical);
        }
      });
    }
  }

  /**
   * Analyze HTML
   */
  analyzeHtml(app, html) {
    var patterns = this.parsePatterns(app.props.html);

    if ( patterns.length ) {
      patterns.forEach(pattern => {
        if ( pattern.regex.test(html) ) {
          this.addDetected(app, pattern, 'html', html);
        }
      });
    }
  }

  /**
   * Analyze script tag
   */
  analyzeScripts(app, scripts) {
    var patterns = this.parsePatterns(app.props.script);

    if ( patterns.length ) {
      patterns.forEach(pattern => {
        var match;

        scripts.forEach(uri => {
          if ( pattern.regex.test(uri) ) {
            this.addDetected(app, pattern, 'script', uri);
          }
        });
      });
    }
  }

  /**
   * Analyze meta tag
   */
  analyzeMeta(app, html) {
    var regex = /<meta[^>]+>/ig;
    var patterns = this.parsePatterns(app.props.meta);
    var content = '';
    var matches = [];

    while ( patterns && ( matches = regex.exec(html) ) ) {
      for ( var meta in patterns ) {

        const r = new RegExp('(?:name|property)=["\']' + meta + '["\']', 'i');

        if (r.test(matches[0]) ) {
          content = matches[0].match(/content=("|')([^"']+)("|')/i);

          patterns[meta].forEach(pattern => {
            if ( content && content.length === 4 && pattern.regex.test(content[2]) ) {
              this.addDetected(app, pattern, 'meta', content[2], meta);
            }
          });
        }
      }
    }
  }

  /**
   * analyze response headers
   */
  analyzeHeaders(app, headers) {
    var patterns = this.parsePatterns(app.props.headers);

    if ( headers ) {
      Object.keys(patterns).forEach(headerName => {
        patterns[headerName].forEach(pattern => {
          headerName = headerName.toLowerCase();

          if ( headerName in headers ) {
            headers[headerName].forEach(headerValue => {
              if ( pattern.regex.test(headerValue) ) {
                this.addDetected(app, pattern, 'headers', headerValue, headerName);
              }
            });
          }
        });
      });
    }
  }

  /**
   * Analyze environment variables
   */
  analyzeEnv(app, envs) {
    var patterns = this.parsePatterns(app.props.env);

    if ( patterns.length ) {
      patterns.forEach(pattern => {
        Object.keys(envs).forEach(env => {
          if ( pattern.regex.test(envs[env]) ) {
            this.addDetected(app, pattern, 'env', envs[env]);
          }
        })
      });
    }
  }

  /**
   * Analyze JavaScript variables
   */
  analyzeJs(app, results) {
    Object.keys(results).forEach(string => {
      Object.keys(results[string]).forEach(index => {
        const pattern = this.jsPatterns[app.name][string][index];
        const value = results[string][index];

        if ( pattern.regex.test(value) ) {
          this.addDetected(app, pattern, 'js', value);
        }
      });
    });
  }

  /**
   * Analyze robots.txt
   */
  analyzeRobotsTxt(app, robotsTxt) {
    var patterns = this.parsePatterns(app.props.robotsTxt);

    if ( patterns.length ) {
      patterns.forEach(pattern => {
        if ( pattern.regex.test(robotsTxt) ) {
          this.addDetected(app, pattern, 'robotsTxt', robotsTxt);
        }
      });
    }
  }

  /**
   * Mark application as detected, set confidence and version
   */
  addDetected(app, pattern, type, value, key) {
    app.detected = true;

    // Set confidence level
    app.confidence[type + ' ' + ( key ? key + ' ' : '' ) + pattern.regex] = pattern.confidence || 100;

    // Detect version number
    if ( pattern.version ) {
      var versions = [];
      var version  = pattern.version;
      var matches  = pattern.regex.exec(value);

      if ( matches ) {
        matches.forEach((match, i) => {
          // Parse ternary operator
          var ternary = new RegExp('\\\\' + i + '\\?([^:]+):(.*)$').exec(version);

          if ( ternary && ternary.length === 3 ) {
            version = version.replace(ternary[0], match ? ternary[1] : ternary[2]);
          }

          // Replace back references
          version = version.replace(new RegExp('\\\\' + i, 'g'), match || '');
        });

        if ( version && versions.indexOf(version) === -1 ) {
          versions.push(version);
        }

        if ( versions.length ) {
          // Use the longest detected version number
          app.version = versions.reduce((a, b) => a.length > b.length ? a : b);
        }
      }
    }
  }
}

/**
 * Application class
 */
class Application {
  constructor(name, props, detected) {
    this.confidence      = {};
    this.confidenceTotal = 0;
    this.detected        = Boolean(detected);
    this.excludes        = [];
    this.name            = name;
    this.props           = props;
    this.version         = '';
  }

  /**
   * Calculate confidence total
   */
  getConfidence() {
    var total = 0;

    for ( var id in this.confidence ) {
      total += this.confidence[id];
    }

    return this.confidenceTotal = Math.min(total, 100);
  }
}

if ( typeof module === 'object' ) {
  module.exports = Wappalyzer;
}
<|endoftext|>


<commit_before>import React from 'react'
import {withRouter} from 'react-router-dom'
import {connect} from "react-redux"
import {hot} from "react-hot-loader";
import ActionsUtils from "../actions/ActionsUtils";
import HttpService from "../http/HttpService";
import InitializeError from "./errors/InitializeError";
import api from "../api";
import * as queryString from "query-string";
import LoaderSpinner from "../components/Spinner";
import SystemUtils from "../common/SystemUtils";

const OAUTH2_BACKEND = "OAuth2"
const HTTP_UNAUTHORIZED_CODE = 401
const HTTP_APPLICATION_CODE = 500
const ACCESS_TOKEN_CODE = "accessToken"

class NussknackerInitializer extends React.Component {
  redirectToAuthorizeUrl = () => {
    window.location.replace(this.props.authenticationSettings.authorizeUrl)
  }

  errors = {
    401: {
      message: "Unauthorized Error",
      description: "It seems you are not authenticated... Why not try to authenticate again?",
      buttonLabel: "Try authenticate again"
    },
     504: {
       message: "504 Gateway Timeout Error",
       description: "It seems server has some problems... Why not to try refreshing your page? Or you can contact with system administrators."
     },
    500: {
      message: "Application Unexpected Error",
      showButton: false
    },
    "accessToken": {
      message: "Authentication Error",
      buttonOnClick: this.redirectToAuthorizeUrl,
      buttonLabel: "Go to authentication page",
      description: "It seems application has some problem with authentication. Please contact with system administrators."
    }
  }

  constructor(props) {
    super(props)

    this.state = {
      error: null,
      initialized: false
    }
  }

  componentDidMount() {
    //It looks like callback hell.. Can we do it better?
    HttpService.fetchSettings().then(settingsResponse => {
      this.props.actions.assignSettings(settingsResponse.data)
      this.authenticationStrategy(settingsResponse.data.authentication).then(response => {
        HttpService.fetchLoggedUser().then(userResponse => {
          this.props.actions.assignUser(userResponse.data)
          this.setState({initialized: true})
        }).catch(this.httpErrorHandler)
      })
    }).catch(this.httpErrorHandler)
  }

  httpErrorHandler = (error) => {
    this.setState({
      error: _.get(this.errors, error.response.status, this.errors[HTTP_APPLICATION_CODE])
    })
  }

  authenticationStrategy = (settings) => {
    // Automatically redirect user when he is not authenticated and backend is OAUTH2
    api.interceptors.response.use(response => response, (error) => {
      if (error.response.status === HTTP_UNAUTHORIZED_CODE && settings.backend === OAUTH2_BACKEND) {
        window.location.replace(settings.authorizeUrl)
      }

      return Promise.reject(error)
    })

    const queryParams = queryString.parse(this.props.history.location.search)
    if (settings.backend === OAUTH2_BACKEND && queryParams.code) {
      return HttpService.fetchOAuth2AccessToken(queryParams.code).then(response => {
        SystemUtils.setAuthorizationToken(response.data.accessToken)
        return Promise.resolve(response)
      }).catch(error => {
        this.setState({error: this.errors[ACCESS_TOKEN_CODE]})
        return Promise.reject(error)
      }).finally(() => {
        this.props.history.replace({search: null})
      })
    }

    if (settings.backend === OAUTH2_BACKEND && !SystemUtils.hasAccessToken()) {
      window.location.replace(settings.authorizeUrl)
      return Promise.reject()
    } else if (settings.backend !== OAUTH2_BACKEND && SystemUtils.hasAccessToken()) {
      SystemUtils.clearAuthorizationToken()
    }

    return Promise.resolve()
  }

  render() {
    if (this.state.error != null) {
      return (
        <InitializeError error={this.state.error}
          buttonLabel={this.state.error.buttonLabel}
          buttonOnClick={this.state.error.buttonOnClick}
          message={this.state.error.message}
          description={this.state.error.description}
          showButton={this.state.error.showButton}
        />
      )
    }

    if (this.state.initialized) {
      return this.props.children
    }

    return <LoaderSpinner show={this.state.initialized === false} />
  }
}

function mapState(state) {
  return {
    authenticationSettings: state.settings.authenticationSettings
  }
}

export default hot(module)(withRouter(connect(mapState, ActionsUtils.mapDispatchWithEspActions)(NussknackerInitializer)))
<commit_msg>Fix initializer handle error (#329)<commit_after>import React from 'react'
import {withRouter} from 'react-router-dom'
import {connect} from "react-redux"
import {hot} from "react-hot-loader";
import ActionsUtils from "../actions/ActionsUtils";
import HttpService from "../http/HttpService";
import InitializeError from "./errors/InitializeError";
import api from "../api";
import * as queryString from "query-string";
import LoaderSpinner from "../components/Spinner";
import SystemUtils from "../common/SystemUtils";

const OAUTH2_BACKEND = "OAuth2"
const HTTP_UNAUTHORIZED_CODE = 401
const HTTP_APPLICATION_CODE = 500
const ACCESS_TOKEN_CODE = "accessToken"

class NussknackerInitializer extends React.Component {
  redirectToAuthorizeUrl = () => {
    window.location.replace(this.props.authenticationSettings.authorizeUrl)
  }

  errors = {
    401: {
      message: "Unauthorized Error",
      description: "It seems you are not authenticated... Why not try to authenticate again?",
      buttonLabel: "Try authenticate again"
    },
     504: {
       message: "504 Gateway Timeout Error",
       description: "It seems server has some problems... Why not to try refreshing your page? Or you can contact with system administrators."
     },
    500: {
      message: "Application Unexpected Error",
      showButton: false
    },
    "accessToken": {
      message: "Authentication Error",
      buttonOnClick: this.redirectToAuthorizeUrl,
      buttonLabel: "Go to authentication page",
      description: "It seems application has some problem with authentication. Please contact with system administrators."
    }
  }

  constructor(props) {
    super(props)

    this.state = {
      error: null,
      initialized: false
    }
  }

  componentDidMount() {
    //It looks like callback hell.. Can we do it better?
    HttpService.fetchSettings().then(settingsResponse => {
      this.props.actions.assignSettings(settingsResponse.data)
      this.authenticationStrategy(settingsResponse.data.authentication).then(response => {
        HttpService.fetchLoggedUser().then(userResponse => {
          this.props.actions.assignUser(userResponse.data)
          this.setState({initialized: true})
        }).catch(this.httpErrorHandler)
      })
    }).catch(this.httpErrorHandler)
  }

  httpErrorHandler = (error) => {
    this.setState({
      error: _.get(this.errors, _.get(error, 'response.status'), this.errors[HTTP_APPLICATION_CODE])
    })
  }

  authenticationStrategy = (settings) => {
    // Automatically redirect user when he is not authenticated and backend is OAUTH2
    api.interceptors.response.use(response => response, (error) => {
      if (error.response.status === HTTP_UNAUTHORIZED_CODE && settings.backend === OAUTH2_BACKEND) {
        window.location.replace(settings.authorizeUrl)
      }

      return Promise.reject(error)
    })

    const queryParams = queryString.parse(this.props.history.location.search)
    if (settings.backend === OAUTH2_BACKEND && queryParams.code) {
      return HttpService.fetchOAuth2AccessToken(queryParams.code).then(response => {
        SystemUtils.setAuthorizationToken(response.data.accessToken)
        return Promise.resolve(response)
      }).catch(error => {
        this.setState({error: this.errors[ACCESS_TOKEN_CODE]})
        return Promise.reject(error)
      }).finally(() => {
        this.props.history.replace({search: null})
      })
    }

    if (settings.backend === OAUTH2_BACKEND && !SystemUtils.hasAccessToken()) {
      window.location.replace(settings.authorizeUrl)
      return Promise.reject()
    } else if (settings.backend !== OAUTH2_BACKEND && SystemUtils.hasAccessToken()) {
      SystemUtils.clearAuthorizationToken()
    }

    return Promise.resolve()
  }

  render() {
    if (this.state.error != null) {
      return (
        <InitializeError error={this.state.error}
          buttonLabel={this.state.error.buttonLabel}
          buttonOnClick={this.state.error.buttonOnClick}
          message={this.state.error.message}
          description={this.state.error.description}
          showButton={this.state.error.showButton}
        />
      )
    }

    if (this.state.initialized) {
      return this.props.children
    }

    return <LoaderSpinner show={this.state.initialized === false} />
  }
}

function mapState(state) {
  return {
    authenticationSettings: state.settings.authenticationSettings
  }
}

export default hot(module)(withRouter(connect(mapState, ActionsUtils.mapDispatchWithEspActions)(NussknackerInitializer)))
<|endoftext|>


<commit_before>/**
 * This module provides an API for interaction with vghl.myvirtualgaming.com.
 */
'use strict';

const moment = require('moment-timezone');

const API = require('./api');

const config = require('../../config.json');

const timezone = 'America/New_York';

const helper = {
    static: {
        codename: {
            vghlclub: 'VGCLUB',
            vghlwc: 'VGHLWC'
        }
    }
};

class MyVirtualGaming_API extends API {
    constructor(options = {}) {
        super(options);

        const {
            subdomain = 'vghl'
        } = options;

        this.subdomain = subdomain;

        this.buildUrl = this.buildUrl.bind(this);
        this.getGames = this.getGames.bind(this);
        this.getInfo = this.getInfo.bind(this);
        this.getTeams = this.getTeams.bind(this);
        this.normalize = this.normalize.bind(this);
    }

    buildUrl({
        league = 'vghl',
        path = '',
        ...params
    } = {}) {
        return `https://${this.subdomain}.myvirtualgaming.com/vghlleagues/${league}/${path}?${this.buildQueryString(params)}`.replace(/\?+$/, '');
    }

    getGames({leagueId, seasonId}) {
        if (!leagueId) {
            throw new TypeError(`leagueId is not defined`);
        }

        return new Promise((resolve, reject) => {
            this.getTeams({leagueId}).then(teams => {
                teams = Object.values(teams).reduce((teams, team) => ({...teams, [team.shortname]: parseInt(team.id)}), {});

                this.get({
                    league: leagueId,
                    path: 'schedule',
                    ...(seasonId ? {filter_schedule: seasonId} : undefined)
                }).then(html => {
                    const reWeeks = /<option(?:[^>]+)?value=["']?(\d{8})["']?(?:[^>]+)?>\d{4}-\d{2}-\d{2}<\/option>/ig;
                    const promises = [];
                    const games = [];
                    let week;

                    while (week = reWeeks.exec(html)) {
                        promises.push(this.get({
                            league: leagueId,
                            path: 'schedule',
                            filter_scheduled_week: week[1]
                        }));
                    }

                    Promise.all(promises).then(html => {
                        html = html.join('');

                        const reDate = /<div(?:[^>]+)?col-sm-12(?:[^>]+)?><table(?:[^>]+)?><thead(?:[^>]+)?><tr(?:[^>]+)?><th(?:[^>]+)?>\s+\w+ (\d+)\w{2} (\w+) (\d{4}) @ (\d+:\d+[ap]m)\s+<\/th><\/tr><\/thead><\/table><\/div>/i;
                        const reGame = /<div(?:[^>]+)?mvg-table(?:[^>]+)?>.*?<div(?:[^>]+)?schedule-team-name(?:[^>]+)?>(.*?)<\/div>.*?<div(?:[^>]+)?schedule-team-score(?:[^>]+)?>(.*?)<\/div>.*?<div(?:[^>]+)?schedule-team-name(?:[^>]+)?>(.*?)<\/div>.*?<div(?:[^>]+)?schedule-team-score(?:[^>]+)?>(.*?)<\/div>.*?<div(?:[^>]+)?schedule-summary-link(?:[^>]+)?><a(?:[^>]+)?&(?:amp;)?id=(\d+)(?:[^>]+)?>.*?<\/a><\/div>/i;
                        const reDateOrGame = new RegExp(`(?:${reDate.source}|${reGame.source})`, 'ig');
                        let date;
                        let line;

                        while (line = reDateOrGame.exec(html)) {
                            let data;

                            if (data = reDate.exec(line)) {
                                date = moment.tz(`${data[2]} ${data[1]}, ${data[3]} ${data[4]}`, 'MMMM D, YYYY h:mma', timezone);

                                if (moment.tz(timezone).month() <= 6 && date.month() >= 7) {
                                    date.subtract(1, 'years');
                                } else if (moment.tz(timezone).month() >= 7 && date.month() <= 6) {
                                    date.add(1, 'years');
                                }
                            }

                            if (data = reGame.exec(line)) {
                                games.push({
                                    id: parseInt(data[5]),
                                    date: date.toISOString(),
                                    visitor: {
                                        id: teams[this.normalize(data[1]).trim()],
                                        score: !isNaN(data[2]) ? parseInt(data[2]) : null
                                    },
                                    home: {
                                        id: teams[this.normalize(data[3]).trim()],
                                        score: !isNaN(data[4]) ? parseInt(data[4]) : null
                                    }
                                });
                            }
                        }

                        resolve(games);
                    }).catch(err => {
                        reject(err);
                    });
                }).catch(reject);
            }).catch(reject);
        });
    }

    getInfo({leagueId, seasonId}) {
        if (!leagueId) {
            throw new TypeError(`leagueId is not defined`);
        }

        return new Promise((resolve, reject) => {
            this.get({
                league: leagueId,
                path: leagueId,
                format: 'feed',
                type: 'atom'
            }).then(json => {
                if (!json.feed.id.match(`/vghlleagues/${leagueId}/${leagueId}`)) {
                    return reject('Failed to get league info: feed did not match requested league');
                }

                this.get({
                    league: leagueId,
                    path: 'standings',
                    ...(seasonId ? {filter_schedule: seasonId} : undefined)
                }).then(html => {
                    const seasons = (html.match(/<select(?:[^>]+)?\bfilter_schedule\b(?:[^>]+)?>(.*?)<\/select>/) || ['', ''])[1].match(/<option(?:[^>]+)?value="(\d+)"(?:[^>]+)?>/g).map(opt => opt.replace(/.*?value="(\d+)".*/, '$1'));

                    resolve({
                        codename: this.normalize(helper.static.codename[leagueId] || json.feed.title._value.replace(/^(\S+).*/, '$1').trim()),
                        id: leagueId,
                        name: this.normalize(json.feed.title._value.replace(/(.*?) Home$/, '$1').trim()),
                        seasonId: seasons[seasons.length - 1]
                    });
                }).catch(err => {
                    if (!(err instanceof API.Error)) {
                        throw err;
                    }

                    const seasons = (err.content.match(/<select(?:[^>]+)?\bfilter_schedule\b(?:[^>]+)?>(.*?)<\/select>/) || ['', ''])[1].match(/<option(?:[^>]+)?value="(\d+)"(?:[^>]+)?>/g).map(opt => opt.replace(/.*?value="(\d+)".*/, '$1'));

                    if (!seasons.length) {
                        throw err;
                    }

                    resolve({
                        codename: this.normalize(helper.static.codename[leagueId] || json.feed.title._value.replace(/^(\S+).*/, '$1').trim()),
                        id: leagueId,
                        name: this.normalize(json.feed.title._value.replace(/(.*?) Home$/, '$1').trim()),
                        seasonId: seasons[seasons.length - 1]
                    });
                });
            }).catch(reject)
        });
    }

    getTeams({leagueId, seasonId}) {
        if (!leagueId) {
            throw new TypeError(`leagueId is not defined`);
        }

        return new Promise((resolve, reject) => {
            this.get({
                league: leagueId,
                path: 'player-statistics'
            }).then(html => {
                const reTeams = /<option(?:[^>]+)?value=["']?(\d+)["']?(?:[^>]+)?>(.*?)<\/option>/ig;
                const teamList = html.match(/<select(?:[^>]+)?filter_stat_team(?:[^>]+)?>(.*?)<\/select>/i)[1];
                const teams = {};
                let team;

                while (team = reTeams.exec(teamList)) {
                    const id = parseInt(team[1]);
                    teams[id] = {id: id, name: this.normalize(team[2].trim()), shortname: this.normalize(team[2].trim())};
                }

                this.get({
                    league: leagueId,
                    path: 'standings',
                    ...(seasonId ? {filter_schedule: seasonId} : undefined)
                }).then(html => {
                    const reTeams = new RegExp(`<a(?:[^>]+)?/${leagueId}/rosters\\?id=(\\d+)(?:[^>]+)?><img(?:[^>]+)?> (.*?)</a>`, 'ig');
                    let team;

                    while (team = reTeams.exec(html)) {
                        const id = parseInt(team[1]);

                        teams[id] = {
                            id: id,
                            ...teams[id],
                            shortname: this.normalize(({...teams[id]}.shortname || '').replace(this.normalize(team[2]), '').trim() || team[2])
                        };
                    }

                    resolve(teams);
                }).catch(reject);
            }).catch(reject);
        });
    }

    normalize(string) {
        return super.normalize(string).replace(/Bellevile/, 'Belleville');
    }
}

module.exports = MyVirtualGaming_API;
module.exports.new = (options = {...config.sites}.myvirtualgaming) => new MyVirtualGaming_API(options);
<commit_msg>Updated seasonId usage in myvirtualgaming api<commit_after>/**
 * This module provides an API for interaction with vghl.myvirtualgaming.com.
 */
'use strict';

const moment = require('moment-timezone');

const API = require('./api');

const config = require('../../config.json');

const timezone = 'America/New_York';

const helper = {
    static: {
        codename: {
            vghlclub: 'VGCLUB',
            vghlwc: 'VGHLWC'
        }
    }
};

class MyVirtualGaming_API extends API {
    constructor(options = {}) {
        super(options);

        const {
            subdomain = 'vghl'
        } = options;

        this.subdomain = subdomain;

        this.buildUrl = this.buildUrl.bind(this);
        this.getGames = this.getGames.bind(this);
        this.getInfo = this.getInfo.bind(this);
        this.getTeams = this.getTeams.bind(this);
        this.normalize = this.normalize.bind(this);
    }

    buildUrl({
        league = 'vghl',
        path = '',
        ...params
    } = {}) {
        return `https://${this.subdomain}.myvirtualgaming.com/vghlleagues/${league}/${path}?${this.buildQueryString(params)}`.replace(/\?+$/, '');
    }

    getGames({leagueId, seasonId}) {
        if (!leagueId) {
            throw new TypeError(`leagueId is not defined`);
        }

        return new Promise((resolve, reject) => {
            this.getTeams({leagueId, seasonId}).then(teams => {
                teams = Object.values(teams).reduce((teams, team) => ({...teams, [team.shortname]: parseInt(team.id)}), {});

                this.get({
                    league: leagueId,
                    path: 'schedule'
                }).then(html => {
                    const reWeeks = /<option(?:[^>]+)?value=["']?(\d{8})["']?(?:[^>]+)?>\d{4}-\d{2}-\d{2}<\/option>/ig;
                    const promises = [];
                    const games = [];
                    let week;

                    while (week = reWeeks.exec(html)) {
                        promises.push(this.get({
                            league: leagueId,
                            path: 'schedule',
                            filter_scheduled_week: week[1]
                        }));
                    }

                    Promise.all(promises).then(html => {
                        html = html.join('');

                        const reDate = /<div(?:[^>]+)?col-sm-12(?:[^>]+)?><table(?:[^>]+)?><thead(?:[^>]+)?><tr(?:[^>]+)?><th(?:[^>]+)?>\s+\w+ (\d+)\w{2} (\w+) (\d{4}) @ (\d+:\d+[ap]m)\s+<\/th><\/tr><\/thead><\/table><\/div>/i;
                        const reGame = /<div(?:[^>]+)?mvg-table(?:[^>]+)?>.*?<div(?:[^>]+)?schedule-team-name(?:[^>]+)?>(.*?)<\/div>.*?<div(?:[^>]+)?schedule-team-score(?:[^>]+)?>(.*?)<\/div>.*?<div(?:[^>]+)?schedule-team-name(?:[^>]+)?>(.*?)<\/div>.*?<div(?:[^>]+)?schedule-team-score(?:[^>]+)?>(.*?)<\/div>.*?<div(?:[^>]+)?schedule-summary-link(?:[^>]+)?><a(?:[^>]+)?&(?:amp;)?id=(\d+)(?:[^>]+)?>.*?<\/a><\/div>/i;
                        const reDateOrGame = new RegExp(`(?:${reDate.source}|${reGame.source})`, 'ig');
                        let date;
                        let line;

                        while (line = reDateOrGame.exec(html)) {
                            let data;

                            if (data = reDate.exec(line)) {
                                date = moment.tz(`${data[2]} ${data[1]}, ${data[3]} ${data[4]}`, 'MMMM D, YYYY h:mma', timezone);

                                if (moment.tz(timezone).month() <= 6 && date.month() >= 7) {
                                    date.subtract(1, 'years');
                                } else if (moment.tz(timezone).month() >= 7 && date.month() <= 6) {
                                    date.add(1, 'years');
                                }
                            }

                            if (data = reGame.exec(line)) {
                                games.push({
                                    id: parseInt(data[5]),
                                    date: date.toISOString(),
                                    visitor: {
                                        id: teams[this.normalize(data[1]).trim()],
                                        score: !isNaN(data[2]) ? parseInt(data[2]) : null
                                    },
                                    home: {
                                        id: teams[this.normalize(data[3]).trim()],
                                        score: !isNaN(data[4]) ? parseInt(data[4]) : null
                                    }
                                });
                            }
                        }

                        resolve(games);
                    }).catch(err => {
                        reject(err);
                    });
                }).catch(reject);
            }).catch(reject);
        });
    }

    getInfo({leagueId, seasonId}) {
        if (!leagueId) {
            throw new TypeError(`leagueId is not defined`);
        }

        return new Promise((resolve, reject) => {
            this.get({
                league: leagueId,
                path: leagueId,
                format: 'feed',
                type: 'atom'
            }).then(json => {
                if (!json.feed.id.match(`/vghlleagues/${leagueId}/${leagueId}`)) {
                    return reject('Failed to get league info: feed did not match requested league');
                }

                this.get({
                    league: leagueId,
                    path: 'standings',
                    ...(seasonId ? {filter_schedule: seasonId} : undefined)
                }).then(html => {
                    const seasons = (html.match(/<select(?:[^>]+)?\bfilter_schedule\b(?:[^>]+)?>(.*?)<\/select>/) || ['', ''])[1].match(/<option(?:[^>]+)?value="(\d+)"(?:[^>]+)?>/g).map(opt => opt.replace(/.*?value="(\d+)".*/, '$1'));

                    resolve({
                        codename: this.normalize(helper.static.codename[leagueId] || json.feed.title._value.replace(/^(\S+).*/, '$1').trim()),
                        id: leagueId,
                        name: this.normalize(json.feed.title._value.replace(/(.*?) Home$/, '$1').trim()),
                        seasonId: seasons[seasons.length - 1]
                    });
                }).catch(err => {
                    if (!(err instanceof API.Error)) {
                        throw err;
                    }

                    const seasons = (err.content.match(/<select(?:[^>]+)?\bfilter_schedule\b(?:[^>]+)?>(.*?)<\/select>/) || ['', ''])[1].match(/<option(?:[^>]+)?value="(\d+)"(?:[^>]+)?>/g).map(opt => opt.replace(/.*?value="(\d+)".*/, '$1'));

                    if (!seasons.length) {
                        throw err;
                    }

                    resolve({
                        codename: this.normalize(helper.static.codename[leagueId] || json.feed.title._value.replace(/^(\S+).*/, '$1').trim()),
                        id: leagueId,
                        name: this.normalize(json.feed.title._value.replace(/(.*?) Home$/, '$1').trim()),
                        seasonId: seasons[seasons.length - 1]
                    });
                });
            }).catch(reject)
        });
    }

    getTeams({leagueId, seasonId}) {
        if (!leagueId) {
            throw new TypeError(`leagueId is not defined`);
        }

        return new Promise((resolve, reject) => {
            this.get({
                league: leagueId,
                path: 'player-statistics',
                ...(seasonId ? {filter_schedule: seasonId} : undefined)
            }).then(html => {
                const reTeams = /<option(?:[^>]+)?value=["']?(\d+)["']?(?:[^>]+)?>(.*?)<\/option>/ig;
                const teamList = html.match(/<select(?:[^>]+)?filter_stat_team(?:[^>]+)?>(.*?)<\/select>/i)[1];
                const teams = {};
                let team;

                while (team = reTeams.exec(teamList)) {
                    const id = parseInt(team[1]);
                    teams[id] = {id: id, name: this.normalize(team[2].trim()), shortname: this.normalize(team[2].trim())};
                }

                this.get({
                    league: leagueId,
                    path: 'standings',
                    ...(seasonId ? {filter_schedule: seasonId} : undefined)
                }).then(html => {
                    const reTeams = new RegExp(`<a(?:[^>]+)?/${leagueId}/rosters\\?id=(\\d+)(?:[^>]+)?><img(?:[^>]+)?> (.*?)</a>`, 'ig');
                    let team;

                    while (team = reTeams.exec(html)) {
                        const id = parseInt(team[1]);

                        teams[id] = {
                            id: id,
                            ...teams[id],
                            shortname: this.normalize(({...teams[id]}.shortname || '').replace(this.normalize(team[2]), '').trim() || team[2])
                        };
                    }

                    resolve(teams);
                }).catch(reject);
            }).catch(reject);
        });
    }

    normalize(string) {
        return super.normalize(string).replace(/Bellevile/, 'Belleville');
    }
}

module.exports = MyVirtualGaming_API;
module.exports.new = (options = {...config.sites}.myvirtualgaming) => new MyVirtualGaming_API(options);
<|endoftext|>


<commit_before>/*!
Deck JS - deck.smartsyntax
Copyright (c) 2012 Rémi Emonet
Dual licensed under the MIT license and GPL license.
https://github.com/imakewebthings/deck.js/blob/master/MIT-license.txt
https://github.com/imakewebthings/deck.js/blob/master/GPL-license.txt
*/

/*
This module provides a support for a shorter syntax for slides.
*/

(function($, deck, undefined) {
    var $d = $(document);
    var may = function(f) {return f ? f : function() {}};
    var startsWith = function(longStr, part) {return longStr.substr(0, part.length) == part;}
    var startsWithIgnoreCase = function(longStr, part) {return longStr.substr(0, part.length).toUpperCase() == part.toUpperCase();}
    var maybeAddClasses = function(toWhat, spaceSeparatedClasses, uniqueId) {
        if (uniqueId != "") $(toWhat).attr("id", uniqueId);
        if (spaceSeparatedClasses == "") return;
        var parts = spaceSeparatedClasses.split(/ +/);
        for (i in parts) {
            $(toWhat).addClass(parts[i]);
        }
    }

    var interpretationOfSmartLanguage = function(smart, doc) {
        var res = new Array();
        var inSlide = null;
        var indent = "";
        var deepestList = null;
        var remain = smart;

        var processMath = function(content) {
            return content.replace(/\$([^$][^$]*)\$/g, '\\displaystyle $1').replace(/\$\$/, '$');
        }

        var setEnrichedContent = function(what, content) {
            content = processMath(content);
            return what.innerHTML = content;
        }
        var endSlide = function() {
            inSlide = null;
            indent = new Array();
            indent = "";
            deepestList = null;
        }

        while (true) {
            var nl = remain.indexOf("\n");
            var line = remain.substring(0, nl).replace(/^[ \t]*/, "");
            // we iterate over the lines
            // treat trailing unique-id and classes before anything
            var uniqueId = "";
            while (line.match(/^(.*)#([^\]\| >]*)$/)) {
                uniqueId = RegExp.$2;
                line = RegExp.$1;
            }
            var addClasses = "";
            {
                while (line.match(/^(.*)\[([^\] >]*)\]$/)) {
                    addClasses = RegExp.$2 + " " + addClasses;
                    line = RegExp.$1;
                }
            }
            if (line == "") {
            } else if (line.match(/^==(.*)==$/)) {
                var title = RegExp.$1;
                if (inSlide) endSlide();
                inSlide = doc.createElement("section");
                $(inSlide).addClass("slide");
                maybeAddClasses(inSlide, addClasses, uniqueId);
                var h = doc.createElement("h1");
                setEnrichedContent(h, title);
                inSlide.appendChild(h);
                deepestList = inSlide;
                res[res.length] = inSlide;
            } else if (line.match(/^=(.*)=$/)) {
                var title = RegExp.$1;
                if (inSlide) endSlide();
                inSlide = doc.createElement("section");
                $(inSlide).addClass("slide");
                maybeAddClasses(inSlide, addClasses, uniqueId);
                var h = doc.createElement("h2");
                setEnrichedContent(h, title);
                inSlide.appendChild(h);
                deepestList = inSlide;
                res[res.length] = inSlide;
            } else if (line.match(/^([-*#]+)(.*)$/)) {
                var pref = RegExp.$1;
                var content = RegExp.$2;
                if (indent == "" && pref == "") {
                    // do not create the li
                } else if (pref == indent) {
                    var li = doc.createElement("li");
                    maybeAddClasses(li, addClasses, uniqueId);
                    setEnrichedContent(li, content);
                    deepestList.appendChild(li);
                } else {
                    // un-push as needed
                    while (! startsWith(pref, indent)) {
                        deepestList = deepestList.parentNode;
                        if (deepestList.tagName == "LI") deepestList = deepestList.parentNode;
                        indent = indent.substr(0, indent.length - 1);
                    }
                    // clean the special '-' that we can use for magic unpush
                    pref = pref.replace(/^-*/, "");
                    // re-push as needed
                    while (pref.length > indent.length) {
                        var asso = {"*": "ul", "#": "ol"};
                        var toPush = pref.substr(indent.length, 1);
                        indent = indent.concat(toPush);
                        var list = doc.createElement(asso[toPush]);
                        if ((deepestList.tagName == "UL" || deepestList.tagName == "OL") && $(">li",deepestList).size() > 0) {
                            $(">li", deepestList).last().append(list);
                        } else {
                            deepestList.appendChild(list);
                        }
                        deepestList = list;
                    }
                    if (indent == "" && pref == "") {
                        // do not create the li
                    } else {
                        var li = doc.createElement("li");
                        maybeAddClasses(li, addClasses, uniqueId);
                        setEnrichedContent(li, content);
                        deepestList.appendChild(li);
                    }
                }
            } else if (line.match(/\/[*]/)) { // block-comments
                var opened = 0;
                while (line != null && remain.length != 0) {
                    if (line.match(/\/[*]/)) {
                        opened += 1;
                    }
                    if (line.match(/.*[*]\//)) {
                        opened -= 1;
                        if (opened <= 0) {
                            // normal stopping condition
                            break;
                        }
                    }
                    if (nl != -1) remain = remain.substring(nl + 1);
                    nl = remain.indexOf("\n");
                    line = remain.substring(0, nl);//.replace(/^ */, "");
                }
            } else if (startsWithIgnoreCase(line, "// ")) {
                var di = doc.createElement("div");
                maybeAddClasses(di, addClasses, uniqueId);
                //alert(line + "\n" + deepestList.innerHTML)
                $(di).addClass("comment").text(line.replace(/\/\/ */, "")).appendTo($(">*:not(.comment)", deepestList).last());
            } else if (startsWithIgnoreCase(line, "@CSS ") || startsWithIgnoreCase(line, "@CSS:")) {
                var what = line.replace(/@CSS\:? */i, "");
                var obj = $("


<commit_before>import React from 'react'
import { storiesOf } from '@storybook/react'

storiesOf('Typography', module)
.add('h1-h6', () => (

h1

h2

h3

h4

h5

h6

))
.add('f1-f6', () => (

f1

f2

f3

f4

f5

f6

))
.add('f light', () => (

f00-light

f0-light

f1-light

f2-light

f3-light

))
.add('line-height', () =>(

      lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default

      lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed

      lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra

))
.add('typographic styles', () => (

text-normal

text-bold

text-uppercase

no-wrap

ws-normal

wb-break-all

no-underline

text-emphasized

text-small

lead

))
<commit_msg>add stories for text alignment, list styles, and text shadows<commit_after>import React from 'react'
import { storiesOf } from '@storybook/react'

storiesOf('Typography', module)
.add('h1-h6', () => (

h1

h2

h3

h4

h5

h6

))
.add('f1-f6', () => (

f1

f2

f3

f4

f5

f6

))
.add('f light', () => (

f00-light

f0-light

f1-light

f2-light

f3-light

))
.add('line-height', () =>(

      lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default lh-default

      lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed lh-condensed

      lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra lh-condensed-ultra

))
.add('typographic styles', () => (

text-normal

text-bold

text-uppercase

no-wrap

ws-normal

wb-break-all

no-underline

text-emphasized

text-small

lead

))
.add('text alignment', () => (

text-left

text-center

text-right

))
.add('responsive text alignment', () => (

Left in a small viewport, centered in mid-sized viewports, and right aligned in larger viewports

))
.add('list-style-none', () => (

list-style-none

list-style-none

list-style-none

))
.add('text shadows', () => (

.text-shadow-dark helps white text stand out on dark or photographic backgrounds

.text-shadow-light creates an embossed effect for dark text

))
<|endoftext|>


<commit_before>// ########### Top 10 List ###########

var sortDesc = function(all_counties, key) {
    return all_counties.sort(function(a, b) {
        var x = a[key]; var y = b[key];
        return ((x > y) ? -1 : ((x < y) ? 1 : 0));
    });
}

var getTop = function(all_counties, key){
  top_counties = sortDesc(all_counties, key).slice(0,10);
  return top_counties
}

var clear_top_list = function(){
  $('#top-list span').remove()
}

var top_list = function(all_counties, food_selection, food){
   // Append top counties to DOM - interactions.js
    var top_counties = getTop(all_counties, 'food_quant')

    top_counties.forEach(function(county) {
      if($('#held-counties').has('#county-'+county.id).length > 0){

        a = $(county_tag(county)).addClass('held').append(check_icon())
        $('#top-list').append(a)
        $(".draggable").draggable({ disabled: false });

        if($('.drag-here#county-'+county.id) == 'county-'+county.id){
          $('#top-list').append(county_tag(county).addClass('held').addClass('disabled').removeClass('draggable'))
          $('#held-counties').append(county_tag(county).addClass('held').addClass('disabled').removeClass('draggable'))
          $(".disabled").draggable({ disabled: true });
        }
      }
      else{
        $('#top-list').append(holdable_county(county));
      }
    });
}

// Tooltip + mousevents

// counties = d3.select('#map').selectAll('.holdable')

// console.log(counties)
// $('#map').on("mouseover", function(d) {
//   id = county_id($(this).attr('id'))
//   county = find_county_obj(all_counties, id)

//   d3.select(this)
//     .transition().duration(200)
//     .style("opacity", 1);

//   tooltip.transition().duration(200)
//   .style("opacity", 1);
//   tooltip.text(county.county + " County, " + county.state + "                 " + county.food + ": " + county.food_quant)
//   .style("background-color", "#2C3E50")
//   .style("left", (d3.event.pageX + 10) + "px")
//   .style("top", (d3.event.pageY -30) + "px");
// })

// $('.holdable').on("mouseout", function() {
//   d3.select(this)
//   .transition().duration(300)
//   .style("opacity", 0.8);
//   tooltip.transition().duration(300)
//   .style("opacity", 0);
// })

<commit_msg>no duplicates when you change to food data. top list reflects what was already there<commit_after>// ########### Top 10 List ###########

var sortDesc = function(all_counties, key) {
    return all_counties.sort(function(a, b) {
        var x = a[key]; var y = b[key];
        return ((x > y) ? -1 : ((x < y) ? 1 : 0));
    });
}

var getTop = function(all_counties, key){
  top_counties = sortDesc(all_counties, key).slice(0,10);
  return top_counties
}

var clear_top_list = function(){
  $('#top-list span').remove()
}

var top_list = function(all_counties, food_selection, food){
   // Append top counties to DOM - interactions.js
    var top_counties = getTop(all_counties, 'food_quant')

    top_counties.forEach(function(county) {
      if($('#held-counties').has('#county-'+county.id).length > 0){

        a = $(county_tag(county)).addClass('held').removeClass('draggable').append(check_icon())
        $('#top-list').append(a)
        $(".draggable").draggable({ disabled: false });

        if($('.drag-here').attr('id') == 'county-'+county.id){
          $('#top-list #county-'+county.id).addClass('disabled')
          $(".disabled").draggable({ disabled: true });
        }

      }
      else{
        $('#top-list').append(holdable_county(county));
      }
    });
}

// Tooltip + mousevents

// counties = d3.select('#map').selectAll('.holdable')

// console.log(counties)
// $('#map').on("mouseover", function(d) {
//   id = county_id($(this).attr('id'))
//   county = find_county_obj(all_counties, id)

//   d3.select(this)
//     .transition().duration(200)
//     .style("opacity", 1);

//   tooltip.transition().duration(200)
//   .style("opacity", 1);
//   tooltip.text(county.county + " County, " + county.state + "                 " + county.food + ": " + county.food_quant)
//   .style("background-color", "#2C3E50")
//   .style("left", (d3.event.pageX + 10) + "px")
//   .style("top", (d3.event.pageY -30) + "px");
// })

// $('.holdable').on("mouseout", function() {
//   d3.select(this)
//   .transition().duration(300)
//   .style("opacity", 0.8);
//   tooltip.transition().duration(300)
//   .style("opacity", 0);
// })

<|endoftext|>


<commit_before>'use strict';

var isDate        = require('es5-ext/date/is-date')
  , toTokens      = require('es5-ext/function/#/to-string-tokens')
  , isPlainObject = require('es5-ext/object/is-plain-object')
  , toArray       = require('es5-ext/object/to-array')
  , isRegExp      = require('es5-ext/reg-exp/is-reg-exp')
  , repeat        = require('es5-ext/string/#/repeat')

  , isArray = Array.isArray, map = Array.prototype.map
  , slice = Array.prototype.slice, min = Math.min
  , match = String.prototype.match, stringify = JSON.stringify
  , functionRe = new RegExp('^\\s*function[\\0-\'\\)-\\uffff]*' +
		'\\(([\\0-\\(\\*-\\uffff]*)\\)\\s*\\{([\\0-\\uffff]*)\\}\\s*$')
  , setNest, convertValue;

setNest = function (str, nest, tabWidth) {
	var data, current, tabs = true, add, remove;
	data = str.split('\n');
	current = min.apply(null, data.map(function (str) {
		if (!str) return Infinity;
		return str.match(/^(\t*)/)[1].length;
	}));
	if (current === Infinity) current = 0;

	if (nest > current) {
		if (tabs) add = repeat.call('\t', nest - current);
		else add = repeat.call(' ', (nest - current) * tabWidth);
	} else {
		remove = current - nest;
		if (!tabs) remove *= tabWidth;
	}
	return data.map(function (str) {
		if (!str) return str;
		if (add) return add + str;
		return str.slice(remove);
	}).join('\n');
};

convertValue = function (value, nest) {
	var type = typeof value, data;
	if ((value == null) || (type === 'boolean') || (type === 'number') ||
			isRegExp(value)) {
		return String(value);
	}
	if (type === 'function') {
		data = match.call(value, functionRe);
		return 'function (' + data[1] + ') {' + setNest(data[2], nest) +
			repeat.call('\t', nest) + '}';
	}
	if (isDate(value)) return 'new Date(' + value.getTime() + ')';
	if (isPlainObject(value)) {
		data = '{\n' + repeat.call('\t', nest + 1);
		data += toArray(value, function (value, name) {
			return stringify(name) + ': ' + convertValue(value, nest + 1);
		}).join(',\n' + repeat.call('\t', nest + 1)) + '\n' +
			repeat.call('\t', nest) + '}';
		return data;
	}
	if (isArray(value)) {
		return '[' + value.map(function (value) {
			return convertValue(value, nest + 1);
		}).join(', ') + ']';
	}
	return stringify(String(value));
};

module.exports = function (fn/*, …localVars*/) {
	var data = toTokens.call(fn), localVars = slice.call(arguments, 1);

	return '(function (' + data.args + ') { \'use strict\';' +
		setNest(data.body, 0) + '}(' + map.call(localVars, function (value) {
			return convertValue(value, 1);
		}).join(',') +  '));';
};
<commit_msg>Do not apply any nesting to function body<commit_after>'use strict';

var isDate        = require('es5-ext/date/is-date')
  , toTokens      = require('es5-ext/function/#/to-string-tokens')
  , isPlainObject = require('es5-ext/object/is-plain-object')
  , toArray       = require('es5-ext/object/to-array')
  , isRegExp      = require('es5-ext/reg-exp/is-reg-exp')
  , repeat        = require('es5-ext/string/#/repeat')

  , isArray = Array.isArray, map = Array.prototype.map
  , slice = Array.prototype.slice, min = Math.min
  , match = String.prototype.match, stringify = JSON.stringify
  , functionRe = new RegExp('^\\s*function[\\0-\'\\)-\\uffff]*' +
		'\\(([\\0-\\(\\*-\\uffff]*)\\)\\s*\\{([\\0-\\uffff]*)\\}\\s*$')
  , setNest, convertValue;

setNest = function (str, nest, tabWidth) {
	var data, current, tabs = true, add, remove;
	data = str.split('\n');
	current = min.apply(null, data.map(function (str) {
		if (!str) return Infinity;
		return str.match(/^(\t*)/)[1].length;
	}));
	if (current === Infinity) current = 0;

	if (nest > current) {
		if (tabs) add = repeat.call('\t', nest - current);
		else add = repeat.call(' ', (nest - current) * tabWidth);
	} else {
		remove = current - nest;
		if (!tabs) remove *= tabWidth;
	}
	return data.map(function (str) {
		if (!str) return str;
		if (add) return add + str;
		return str.slice(remove);
	}).join('\n');
};

convertValue = function (value, nest) {
	var type = typeof value, data;
	if ((value == null) || (type === 'boolean') || (type === 'number') ||
			isRegExp(value)) {
		return String(value);
	}
	if (type === 'function') {
		data = match.call(value, functionRe);
		return 'function (' + data[1] + ') {' + setNest(data[2], nest) +
			repeat.call('\t', nest) + '}';
	}
	if (isDate(value)) return 'new Date(' + value.getTime() + ')';
	if (isPlainObject(value)) {
		data = '{\n' + repeat.call('\t', nest + 1);
		data += toArray(value, function (value, name) {
			return stringify(name) + ': ' + convertValue(value, nest + 1);
		}).join(',\n' + repeat.call('\t', nest + 1)) + '\n' +
			repeat.call('\t', nest) + '}';
		return data;
	}
	if (isArray(value)) {
		return '[' + value.map(function (value) {
			return convertValue(value, nest + 1);
		}).join(', ') + ']';
	}
	return stringify(String(value));
};

module.exports = function (fn/*, …localVars*/) {
	var data = toTokens.call(fn), localVars = slice.call(arguments, 1);

	return '(function (' + data.args + ') { \'use strict\';' + data.body + '}(' +
		map.call(localVars, function (value) {
			return convertValue(value, 1);
		}).join(',') +  '));';
};
<|endoftext|>


<commit_before>
var _ = require('lodash');
var fs = require('fs');
var PluginService = require('../services/KongPluginService');
var Kong = require("../services/KongService");
var async = require("async");

var KongConsumersController  =  {

    apis : function(req,res) {

        var consumerId = req.param("id");

        // Fetch all acls of the specified consumer
        Kong.listAllCb(req,'/consumers/' + consumerId + '/acls', function (err,_acls) {
            if(err) return res.negotiate(err);

            // Make an array of group names
            var consumerGroups = _.map(_acls.data,function(item){
                return item.group;
            });

            // Fetch all apis
            Kong.listAllCb(req,'/apis',function (err,data) {
                if(err) return res.negotiate(err);

                var apis = data.data;

                var apiPluginsFns = [];

                // Prepare apis
                apis.forEach(function(api){
                    // Add consumer id
                    api.consumer_id = consumerId;

                    apiPluginsFns.push(function(cb){
                        return Kong.listAllCb(req,'/apis/' + api.id + '/plugins',cb);
                    });
                });

                // Foreach api, fetch it's assigned plugins
                async.series(apiPluginsFns,function (err,data) {
                    if(err) return res.negotiate(err);

                    data.forEach(function(plugins,index){

                        // Separate acl plugins in an acl property
                        var acl = _.find(plugins.data,function(item){
                            return item.name === "acl" && item.enabled === true;
                        });

                        if(acl) {
                            apis[index].acl = acl;
                        }

                        // Add plugins to their respective api
                        apis[index].plugins = plugins;
                    });

                    // Gather apis with no access control restrictions whatsoever
                    var open =  _.filter(apis,function (api) {
                        return !api.acl;
                    })

                    // Gather apis with access control restrictions whitelisting at least one of the consumer's groups.
                    var whitelisted = _.filter(apis,function (api) {
                        return api.acl && _.intersection(api.acl.config.whitelist,consumerGroups).length > 0;
                    });

                    return res.json({
                        total : open.length + whitelisted.length,
                        data  : open.concat(whitelisted)
                    });
                });
            });
        });

    }

};

module.exports = KongConsumersController;
<commit_msg>comment<commit_after>
var _ = require('lodash');
var fs = require('fs');
var PluginService = require('../services/KongPluginService');
var Kong = require("../services/KongService");
var async = require("async");

var KongConsumersController  =  {

    apis : function(req,res) {

        var consumerId = req.param("id");

        // Fetch all acls of the specified consumer
        Kong.listAllCb(req,'/consumers/' + consumerId + '/acls', function (err,_acls) {
            if(err) return res.negotiate(err);

            // Make an array of group names
            var consumerGroups = _.map(_acls.data,function(item){
                return item.group;
            });

            // Fetch all apis
            Kong.listAllCb(req,'/apis',function (err,data) {
                if(err) return res.negotiate(err);

                var apis = data.data;

                var apiPluginsFns = [];

                // Prepare api objects
                apis.forEach(function(api){
                    // Add consumer id
                    api.consumer_id = consumerId;

                    apiPluginsFns.push(function(cb){
                        return Kong.listAllCb(req,'/apis/' + api.id + '/plugins',cb);
                    });
                });

                // Foreach api, fetch it's assigned plugins
                async.series(apiPluginsFns,function (err,data) {
                    if(err) return res.negotiate(err);

                    data.forEach(function(plugins,index){

                        // Separate acl plugins in an acl property
                        var acl = _.find(plugins.data,function(item){
                            return item.name === "acl" && item.enabled === true;
                        });

                        if(acl) {
                            apis[index].acl = acl;
                        }

                        // Add plugins to their respective api
                        apis[index].plugins = plugins;
                    });

                    // Gather apis with no access control restrictions whatsoever
                    var open =  _.filter(apis,function (api) {
                        return !api.acl;
                    })

                    // Gather apis with access control restrictions whitelisting at least one of the consumer's groups.
                    var whitelisted = _.filter(apis,function (api) {
                        return api.acl && _.intersection(api.acl.config.whitelist,consumerGroups).length > 0;
                    });

                    return res.json({
                        total : open.length + whitelisted.length,
                        data  : open.concat(whitelisted)
                    });
                });
            });
        });

    }

};

module.exports = KongConsumersController;
<|endoftext|>


<commit_before>"use strict";

var zmq = require("zmq");
var axon = require("axon");

var RPCClient = require("./RPCClient");
var SourceClient = require("./SourceClient");
var SharedObjectClient = require("./SharedObjectClient");

class Client {
    constructor(descriptor){
        this.descriptor = descriptor;
        this.transports = {};

        this._setupTransports();
        this._setupEndpoints();
    }

    _setupTransports(){
        for(let transport in this.descriptor.transports){
            switch (transport){
                case 'source':
                    this._setupSource(this.descriptor.transports.source.client);
                    break;
                case 'sink':
                    this._setupSink(this.descriptor.transports.sink.client);
                    break;
                case 'rpc':
                    this._setupRpc(this.descriptor.transports.rpc.client);
                    break;
                default:
                    break;
            }
        }
    }

    _setupSource(hostname){
        var sock = new zmq.socket('sub');
        this.transports.source = sock;
        sock.connect(hostname);
        sock.subscribe("");
        //sock.on('message', this._sourceCallback.bind(this));
    }

    _setupSink(hostname){
        var sock = new zmq.socket('pub');
        this.transports.sink = sock;
        sock.connect(hostname);
    }

    _sourceCallback(message){
        // TODO: pass message to eventemitter
    }

    _setupRpc(hostname){
        var sock = new axon.socket('req');
        sock.connect(hostname);
        this.transports.rpc = sock;
    }

    _setupEndpoints(){
        for(let endpoint of this.descriptor.endpoints){
            switch(endpoint.type){
                case 'RPC':
                    this[endpoint.name] = new RPCClient(endpoint, this.transports);
                    break;
                case 'Source':
                    this[endpoint.name] = new SourceClient(endpoint, this.transports);
                    break;
                case 'SharedObject':
                    this[endpoint.name] = new SharedObjectClient(endpoint, this.transports);
                    break;
                default:
                    throw "Unknown endpoint type.";
            }
        }
    }
}

module.exports = Client;
<commit_msg>set maxListeners to # Source definitions<commit_after>"use strict";

var zmq = require("zmq");
var axon = require("axon");

var RPCClient = require("./RPCClient");
var SourceClient = require("./SourceClient");
var SharedObjectClient = require("./SharedObjectClient");

class Client {
    constructor(descriptor){
        this.descriptor = descriptor;
        this.transports = {};

        this._setupTransports();
        this._setupEndpoints();
    }

    _setupTransports(){
        for(let transport in this.descriptor.transports){
            switch (transport){
                case 'source':
                    this._setupSource(this.descriptor.transports.source.client);
                    break;
                case 'sink':
                    this._setupSink(this.descriptor.transports.sink.client);
                    break;
                case 'rpc':
                    this._setupRpc(this.descriptor.transports.rpc.client);
                    break;
                default:
                    break;
            }
        }
    }

    _setupSource(hostname){
        var sock = new zmq.socket('sub');
        this.transports.source = sock;
        sock.connect(hostname);
        sock.subscribe("");
        sock.setMaxListeners(Object.keys(this.descriptor.endpoints.filter((endp) => { endp.type == "Source" })).length);
        //sock.on('message', this._sourceCallback.bind(this));
    }

    _setupSink(hostname){
        var sock = new zmq.socket('pub');
        this.transports.sink = sock;
        sock.connect(hostname);
    }

    _sourceCallback(message){
        // TODO: pass message to eventemitter
    }

    _setupRpc(hostname){
        var sock = new axon.socket('req');
        sock.connect(hostname);
        this.transports.rpc = sock;
    }

    _setupEndpoints(){
        for(let endpoint of this.descriptor.endpoints){
            switch(endpoint.type){
                case 'RPC':
                    this[endpoint.name] = new RPCClient(endpoint, this.transports);
                    break;
                case 'Source':
                    this[endpoint.name] = new SourceClient(endpoint, this.transports);
                    break;
                case 'SharedObject':
                    this[endpoint.name] = new SharedObjectClient(endpoint, this.transports);
                    break;
                default:
                    throw "Unknown endpoint type.";
            }
        }
    }
}

module.exports = Client;
<|endoftext|>


<commit_before>"use strict";
var $ = function(id) { return document.getElementById(id); };

var options, mail, label, text, hide; // Declare variables
options = document.getElementsByName('contact'); // Get the radio buttons
mail = $('mail');
label = $('label'); // the mail radio button and its label
text = $('mailingAddress');
label.className = 'hide'; // Hide label for that mailing address textarea
text.className = 'hide'; // Hide mailing address textarea

// Loop through radios
for ( var i = 0; i < options.length; i++ ) {
    if ( options[i].addEventListener ) {
        // Add event listener if event listener supported
        options[i].addEventListener('click', radioChanged);
    }
    else {
        // Otherwise; IE fallback: onclick
        options[i].attachEvent('onclick', radioChanged);
    }
}

var form = $('registration_form');

/*
 * processEntries
 * Process all the entries provided via standard input by the user
 */
var processEntries = function() {

    var isValid = true;
    // get values for user entries
    var email = $("email_address").value;
    var phone = $("phone").value;
    var country = $("country").value;
    var terms = $("terms").checked;
    var mailchecked = $("mail").checked;

    // check user entries for validity
    if ( email == "" ) {
        $("email_address").nextElementSibling.firstChild.nodeValue = "This field is required.";
        isValid = false;
    }
    else {
        $("email_address").nextElementSibling.firstChild.nodeValue = "";
    }

    if ( phone == "" ) {
        $("phone").nextElementSibling.firstChild.nodeValue = "This field is required.";
        isValid = false;
    }
    else {
        $("phone").nextElementSibling.firstChild.nodeValue = "";
    }

    if ( country == "" ) {
        $("country").nextElementSibling.firstChild.nodeValue = "Please select a country.";
        isValid = false;
    }
    else {
        $("country").nextElementSibling.firstChild.nodeValue = "";
    }

    if ( terms == false ) {
        $("terms").nextElementSibling.firstChild.nodeValue = "This box must be checked.";
        isValid = false;
    }
    else {
        $("terms").nextElementSibling.firstChild.nodeValue = "";
    }

    if( isValid ) {
    	$("registration_form").submit();
    }

};

function radioChanged() {

    // Is mail button checked?
    if ( mail.checked ) {
        hide = '';
    }
    else {
        hide = 'hide';
    }

    // Text input visibility
    label.className = hide;
    text.className = hide;

    // If text input hidden, empty its contents
    if ( hide ) {
        text.value = '';
    }
}

/*
 * resetForm
 * Erases all the form information upon the 'reset_form' button click
 */
var resetForm = function() {

    $("registration_form").reset();
    label.className = 'hide';  // Hide label for that mailing address textarea
    text.className = 'hide';  // Hide mailing address textarea
    $("email_address").nextElementSibling.firstChild.nodeValue = "*";
    $("phone").nextElementSibling.firstChild.nodeValue = "*";
    $("country").nextElementSibling.firstChild.nodeValue = "*";
    $("terms").nextElementSibling.firstChild.nodeValue = "*";
    $("email_address").focus();

    // Remove saved data from local storage as well
    localStorage.clear();

};

/*
 * populateStorage
 * Save data items into local storage
 */
function populateStorage() {

    localStorage.setItem('email', $('email_address').value);
    localStorage.setItem('phone', $('phone').value);
    localStorage.setItem('country', $('country').value);

    // Loop through radios
    for ( var i = 0; i < options.length; i++ ) {
        if ( options[i].checked ) {
            localStorage.setItem('contact', options[i].value);
            break;
        }
    }

    localStorage.setItem('mailingAddress', $('mailingAddress').value);
    localStorage.setItem('terms', $('terms').checked);
    localStorage.setItem('comments', $('comments').checked);

}

/*
 * retrieveData
 * Retrieve data items from local storage and put data back into the web page
 */
function retrieveData() {

    $('email_address').value = localStorage.getItem('email');
    $('phone').value = localStorage.getItem('phone');
    $('country').value = localStorage.getItem('country');

    var contact = localStorage.getItem('contact');

    // Loop through radios. Check the last checked option
    for ( var i = 0; i < options.length; i++ ) {
        if ( options[i].value === contact ) {
            options[i].checked = true;
        }
    }

    $('mailingAddress').value = localStorage.getItem('mailingAddress');
    $('terms').value = localStorage.getItem('terms');
    $('comments').value = localStorage.getItem('comments');

}

window.onload = function() {

    $("register").onclick = processEntries;
    $("reset_form").onclick = resetForm;
    $("email_address").focus();

};
<commit_msg>Completed step 2.4, using event delegation approach<commit_after>"use strict";
var $ = function(id) { return document.getElementById(id); };

var options, mail, label, text, hide; // Declare variables
options = document.getElementsByName('contact'); // Get the radio buttons
mail = $('mail');
label = $('label'); // the mail radio button and its label
text = $('mailingAddress');
label.className = 'hide'; // Hide label for that mailing address textarea
text.className = 'hide'; // Hide mailing address textarea

// Loop through radios
for ( var i = 0; i < options.length; i++ ) {
    if ( options[i].addEventListener ) {
        // Add event listener if event listener supported
        options[i].addEventListener('click', radioChanged);
    }
    else {
        // Otherwise; IE fallback: onclick
        options[i].attachEvent('onclick', radioChanged);
    }
}

// Set up event listeners to call populateStorage() on change
// Get form
var form = $('registration_form');

if ( form.addEventListener ) {
    // If event listeners work, add listener on change
    form.addEventListener('change', function(e) {
        populateStorage(e);
    }, false);
}
else {
    // Otherwise, use old IE model: onchange
    form.attachEvent('onchange', function(e) {
        populateStorage(e);
    });
}

/*
 * processEntries
 * Process all the entries provided via standard input by the user
 */
var processEntries = function() {

    var isValid = true;
    // get values for user entries
    var email = $("email_address").value;
    var phone = $("phone").value;
    var country = $("country").value;
    var terms = $("terms").checked;
    var mailchecked = $("mail").checked;

    // check user entries for validity
    if ( email == "" ) {
        $("email_address").nextElementSibling.firstChild.nodeValue = "This field is required.";
        isValid = false;
    }
    else {
        $("email_address").nextElementSibling.firstChild.nodeValue = "";
    }

    if ( phone == "" ) {
        $("phone").nextElementSibling.firstChild.nodeValue = "This field is required.";
        isValid = false;
    }
    else {
        $("phone").nextElementSibling.firstChild.nodeValue = "";
    }

    if ( country == "" ) {
        $("country").nextElementSibling.firstChild.nodeValue = "Please select a country.";
        isValid = false;
    }
    else {
        $("country").nextElementSibling.firstChild.nodeValue = "";
    }

    if ( terms == false ) {
        $("terms").nextElementSibling.firstChild.nodeValue = "This box must be checked.";
        isValid = false;
    }
    else {
        $("terms").nextElementSibling.firstChild.nodeValue = "";
    }

    if( isValid ) {
    	$("registration_form").submit();
    }

};

function radioChanged() {

    // Is mail button checked?
    if ( mail.checked ) {
        hide = '';
    }
    else {
        hide = 'hide';
    }

    // Text input visibility
    label.className = hide;
    text.className = hide;

    // If text input hidden, empty its contents
    if ( hide ) {
        text.value = '';
    }
}

/*
 * resetForm
 * Erases all the form information upon the 'reset_form' button click
 */
var resetForm = function() {

    $("registration_form").reset();
    label.className = 'hide';  // Hide label for that mailing address textarea
    text.className = 'hide';  // Hide mailing address textarea
    $("email_address").nextElementSibling.firstChild.nodeValue = "*";
    $("phone").nextElementSibling.firstChild.nodeValue = "*";
    $("country").nextElementSibling.firstChild.nodeValue = "*";
    $("terms").nextElementSibling.firstChild.nodeValue = "*";
    $("email_address").focus();

    // Remove saved data from local storage as well
    localStorage.clear();

};

// Check whether there is any data item in web page that has been stored in localStorage or not
if ( !localStorage.getItem('email') ) {
    // If localStorage was empty, then write data into it
    populateStorage();
}
else {
    // If there is any data item has been stored, then retrieve data from local storage
    retrieveData();
}

/*
 * populateStorage
 * Save data items into local storage
 */
function populateStorage( event ) {

    localStorage.setItem('email', $('email_address').value);
    localStorage.setItem('phone', $('phone').value);
    localStorage.setItem('country', $('country').value);

    // Loop through radios
    for ( var i = 0; i < options.length; i++ ) {
        if ( options[i].checked ) {
            localStorage.setItem('contact', options[i].value);
            break;
        }
    }

    localStorage.setItem('mailingAddress', $('mailingAddress').value);
    localStorage.setItem('terms', $('terms').checked);
    localStorage.setItem('comments', $('comments').checked);

}

/*
 * retrieveData
 * Retrieve data items from local storage and put data back into the web page
 */
function retrieveData() {

    $('email_address').value = localStorage.getItem('email');
    $('phone').value = localStorage.getItem('phone');
    $('country').value = localStorage.getItem('country');

    var contact = localStorage.getItem('contact');

    // Loop through radios. Check the last checked option
    for ( var i = 0; i < options.length; i++ ) {
        if ( options[i].value === contact ) {
            options[i].checked = true;
        }
    }

    $('mailingAddress').value = localStorage.getItem('mailingAddress');
    $('terms').value = localStorage.getItem('terms');
    $('comments').value = localStorage.getItem('comments');

}

window.onload = function() {

    $("register").onclick = processEntries;
    $("reset_form").onclick = resetForm;
    $("email_address").focus();

};
<|endoftext|>