<commit_before>//
// TCGA Scraper
//
// A TCGA Web Toolbox Module that scrapes the TCGA http/ftp site
// into RDF triples and provides a query runner
//
//

(function(TCGA){
  //Check for TCGA, fail if not found
  if (!TCGA) { throw "TCGA required"; }

  var uuid = function uuid(a){
      //Function from https://gist.github.com/982883 (@jed)
      return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,uuid);
    };

  // Semaphore from https://gist.github.com/1296828
  var Sync = function(syncCount, callback, preventInstantCallbackExecution) {
        this.syncCount = syncCount;
        this.callback = callback;
        if(preventInstantCallbackExecution === false && this.syncCount === 0) {
            this.executeCallback();
        }
    };
    Sync.prototype.decrement = function() {
        --this.syncCount;
        if(this.syncCount === 0) {
            this.executeCallback();
        }
    };
    Sync.prototype.increment = function() {
        ++this.syncCount;
    };
    Sync.prototype.executeCallback = function() {
        if (typeof this.callback === "function") this.callback();
    };

  var fsErrorCallback = function fsErrorCallback(e) {
    var msg = '';
    console.error(e);

    switch (e.code) {
      case FileError.QUOTA_EXCEEDED_ERR:
        msg = 'QUOTA_EXCEEDED_ERR';
        break;
      case FileError.NOT_FOUND_ERR:
        msg = 'NOT_FOUND_ERR';
        break;
      case FileError.SECURITY_ERR:
        msg = 'SECURITY_ERR';
        break;
      case FileError.INVALID_MODIFICATION_ERR:
        msg = 'INVALID_MODIFICATION_ERR';
        break;
      case FileError.INVALID_STATE_ERR:
        msg = 'INVALID_STATE_ERR';
        break;
      default:
        msg = 'Unknown Error';
        break;
    };

    console.log('Error: ' + msg);
  };

  function toArray(list) {
    return Array.prototype.slice.call(list || [], 0);
  }

  var TCGAScraper = {

    init : function init(){

      var that = this;

      //Initialize the RDF Store
      this.store = new rdfstore.Store(function(store){
        store.registerDefaultProfileNamespaces();
        store.registerDefaultNamespace("tcga", "http://tcga.github.com/#");
        console.log("Store ready");
      });

      //Initialize the File System
      window.requestFileSystem  = window.requestFileSystem || window.webkitRequestFileSystem;
      this.fileSystem = window.requestFileSystem(window.PERSISTENT, 500*1024*1024, function(newFs){
        that.fileSystem = newFs;
        console.log("Filesystem ready");
      }, fsErrorCallback);

      // Remove old databases
      var db = openDatabase('tcga', '1.0', 'Scrapes of the TCGA as text/n3', 500000000);
      var onerror = function(tx, err){ console.error(err); },
          onsuccess function(tx, resp){ console.log("Removed old scrapes table"); db.close();});
      db.transaction(function(tx){
        tx.executeSql("DROP TABLE scrapes", [], onsuccess, onerror);
      });
    },

    store : null,

    fileSystem : null,

    scrapeList : null,

    gui : '

TCGA SPARQL Interface

<form class="span6" id="query">
SPARQL Query
<textarea class="span6" id="sparql" rows="10">SELECT * WHERE { ?s ?p ?o . } LIMIT 25</textarea>
Enter your SPARQL Query and click submit.

<button type="submit" class="btn btn-primary">Submit Query</button> <button class="btn">Cancel</button>
</form>

',

    nav : 'SPARQL',

    name : 'tcga-sparql',

    types : {
      9 : "tcga:disease-study",
      10 : "tcga:center-type",
      11 : "tcga:center-domain",
      12 : "tcga:platform",
      13 : "tcga:data-type",
      14 : "tcga:archive",
      15 : "tcga:file",
      file : "tcga:file"
    },

    scrape : function(options){
      var opts = options || {},
          that = this, // Capture context for use in closures
          target = opts.url || "https://tcga-data.nci.nih.gov/tcgafiles/ftp_auth/distro_ftpusers/anonymous/tumor/",
          store = opts.store || this.store,
          parent = opts.parent,
          callback = opts.callback || (!opts.parent && (this.save).bind(that)) || null;

      if (!store) {
        console.error("RDFStore required");
        return;
      }

      if (!opts.url) console.log("Beginning scrape of: ",target);

      if (!that.scraping) that.scraping = true;

      TCGA.get(target, function(error, response){

        if (error) {
          console.error("Failed to get", target);
          return;
        }

        var links = $("a", $(response)),
            link, index, children = [],
            querystring = "@prefix tcga:<http://tcga.github.com/#> .\n";

        links.each(function(index, link){

          var name = $(link).attr('href'),
              id = uuid(),
              url = target + name,
              type = that.types[target.split("/").length];

          // Filter out links beginning with ? or /
          // (i.e. column headers and parent links)
          if(name.match(/^[\?\/]/)) return;

          // Things with extensions are files (e.g. reallylong_name.tiff)
          // TODO Use MIME types to determine files.
          if(name.match(/^.*\.[^\/]+$/)) type = that.types.file;

          // TODO when should this NOT be done (e.g. files)
          if(type !== that.types.file) name = name.slice(0,-1); // Remove the trailing "/"

          querystring += 'tcga:'+id+' tcga:url "'+url+'" ;\n';
          querystring += "tcga:type "+type+" ;\n";
          if(parent){
            querystring += "tcga:parent tcga:"+parent+" ;\n";
          }
          querystring += 'tcga:ftp-name "'+name+'" .\n';

          if (type !== that.types.file && target.split("/").length <= 8){
            children.push({store:store, url:url, parent:id});
          }

        });

        // Insert the queries
        try{
          store.load("text/turtle", querystring, function(success, results){
            if (!success) {
              console.error("Unable to load data for", target, ":", results);
            }
            if (success){
              console.log("Parsed", target.slice(81), "into", results, "triples");
            }
            // Depth first traversal of children
            if (success && children.length > 0){
              var counter = new Sync(children.length, callback);
              var nextChild = function nextChild(children){
                var child = children.pop();
                if (child){
                  child.callback = function(){
                    counter.decrement();
                    nextChild(children);
                  };
                  that.scrape(child);
                }
              };
              nextChild(children);
            }
            else {
              if (callback && typeof callback === 'function') callback();
            }

          });
        }
        catch(e){
          console.error("Failed to load triples for", target);
          console.dir(e);
          if (callback && typeof callback === 'function') callback();
        }

      });
    },

    load : function(callback){
      var that = this,
          dirReader, scrapes = [], readEntries;

      if (!that.fileSystem) {
        console.log("Unable to load most recent scrape: filesystem not loaded");
        return;
      }

      that.getScrapeList(function(scrapes){
        var scrape = scrapes[scrapes.length-1], //Get the most recent scrape
            scrapeDate = new Date(parseInt(scrape.name.match(/-([0-9]+)\./)[1]));
        console.log("Loading scrape from:", scrapeDate);
        scrape.file(function(scrapefile){
          var reader = new FileReader();

          reader.onloadend = function(e){
            that.store.load("text/n3", this.result, function(succ, results){
              if (!succ) {
                console.error("Failed to load triples from scrape on", scrapeDate);
                return;
              }
              console.log("Loaded", results, "triples scraped on", scrapeDate);
            });
          }

          reader.readAsText(scrapefile);
        }, fsErrorCallback);
      });
    },

    getScrapeList : function(callback){
      var that = this,
          dirReader, scrapes = [], readEntries;

      if (!that.fileSystem) {
        console.log("Unable get scrape list: filesystem not loaded");
        return;
      }

      dirReader = that.fileSystem.root.createReader();
      readEntries = function() {
         dirReader.readEntries (function(results) {
          if (!results.length) {
            that.scrapeList = scrapes;
            if (callback && typeof callback === 'function') callback(scrapes);
          } else {
            scrapes = scrapes.concat(toArray(results));
            readEntries();
          }
        }, fsErrorCallback);
      };
      readEntries(); // Start reading dirs.
    },

    save : function(callback){
      var that = this,
          now = new Date(),
          filename = ["tcgascrape-",now.valueOf(),".nt"].join("");

      if (!that.fileSystem) {
        console.log("Unable to save scrape: filesystem not loaded");
        return;
      }

      that.store.graph(function(succ,graph){
        if (!succ) {
          console.error("Unable to get graph for serialization"); return;
        }
        that.fileSystem.root.getFile(filename, {create: true, exclusive: false}, function(fileEntry) {
          var url = fileEntry.toURL();
          fileEntry.createWriter(function(fileWriter) {

            fileWriter.onwriteend = function(e) {
              console.log('Saved scrape from', now.toString(), 'to', url);
              if (callback && typeof callback === 'function') callback();
            };

            fileWriter.onerror = function(e) {
              console.log('Write failed: ' + e.toString());
            };

            var bb = new window.WebKitBlobBuilder(); // Note: window.WebKitBlobBuilder in Chrome 12.
            bb.append(graph.toNT());
            fileWriter.write(bb.getBlob('text/plain'));

          });
        }, fsErrorCallback);
      });
    }

  };

  TCGAScraper.init();
  TCGA.registerTab(TCGAScraper.name, TCGAScraper.nav, TCGAScraper.gui);

  var parseResults = function parseResults(resp){
    var tableTemplate = "

";
    if (typeof resp === "number") {
      $("#message").addClass("alert").addClass("alert-success").text("Successfully added this many triples: "+resp);
    }
    else if (typeof resp === 'object' && resp.length > 0) {
      $("#results").html(tableTemplate);
      var labels = Object.keys(resp[0]),
          $heads = $("#results table thead tr").first(),
          $body = $("#results table tbody");
      labels.forEach(function(label){
        $heads.append($("").text(label));
      });
      resp.forEach(function(row){
        var $rowhtml = $("
");
        labels.forEach(function(label){
          $rowhtml.append($("").text(row[label].value));
        });
        $body.append($rowhtml);
      });
    }
  };

  $("#query").submit(function(e){
    var query = $("#sparql", this).val();
    if(query !== ""){
      try {
        TCGAScraper.store.execute(query, function(succ, resp){
          if(!succ) $("#message").addClass("alert").addClass("alert-error").text("Unable to execute query: " + query);
          else {
            parseResults(resp);
          }
        });
      }
      catch (e){
        $("#message").addClass("alert").addClass("alert-error").text("Unable to parse query: " + query);
      }
    }
    return false;
  });
  TCGA.Scraper = TCGA.Scraper || TCGAScraper;
})(TCGA);
<commit_msg>Fixed a variety of typos<commit_after>//
// TCGA Scraper
//
// A TCGA Web Toolbox Module that scrapes the TCGA http/ftp site
// into RDF triples and provides a query runner
//
//

(function(TCGA){
  //Check for TCGA, fail if not found
  if (!TCGA) { throw "TCGA required"; }

  var uuid = function uuid(a){
      //Function from https://gist.github.com/982883 (@jed)
      return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,uuid);
    };

  // Semaphore from https://gist.github.com/1296828
  var Sync = function(syncCount, callback, preventInstantCallbackExecution) {
        this.syncCount = syncCount;
        this.callback = callback;
        if(preventInstantCallbackExecution === false && this.syncCount === 0) {
            this.executeCallback();
        }
    };
    Sync.prototype.decrement = function() {
        --this.syncCount;
        if(this.syncCount === 0) {
            this.executeCallback();
        }
    };
    Sync.prototype.increment = function() {
        ++this.syncCount;
    };
    Sync.prototype.executeCallback = function() {
        if (typeof this.callback === "function") this.callback();
    };

  var fsErrorCallback = function fsErrorCallback(e) {
    var msg = '';
    console.error(e);

    switch (e.code) {
      case FileError.QUOTA_EXCEEDED_ERR:
        msg = 'QUOTA_EXCEEDED_ERR';
        break;
      case FileError.NOT_FOUND_ERR:
        msg = 'NOT_FOUND_ERR';
        break;
      case FileError.SECURITY_ERR:
        msg = 'SECURITY_ERR';
        break;
      case FileError.INVALID_MODIFICATION_ERR:
        msg = 'INVALID_MODIFICATION_ERR';
        break;
      case FileError.INVALID_STATE_ERR:
        msg = 'INVALID_STATE_ERR';
        break;
      default:
        msg = 'Unknown Error';
        break;
    }

    console.log('Error: ' + msg);
  };

  function toArray(list) {
    return Array.prototype.slice.call(list || [], 0);
  }

  var TCGAScraper = {

    init : function init(){

      var that = this;

      //Initialize the RDF Store
      this.store = new rdfstore.Store(function(store){
        store.registerDefaultProfileNamespaces();
        store.registerDefaultNamespace("tcga", "http://tcga.github.com/#");
        console.log("Store ready");
      });

      //Initialize the File System
      window.requestFileSystem  = window.requestFileSystem || window.webkitRequestFileSystem;
      this.fileSystem = window.requestFileSystem(window.PERSISTENT, 500*1024*1024, function(newFs){
        that.fileSystem = newFs;
        console.log("Filesystem ready");
      }, fsErrorCallback);

      // Remove old databases
      var db = openDatabase('tcga', '1.0', 'Scrapes of the TCGA as text/n3', 500000000);
      var onerror = function(tx, err){
            if (!err.message.match(/no such table/)) console.error(err);
            else db = null;
          },
          onsuccess = function(tx, resp){ console.log("Removed old scrapes table"); db = null;};
      db.transaction(function(tx){
        tx.executeSql("DROP TABLE scrapes", [], onsuccess, onerror);
      });
    },

    store : null,

    fileSystem : null,

    scrapeList : null,

    gui : '

TCGA SPARQL Interface

<form class="span6" id="query">
SPARQL Query
<textarea class="span6" id="sparql" rows="10">SELECT * WHERE { ?s ?p ?o . } LIMIT 25</textarea>
Enter your SPARQL Query and click submit.

<button type="submit" class="btn btn-primary">Submit Query</button> <button class="btn">Cancel</button>
</form>

',

    nav : 'SPARQL',

    name : 'tcga-sparql',

    types : {
      9 : "tcga:disease-study",
      10 : "tcga:center-type",
      11 : "tcga:center-domain",
      12 : "tcga:platform",
      13 : "tcga:data-type",
      14 : "tcga:archive",
      15 : "tcga:file",
      file : "tcga:file"
    },

    scrape : function(options){
      var opts = options || {},
          that = this, // Capture context for use in closures
          target = opts.url || "https://tcga-data.nci.nih.gov/tcgafiles/ftp_auth/distro_ftpusers/anonymous/tumor/",
          store = opts.store || this.store,
          parent = opts.parent,
          callback = opts.callback || (!opts.parent && (this.save).bind(that)) || null;

      if (!store) {
        console.error("RDFStore required");
        return;
      }

      if (!opts.url) console.log("Beginning scrape of: ",target);

      if (!that.scraping) that.scraping = true;

      TCGA.get(target, function(error, response){

        if (error) {
          console.error("Failed to get", target);
          return;
        }

        var links = $("a", $(response)),
            link, index, children = [],
            querystring = "@prefix tcga:<http://tcga.github.com/#> .\n";

        links.each(function(index, link){

          var name = $(link).attr('href'),
              id = uuid(),
              url = target + name,
              type = that.types[target.split("/").length];

          // Filter out links beginning with ? or /
          // (i.e. column headers and parent links)
          if(name.match(/^[\?\/]/)) return;

          // Things with extensions are files (e.g. reallylong_name.tiff)
          // TODO Use MIME types to determine files.
          if(name.match(/^.*\.[^\/]+$/)) type = that.types.file;

          // TODO when should this NOT be done (e.g. files)
          if(type !== that.types.file) name = name.slice(0,-1); // Remove the trailing "/"

          querystring += 'tcga:'+id+' tcga:url "'+url+'" ;\n';
          querystring += "tcga:type "+type+" ;\n";
          if(parent){
            querystring += "tcga:parent tcga:"+parent+" ;\n";
          }
          querystring += 'tcga:ftp-name "'+name+'" .\n';

          if (type !== that.types.file && target.split("/").length <= 8){
            children.push({store:store, url:url, parent:id});
          }

        });

        // Insert the queries
        try{
          store.load("text/turtle", querystring, function(success, results){
            if (!success) {
              console.error("Unable to load data for", target, ":", results);
            }
            if (success){
              console.log("Parsed", target.slice(81), "into", results, "triples");
            }
            // Depth first traversal of children
            if (success && children.length > 0){
              var counter = new Sync(children.length, callback);
              var nextChild = function nextChild(children){
                var child = children.pop();
                if (child){
                  child.callback = function(){
                    counter.decrement();
                    nextChild(children);
                  };
                  that.scrape(child);
                }
              };
              nextChild(children);
            }
            else {
              if (callback && typeof callback === 'function') callback();
            }

          });
        }
        catch(e){
          console.error("Failed to load triples for", target);
          console.dir(e);
          if (callback && typeof callback === 'function') callback();
        }

      });
    },

    load : function(callback){
      var that = this,
          dirReader, scrapes = [], readEntries;

      if (!that.fileSystem) {
        console.log("Unable to load most recent scrape: filesystem not loaded");
        return;
      }

      that.getScrapeList(function(scrapes){
        var scrape = scrapes[scrapes.length-1], //Get the most recent scrape
            scrapeDate = new Date(parseInt(scrape.name.match(/-([0-9]+)\./)[1],10));
        console.log("Loading scrape from:", scrapeDate);
        scrape.file(function(scrapefile){
          var reader = new FileReader();

          reader.onloadend = function(e){
            that.store.load("text/n3", this.result, function(succ, results){
              if (!succ) {
                console.error("Failed to load triples from scrape on", scrapeDate);
                return;
              }
              console.log("Loaded", results, "triples scraped on", scrapeDate);
            });
          }

          reader.readAsText(scrapefile);
        }, fsErrorCallback);
      });
    },

    getScrapeList : function(callback){
      var that = this,
          dirReader, scrapes = [], readEntries;

      if (!that.fileSystem) {
        console.log("Unable get scrape list: filesystem not loaded");
        return;
      }

      dirReader = that.fileSystem.root.createReader();
      readEntries = function() {
         dirReader.readEntries (function(results) {
          if (!results.length) {
            that.scrapeList = scrapes;
            if (callback && typeof callback === 'function') callback(scrapes);
          } else {
            scrapes = scrapes.concat(toArray(results));
            readEntries();
          }
        }, fsErrorCallback);
      };
      readEntries(); // Start reading dirs.
    },

    save : function(callback){
      var that = this,
          now = new Date(),
          filename = ["tcgascrape-",now.valueOf(),".nt"].join("");

      if (!that.fileSystem) {
        console.log("Unable to save scrape: filesystem not loaded");
        return;
      }

      that.store.graph(function(succ,graph){
        if (!succ) {
          console.error("Unable to get graph for serialization"); return;
        }
        that.fileSystem.root.getFile(filename, {create: true, exclusive: false}, function(fileEntry) {
          var url = fileEntry.toURL();
          fileEntry.createWriter(function(fileWriter) {

            fileWriter.onwriteend = function(e) {
              console.log('Saved scrape from', now.toString(), 'to', url);
              if (callback && typeof callback === 'function') callback();
            };

            fileWriter.onerror = function(e) {
              console.log('Write failed: ' + e.toString());
            };

            var bb = new window.WebKitBlobBuilder(); // Note: window.WebKitBlobBuilder in Chrome 12.
            bb.append(graph.toNT());
            fileWriter.write(bb.getBlob('text/plain'));

          });
        }, fsErrorCallback);
      });
    },

  TCGAScraper.init();
  TCGA.registerTab(TCGAScraper.name, TCGAScraper.nav, TCGAScraper.gui);

  var parseResults = function parseResults(resp){
    var tableTemplate = "

";
    if (typeof resp === "number") {
      $("#message").addClass("alert").addClass("alert-success").text("Successfully added this many triples: "+resp);
    }
    else if (typeof resp === 'object' && resp.length > 0) {
      $("#results").html(tableTemplate);
      var labels = Object.keys(resp[0]),
          $heads = $("#results table thead tr").first(),
          $body = $("#results table tbody");
      labels.forEach(function(label){
        $heads.append($("").text(label));
      });
      resp.forEach(function(row){
        var $rowhtml = $("
");
        labels.forEach(function(label){
          $rowhtml.append($("").text(row[label].value));
        });
        $body.append($rowhtml);
      });
    }
  };

  $("#query").submit(function(e){
    var query = $("#sparql", this).val();
    if(query !== ""){
      try {
        TCGAScraper.store.execute(query, function(succ, resp){
          if(!succ) $("#message").addClass("alert").addClass("alert-error").text("Unable to execute query: " + query);
          else {
            parseResults(resp);
          }
        });
      }
      catch (e){
        $("#message").addClass("alert").addClass("alert-error").text("Unable to parse query: " + query);
      }
    }
    return false;
  });
  TCGA.Scraper = TCGA.Scraper || TCGAScraper;
})(TCGA);
<|endoftext|>


<commit_before>/* Taiwanese LANGUAGE
================================================== */
if(typeof VMM != 'undefined') {
	VMM.Language = {
		lang: "zh-tw",
		api: {
			wikipedia: "zh"
		},
		date: {
			month: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"],
			month_abbr: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"],
			day: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
			day_abbr: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"]
		},
		dateformats: {
			year: "yyyy年",
			month_short: "mmm",
			month: "yyyy年 mmmm",
			full_short: "mmm d",
			full: "yyyy年mmmm d日",
			time_short: "HH:MM:ss",
			time_no_seconds_short: "HH:MM",
			time_no_seconds_small_date: "HH:MM'
'yyyy年mmmm d日''",
			full_long: "dddd',' yyyy年mmmm d日 'um' HH:MM",
			full_long_small_date: "HH:MM'
'dddd',' yyyy年mmmm d日''"
		},
		messages: {
			loading_timeline: "載入時間線... ",
			return_to_title: "回到開頭",
			expand_timeline: "展開時間",
			contract_timeline: "縮短時間",
			wikipedia: "擷取自維基百科, 自由之百科全書",
			loading_content: "載入內容",
			loading: "載入中"

		}
	}
}
<commit_msg>Update zh-tw.js<commit_after>/* Taiwanese LANGUAGE
================================================== */
if(typeof VMM != 'undefined') {
	VMM.Language = {
		lang: "zh-tw",
		api: {
			wikipedia: "zh"
		},
		date: {
			month: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"],
			month_abbr: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"],
			day: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
			day_abbr: ["週日", "週一", "週二", "週三", "週四", "週五", "週六"]
		},
		dateformats: {
			year: "yyyy年",
			month_short: "mmm",
			month: "yyyy年 mmmm",
			full_short: "mmm d",
			full: "yyyy年mmmm d日",
			time_short: "HH:MM:ss",
			time_no_seconds_short: "HH:MM",
			time_no_seconds_small_date: "HH:MM'
'yyyy年mmmm d日''",
			full_long: "dddd',' yyyy年mmmm d日 'um' HH:MM",
			full_long_small_date: "HH:MM'
'dddd',' yyyy年mmmm d日''"
		},
		messages: {
			loading_timeline: "載入時間線... ",
			return_to_title: "回到開頭",
			expand_timeline: "展開時間",
			contract_timeline: "縮短時間",
			wikipedia: "擷取自維基百科, 自由之百科全書",
			loading_content: "載入內容",
			loading: "載入中"

		}
	}
}
<|endoftext|>


<commit_before>
/* eslint no-process-exit: 0 */
/* A script to simulate actual game player with a player driver. */

require('babel-register');

const RG = require('../client/src/battles');
RG.Verify = require('../client/src/verify');
const RGTest = require('../tests/roguetest');
RG.Factory.Game = require('../client/src/factory.game');

const ROT = require('../lib/rot.js');
const PlayerDriver = require('../tests/helpers/player-driver');
const fs = require('fs');
const cmdLineArgs = require('command-line-args');

// Parse command line args
const optDefs = [
  {name: 'name', type: String,
      descr: 'Name of the character' },
  {name: 'frame_period', type: Number,
      descr: 'Print every Nth frame' },
  {name: 'load', type: Boolean,
      descr: 'Load game from the file'},
  {name: 'loadturn', type: Number,
      descr: 'Number of turn to load (optional)'},
  {name: 'maxturns', type: Number,
      descr: 'Turns to simulate'},
  {name: 'nosave', type: Boolean,
    descr: 'Disables saving during the simulation'},
  {name: 'save_period', type: Number,
    descr: 'Number of turns between saves'},
  {name: 'help', alias: 'h', type: Boolean,
    descr: 'Prints help message'}
];
let opts = cmdLineArgs(optDefs);
opts = getDefaults(opts);
if (opts.help) {
    usage();
}

ROT.RNG.setSeed(0);
RG.Rand = new RG.Random();
RG.RAND.setSeed(0);

const conf = {
    playMode: 'OverWorld',
    playerLevel: 'Medium',
    sqrPerItem: 100,
    sqrPerActor: 100,
    yMult: 0.5,
    playerClass: 'Blademaster',
    playerRace: 'human'
};

const gameFact = new RG.Factory.Game();
let newGame = gameFact.createNewGame(conf);

// To load previous stage quickly
const loadGame = opts.load ? true : false;
const pName = opts.name;
let loadTurn = opts.loadturn ? opts.loadturn : 0;
const saveGameEnabled = !opts.nosave;
let driver = new PlayerDriver();
const fname = `save_dumps/${pName}_temp_${loadTurn}.json`;
// const fname = 'save_dumps/1519583443971_saveGame_Tunas.json';
// const fname = 'save_dumps/bsave_1519586656174_saveGame_Tunas.json';
// const fname = 'save_dumps/remove_bug.json';

if (loadGame) {
    const buf = fs.readFileSync(fname);
    // const jsonParsed = JSON.parse(buf.toString());
    const jsonParsed = JSON.parse(buf);
    if (jsonParsed.driver) {
        driver = PlayerDriver.fromJSON(jsonParsed.driver);
    }
    if (jsonParsed.nTurns) {
        loadTurn = jsonParsed.nTurns;
    }
    else {
        console.warn('No nTurns found in same. Give it with -nturns');
    }
    const fromJSON = new RG.Game.FromJSON();
    newGame = fromJSON.createGame(jsonParsed);
    console.log(`===== Game Loaded from turn ${loadTurn}`);
}

const player = newGame.getPlayer();
player.setName(pName);
player.remove('Hunger'); // AI not smart enough yet to deal with this
driver.setPlayer(player);
driver.screenPeriod = opts.framePeriod;

console.log('===== Begin Game simulation =====');
driver.nTurns = loadGame ? loadTurn : 0;
const catcher = new RGTest.MsgCatcher();
// const area = game.getArea(0);
// const [aX, aY] = [area.getMaxX(), area.getMaxY()];
// game.movePlayer(aX - 1, 0);

const maxTurns = loadTurn + opts.maxturns;
const savePeriod = opts.save_period ? opts.save_period : 2000;

// Execute game in try-catch so we can dump save data on failure
try {
    const startI = loadGame ? loadTurn : 0;
    for (let nTurn = startI; nTurn < maxTurns; nTurn++) {
        if (nTurn % 50 === 0) {
            newGame.getPlayerOwPos();
            const compl = `${nTurn / maxTurns * 100}% completed`;
            console.log(`[TURN ${nTurn}, ${compl}`);
        }

        // Save the game between certain intervals
        if (saveGameEnabled) {
            if (nTurn > startI && (nTurn % (savePeriod) === 0)) {
                if (maxTurns >= 1000) { // Don't save for short games
                    [newGame, driver] = saveGameToFile(nTurn, newGame, driver);
                    driver.screenPeriod = opts.framePeriod;
                }
            }
        }

        newGame.update(driver.nextCmd());
        if (newGame.isGameOver()) {
            console.log('>>> GAME OVER <<<');
            break;
        }
    }
}
catch (e) {
    console.log(e);
    let jsonStr = '';
    try {
        const json = newGame.toJSON();
        jsonStr = JSON.stringify(json);
    }
    catch (e2) {
        console.log(e2);
        jsonStr = JSON.stringify(driver);
    }
    const fname = 'save_dumps/battles_game_error_dump.json';
    fs.writeFileSync(fname, jsonStr);
}

console.log('Simulation OK. Saving final state');
const json = newGame.toJSON();
const jsonStr = JSON.stringify(json);

const nTurns = driver.nTurns;
const finalFname = `save_dumps/${pName}_game_final_${nTurns}.json`;
fs.writeFileSync(finalFname, jsonStr);
console.log('Final state saved to file ' + finalFname);

catcher.hasNotify = false;
console.log('===== End Game simulation =====');

//---------------------------------------------------------------------------
// END OF SCRIPT, HELPER FUNCTIONS
//---------------------------------------------------------------------------

function getDefaults(opt) {
    const obj = Object.assign({}, opt);
    obj.name = obj.name || 'Xanthur';
    obj.maxturns = obj.maxturns || 10000;
    obj.framePeriod = obj.frame_period || 1;
    return obj;
}

// Saves the game, returns new game and driver objects
// ie {newgame, newdriver} = saveGameToFile(game, driver)
function saveGameToFile(nTurn, game, driver) {
    console.log('\tsaveGameEnabled. Turn check OK.');
    console.log('\tDumping chunk load status now:');
    game.getChunkManager().debugPrint();

    const fname = `save_dumps/${pName}_temp_${nTurn}.json`;
    const json = newGame.toJSON();
    json.nTurns = nTurn;
    json.driver = driver.toJSON();
    const jsonStr = JSON.stringify(json);
    console.log(`Saving/restoring game to ${fname}`);
    fs.writeFileSync(fname, jsonStr);
    const jsonParsed = JSON.parse(jsonStr);

    const fromJSON = new RG.Game.FromJSON();
    newGame = fromJSON.createGame(jsonParsed);
    driver = PlayerDriver.fromJSON(jsonParsed.driver);
    driver.setPlayer(newGame.getPlayer());

    return [newGame, driver];
}

function usage() {
    optDefs.forEach(opt => {
        const str = JSON.stringify(opt);
        console.log(str);
    });
    process.exit(0);
}
<commit_msg>Saves also the driver now at the end of simulation.<commit_after>
/* eslint no-process-exit: 0 */
/* A script to simulate actual game player with a player driver. */

require('babel-register');

const RG = require('../client/src/battles');
RG.Verify = require('../client/src/verify');
const RGTest = require('../tests/roguetest');
RG.Factory.Game = require('../client/src/factory.game');

const ROT = require('../lib/rot.js');
const PlayerDriver = require('../tests/helpers/player-driver');
const fs = require('fs');
const cmdLineArgs = require('command-line-args');

// Parse command line args
const optDefs = [
  {name: 'name', type: String,
      descr: 'Name of the character' },
  {name: 'frame_period', type: Number,
      descr: 'Print every Nth frame' },
  {name: 'load', type: Boolean,
      descr: 'Load game from the file'},
  {name: 'loadturn', type: Number,
      descr: 'Number of turn to load (optional)'},
  {name: 'maxturns', type: Number,
      descr: 'Turns to simulate'},
  {name: 'nosave', type: Boolean,
    descr: 'Disables saving during the simulation'},
  {name: 'save_period', type: Number,
    descr: 'Number of turns between saves'},
  {name: 'help', alias: 'h', type: Boolean,
    descr: 'Prints help message'}
];
let opts = cmdLineArgs(optDefs);
opts = getDefaults(opts);
if (opts.help) {
    usage();
}

ROT.RNG.setSeed(0);
RG.Rand = new RG.Random();
RG.RAND.setSeed(0);

const conf = {
    playMode: 'OverWorld',
    playerLevel: 'Medium',
    sqrPerItem: 100,
    sqrPerActor: 100,
    yMult: 0.5,
    playerClass: 'Blademaster',
    playerRace: 'human'
};

const gameFact = new RG.Factory.Game();
let newGame = gameFact.createNewGame(conf);

// To load previous stage quickly
const loadGame = opts.load ? true : false;
const pName = opts.name;
let loadTurn = opts.loadturn ? opts.loadturn : 0;
const saveGameEnabled = !opts.nosave;
let driver = new PlayerDriver();
const fname = `save_dumps/${pName}_temp_${loadTurn}.json`;
// const fname = 'save_dumps/1519583443971_saveGame_Tunas.json';
// const fname = 'save_dumps/bsave_1519586656174_saveGame_Tunas.json';
// const fname = 'save_dumps/remove_bug.json';

if (loadGame) {
    const buf = fs.readFileSync(fname);
    // const jsonParsed = JSON.parse(buf.toString());
    const jsonParsed = JSON.parse(buf);
    if (jsonParsed.driver) {
        driver = PlayerDriver.fromJSON(jsonParsed.driver);
    }
    if (jsonParsed.nTurns) {
        loadTurn = jsonParsed.nTurns;
    }
    else {
        console.warn('No nTurns found in same. Give it with -nturns');
    }
    const fromJSON = new RG.Game.FromJSON();
    newGame = fromJSON.createGame(jsonParsed);
    console.log(`===== Game Loaded from turn ${loadTurn}`);
}

const player = newGame.getPlayer();
player.setName(pName);
player.remove('Hunger'); // AI not smart enough yet to deal with this
driver.setPlayer(player);
driver.screenPeriod = opts.framePeriod;

console.log('===== Begin Game simulation =====');
driver.nTurns = loadGame ? loadTurn : 0;
const catcher = new RGTest.MsgCatcher();
// const area = game.getArea(0);
// const [aX, aY] = [area.getMaxX(), area.getMaxY()];
// game.movePlayer(aX - 1, 0);

const maxTurns = loadTurn + opts.maxturns;
const savePeriod = opts.save_period ? opts.save_period : 2000;

// Execute game in try-catch so we can dump save data on failure
try {
    const startI = loadGame ? loadTurn : 0;
    for (let nTurn = startI; nTurn < maxTurns; nTurn++) {
        if (nTurn % 50 === 0) {
            newGame.getPlayerOwPos();
            const compl = `${nTurn / maxTurns * 100}% completed`;
            console.log(`[TURN ${nTurn}, ${compl}`);
        }

        // Save the game between certain intervals
        if (saveGameEnabled) {
            if (nTurn > startI && (nTurn % (savePeriod) === 0)) {
                if (maxTurns >= 1000) { // Don't save for short games
                    [newGame, driver] = saveGameToFile(nTurn, newGame, driver);
                    driver.screenPeriod = opts.framePeriod;
                }
            }
        }

        newGame.update(driver.nextCmd());
        if (newGame.isGameOver()) {
            console.log('>>> GAME OVER <<<');
            break;
        }
    }
}
catch (e) {
    console.log(e);
    let jsonStr = '';
    try {
        const json = newGame.toJSON();
        jsonStr = JSON.stringify(json);
    }
    catch (e2) {
        console.log(e2);
        jsonStr = JSON.stringify(driver);
    }
    const fname = 'save_dumps/battles_game_error_dump.json';
    fs.writeFileSync(fname, jsonStr);
}

const nTiles = Object.keys(driver.state.tilesVisited).length;
console.log(`Player visited ${nTiles} different tiles`);

console.log('Simulation OK. Saving final state');
const json = newGame.toJSON();
const jsonStr = JSON.stringify(json);

const nTurns = driver.nTurns;
json.nTurns = nTurns;
json.driver = driver;

const finalFname = `save_dumps/${pName}_game_final_${nTurns}.json`;
fs.writeFileSync(finalFname, jsonStr);
console.log('Final state saved to file ' + finalFname);

catcher.hasNotify = false;
console.log('===== End Game simulation =====');

//---------------------------------------------------------------------------
// END OF SCRIPT, HELPER FUNCTIONS
//---------------------------------------------------------------------------

function getDefaults(opt) {
    const obj = Object.assign({}, opt);
    obj.name = obj.name || 'Xanthur';
    obj.maxturns = obj.maxturns || 10000;
    obj.framePeriod = obj.frame_period || 1;
    return obj;
}

// Saves the game, returns new game and driver objects
// ie {newgame, newdriver} = saveGameToFile(game, driver)
function saveGameToFile(nTurn, game, driver) {
    console.log('\tsaveGameEnabled. Turn check OK.');
    console.log('\tDumping chunk load status now:');
    game.getChunkManager().debugPrint();

    const fname = `save_dumps/${pName}_temp_${nTurn}.json`;
    const json = newGame.toJSON();
    json.nTurns = nTurn;
    json.driver = driver.toJSON();
    const jsonStr = JSON.stringify(json);
    console.log(`Saving/restoring game to ${fname}`);
    fs.writeFileSync(fname, jsonStr);
    const jsonParsed = JSON.parse(jsonStr);

    const fromJSON = new RG.Game.FromJSON();
    newGame = fromJSON.createGame(jsonParsed);
    driver = PlayerDriver.fromJSON(jsonParsed.driver);
    driver.setPlayer(newGame.getPlayer());

    return [newGame, driver];
}

function usage() {
    optDefs.forEach(opt => {
        const str = JSON.stringify(opt);
        console.log(str);
    });
    process.exit(0);
}
<|endoftext|>


<commit_before>/*globals
canvas, context,
points,
update, draw, init,
rect, drawRect,
SpatialGrid*/
(function( window, document, undefined ) {
  'use strict';

  SpatialGrid.prototype.draw = function( ctx ) {
    var cellWidth  = this.cellWidth,
        cellHeight = this.cellHeight;

    var x, y;
    for ( var i = 0, il = this.count * this.count; i < il; i++ ) {
      x = i % this.count;
      y = Math.floor( i / this.count );

      ctx.rect( x * cellWidth, y * cellHeight, cellWidth, cellHeight );
    }
  };

  var potentials = [],
      actuals    = [];

  var usingGrid = true,
      drawingGrid = false;

  var grid = new SpatialGrid( 0, 0, canvas.width, canvas.height, 16 );

  function updateGrid() {
    update();

    if ( usingGrid ) {
      grid.clear();
      grid.insertAll( points );

      potentials = grid.retrieve( rect.x, rect.y, rect.width, rect.height )
        .reduce(function( array, points ) {
          return array.concat( points );
        }, [] );
    } else {
      potentials = points;
    }

    actuals = potentials.filter(function( point ) {
      return rect.contains( point.x, point.y );
    });
  }

  function drawGrid( ctx ) {
    draw( ctx );

    // Grid.
    if ( usingGrid && drawingGrid ) {
      ctx.beginPath();
      grid.draw( ctx );
      ctx.lineWidth = 1;
      ctx.strokeStyle = 'red';
      ctx.stroke();
    }

    drawRect( ctx );

    // Potentials.
    ctx.font = '12pt monospace';
    ctx.fillStyle = 'yellow';
    ctx.fillText( 'potential: ' + potentials.length, 25, 60 );

    if ( usingGrid ) {
      ctx.beginPath();
      potentials.forEach(function( point ) {
        point.draw( ctx );
      });
      ctx.fill();
    }

    // Actuals.
    ctx.beginPath();
    actuals.forEach(function( point ) {
      point.draw( ctx );
    });

    ctx.fillStyle = '#0f0';
    ctx.fill();

    ctx.fillText( 'actual: ' + actuals.length, 25, 30 );
  }

  function tick() {
    updateGrid();
    drawGrid( context );
    window.requestAnimationFrame( tick );
  }

  document.getElementById( 'toggleGrid' )
    .addEventListener( 'click', function() {
      usingGrid = !usingGrid;
    });

  document.getElementById( 'toggleGridVisibility' )
    .addEventListener( 'click', function() {
      drawingGrid = !drawingGrid;
    });

  init();
  tick();
}) ( window, document );
<commit_msg>spatial-grid: Draw cells intersecting with a bounding box.<commit_after>/*globals
canvas, context,
points,
update, draw, init,
rect, drawRect,
SpatialGrid*/
(function( window, document, undefined ) {
  'use strict';

  SpatialGrid.prototype.draw = function( ctx ) {
    var cellWidth  = this.cellWidth,
        cellHeight = this.cellHeight;

    var x, y;
    for ( var i = 0, il = this.count * this.count; i < il; i++ ) {
      x = i % this.count;
      y = Math.floor( i / this.count );

      ctx.rect( x * cellWidth, y * cellHeight, cellWidth, cellHeight );
    }
  };

  /**
   * Draws the cells intersecting the given bounding box.
   */
  SpatialGrid.prototype.drawIntersection = function( ctx, x, y, width, height ) {
    var xminIndex = this.xIndexOf( x ),
        yminIndex = this.yIndexOf( y ),
        xmaxIndex = this.xIndexOf( x + width ),
        ymaxIndex = this.yIndexOf( y + height );

    var xmin = xminIndex * this.cellWidth,
        ymin = yminIndex * this.cellHeight,
        xmax = ( xmaxIndex + 1 ) * this.cellWidth,
        ymax = ( ymaxIndex + 1 ) * this.cellHeight;

    ctx.rect( xmin, ymin, xmax - xmin, ymax - ymin );
  };

  var potentials = [],
      actuals    = [];

  var usingGrid = true,
      drawingGrid = false;

  var grid = new SpatialGrid( 0, 0, canvas.width, canvas.height, 16 );

  function updateGrid() {
    update();

    if ( usingGrid ) {
      grid.clear();
      grid.insertAll( points );

      potentials = grid.retrieve( rect.x, rect.y, rect.width, rect.height )
        .reduce(function( array, points ) {
          return array.concat( points );
        }, [] );
    } else {
      potentials = points;
    }

    actuals = potentials.filter(function( point ) {
      return rect.contains( point.x, point.y );
    });
  }

  function drawGrid( ctx ) {
    draw( ctx );

    // Grid.
    if ( usingGrid && drawingGrid ) {
      ctx.beginPath();
      grid.draw( ctx );
      ctx.lineWidth = 1;
      ctx.strokeStyle = 'red';
      ctx.stroke();

      // Intersection.
      ctx.beginPath();
      grid.drawIntersection( ctx, rect.x, rect.y, rect.width, rect.height );
      ctx.fillStyle = 'rgba(255, 255, 255, 0.25)';
      ctx.fill();
    }

    drawRect( ctx );

    // Potentials.
    ctx.font = '12pt monospace';
    ctx.fillStyle = 'yellow';
    ctx.fillText( 'potential: ' + potentials.length, 25, 60 );

    if ( usingGrid ) {
      ctx.beginPath();
      potentials.forEach(function( point ) {
        point.draw( ctx );
      });
      ctx.fill();
    }

    // Actuals.
    ctx.beginPath();
    actuals.forEach(function( point ) {
      point.draw( ctx );
    });

    ctx.fillStyle = '#0f0';
    ctx.fill();

    ctx.fillText( 'actual: ' + actuals.length, 25, 30 );
  }

  function tick() {
    updateGrid();
    drawGrid( context );
    window.requestAnimationFrame( tick );
  }

  document.getElementById( 'toggleGrid' )
    .addEventListener( 'click', function() {
      usingGrid = !usingGrid;
    });

  document.getElementById( 'toggleGridVisibility' )
    .addEventListener( 'click', function() {
      drawingGrid = !drawingGrid;
    });

  init();
  tick();
}) ( window, document );
<|endoftext|>


<commit_before>import fs from 'fs';
import path from 'path';
import t from 'tcomb';
import parse from './parse';
import template from './template';
import debug from 'debug';
import upperFirst from 'lodash/upperFirst';
import camelCase from 'lodash/camelCase';

debug.enable('brc:*');
const log = debug('brc:generate-readmes');

const checkDocs = (json, fileName) => {
  log('Checking extracted docs have necessary keys...');
  if (!json.name) {
    throw new Error(`Missing name for file ${fileName}`);
  }
  if (!json.description) {
    throw new Error(`Missing description for file ${fileName}.`);
  }

};

const generateReadMe = (dir, fileName) => {
  const filePath = path.join(dir, fileName);
  log(`Extracting docs from ${filePath}`);
  const json = parse(filePath);
  log(`Extracted: ${t.stringify(json)}`);
  checkDocs(json, fileName);
  const readMeContent = template(json);
  const readMeFilePath = path.join(dir, 'README.md');
  log(`Writing README.md for file '${fileName}'`);
  try {
    fs.writeFileSync(readMeFilePath, readMeContent, 'utf-8');
    log(`README.md for ${fileName} created at ${readMeFilePath}!`);
  } catch (e) {
    log(`Error creating ${fileName} README.md: ${t.stringify(e.getMessage())}`);
  }
};

const walkThroughDirs = (dir, parent, cb) => {
  if (fs.statSync(dir).isDirectory()) {
    log(`Walking through ${dir}`);
    fs.readdir(dir, (err, results = []) => {
      log(`${dir} contains: ${results.join('\n')}`);
      results
      .forEach(r => {
        const pathToCheck = path.join(dir, r);
        log(`Checking path: ${pathToCheck}`);
        if (fs.statSync(pathToCheck).isFile() && r === `${upperFirst(camelCase(parent))}.js`) {
          log(`${r} is a file!`);
          cb(dir, r);
        } else if (fs.statSync(pathToCheck).isDirectory()) {
          log(`${r} is a dir!`);
          walkThroughDirs(path.join(dir, r), r, cb);
        }
      });
    });
  } else {
    log(`${dir} is not a dir!`);
  }
};

const walkThroughFirstLevelDirs = (dir, cb) => {
  if (fs.statSync(dir).isDirectory()) {
    log(`Walking through "${dir}"`);

    const results = fs.readdirSync(dir);

    log(`"${dir}" contains: ${results.join('\n')}`);

    results.forEach(r => {
      const pathToCheck = path.join(dir, r);
      log(`Checking path: ${pathToCheck}`);
      if (fs.statSync(pathToCheck).isDirectory()) {
        const mainFileName = `${upperFirst(camelCase(r))}.js`;

        const mainFilePath = path.join(dir, r, mainFileName);

        let isFile = null;
        try {
          isFile = fs.statSync(mainFilePath).isFile();
        } catch (e) {
          log(e);
        }

        if (isFile) {
          log(`"${r}" contains a main file: "${mainFileName}"!`);
          cb(pathToCheck, mainFileName);
        } else {
          log(`"${r}" does not contain a main file...`);
        }
      } else {
        log(`"${r}" is a file: ignoring!`);
      }
    });
  } else {
    log(`"${dir}" is not a directory!`);
  }
};

const _root = process.argv[2] || 'src';

walkThroughFirstLevelDirs(path.resolve(_root), generateReadMe);
<commit_msg>silence spammy logs<commit_after>import fs from 'fs';
import path from 'path';
import t from 'tcomb';
import parse from './parse';
import template from './template';
import debug from 'debug';
import upperFirst from 'lodash/upperFirst';
import camelCase from 'lodash/camelCase';

debug.enable('brc:*');
const log = () => {};// debug('brc:generate-readmes');

const checkDocs = (json, fileName) => {
  log('Checking extracted docs have necessary keys...');
  if (!json.name) {
    throw new Error(`Missing name for file ${fileName}`);
  }
  if (!json.description) {
    throw new Error(`Missing description for file ${fileName}.`);
  }

};

const generateReadMe = (dir, fileName) => {
  const filePath = path.join(dir, fileName);
  log(`Extracting docs from ${filePath}`);
  const json = parse(filePath);
  log(`Extracted: ${t.stringify(json)}`);
  checkDocs(json, fileName);
  const readMeContent = template(json);
  const readMeFilePath = path.join(dir, 'README.md');
  log(`Writing README.md for file '${fileName}'`);
  try {
    fs.writeFileSync(readMeFilePath, readMeContent, 'utf-8');
    log(`README.md for ${fileName} created at ${readMeFilePath}!`);
  } catch (e) {
    log(`Error creating ${fileName} README.md: ${t.stringify(e.getMessage())}`);
  }
};

const walkThroughDirs = (dir, parent, cb) => {
  if (fs.statSync(dir).isDirectory()) {
    log(`Walking through ${dir}`);
    fs.readdir(dir, (err, results = []) => {
      log(`${dir} contains: ${results.join('\n')}`);
      results
      .forEach(r => {
        const pathToCheck = path.join(dir, r);
        log(`Checking path: ${pathToCheck}`);
        if (fs.statSync(pathToCheck).isFile() && r === `${upperFirst(camelCase(parent))}.js`) {
          log(`${r} is a file!`);
          cb(dir, r);
        } else if (fs.statSync(pathToCheck).isDirectory()) {
          log(`${r} is a dir!`);
          walkThroughDirs(path.join(dir, r), r, cb);
        }
      });
    });
  } else {
    log(`${dir} is not a dir!`);
  }
};

const walkThroughFirstLevelDirs = (dir, cb) => {
  if (fs.statSync(dir).isDirectory()) {
    log(`Walking through "${dir}"`);

    const results = fs.readdirSync(dir);

    log(`"${dir}" contains: ${results.join('\n')}`);

    results.forEach(r => {
      const pathToCheck = path.join(dir, r);
      log(`Checking path: ${pathToCheck}`);
      if (fs.statSync(pathToCheck).isDirectory()) {
        const mainFileName = `${upperFirst(camelCase(r))}.js`;

        const mainFilePath = path.join(dir, r, mainFileName);

        let isFile = null;
        try {
          isFile = fs.statSync(mainFilePath).isFile();
        } catch (e) {
          log(e);
        }

        if (isFile) {
          log(`"${r}" contains a main file: "${mainFileName}"!`);
          cb(pathToCheck, mainFileName);
        } else {
          log(`"${r}" does not contain a main file...`);
        }
      } else {
        log(`"${r}" is a file: ignoring!`);
      }
    });
  } else {
    log(`"${dir}" is not a directory!`);
  }
};

const _root = process.argv[2] || 'src';

walkThroughFirstLevelDirs(path.resolve(_root), generateReadMe);
<|endoftext|>


<commit_before>// Check various bits of the HELO string
var net_utils = require('./net_utils');

var checks = [
    'init',               // config loading, multiplicity detection
    'no_dot',             // HELO has no "dot" in hostname
    'match_re',           // List of regexps
    'bare_ip',            // HELO is bare IP (vs required Address Literal)
    'dynamic',            // HELO looks dynamic (dsl|dialup|etc...)
    'big_company',        // Well known HELOs that must match rdns
    'literal_mismatch',   // IP literal that doesn't match remote IP
    'valid_tld',          // hostname has a valid TLD
    'rdns_match',         // hostname matches rDNS
    'mismatch',           // hostname differs between invocations
];

exports.register = function () {
    var plugin = this;

    for (var i=0; i < checks.length; i++) {
        var hook = checks[i];
        plugin.register_hook('helo', hook);
        plugin.register_hook('ehlo', hook);
    }
};

exports.hook_connect = function (next, connection) {
    var plugin = this;
    plugin.cfg = plugin.config.get('helo.checks.ini', {
        booleans: [
            '+check.no_dot',
            '+check.match_re',
            '+check.bare_ip',
            '+check.dynamic',
            '+check.big_company',
            '+check.valid_tld',
            '+check.rdns_match',
            '+check.mismatch',

            '+reject.no_dot',
            '+reject.match_re',
            '+reject.bare_ip',
            '+reject.dynamic',
            '+reject.big_company',
            '-reject.valid_tld',
            '-reject.literal_mismatch',
            '-reject.rdns_match',
            '-reject.mismatch',

            '+skip.private_ip',
            '+skip.whitelist',
            '+skip.relaying',
        ],
    });

    // backwards compatible with old config file
    if (plugin.cfg.check_no_dot !== undefined) {
        plugin.cfg.check.no_dot = plugin.cfg.check_no_dot ? true : false;
    }
    if (plugin.cfg.check_dynamic !== undefined) {
        plugin.cfg.check.dynamic = plugin.cfg.check_dynamic ? true : false;
    }
    if (plugin.cfg.check_raw_ip !== undefined) {
        plugin.cfg.check.bare_ip = plugin.cfg.check_raw_ip ? true : false;
    }

    return next();
};

exports.init = function (next, connection, helo) {
    var plugin = this;

    var hc = connection.results.get('helo.checks');
    if (!hc) {     // first HELO result
        connection.results.add(plugin, {helo_host: helo});
        return next();
    }

    // we've been here before
    connection.results.add(plugin, {multi: true});

    return next();
};

exports.should_skip = function (connection, test_name) {
    var plugin = this;

    var hc = connection.results.get('helo.checks');
    if (hc && hc.multi && test_name !== 'mismatch') return true;

    if (!plugin.cfg.check[test_name]) {
        connection.results.add(plugin, {skip: test_name + '(config)'});
        return true;
    }

    if (plugin.cfg.skip.relaying && connection.relaying) {
        connection.results.add(plugin, {skip: test_name + '(relay)'});
        return true;
    }

    if (plugin.cfg.skip.private_ip && net_utils.is_rfc1918(connection.remote_ip)) {
        connection.results.add(plugin, {skip: test_name + '(private)'});
        return true;
    }

    return false;
};

exports.mismatch = function (next, connection, helo) {
    var plugin = this;

    if (plugin.should_skip(connection, 'mismatch')) return next();

    var prev_helo = connection.results.get('helo.checks').helo_host;
    if (!prev_helo) {
        connection.results.add(plugin, {skip: 'mismatch(1st)'});
        return next();
    }

    if (prev_helo === helo) {
        connection.results.add(plugin, {pass: 'mismatch'});
        return next();
    }

    var msg = 'mismatch(' + prev_helo + ' / ' + helo + ')';
    connection.results.add(plugin, {fail: msg});
    if (plugin.cfg.reject.mismatch) return next(DENY, 'HELO host ' + msg);

    return next();
};

exports.no_dot = function (next, connection, helo) {
    var plugin = this;

    if (plugin.should_skip(connection, 'no_dot')) return next();

    if (!/\./.test(helo)) {
        connection.results.add(plugin, {fail: 'no_dot'});
        if (plugin.cfg.reject.no_dot) return next(DENY, 'HELO must have a dot');
    }
    else {
        connection.results.add(plugin, {pass: 'no_dot'});
    }

    return next();
};

exports.match_re = function (next, connection, helo) {
    var plugin = this;

    if (plugin.should_skip(connection, 'match_re')) return next();

    var regexps = plugin.config.get('helo.checks.regexps', 'list');

    var fail=0;
    for (var i=0; i < regexps.length; i++) {
        var re = new RegExp('^' + regexps[i] + '$');
        if (re.test(helo)) {
            connection.results.add(plugin, {fail: 'match_re(' + regexps[i] + ')'});
            fail++;
        }
    }
    if (fail && plugin.cfg.reject.match_re) return next(DENY, "BAD HELO");
    if (!fail) connection.results.add(plugin, {pass: 'match_re'});
    return next();
};

exports.rdns_match = function (next, connection, helo) {
    var plugin = this;

    if (plugin.should_skip(connection, 'rdns_match')) return next();

    if (!helo) {
        connection.results.add(plugin, {fail: 'rdns_match(empty)'});
        return next();
    }

    if (helo.match(/^\[(?:[0-9\.]+)\]$/)) {
        connection.results.add(plugin, {fail: 'rdns_match(literal)'});
        return next();
    }

    var r_host = connection.remote_host;
    if (r_host && helo === r_host) {
        connection.results.add(plugin, {pass: 'rdns_match(exact)'});
        return next();
    }

    if (net_utils.get_organizational_domain(r_host) ===
        net_utils.get_organizational_domain(helo)) {
        connection.results.add(plugin, {pass: 'rdns_match(org_dom)'});
        return next();
    }

    connection.results.add(plugin, {fail: 'rdns_match'});
    if (plugin.cfg.reject.rdns_match) {
        return next(DENY, 'HELO host does not match rDNS');
    }
    return next();
};

exports.bare_ip = function (next, connection, helo) {
    var plugin = this;

    if (plugin.should_skip(connection, 'bare_ip')) return next();

    // RFC 2821, 4.1.1.1  Address literals must be in brackets
    // RAW IPs must be formatted: "[1.2.3.4]" not "1.2.3.4" in HELO
    if(/^\d+\.\d+\.\d+\.\d+$/.test(helo)) {
        connection.results.add(plugin, {fail: 'bare_ip(invalid literal)'});
        if (plugin.cfg.reject.bare_ip) return next(DENY, "Invalid address format in HELO");
        return next();
    }

    connection.results.add(plugin, {pass: 'bare_ip'});
    return next();
};

exports.dynamic = function (next, connection, helo) {
    var plugin = this;

    if (plugin.should_skip(connection, 'dynamic')) return next();

    // Skip if no dots or an IP literal or address
    if (!/\./.test(helo)) {
        connection.results.add(plugin, {skip: 'dynamic(no dots)'});
        return next();
    }

    if (/^\[?\d+\.\d+\.\d+\.\d+\]?$/.test(helo)) {
        connection.results.add(plugin, {skip: 'dynamic(literal)'});
        return next();
    }

    if (net_utils.is_ip_in_str(connection.remote_ip, helo)) {
        connection.results.add(plugin, {fail: 'dynamic'});
        if (plugin.cfg.reject.dynamic) return next(DENY, 'HELO is dynamic');
        return next();
    }

    connection.results.add(plugin, {pass: 'dynamic'});
    return next();
};

exports.big_company = function (next, connection, helo) {
    var plugin = this;

    if (plugin.should_skip(connection, 'big_company')) return next();

    var rdns = connection.remote_host;
    if (!rdns || rdns === 'Unknown' || rdns === 'DNSERROR') {
        connection.results.add(plugin, {fail: 'big_co(rDNS)'});
        if (plugin.cfg.reject.big_company) {
            return next(DENY, "Big company w/o rDNS? Unlikely.");
        }
        return next();
    }

    if (!plugin.cfg.bigco) {
        connection.results.add(plugin, {err: 'big_co(config missing)'});
        return next();
    }
    if (!plugin.cfg.bigco[helo]) {
        connection.results.add(plugin, {skip: 'big_co(not)'});
        return next();
    }

    var allowed_rdns = plugin.cfg.bigco[helo].split(/,/);
    for (var i=0; i < allowed_rdns.length; i++) {
        var re = new RegExp(allowed_rdns[i].replace(/\./g, '\\.') + '$');
        if (re.test(rdns)) {
            connection.results.add(plugin, {pass: 'big_co'});
            return next();
        }
    }

    connection.results.add(plugin, {fail: 'big_co'});
    if (plugin.cfg.reject.big_company) {
        return next(DENY, "You are not who you say you are");
    }
    return next();
};

exports.literal_mismatch = function (next, connection, helo) {
    var plugin = this;

    if (plugin.should_skip(connection, 'literal_mismatch')) return next();

    var literal = /^\[(\d+\.\d+\.\d+\.\d+)\]$/.exec(helo);
    if (!literal) {
        connection.results.add(plugin, {pass: 'literal_mismatch'});
        return next();
    }

    if (parseInt(plugin.cfg.check.literal_mismatch) === 2) {
        // Only match the /24
        if (literal[1].split(/\./).splice(0,3).join('.') !==
            connection.remote_ip.split(/\./).splice(0,3).join('.'))
        {
            connection.results.add(plugin, {fail: 'literal_mismatch'});
            if (plugin.cfg.reject.literal_mismatch) {
                return next(DENY, 'HELO IP literal not in the same /24 as your IP address');
            }
            return next();
        }
        connection.results.add(plugin, {pass: 'literal_mismatch'});
        return next();
    }

    if (literal[1] !== connection.remote_ip) {
        connection.results.add(plugin, {pass: 'literal_mismatch'});
        if (plugin.cfg.reject.literal_mismatch) return next(DENY, 'HELO IP literal does not match your IP address');
        return next();
    }

    connection.results.add(plugin, {pass: 'literal_mismatch'});
    return next();
};

exports.valid_tld = function (next, connection, helo) {
    var plugin = this;

    if (plugin.should_skip(connection, 'valid_tld')) return next();

    if (/^\[\d+\.\d+\.\d+\.\d+\]$/.test(helo)) {
        connection.results.add(plugin, {skip: 'valid_tld(literal)'});
        return next();
    }

    var tld = (helo.split(/\./).reverse())[0];
    if (net_utils.is_public_suffix(tld)) {
        connection.results.add(plugin, {pass: 'valid_tld'});
        return next();
    }

    connection.results.add(plugin, {fail: 'valid_tld('+tld+')'});
    if (plugin.cfg.reject.valid_tld) {
        return next(DENY, "HELO must have a valid TLD");
    }
    return next();
};
<commit_msg>helo: added emit_log<commit_after>// Check various bits of the HELO string
var net_utils = require('./net_utils');

var checks = [
    'init',               // config loading, multiplicity detection
    'no_dot',             // HELO has no "dot" in hostname
    'match_re',           // List of regexps
    'bare_ip',            // HELO is bare IP (vs required Address Literal)
    'dynamic',            // HELO looks dynamic (dsl|dialup|etc...)
    'big_company',        // Well known HELOs that must match rdns
    'literal_mismatch',   // IP literal that doesn't match remote IP
    'valid_tld',          // hostname has a valid TLD
    'rdns_match',         // hostname matches rDNS
    'mismatch',           // hostname differs between invocations
    'emit_log',           // emit a loginfo summary
];

exports.register = function () {
    var plugin = this;

    for (var i=0; i < checks.length; i++) {
        var hook = checks[i];
        plugin.register_hook('helo', hook);
        plugin.register_hook('ehlo', hook);
    }
};

exports.hook_connect = function (next, connection) {
    var plugin = this;
    plugin.cfg = plugin.config.get('helo.checks.ini', {
        booleans: [
            '+check.no_dot',
            '+check.match_re',
            '+check.bare_ip',
            '+check.dynamic',
            '+check.big_company',
            '+check.valid_tld',
            '+check.rdns_match',
            '+check.mismatch',

            '+reject.no_dot',
            '+reject.match_re',
            '+reject.bare_ip',
            '+reject.dynamic',
            '+reject.big_company',
            '-reject.valid_tld',
            '-reject.literal_mismatch',
            '-reject.rdns_match',
            '-reject.mismatch',

            '+skip.private_ip',
            '+skip.whitelist',
            '+skip.relaying',
        ],
    });

    // backwards compatible with old config file
    if (plugin.cfg.check_no_dot !== undefined) {
        plugin.cfg.check.no_dot = plugin.cfg.check_no_dot ? true : false;
    }
    if (plugin.cfg.check_dynamic !== undefined) {
        plugin.cfg.check.dynamic = plugin.cfg.check_dynamic ? true : false;
    }
    if (plugin.cfg.check_raw_ip !== undefined) {
        plugin.cfg.check.bare_ip = plugin.cfg.check_raw_ip ? true : false;
    }

    return next();
};

exports.init = function (next, connection, helo) {
    var plugin = this;

    var hc = connection.results.get('helo.checks');
    if (!hc) {     // first HELO result
        connection.results.add(plugin, {helo_host: helo});
        return next();
    }

    // we've been here before
    connection.results.add(plugin, {multi: true});

    return next();
};

exports.should_skip = function (connection, test_name) {
    var plugin = this;

    var hc = connection.results.get('helo.checks');
    if (hc && hc.multi && test_name !== 'mismatch') return true;

    if (!plugin.cfg.check[test_name]) {
        connection.results.add(plugin, {skip: test_name + '(config)'});
        return true;
    }

    if (plugin.cfg.skip.relaying && connection.relaying) {
        connection.results.add(plugin, {skip: test_name + '(relay)'});
        return true;
    }

    if (plugin.cfg.skip.private_ip && net_utils.is_rfc1918(connection.remote_ip)) {
        connection.results.add(plugin, {skip: test_name + '(private)'});
        return true;
    }

    return false;
};

exports.mismatch = function (next, connection, helo) {
    var plugin = this;

    if (plugin.should_skip(connection, 'mismatch')) return next();

    var prev_helo = connection.results.get('helo.checks').helo_host;
    if (!prev_helo) {
        connection.results.add(plugin, {skip: 'mismatch(1st)'});
        return next();
    }

    if (prev_helo === helo) {
        connection.results.add(plugin, {pass: 'mismatch'});
        return next();
    }

    var msg = 'mismatch(' + prev_helo + ' / ' + helo + ')';
    connection.results.add(plugin, {fail: msg});
    if (plugin.cfg.reject.mismatch) return next(DENY, 'HELO host ' + msg);

    return next();
};

exports.no_dot = function (next, connection, helo) {
    var plugin = this;

    if (plugin.should_skip(connection, 'no_dot')) return next();

    if (!/\./.test(helo)) {
        connection.results.add(plugin, {fail: 'no_dot'});
        if (plugin.cfg.reject.no_dot) return next(DENY, 'HELO must have a dot');
    }
    else {
        connection.results.add(plugin, {pass: 'no_dot'});
    }

    return next();
};

exports.match_re = function (next, connection, helo) {
    var plugin = this;

    if (plugin.should_skip(connection, 'match_re')) return next();

    var regexps = plugin.config.get('helo.checks.regexps', 'list');

    var fail=0;
    for (var i=0; i < regexps.length; i++) {
        var re = new RegExp('^' + regexps[i] + '$');
        if (re.test(helo)) {
            connection.results.add(plugin, {fail: 'match_re(' + regexps[i] + ')'});
            fail++;
        }
    }
    if (fail && plugin.cfg.reject.match_re) return next(DENY, "BAD HELO");
    if (!fail) connection.results.add(plugin, {pass: 'match_re'});
    return next();
};

exports.rdns_match = function (next, connection, helo) {
    var plugin = this;

    if (plugin.should_skip(connection, 'rdns_match')) return next();

    if (!helo) {
        connection.results.add(plugin, {fail: 'rdns_match(empty)'});
        return next();
    }

    if (helo.match(/^\[(?:[0-9\.]+)\]$/)) {
        connection.results.add(plugin, {fail: 'rdns_match(literal)'});
        return next();
    }

    var r_host = connection.remote_host;
    if (r_host && helo === r_host) {
        connection.results.add(plugin, {pass: 'rdns_match(exact)'});
        return next();
    }

    if (net_utils.get_organizational_domain(r_host) ===
        net_utils.get_organizational_domain(helo)) {
        connection.results.add(plugin, {pass: 'rdns_match(org_dom)'});
        return next();
    }

    connection.results.add(plugin, {fail: 'rdns_match'});
    if (plugin.cfg.reject.rdns_match) {
        return next(DENY, 'HELO host does not match rDNS');
    }
    return next();
};

exports.bare_ip = function (next, connection, helo) {
    var plugin = this;

    if (plugin.should_skip(connection, 'bare_ip')) return next();

    // RFC 2821, 4.1.1.1  Address literals must be in brackets
    // RAW IPs must be formatted: "[1.2.3.4]" not "1.2.3.4" in HELO
    if(/^\d+\.\d+\.\d+\.\d+$/.test(helo)) {
        connection.results.add(plugin, {fail: 'bare_ip(invalid literal)'});
        if (plugin.cfg.reject.bare_ip) return next(DENY, "Invalid address format in HELO");
        return next();
    }

    connection.results.add(plugin, {pass: 'bare_ip'});
    return next();
};

exports.dynamic = function (next, connection, helo) {
    var plugin = this;

    if (plugin.should_skip(connection, 'dynamic')) return next();

    // Skip if no dots or an IP literal or address
    if (!/\./.test(helo)) {
        connection.results.add(plugin, {skip: 'dynamic(no dots)'});
        return next();
    }

    if (/^\[?\d+\.\d+\.\d+\.\d+\]?$/.test(helo)) {
        connection.results.add(plugin, {skip: 'dynamic(literal)'});
        return next();
    }

    if (net_utils.is_ip_in_str(connection.remote_ip, helo)) {
        connection.results.add(plugin, {fail: 'dynamic'});
        if (plugin.cfg.reject.dynamic) return next(DENY, 'HELO is dynamic');
        return next();
    }

    connection.results.add(plugin, {pass: 'dynamic'});
    return next();
};

exports.big_company = function (next, connection, helo) {
    var plugin = this;

    if (plugin.should_skip(connection, 'big_company')) return next();

    var rdns = connection.remote_host;
    if (!rdns || rdns === 'Unknown' || rdns === 'DNSERROR') {
        connection.results.add(plugin, {fail: 'big_co(rDNS)'});
        if (plugin.cfg.reject.big_company) {
            return next(DENY, "Big company w/o rDNS? Unlikely.");
        }
        return next();
    }

    if (!plugin.cfg.bigco) {
        connection.results.add(plugin, {err: 'big_co(config missing)'});
        return next();
    }

    if (!plugin.cfg.bigco[helo]) {
        connection.results.add(plugin, {pass: 'big_co(not)'});
        return next();
    }

    var allowed_rdns = plugin.cfg.bigco[helo].split(/,/);
    for (var i=0; i < allowed_rdns.length; i++) {
        var re = new RegExp(allowed_rdns[i].replace(/\./g, '\\.') + '$');
        if (re.test(rdns)) {
            connection.results.add(plugin, {pass: 'big_co'});
            return next();
        }
    }

    connection.results.add(plugin, {fail: 'big_co'});
    if (plugin.cfg.reject.big_company) {
        return next(DENY, "You are not who you say you are");
    }
    return next();
};

exports.literal_mismatch = function (next, connection, helo) {
    var plugin = this;

    if (plugin.should_skip(connection, 'literal_mismatch')) return next();

    var literal = /^\[(\d+\.\d+\.\d+\.\d+)\]$/.exec(helo);
    if (!literal) {
        connection.results.add(plugin, {pass: 'literal_mismatch'});
        return next();
    }

    if (parseInt(plugin.cfg.check.literal_mismatch) === 2) {
        // Only match the /24
        if (literal[1].split(/\./).splice(0,3).join('.') !==
            connection.remote_ip.split(/\./).splice(0,3).join('.'))
        {
            connection.results.add(plugin, {fail: 'literal_mismatch'});
            if (plugin.cfg.reject.literal_mismatch) {
                return next(DENY, 'HELO IP literal not in the same /24 as your IP address');
            }
            return next();
        }
        connection.results.add(plugin, {pass: 'literal_mismatch'});
        return next();
    }

    if (literal[1] !== connection.remote_ip) {
        connection.results.add(plugin, {pass: 'literal_mismatch'});
        if (plugin.cfg.reject.literal_mismatch) return next(DENY, 'HELO IP literal does not match your IP address');
        return next();
    }

    connection.results.add(plugin, {pass: 'literal_mismatch'});
    return next();
};

exports.valid_tld = function (next, connection, helo) {
    var plugin = this;

    if (plugin.should_skip(connection, 'valid_tld')) return next();

    if (/^\[\d+\.\d+\.\d+\.\d+\]$/.test(helo)) {
        connection.results.add(plugin, {skip: 'valid_tld(literal)'});
        return next();
    }

    var tld = (helo.split(/\./).reverse())[0];
    if (net_utils.is_public_suffix(tld)) {
        connection.results.add(plugin, {pass: 'valid_tld'});
        return next();
    }

    connection.results.add(plugin, {fail: 'valid_tld('+tld+')'});
    if (plugin.cfg.reject.valid_tld) {
        return next(DENY, "HELO must have a valid TLD");
    }
    return next();
};

exports.emit_log = function (next, connection, helo) {
    var plugin = this;
    // Spits out an INFO log entry. Default looks like this:
    // [helo.checks] helo_host: [182.212.17.35], fail:big_co(rDNS) rdns_match(literal), pass:no_dot, match_re, bare_ip, literal_mismatch, mismatch, skip:dynamic(literal), valid_tld(literal)
    //
    // Although sometimes useful, that's a bit verbose. I find that I'm rarely
    // interested in the passes, the helo_host is already logged elsewhere,
    // and so I set this in config/results.ini:
    //
    // [helo.checks]
    // order=fail,pass,msg,err,skip
    // hide=helo_host,multi,pass
    //
    // Thus set, my log entries look like this:
    //
    // [UUID] [helo.checks] fail:rdns_match
    // [UUID] [helo.checks]
    // [UUID] [helo.checks] fail:dynamic
    connection.loginfo(plugin, connection.results.collate(plugin));
    return next();
};
<|endoftext|>


<commit_before>import consts from '../constants';
import request from 'request-promise';

var githubClientId;
var githubSecret;

export default {
  getAccessToken(code) {
    return request.post({
      uri: consts.github.OAUTH_URL + '/access_token',
      headers: {
        'Accept': 'application/json'
      },
      body: {
        client_id: process.env.GITHUB_CLIENT_ID || githubClientId,
        client_secret: process.env.GITHUB_SECRET || githubSecret,
        code: code
      },
      json: true
    });
  },
  getClientId() {
    return process.env.GITHUB_CLIENT_ID || githubClientId;
  },
  getLoggedUser(token) {
    return request.get({
      uri: consts.github.API_URL + '/user',
      headers: {
        'Authorization': 'token ' + token,
        'User-Agent': 'metavrse.io'
      },
      json: true
    });
  },
  setGithubApp(clientId, secret) {
    if(process.env.GITHUB_CLIENT_ID || process.env.GITHUB_SECRET) {
      throw new Error('Already using info from env variables');
    }

    if(githubClientId || githubSecret) {
      throw new Error('Github app already set');
    }

    githubClientId = clientId;
    githubSecret = secret;
  }
};
<commit_msg>defining gihub app env override as overrides of env variables<commit_after>import consts from '../constants';
import request from 'request-promise';

export default {
  getAccessToken(code) {
    return request.post({
      uri: consts.github.OAUTH_URL + '/access_token',
      headers: {
        'Accept': 'application/json'
      },
      body: {
        client_id: process.env.GITHUB_CLIENT_ID,
        client_secret: process.env.GITHUB_SECRET,
        code: code
      },
      json: true
    });
  },
  getClientId() {
    return process.env.GITHUB_CLIENT_ID;
  },
  getLoggedUser(token) {
    return request.get({
      uri: consts.github.API_URL + '/user',
      headers: {
        'Authorization': 'token ' + token,
        'User-Agent': 'metavrse.io'
      },
      json: true
    });
  },
  setGithubApp(clientId, secret) {
    if(process.env.GITHUB_CLIENT_ID || process.env.GITHUB_SECRET) {
      throw new Error('Github app already set');
    }

    process.env.GITHUB_CLIENT_ID = clientId;
    process.env.GITHUB_SECRET = secret;
  }
};
<|endoftext|>


<commit_before>/* vim:set ts=2 sw=2 sts=2 expandtab */
/*jshint asi: true undef: true es5: true node: true browser: true devel: true
         forin: true latedef: false globalstrict: true */

'use strict';

var create = Object.create

var Method = require('method')
var Box = require('./box')

var unbind = Function.call.bind(Function.bind, Function.call)

// Define a shortcut for `Array.prototype.slice.call`.
var slice = Array.slice || unbind(Array.prototype.slice)

var end = Box('end of the sequence')
exports.end = end

var accumulated = Box('Indicator that source has being accumulateed')
exports.accumulated = accumulated

var error = Box('error')
exports.error = error

var accumulate = Method(function(self, next, start) {
  next(end(), next(self, start))
})
exports.accumulate = accumulate

// Implement accumulation for undefined and null values.
// Reducing/accumulating a null value will pass the initial start value to
// the accumulating function, then end.
function accumulateEmpty(_, f, start) { f(end(), start) }
accumulate.define(undefined, accumulateEmpty)
accumulate.define(null, accumulateEmpty)

// Implement accumulation method for native arrays, making arrays compatible
// with reducer methods and other reducible values.
accumulate.define(Array, function(array, next, initial) {
  var state = initial, index = 0, count = array.length
  while (index < count) {
    state = next(array[index++], state)
    if (state && state.is === accumulated) break
  }
  next(end(), state)
})

function transformer(source, transform) {
  return convert(source, function(self, next, initial) {
    return accumulate(transform(source), next, initial)
  })
}
exports.transformer = transformer

function convert(source, method) {
  /**
  Make a `source` object accumulatable by creating a prototypal copy and
  implementing the `accumulate` protocol on it with the given `method`.
  Returns an accumulatable/reducible object.
  **/
  return accumulate.implement(create(source), method)
}
exports.convert = convert

function transform(source, f) {
  return convert(source, function(self, next, initial) {
    accumulate(source, function(value, result) {
      return value && value.isBoxed ? next(value, result)
                                    : f(next, value, result)
    }, initial)
  })
}
exports.transform = transform

function filter(source, predicate) {
  /**
  Composes filtered version of given `source`, such that only items contained
  will be once on which `f(item)` was `true`.
  **/
  return transform(source, function(next, value, accumulated) {
    return predicate(value) ? next(value, accumulated) : accumulated
  })
}
exports.filter = filter

function map(source, f) {
  /**
  Composes version of given `source` where each item of source is mapped using `f`.
  **/
  return transform(source, function(next, value, accumulated) {
    return next(f(value), accumulated)
  })
}
exports.map = map

function take(source, n) {
  /**
  Composes version of given `source` containing only element up until `f(item)`
  was true.
  **/
  return transformer(source, function(source) {
    var count = n >= 0 ? n : Infinity
    return transform(source, function(next, value, result) {
      count = count - 1
      return count === 0 ? next(accumulated(), next(value, result)) :
             count > 0 ? next(value, result) :
                         next(accumulated(), result)
    })
  })
}
exports.take = take

function drop(source, n) {
  /**
  Reduces given `reducible` to first `n` items.
  **/
  return transformer(source, function(source) {
    var count = n >= 0 ? n : 1
    return transform(source, function(next, value, result) {
      return count -- > 0 ? result :
                            next(value, result)
    })
  })
}
exports.drop = drop

function takeWhile(source, predicate) {
  /**
  Composes version of given `source` containing only firs `n` items of it.
  **/
  return transform(source, function(next, value, state) {
    return predicate(value) ? next(value, state) :
                              next(accumulated(), state)
  })
}
exports.takeWhile = takeWhile

function dropWhile(source, predicate) {
  /**
  Reduces `reducible` further by dropping first `n`
  items to on which `f(item)` ruturns `true`
  **/
  return transformer(source, function(source) {
    var active = true
    return transform(source, function(next, value, result) {
      return active && (active = predicate(value)) ? result :
                                                     next(value, result)
    })
  })
}
exports.dropWhile = dropWhile

function tail(source) {
  return drop(source, 1)
}
exports.tail = tail

//console.log(into(skip(2, [ 1, 2, 3, 4, 5, 6 ])))
//

function append1(left, right) {
  return convert({}, function(self, next, initial) {
    accumulate(left, function(value, result) {
      return value && value.is === end ? accumulate(right, next, result) :
                                         next(value, result)
    }, initial)
  })
}
function append(left, right, rest) {
  /**
  Joins given `reducible`s into `reducible` of items
  of all the `reducibles` preserving an order of items.
  **/
  return rest ? slice(arguments, 1).reduce(append1, left) :
                append1(left, right)
}
exports.append = append

function capture(source, recover) {
  return convert(source, function(self, next, initial) {
    accumulate(source, function(value, result) {
      if (value && value.is === error) {
        accumulate(recover(value.value, result), next, result)
      } else {
        next(value, result)
      }
    }, initial)
  })
}
exports.capture = capture

function reductions(source, f, initial) {
  /**
  Returns `reducible` collection of the intermediate values of the reduction
  (as per reduce) of coll by `f`, starting with `initial` value.

  ## Example

  reductions([1 1 1 1], function(x, y) { return x + y }, 0)
  // => [ 1, 2, 3, 4 ]
  **/
  return convert(source, function(self, next, result) {
    var state = initial
    accumulate(source, function(value, result) {
      state = value && value.isBoxed ? next(value, result) : f(state, value)
      return next(state, result)
    }, result)
  })
}
exports.reductions = reductions

function adjust(source, f, initial) {
  /**
  Function takes reducible `source`, `f` transformer function and `initial`
  state. Adapted version of `source` is returned in result. `f` is called with
  each item of the source and curried state and is expected to return array
  of adjusted item and new state (which will be curried to next call) pair.

  ## Example

  var delimiterChar = ' '
  var data = [ 'Bite my', ' shiny, metal ', 'ass!' ]
  var chunks = adjust(data, function(chunk, prefix) {
    var text = prefix + chunk
    var delimiterIndex = text.lastIndexOf(delimiterChar)
    var splitIndex = delimiterIndex >= 0 ? delimiterIndex : text.length
    var capturedChunk = text.substr(0, splitIndex)
    var curriedChunk = text.substr(splitIndex + 1)
    return [ capturedChunk, curriedChunk ]
  }, '')
  var words = expand(chunks, function(chunk) {
    return chunk.split(delimiterChar)
  })

  // => [ 'Bite', 'my', 'shiny', 'metal', 'ass!' ]
  **/
  return convert(source, function(self, next, result) {
    var state = initial
    accumulate(source, function(value, result) {
      if (value && value.isBoxed) return next(value, result)
      var pair = f(value, state)
      state = pair[1]
      return next(pair[0], result)
    }, result)
  })
}
exports.adjust = adjust
<commit_msg>Add docstring for tail function<commit_after>/* vim:set ts=2 sw=2 sts=2 expandtab */
/*jshint asi: true undef: true es5: true node: true browser: true devel: true
         forin: true latedef: false globalstrict: true */

'use strict';

var create = Object.create

var Method = require('method')
var Box = require('./box')

var unbind = Function.call.bind(Function.bind, Function.call)

// Define a shortcut for `Array.prototype.slice.call`.
var slice = Array.slice || unbind(Array.prototype.slice)

var end = Box('end of the sequence')
exports.end = end

var accumulated = Box('Indicator that source has being accumulateed')
exports.accumulated = accumulated

var error = Box('error')
exports.error = error

var accumulate = Method(function(self, next, start) {
  next(end(), next(self, start))
})
exports.accumulate = accumulate

// Implement accumulation for undefined and null values.
// Reducing/accumulating a null value will pass the initial start value to
// the accumulating function, then end.
function accumulateEmpty(_, f, start) { f(end(), start) }
accumulate.define(undefined, accumulateEmpty)
accumulate.define(null, accumulateEmpty)

// Implement accumulation method for native arrays, making arrays compatible
// with reducer methods and other reducible values.
accumulate.define(Array, function(array, next, initial) {
  var state = initial, index = 0, count = array.length
  while (index < count) {
    state = next(array[index++], state)
    if (state && state.is === accumulated) break
  }
  next(end(), state)
})

function transformer(source, transform) {
  return convert(source, function(self, next, initial) {
    return accumulate(transform(source), next, initial)
  })
}
exports.transformer = transformer

function convert(source, method) {
  /**
  Make a `source` object accumulatable by creating a prototypal copy and
  implementing the `accumulate` protocol on it with the given `method`.
  Returns an accumulatable/reducible object.
  **/
  return accumulate.implement(create(source), method)
}
exports.convert = convert

function transform(source, f) {
  return convert(source, function(self, next, initial) {
    accumulate(source, function(value, result) {
      return value && value.isBoxed ? next(value, result)
                                    : f(next, value, result)
    }, initial)
  })
}
exports.transform = transform

function filter(source, predicate) {
  /**
  Composes filtered version of given `source`, such that only items contained
  will be once on which `f(item)` was `true`.
  **/
  return transform(source, function(next, value, accumulated) {
    return predicate(value) ? next(value, accumulated) : accumulated
  })
}
exports.filter = filter

function map(source, f) {
  /**
  Composes version of given `source` where each item of source is mapped using `f`.
  **/
  return transform(source, function(next, value, accumulated) {
    return next(f(value), accumulated)
  })
}
exports.map = map

function take(source, n) {
  /**
  Composes version of given `source` containing only element up until `f(item)`
  was true.
  **/
  return transformer(source, function(source) {
    var count = n >= 0 ? n : Infinity
    return transform(source, function(next, value, result) {
      count = count - 1
      return count === 0 ? next(accumulated(), next(value, result)) :
             count > 0 ? next(value, result) :
                         next(accumulated(), result)
    })
  })
}
exports.take = take

function drop(source, n) {
  /**
  Reduces given `reducible` to first `n` items.
  **/
  return transformer(source, function(source) {
    var count = n >= 0 ? n : 1
    return transform(source, function(next, value, result) {
      return count -- > 0 ? result :
                            next(value, result)
    })
  })
}
exports.drop = drop

function takeWhile(source, predicate) {
  /**
  Composes version of given `source` containing only firs `n` items of it.
  **/
  return transform(source, function(next, value, state) {
    return predicate(value) ? next(value, state) :
                              next(accumulated(), state)
  })
}
exports.takeWhile = takeWhile

function dropWhile(source, predicate) {
  /**
  Reduces `reducible` further by dropping first `n`
  items to on which `f(item)` ruturns `true`
  **/
  return transformer(source, function(source) {
    var active = true
    return transform(source, function(next, value, result) {
      return active && (active = predicate(value)) ? result :
                                                     next(value, result)
    })
  })
}
exports.dropWhile = dropWhile

function tail(source) {
  /**
  Get the last value of a reducible.
  Reduces a reducible to it's tailing value.
  **/
  return drop(source, 1)
}
exports.tail = tail

//console.log(into(skip(2, [ 1, 2, 3, 4, 5, 6 ])))
//

function append1(left, right) {
  return convert({}, function(self, next, initial) {
    accumulate(left, function(value, result) {
      return value && value.is === end ? accumulate(right, next, result) :
                                         next(value, result)
    }, initial)
  })
}
function append(left, right, rest) {
  /**
  Joins given `reducible`s into `reducible` of items
  of all the `reducibles` preserving an order of items.
  **/
  return rest ? slice(arguments, 1).reduce(append1, left) :
                append1(left, right)
}
exports.append = append

function capture(source, recover) {
  return convert(source, function(self, next, initial) {
    accumulate(source, function(value, result) {
      if (value && value.is === error) {
        accumulate(recover(value.value, result), next, result)
      } else {
        next(value, result)
      }
    }, initial)
  })
}
exports.capture = capture

function reductions(source, f, initial) {
  /**
  Returns `reducible` collection of the intermediate values of the reduction
  (as per reduce) of coll by `f`, starting with `initial` value.

  ## Example

  reductions([1 1 1 1], function(x, y) { return x + y }, 0)
  // => [ 1, 2, 3, 4 ]
  **/
  return convert(source, function(self, next, result) {
    var state = initial
    accumulate(source, function(value, result) {
      state = value && value.isBoxed ? next(value, result) : f(state, value)
      return next(state, result)
    }, result)
  })
}
exports.reductions = reductions

function adjust(source, f, initial) {
  /**
  Function takes reducible `source`, `f` transformer function and `initial`
  state. Adapted version of `source` is returned in result. `f` is called with
  each item of the source and curried state and is expected to return array
  of adjusted item and new state (which will be curried to next call) pair.

  ## Example

  var delimiterChar = ' '
  var data = [ 'Bite my', ' shiny, metal ', 'ass!' ]
  var chunks = adjust(data, function(chunk, prefix) {
    var text = prefix + chunk
    var delimiterIndex = text.lastIndexOf(delimiterChar)
    var splitIndex = delimiterIndex >= 0 ? delimiterIndex : text.length
    var capturedChunk = text.substr(0, splitIndex)
    var curriedChunk = text.substr(splitIndex + 1)
    return [ capturedChunk, curriedChunk ]
  }, '')
  var words = expand(chunks, function(chunk) {
    return chunk.split(delimiterChar)
  })

  // => [ 'Bite', 'my', 'shiny', 'metal', 'ass!' ]
  **/
  return convert(source, function(self, next, result) {
    var state = initial
    accumulate(source, function(value, result) {
      if (value && value.isBoxed) return next(value, result)
      var pair = f(value, state)
      state = pair[1]
      return next(pair[0], result)
    }, result)
  })
}
exports.adjust = adjust
<|endoftext|>


<commit_before>module.exports = {
  screen: ["sumo/scss/screen.scss"],
  common: [
    "sumo/js/i18n.js",
    "underscore/underscore.js",
    "jquery",
    "sumo/js/libs/jquery.cookie.js",
    "sumo/js/libs/jquery.placeholder.js",
    "sumo/js/templates/macros.js",
    "sumo/js/templates/search-results-list.js",
    "sumo/js/templates/search-results.js",
    "nunjucks/browser/nunjucks-slim.js",
    "sumo/js/nunjucks.js",
    "sumo/js/cached_xhr.js",
    "sumo/js/search_utils.js",
    "sumo/js/browserdetect.js",
    "sumo/js/libs/uitour.js",
    "sumo/js/kbox.js",
    "sumo/js/main.js",
    "sumo/js/libs/modernizr-custom-build.js",
    "sumo/js/geoip-locale.js",
    "sumo/js/ui.js",
    "sumo/js/analytics.js",
    "sumo/js/instant_search.js",
    "sumo/js/responsive-nav-toggle.js",
    "sumo/js/profile-avatars.js",
    "./webpack/protocol-compat.js",
    "protocol/js/protocol-base.js",
    "protocol/js/protocol-utils.js",
    "protocol/js/protocol-supports.js",
    "protocol/js/protocol-details.js",
    "protocol/js/protocol-footer.js",
    "protocol/js/protocol-menu.js",
    "protocol/js/protocol-modal.js",
    "protocol/js/protocol-navigation.js",
    "protocol/js/protocol-newsletter.js",
    "protocol/js/protocol-notification-bar.js",
    "protocol/js/protocol-lang-switcher.js",
    "sumo/js/protocol-nav.js",
    "sumo/js/protocol-details-init.js",
    "sumo/js/protocol-modal-init.js",
    "sumo/js/protocol-notification-init.js",
    "sumo/js/protocol-language-switcher-init.js",
    "sumo/js/sumo-tabs.js",
    "sumo/js/sumo-close-this.js",
  ],
  "common.fx.download": [
    "sumo/js/show-fx-download.js",
  ],
  community: [
    "jquery",
    "community/js/community.js",
    "community/js/select.js",
  ],
  "community.metrics": [
    "kpi/js/kpi.browserify.js",
  ],
  jqueryui: [
    "sumo/js/jquery-ui-custom.js",
  ],
  questions: [
    "sumo/js/markup.js",
    "sumo/js/ajaxvote.js",
    "sumo/js/ajaxpreview.js",
    "sumo/js/remote.js",
    "sumo/js/aaq.js",
    "sumo/js/questions.js",
    "sumo/js/libs/jquery.tokeninput.js",
    "sumo/js/tags.filter.js",
    "sumo/js/tags.js",
    "sumo/js/reportabuse.js",
    "sumo/js/questions.metrics.js",
    "sumo/js/libs/jquery.ajaxupload.js",
    "sumo/js/upload.js",
  ],
  "questions.metrics": [
    "sumo/js/questions.metrics-dashboard.js",
  ],
  "questions.geo": [
    "sumo/js/location.js",
  ],
  products: [
    "sumo/js/compare_versions.js",
    "sumo/js/products.js",
  ],
  search: [
    "sumo/js/search.js",
  ],
  forums: [
    "sumo/js/markup.js",
    "sumo/js/ajaxpreview.js",
    "sumo/js/forums.js",
    "sumo/js/reportabuse.js",
  ],
  gallery: [
    "sumo/js/libs/jquery.ajaxupload.js",
    "sumo/js/gallery.js",
  ],
  wiki: [
    "sumo/js/markup.js",
    "sumo/js/libs/django/urlify.js",
    "sumo/js/libs/django/prepopulate.js",
    "sumo/js/libs/jquery.lazyload.js",
    "sumo/js/libs/jquery.tokeninput.js",
    "sumo/js/users.autocomplete.js",
    "sumo/js/showfor.js",
    "sumo/js/ajaxvote.js",
    "sumo/js/ajaxpreview.js",
    "sumo/js/wiki.js",
    "sumo/js/tags.js",
    "sumo/js/dashboards.js",
    "sumo/js/editable.js",
    "sumo/js/wiki.metrics.js",
    "sumo/js/templates/wiki-related-doc.js",
    "sumo/js/templates/wiki-search-results.js",
    "sumo/js/wiki_search.js",
  ],
  rickshaw: [
    "d3/d3.js",
    "sumo/js/libs/d3.layout.min.js",
    "sumo/js/libs/rickshaw.js",
    "sumo/js/rickshaw_utils.js",
  ],
  "wiki.history": [
    "sumo/js/historycharts.js",
  ],
  "wiki.diff": [
    "sumo/js/libs/diff_match_patch_uncompressed.js",
    "sumo/js/diff.js",
  ],
  "wiki.editor": [
    "codemirror/lib/codemirror.js",
    "codemirror/addon/mode/simple.js",
    "codemirror/addon/hint/show-hint.js",
    "sumo/js/codemirror.sumo-hint.js",
    "sumo/js/codemirror.sumo-mode.js",
  ],
  "wiki.dashboard": [
    "sumo/js/wiki.dashboard.js",
  ],
  users: [
    "sumo/js/users.js",
    "sumo/js/reportabuse.js",
  ],
  messages: [
    "sumo/js/markup.js",
    "sumo/js/libs/jquery.autoresize.js",
    "sumo/js/libs/jquery.tokeninput.js",
    "sumo/js/users.autocomplete.js",
    "sumo/js/ajaxpreview.js",
    "sumo/js/messages.js",
  ],
  groups: [
    "sumo/js/libs/jquery.tokeninput.js",
    "sumo/js/users.autocomplete.js",
    "sumo/js/markup.js",
    "sumo/js/groups.js",
    "sumo/js/editable.js",
  ],
  "kpi.dashboard": [
    "d3/d3.js",
    "kpi/js/kpi.browserify.js",
  ],
  "gtm-snippet": [
    "sumo/js/dnt-helper.js",
    "sumo/js/gtm-snippet.js",
  ],
}
<commit_msg>dedupe chunks across common and other entrypoints<commit_after>const entrypoints = {
  screen: ["sumo/scss/screen.scss"],
  common: [
    "sumo/js/i18n.js",
    "underscore/underscore.js",
    "jquery",
    "sumo/js/libs/jquery.cookie.js",
    "sumo/js/libs/jquery.placeholder.js",
    "sumo/js/templates/macros.js",
    "sumo/js/templates/search-results-list.js",
    "sumo/js/templates/search-results.js",
    "nunjucks/browser/nunjucks-slim.js",
    "sumo/js/nunjucks.js",
    "sumo/js/cached_xhr.js",
    "sumo/js/search_utils.js",
    "sumo/js/browserdetect.js",
    "sumo/js/libs/uitour.js",
    "sumo/js/kbox.js",
    "sumo/js/main.js",
    "sumo/js/libs/modernizr-custom-build.js",
    "sumo/js/geoip-locale.js",
    "sumo/js/ui.js",
    "sumo/js/analytics.js",
    "sumo/js/instant_search.js",
    "sumo/js/responsive-nav-toggle.js",
    "sumo/js/profile-avatars.js",
    "./webpack/protocol-compat.js",
    "protocol/js/protocol-base.js",
    "protocol/js/protocol-utils.js",
    "protocol/js/protocol-supports.js",
    "protocol/js/protocol-details.js",
    "protocol/js/protocol-footer.js",
    "protocol/js/protocol-menu.js",
    "protocol/js/protocol-modal.js",
    "protocol/js/protocol-navigation.js",
    "protocol/js/protocol-newsletter.js",
    "protocol/js/protocol-notification-bar.js",
    "protocol/js/protocol-lang-switcher.js",
    "sumo/js/protocol-nav.js",
    "sumo/js/protocol-details-init.js",
    "sumo/js/protocol-modal-init.js",
    "sumo/js/protocol-notification-init.js",
    "sumo/js/protocol-language-switcher-init.js",
    "sumo/js/sumo-tabs.js",
    "sumo/js/sumo-close-this.js",
  ],
  "common.fx.download": [
    "sumo/js/show-fx-download.js",
  ],
  community: [
    "jquery",
    "community/js/community.js",
    "community/js/select.js",
  ],
  "community.metrics": [
    "kpi/js/kpi.browserify.js",
  ],
  jqueryui: [
    "sumo/js/jquery-ui-custom.js",
  ],
  questions: [
    "sumo/js/markup.js",
    "sumo/js/ajaxvote.js",
    "sumo/js/ajaxpreview.js",
    "sumo/js/remote.js",
    "sumo/js/aaq.js",
    "sumo/js/questions.js",
    "sumo/js/libs/jquery.tokeninput.js",
    "sumo/js/tags.filter.js",
    "sumo/js/tags.js",
    "sumo/js/reportabuse.js",
    "sumo/js/questions.metrics.js",
    "sumo/js/libs/jquery.ajaxupload.js",
    "sumo/js/upload.js",
  ],
  "questions.metrics": [
    "sumo/js/questions.metrics-dashboard.js",
  ],
  "questions.geo": [
    "sumo/js/location.js",
  ],
  products: [
    "sumo/js/compare_versions.js",
    "sumo/js/products.js",
  ],
  search: [
    "sumo/js/search.js",
  ],
  forums: [
    "sumo/js/markup.js",
    "sumo/js/ajaxpreview.js",
    "sumo/js/forums.js",
    "sumo/js/reportabuse.js",
  ],
  gallery: [
    "sumo/js/libs/jquery.ajaxupload.js",
    "sumo/js/gallery.js",
  ],
  wiki: [
    "sumo/js/markup.js",
    "sumo/js/libs/django/urlify.js",
    "sumo/js/libs/django/prepopulate.js",
    "sumo/js/libs/jquery.lazyload.js",
    "sumo/js/libs/jquery.tokeninput.js",
    "sumo/js/users.autocomplete.js",
    "sumo/js/showfor.js",
    "sumo/js/ajaxvote.js",
    "sumo/js/ajaxpreview.js",
    "sumo/js/wiki.js",
    "sumo/js/tags.js",
    "sumo/js/dashboards.js",
    "sumo/js/editable.js",
    "sumo/js/wiki.metrics.js",
    "sumo/js/templates/wiki-related-doc.js",
    "sumo/js/templates/wiki-search-results.js",
    "sumo/js/wiki_search.js",
  ],
  rickshaw: [
    "d3/d3.js",
    "sumo/js/libs/d3.layout.min.js",
    "sumo/js/libs/rickshaw.js",
    "sumo/js/rickshaw_utils.js",
  ],
  "wiki.history": [
    "sumo/js/historycharts.js",
  ],
  "wiki.diff": [
    "sumo/js/libs/diff_match_patch_uncompressed.js",
    "sumo/js/diff.js",
  ],
  "wiki.editor": [
    "codemirror/lib/codemirror.js",
    "codemirror/addon/mode/simple.js",
    "codemirror/addon/hint/show-hint.js",
    "sumo/js/codemirror.sumo-hint.js",
    "sumo/js/codemirror.sumo-mode.js",
  ],
  "wiki.dashboard": [
    "sumo/js/wiki.dashboard.js",
  ],
  users: [
    "sumo/js/users.js",
    "sumo/js/reportabuse.js",
  ],
  messages: [
    "sumo/js/markup.js",
    "sumo/js/libs/jquery.autoresize.js",
    "sumo/js/libs/jquery.tokeninput.js",
    "sumo/js/users.autocomplete.js",
    "sumo/js/ajaxpreview.js",
    "sumo/js/messages.js",
  ],
  groups: [
    "sumo/js/libs/jquery.tokeninput.js",
    "sumo/js/users.autocomplete.js",
    "sumo/js/markup.js",
    "sumo/js/groups.js",
    "sumo/js/editable.js",
  ],
  "kpi.dashboard": [
    "d3/d3.js",
    "kpi/js/kpi.browserify.js",
  ],
  "gtm-snippet": [
    "sumo/js/dnt-helper.js",
    "sumo/js/gtm-snippet.js",
  ],
}

for (let key in entrypoints) {
  if (key !== "common") {
    // mark all entrypoints as dependent on "common" (other than itself)
    // this ensures we don't duplicate chunks across "common" and other bundles
    // and ensures "common" contains the only webpack runtime
    entrypoints[key] = {
      import: entrypoints[key],
      dependOn: "common",
    }
  }
}

module.exports = entrypoints
<|endoftext|>