<commit_before>/**
BBH ♥ Babel Browser Harness
In-browser CDN-based ES6+ transpiling via Babel
Copyright (c) 2016, Michael Spencer
MIT License
*/
;(function() {
  "use strict";

  window.bbh = new function() {
    self = this;

    //-[ Setup ]----------------------------------------------------------------

    var MESSAGE_SYMBOL = "♥".length === 1 ? "♥" : "\u00B7",  // heart or middot
        MESSAGE_PREFIX = "BBH " + MESSAGE_SYMBOL + " ",
        WELCOME = MESSAGE_PREFIX + "Hello",
        ERROR_STRING = "Error Detected :(",
        COMMENT_LINE = " " + MESSAGE_PREFIX.toUpperCase() + " BELOW THIS LINE ",
        GLOBAL_START = Object.keys(window),
        DEFAULT_MODULES = [
          {
            name: 'bbh',
            exports: 'bbh'
          },
          {
            name: 'babel',
            exports: 'Babel',
            src: 'https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.7.7/babel.min.js'
          },
          {
            name: 'requirejs',
            ignores: ['__core-js_shared__', 'requirejs', 'require', 'define'],
            src: 'https://cdnjs.cloudflare.com/ajax/libs/require.js/2.2.0/require.min.js'
          },
        ];

    var babelConfig = {
          presets: ['es2015'],
          plugins: [],
        },
        globalIgnores = [],
        globalLeaks = [],
        modules = [],
        registrations = [],
        isRegistrationMode = false,
        removeModuleScripts = true,
        appendTarget,
        moduleEntries;

    //-[ Check for URL-hash-based Registration Mode ]---------------------------

    loadRegistrationModeFromUrlHash();

    //-[ Execute On Load Complete ]---------------------------------------------

    document.addEventListener('DOMContentLoaded', loaded);
    window.addEventListener('load', loaded);

    function loaded() {
      document.removeEventListener('DOMContentLoaded', loaded);
      window.removeEventListener('load', loaded);
      execute();
    }

    //-[ Methods ]--------------------------------------------------------------

    function execute() {
      importConfig();

      if (isRegistrationMode) {
        listenForRegistrationModeWindowMessage();
        return;
      }

      console.debug(WELCOME);

      buildModuleEntries();
      determineAppendTarget();
      addCommentLine();

      logStatus("Loading Modules");
      loadExternalScripts()
        .then(loadRegistrationsAndMergeScriptsAndErrors)
        .then(mapAndTranspile)
        .catch(logAndThrowError);

      function loadRegistrationsAndMergeScriptsAndErrors(scriptsAndErrors) {
        // Load registrations and append elements
        if (!registrations.length) {
          return scriptsAndErrors;
        }
        return loadRegistrations().then(function(registrationScriptsAndErrors) {
          return scriptsAndErrors.concat(registrationScriptsAndErrors)
        });
      }

      function mapAndTranspile(scriptsAndErrors) {
        var errors = scriptsAndErrors.filter(function(_) { return isError(_) });
        if (errors.length) {
          logStatus(ERROR_STRING)
          errors.forEach(function(_) { logStatus(_.message || _) });
        } else {
          mapGlobals();
          detectLeaks();

          logStatus("Transpiling");
          transpile().then(function(scripts) {
            logStatus("Running");
            return scripts;
          }, function(error) {
            logAndThrowError(error)
          });
        }
      }

      function logStatus(message) {
        console.debug(MESSAGE_PREFIX + message);
      }

      function logAndThrowError(error) {
        logStatus(ERROR_STRING);
        if (isError(error)) {
          throw error;
        } else {
          throw new Error(error && error.message || error || "An unknown error occurred")
        }
      }
    }

    function loadRegistrationModeFromUrlHash() {
      var src, hashIndex, hash;
      if (document.currentScript) {
        src = document.currentScript.getAttribute('src');
        if (src) {
          hashIndex = src.indexOf('#');
          if (~hashIndex) {
            hash = src.substr(hashIndex + 1);
            if (hash === 'registration') {
              isRegistrationMode = true;
            }
          }
        }
      }
    }

    function importConfig() {
      babelConfig = self.babelConfig;
      modules = self.modules;
      removeModuleScripts = self.removeModuleScripts;
      appendTarget = self.appendTarget;
    }

    function determineAppendTarget() {
      appendTarget = appendTarget ||
                     document.querySelector('#bbh, #BBH, #__bbh, #__BBH') ||
                     document.body;
    }

    function addCommentLine() {
      var padLine = new Array(COMMENT_LINE.length + 1).join('-');
      appendTarget.appendChild(document.createComment(padLine));
      appendTarget.appendChild(document.createComment(COMMENT_LINE));
      appendTarget.appendChild(document.createComment(padLine));
    }

    function loadExternalScripts(){
      var urls = moduleEntries.map(function(_) { return _.src }).filter(Boolean);
      return Promise.all(urls.map(function(url) {
        return new Promise(function(resolve, reject){
          var script = document.createElement('script'),
              dataName = url.substr((url.lastIndexOf('/') || -1) + 1);
          script.setAttribute('data-name', dataName);
          script.async = false;
          script.src = url;
          script.onload = function() {
            resolve(script);
          };
          script.onerror = function(e) {
            reject(new Error("The script \"" + (dataName || e.target.src) + "\" is not accessible"))
          }
          appendTarget.appendChild(script);
          if (removeModuleScripts) {
            setTimeout(function() {
              script.remove();
            }, 0);
          }
        })
      }).map(function(p) {
        // catch and return errors to allow for post-processing
        return p.catch(function(error) {
          return error;
        })
      }));
    }

    /**
     * options (Object):
     *   src (String) - Required - URL path to file
     *   timeout (Number) - Optional - Milleseconds to wait before failing
     *   messageId (String)- Optional - ID to use for message debugging
     */
    function register(options) {
      var registration = {
        src: options.src,
        timeout: typeof options.timeout === 'number' ? options.timeout : 3000,  // 3 seconds
        messageId: options.messageId || generateRandomId()
      };
      registrations.push(registration);
    }

    function loadRegistrations() {
      return Promise.all(registrations
        .map(loadRegistration)
        .map(function(p) {
          // catch and return errors to allow for post-processing
          return p.catch(function(error) {
            return error;
          })
        })
      ).then(function(elementsAndErrors) {
        // flatten results
        var result = [];
        elementsAndErrors.forEach(function(_) {
          [].push[Array.isArray(_) ? 'apply' : 'call'](result, _)
        });
        return result;
      });

      function loadRegistration(registration) {
        var iframe = createIframe(registration.src),
            promises = [
              listenForWindowMessage(iframe, registration),
              listenForIframeLoad(iframe, registration)
            ],
            promiseTimer = new Promise(function(resolve, reject) {
              var timer = setTimeout(function() {
                reject(new Error('Registration didn\'t resolve: "' + registration.src + '" (' + registration.timeout + 'ms)'));
              }, registration.timeout);
              Promise.all(promises)
                .then(function() {
                  clearTimeout(timer);
                  resolve();
                }, function(error) {
                  // Ignore errors in timer
                });
            }),
            result = Promise.all(promises.concat([promiseTimer]))
              .then(function(_) {
                // Resolve with the script tags from the window message event
                return _[0];
              });
        appendTarget.appendChild(iframe);
        return result;
      }

      function createIframe(src) {
        var iframe = document.createElement('iframe');
        iframe.src = src;
        iframe.style = "display:none";
        return iframe;
      }

      function listenForIframeLoad(iframe, registration) {
        return new Promise(function(resolve, reject) {
          iframe.onload = onLoad;

          function onLoad() {
            var data = { id: registration.messageId };
            iframe.contentWindow.postMessage(data, '*');
            resolve();
          }
        });
      }

      function listenForWindowMessage(iframe, registration) {
        return new Promise(function(resolve, reject){
          window.addEventListener('message', onMessage);

          function onMessage(event) {
            if (event.data.id === registration.messageId) {
              if (event.data.error) {
                reject(new Error(event.data.error + ' (' + registration.src + ')'));
              } else if (event.origin === document.origin) {
                window.removeEventListener('message', onMessage);
                processMessageData(event.data);
              }
              iframe.remove();
            }
          }

          // Promise resolution happens in here
          function processMessageData(data) {
            try {
              if (Array.isArray(data.scripts)) {
                resolve(data.scripts
                  .map(deserializeScript)
                  .map(function(_) {
                    appendTarget.appendChild(_);
                    return _;
                  })
                );
              } else {
                resolve([]);
              }
            } catch (error) {
              reject(error);
            }
          }

          function deserializeScript(script) {
            var result = document.createElement('script');
            result.setAttribute('type', "text/babel");
            if (script.name) {
              result.setAttribute('name', script.name)
            }
            if (script.src) {
              result.setAttribute('src', script.src)
            } else if (script.textContent) {
              result.textContent = script.textContent;
            }
            return result;
          }
        });
      }
    }

    function listenForRegistrationModeWindowMessage() {
      window.addEventListener('message', registrationModeOnMessage);

      function registrationModeOnMessage(event) {
        if (event.data.id) {
          if (event.origin === document.origin) {
            var scripts = [].slice.call(document.querySelectorAll('script[type="text/babel"]') || []);
            event.source.postMessage({
              id: event.data.id,
              scripts: scripts.map(serializeScript)
            }, '*');
          } else {
            event.source.postMessage({
              id: event.data.id,
              error: "Cross-origin registration rejected"
            }, '*');
          }
        }
        window.removeEventListener('message', registrationModeOnMessage);

        function serializeScript(script) {
          var result = {},
              name = script.getAttribute('name'),
              src = script.getAttribute('src'),
              textContent = script.textContent;
          if (name) {
            result.name = name;
          }
          if (src) {
            result.src = src;
          } else {
            result.textContent = textContent;
          }
          return result;
        }
      }
    }

    function buildModuleEntries() {
      var result = [];
      [modules, DEFAULT_MODULES].forEach(function(_) {
        if (Array.isArray(_)) {
          [].push.apply(result, _);
        } else {
          Object.keys(_).forEach(function(k) { result.push(Object.assign({}, _[k], { name: k })) })
        }
      });
      moduleEntries = result;
    }

    function mapGlobals() {
      moduleEntries.forEach(mapGlobal);

      function mapGlobal(_) {
        _ = {
          name: _.name,
          exports: [].concat(_.exports || []),
          ignores: [].concat(_.ignores || []),
          callNoConflict: typeof _.callNoConflict === 'undefined' || !!_.callNoConflict,
          deleteFromWindow: typeof _.deleteFromWindow === 'undefined' || !!_.deleteFromWindow
        };
        var matchedExports = _.exports.filter(function(k) { return window.hasOwnProperty(k) });
        if (_.name) {
          if (matchedExports.length) {
            _.exported = window[matchedExports[0]];
            (function(_) {
              define(_.name, function(require, exports, module) {
                module.exports = _.exported;
              });
              require([_.name]);
              if (_.callNoConflict && _.exported && typeof _.exported.noConflict === 'function') {
                _.exported.noConflict();
              }
              if (_.deleteFromWindow) {
                _.exports.forEach(function(k) {
                  if (window.hasOwnProperty(k)) {
                    delete window[k];
                  }
                })
              }
            })(_);
          } else {
            // Dummy definition
            define(_.name, function() { return null });
            require([_.name]);
          }
        }
        [].push.apply(globalIgnores, _.ignores);
      }
    }

    function detectLeaks() {
      globalLeaks = Object.keys(window).filter(function(k) { return !~GLOBAL_START.concat(globalIgnores).indexOf(k) });
      if (globalLeaks.length) {
        console.debug(MESSAGE_PREFIX + "Global Leak" + (globalLeaks.length > 1 ? "s" : "") + " Detected: " + JSON.stringify(globalLeaks))
      }
    }

    function transpile() {
      return new Promise(function(resolve, reject) {
        try {
          require(['babel'], function(Babel) {
            var moduleNames = [], modulePrefix = "__bbh_", moduleIndex = 0;

            Promise.resolve([].slice.call(document.querySelectorAll('script[type="text/babel"]') || []))
              .then(function(_) { return Promise.all(_.map(extractWithName)) })
              .then(function(_) { return Promise.all(_.map(transformWithName)) })
              .then(function(_) { return Promise.all(_.map(wrapWithName)) })
              .then(function(_) { return Promise.all(_.map(buildWithName)) })
              .then(function(_) { return Promise.all(_.map(runWithName)) })
              .then(function(_) { resolve(_) })
              .catch(function(error) { reject(error) });

            function extract(element) { return element.src ? fetch(element.src).then(function(res) { return res.text() }).then(function(text) { return text }) : Promise.resolve(element.textContent) }
            function transform(script) { return Babel.transform(script, babelConfig).code }
            function wrap(name, script) { return ";define('" + name + "', function(require, exports, module) { try {" + script + "\n; } catch (error) { console.debug('" + MESSAGE_PREFIX + ERROR_STRING + "'); throw error }}); require(['" + name + "']);" }
            function build(script) { var element = document.createElement('script'); element.async = false; element.textContent = script; return element }
            function run(element) { appendTarget.appendChild(element); return element }

            function extractWithName(element) { return extract(element).then(function(text) { return [element.getAttribute('name') || element.getAttribute('src') || modulePrefix + (++moduleIndex), text] }) }
            function transformWithName(nameAndScript) { return [nameAndScript[0], transform(nameAndScript[1])] }
            function wrapWithName(nameAndScript) { return [nameAndScript[0], wrap.apply(null, nameAndScript)] }
            function buildWithName(nameAndScript) { var name = nameAndScript[0], built = build(nameAndScript[1]); if (name) { built.setAttribute('data-name', name) } return [name, built] }
            function runWithName(nameAndElement) { return [nameAndElement[0], run(nameAndElement[1])] }
          });
        } catch (error) {
          reject(error);
        }
      });
    }

    function isError(o) {
      return o && typeof o === 'object' && (
               Object.prototype.toString(o) === '[object Error]' ||
               (o.name === 'Error' && typeof o.message === 'string')
             );
    }

    function generateRandomId() {
      var min = 1, max = 999999999;
      return '' + (Math.floor(Math.random() * (max - min + 1)) + min);
    }

    //-[ Exports ]--------------------------------------------------------------

    // Configuration
    self.babelConfig = babelConfig;
    self.modules = modules;
    self.removeModuleScripts = removeModuleScripts;
    self.appendTarget = appendTarget;

    // Immutable
    self.welcome = WELCOME;

    // Methods
    self.register = register;

    // Getters
    self.isRegistrationMode = function() { return isRegistrationMode; };

    // Setters
    self.registrationMode = function(bool) { isRegistrationMode = bool === false ? false : true; };
  }
})();
<commit_msg>Register: Add config option to remove register() scripts<commit_after>/**
BBH ♥ Babel Browser Harness
In-browser CDN-based ES6+ transpiling via Babel
Copyright (c) 2016, Michael Spencer
MIT License
*/
;(function() {
  "use strict";

  window.bbh = new function() {
    self = this;

    //-[ Setup ]----------------------------------------------------------------

    var MESSAGE_SYMBOL = "♥".length === 1 ? "♥" : "\u00B7",  // heart or middot
        MESSAGE_PREFIX = "BBH " + MESSAGE_SYMBOL + " ",
        WELCOME = MESSAGE_PREFIX + "Hello",
        ERROR_STRING = "Error Detected :(",
        COMMENT_LINE = " " + MESSAGE_PREFIX.toUpperCase() + " BELOW THIS LINE ",
        GLOBAL_START = Object.keys(window),
        DEFAULT_MODULES = [
          {
            name: 'bbh',
            exports: 'bbh'
          },
          {
            name: 'babel',
            exports: 'Babel',
            src: 'https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.7.7/babel.min.js'
          },
          {
            name: 'requirejs',
            ignores: ['__core-js_shared__', 'requirejs', 'require', 'define'],
            src: 'https://cdnjs.cloudflare.com/ajax/libs/require.js/2.2.0/require.min.js'
          },
        ];

    var babelConfig = {
          presets: ['es2015'],
          plugins: [],
        },
        globalIgnores = [],
        globalLeaks = [],
        modules = [],
        registrations = [],
        isRegistrationMode = false,
        removeRegisterScripts = true,
        removeModuleScripts = true,
        appendTarget,
        moduleEntries;

    //-[ Check for URL-hash-based Registration Mode ]---------------------------

    loadRegistrationModeFromUrlHash();

    //-[ Execute On Load Complete ]---------------------------------------------

    document.addEventListener('DOMContentLoaded', loaded);
    window.addEventListener('load', loaded);

    function loaded() {
      document.removeEventListener('DOMContentLoaded', loaded);
      window.removeEventListener('load', loaded);
      execute();
    }

    //-[ Methods ]--------------------------------------------------------------

    function execute() {
      importConfig();

      if (isRegistrationMode) {
        listenForRegistrationModeWindowMessage();
        return;
      }

      console.debug(WELCOME);

      buildModuleEntries();
      determineAppendTarget();
      addCommentLine();

      logStatus("Loading Modules");
      loadExternalScripts()
        .then(loadRegistrationsAndMergeScriptsAndErrors)
        .then(mapAndTranspile)
        .then(removeRequestedElements)
        .catch(logAndThrowError);

      function loadRegistrationsAndMergeScriptsAndErrors(scriptsAndErrors) {
        // Load registrations and append elements
        if (!registrations.length) {
          return scriptsAndErrors;
        }
        return loadRegistrations().then(function(registrationScriptsAndErrors) {
          return scriptsAndErrors.concat(registrationScriptsAndErrors)
        });
      }

      function mapAndTranspile(scriptsAndErrors) {
        return new Promise(function(resolve, reject) {
          var errors = scriptsAndErrors.filter(function(_) { return isError(_) });
          if (errors.length) {
            logStatus(ERROR_STRING)
            errors.forEach(function(_) { logStatus(_.message || _) });
          } else {
            mapGlobals();
            detectLeaks();

            logStatus("Transpiling");
            transpile()
              .then(function(scripts) {
                logStatus("Running");
                return scripts;
              })
              .then(function(scripts) {
                resolve(scripts);
              })
              .catch(function(error) {
                reject(error);
              });
          }
        })
      }

      function removeRequestedElements() {
        [].slice.call(document.querySelectorAll('[data-remove="true"]') || [])
          .forEach(function(element) {
            element.remove()
          })
      }

      function logStatus(message) {
        console.debug(MESSAGE_PREFIX + message);
      }

      function logAndThrowError(error) {
        logStatus(ERROR_STRING);
        if (isError(error)) {
          throw error;
        } else {
          throw new Error(error && error.message || error || "An unknown error occurred")
        }
      }
    }

    function loadRegistrationModeFromUrlHash() {
      var src, hashIndex, hash;
      if (document.currentScript) {
        src = document.currentScript.getAttribute('src');
        if (src) {
          hashIndex = src.indexOf('#');
          if (~hashIndex) {
            hash = src.substr(hashIndex + 1);
            if (hash === 'registration') {
              isRegistrationMode = true;
            }
          }
        }
      }
    }

    function importConfig() {
      babelConfig = self.babelConfig;
      modules = self.modules;
      removeModuleScripts = self.removeModuleScripts;
      appendTarget = self.appendTarget;
    }

    function determineAppendTarget() {
      appendTarget = appendTarget ||
                     document.querySelector('#bbh, #BBH, #__bbh, #__BBH') ||
                     document.body;
    }

    function addCommentLine() {
      var padLine = new Array(COMMENT_LINE.length + 1).join('-');
      appendTarget.appendChild(document.createComment(padLine));
      appendTarget.appendChild(document.createComment(COMMENT_LINE));
      appendTarget.appendChild(document.createComment(padLine));
    }

    function loadExternalScripts(){
      var urls = moduleEntries.map(function(_) { return _.src }).filter(Boolean);
      return Promise.all(urls.map(function(url) {
        return new Promise(function(resolve, reject){
          var script = document.createElement('script'),
              dataName = url.substr((url.lastIndexOf('/') || -1) + 1);
          script.setAttribute('data-name', dataName);
          script.async = false;
          script.src = url;
          script.onload = function() {
            resolve(script);
          };
          script.onerror = function(e) {
            reject(new Error("The script \"" + (dataName || e.target.src) + "\" is not accessible"))
          }
          if (removeModuleScripts) {
            script.setAttribute('data-remove', "true");
          }
          appendTarget.appendChild(script);
        })
      }).map(function(p) {
        // catch and return errors to allow for post-processing
        return p.catch(function(error) {
          return error;
        })
      }));
    }

    /**
     * options (Object):
     *   src (String) - Required - URL path to file
     *   timeout (Number) - Optional - Milleseconds to wait before failing
     *   messageId (String)- Optional - ID to use for message debugging
     */
    function register(options) {
      var registration = {
        src: options.src,
        timeout: typeof options.timeout === 'number' ? options.timeout : 3000,  // 3 seconds
        messageId: options.messageId || generateRandomId()
      };
      registrations.push(registration);
    }

    function loadRegistrations() {
      return Promise.all(registrations
        .map(loadRegistration)
        .map(function(p) {
          // catch and return errors to allow for post-processing
          return p.catch(function(error) {
            return error;
          })
        })
      ).then(function(elementsAndErrors) {
        // flatten results
        var result = [];
        elementsAndErrors.forEach(function(_) {
          [].push[Array.isArray(_) ? 'apply' : 'call'](result, _)
        });
        return result;
      });

      function loadRegistration(registration) {
        var iframe = createIframe(registration.src),
            promises = [
              listenForWindowMessage(iframe, registration),
              listenForIframeLoad(iframe, registration)
            ],
            promiseTimer = new Promise(function(resolve, reject) {
              var timer = setTimeout(function() {
                reject(new Error('Registration didn\'t resolve: "' + registration.src + '" (' + registration.timeout + 'ms)'));
              }, registration.timeout);
              Promise.all(promises)
                .then(function() {
                  clearTimeout(timer);
                  resolve();
                }, function(error) {
                  // Ignore errors in timer
                });
            }),
            result = Promise.all(promises.concat([promiseTimer]))
              .then(function(_) {
                // Resolve with the script tags from the window message event
                return _[0];
              });
        appendTarget.appendChild(iframe);
        return result;
      }

      function createIframe(src) {
        var iframe = document.createElement('iframe');
        iframe.src = src;
        iframe.style = "display:none";
        return iframe;
      }

      function listenForIframeLoad(iframe, registration) {
        return new Promise(function(resolve, reject) {
          iframe.onload = onLoad;

          function onLoad() {
            var data = { id: registration.messageId };
            iframe.contentWindow.postMessage(data, '*');
            resolve();
          }
        });
      }

      function listenForWindowMessage(iframe, registration) {
        return new Promise(function(resolve, reject){
          window.addEventListener('message', onMessage);

          function onMessage(event) {
            if (event.data.id === registration.messageId) {
              if (event.data.error) {
                reject(new Error(event.data.error + ' (' + registration.src + ')'));
              } else if (event.origin === document.origin) {
                window.removeEventListener('message', onMessage);
                processMessageData(event.data);
              }
              iframe.remove();
            }
          }

          // Promise resolution happens in here
          function processMessageData(data) {
            try {
              if (Array.isArray(data.scripts)) {
                resolve(data.scripts
                  .map(deserializeScript)
                  .map(function(_) {
                    appendTarget.appendChild(_);
                    return _;
                  })
                );
              } else {
                resolve([]);
              }
            } catch (error) {
              reject(error);
            }
          }

          function deserializeScript(script) {
            var result = document.createElement('script');
            result.setAttribute('type', "text/babel");
            if (script.name) {
              result.setAttribute('name', script.name)
            }
            if (script.src) {
              result.setAttribute('src', script.src)
            } else if (script.textContent) {
              result.textContent = script.textContent;
            }
            result.setAttribute('data-src', registration.src);
            if (removeModuleScripts) {
              result.setAttribute('data-remove', "true");
            }
            return result;
          }
        });
      }
    }

    function listenForRegistrationModeWindowMessage() {
      window.addEventListener('message', registrationModeOnMessage);

      function registrationModeOnMessage(event) {
        if (event.data.id) {
          if (event.origin === document.origin) {
            var scripts = [].slice.call(document.querySelectorAll('script[type="text/babel"]') || []);
            event.source.postMessage({
              id: event.data.id,
              scripts: scripts.map(serializeScript)
            }, '*');
          } else {
            event.source.postMessage({
              id: event.data.id,
              error: "Cross-origin registration rejected"
            }, '*');
          }
        }
        window.removeEventListener('message', registrationModeOnMessage);

        function serializeScript(script) {
          var result = {},
              name = script.getAttribute('name'),
              src = script.getAttribute('src'),
              textContent = script.textContent;
          if (name) {
            result.name = name;
          }
          if (src) {
            result.src = src;
          } else {
            result.textContent = textContent;
          }
          return result;
        }
      }
    }

    function buildModuleEntries() {
      var result = [];
      [modules, DEFAULT_MODULES].forEach(function(_) {
        if (Array.isArray(_)) {
          [].push.apply(result, _);
        } else {
          Object.keys(_).forEach(function(k) { result.push(Object.assign({}, _[k], { name: k })) })
        }
      });
      moduleEntries = result;
    }

    function mapGlobals() {
      moduleEntries.forEach(mapGlobal);

      function mapGlobal(_) {
        _ = {
          name: _.name,
          exports: [].concat(_.exports || []),
          ignores: [].concat(_.ignores || []),
          callNoConflict: typeof _.callNoConflict === 'undefined' || !!_.callNoConflict,
          deleteFromWindow: typeof _.deleteFromWindow === 'undefined' || !!_.deleteFromWindow
        };
        var matchedExports = _.exports.filter(function(k) { return window.hasOwnProperty(k) });
        if (_.name) {
          if (matchedExports.length) {
            _.exported = window[matchedExports[0]];
            (function(_) {
              define(_.name, function(require, exports, module) {
                module.exports = _.exported;
              });
              require([_.name]);
              if (_.callNoConflict && _.exported && typeof _.exported.noConflict === 'function') {
                _.exported.noConflict();
              }
              if (_.deleteFromWindow) {
                _.exports.forEach(function(k) {
                  if (window.hasOwnProperty(k)) {
                    delete window[k];
                  }
                })
              }
            })(_);
          } else {
            // Dummy definition
            define(_.name, function() { return null });
            require([_.name]);
          }
        }
        [].push.apply(globalIgnores, _.ignores);
      }
    }

    function detectLeaks() {
      globalLeaks = Object.keys(window).filter(function(k) { return !~GLOBAL_START.concat(globalIgnores).indexOf(k) });
      if (globalLeaks.length) {
        console.debug(MESSAGE_PREFIX + "Global Leak" + (globalLeaks.length > 1 ? "s" : "") + " Detected: " + JSON.stringify(globalLeaks))
      }
    }

    function transpile() {
      return new Promise(function(resolve, reject) {
        try {
          require(['babel'], function(Babel) {
            var moduleNames = [], modulePrefix = "__bbh_", moduleIndex = 0;

            Promise.resolve([].slice.call(document.querySelectorAll('script[type="text/babel"]') || []))
              .then(function(_) { return Promise.all(_.map(extractWithName)) })
              .then(function(_) { return Promise.all(_.map(transformWithName)) })
              .then(function(_) { return Promise.all(_.map(wrapWithName)) })
              .then(function(_) { return Promise.all(_.map(buildWithName)) })
              .then(function(_) { return Promise.all(_.map(runWithName)) })
              .then(function(_) { resolve(_) })
              .catch(function(error) { reject(error) });

            function extract(element) { return element.src ? fetch(element.src).then(function(res) { return res.text() }).then(function(text) { return text }) : Promise.resolve(element.textContent) }
            function transform(script) { return Babel.transform(script, babelConfig).code }
            function wrap(name, script) { return ";define('" + name + "', function(require, exports, module) { try {" + script + "\n; } catch (error) { console.debug('" + MESSAGE_PREFIX + ERROR_STRING + "'); throw error }}); require(['" + name + "']);" }
            function build(script) { var element = document.createElement('script'); element.async = false; element.textContent = script; return element }
            function run(element) { appendTarget.appendChild(element); return element }

            function extractWithName(element) { return extract(element).then(function(text) { return [element.getAttribute('name') || element.getAttribute('src') || modulePrefix + (++moduleIndex), text] }) }
            function transformWithName(nameAndScript) { return [nameAndScript[0], transform(nameAndScript[1])] }
            function wrapWithName(nameAndScript) { return [nameAndScript[0], wrap.apply(null, nameAndScript)] }
            function buildWithName(nameAndScript) { var name = nameAndScript[0], built = build(nameAndScript[1]); if (name) { built.setAttribute('data-name', name) } return [name, built] }
            function runWithName(nameAndElement) { return [nameAndElement[0], run(nameAndElement[1])] }
          });
        } catch (error) {
          reject(error);
        }
      });
    }

    function isError(o) {
      return o && typeof o === 'object' && (
               Object.prototype.toString(o) === '[object Error]' ||
               (o.name === 'Error' && typeof o.message === 'string')
             );
    }

    function generateRandomId() {
      var min = 1, max = 999999999;
      return '' + (Math.floor(Math.random() * (max - min + 1)) + min);
    }

    //-[ Exports ]--------------------------------------------------------------

    // Configuration
    self.babelConfig = babelConfig;
    self.modules = modules;
    self.removeModuleScripts = removeModuleScripts;
    self.removeRegisterScripts = removeRegisterScripts;
    self.appendTarget = appendTarget;

    // Immutable
    self.welcome = WELCOME;

    // Methods
    self.register = register;

    // Getters
    self.isRegistrationMode = function() { return isRegistrationMode; };

    // Setters
    self.registrationMode = function(bool) { isRegistrationMode = bool === false ? false : true; };
  }
})();
<|endoftext|>


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

var address = require('network-address')
var ms = require('ms')
var home = require('osenv').home
var name = process.env.alligator_appname || 'alligator'
var path = require('path')
var Peer = require('./')

var config = require('rc')(name, {
  listen: [
    'shs+tcp://[' + address.ipv4() + ']:4239',
    'shs+ws://[' + address.ipv4() + ']:4238'
  ], path: path.join(home(), '.' + name)
})

config.info = require('./peerInfo').loadOrCreateSync(path.join(config.path, 'peerInfo'))

var peer = new Peer(config)
peer.start()

process.on("SIGINT", peer.stop.bind(peer))
process.on("SIGHUP", peer.stop.bind(peer))
process.on('SIGUSR2', peer.stop.bind(peer, peer.start.bind(peer)))<commit_msg>shell command to set bootstrap peer<commit_after>#!/usr/bin/env node

var address = require('network-address')
var ms = require('ms')
var home = require('osenv').home
var name = process.env.alligator_appname || 'alligator'
var path = require('path')
var Peer = require('./')

var argv = require('minimist')(process.argv.slice(2));

var config = require('rc')(name, {
  listen: [
    'shs+tcp://[' + address.ipv4() + ']:4239',
    'shs+ws://[' + address.ipv4() + ']:4238'
  ], path: path.join(home(), '.' + name)
})

if(argv._.length>0)config.bootstrap = argv._.concat(config.bootstrap||[])

config.info = require('./peerInfo').loadOrCreateSync(path.join(config.path, 'peerInfo'))

var peer = new Peer(config)
peer.start()

process.on("SIGINT", peer.stop.bind(peer))
process.on("SIGHUP", peer.stop.bind(peer))
process.on('SIGUSR2', peer.stop.bind(peer, peer.start.bind(peer)))<|endoftext|>


<commit_before>'use strict';
const Twit = require('twit');
const tracery = require(`tracery-grammar`);
const the_pros = require(`./src/grammar.json`);

// Create tweet from grammar
const grammar = tracery.createGrammar(the_pros);
grammar.addModifiers(tracery.baseEngModifiers);
const tweet = grammar.flatten("#origin#");

// Create twitter client
var T = new Twit(
    { consumer_key:         process.env.TWITTER_CONSUMER_KEY
    , consumer_secret:      process.env.TWITTER_CONSUMER_SECRET
    , access_token:         process.env.TWITTER_ACCESS_TOKEN
    , access_token_secret:  process.env.TWITTER_ACCESS_TOKEN_SECRET
    }
);

console.log(`Tweeting tweet:\n${tweet}`);

// T.post('statuses/update', { status: tweet }, function(err, data, response) {
//     console.log(data)
// })
<commit_msg>Enable tweeting<commit_after>'use strict';
const Twit = require('twit');
const tracery = require(`tracery-grammar`);
const the_pros = require(`./src/grammar.json`);

// Create tweet from grammar
const grammar = tracery.createGrammar(the_pros);
grammar.addModifiers(tracery.baseEngModifiers);
const tweet = grammar.flatten("#origin#");

// Create twitter client
var T = new Twit(
    { consumer_key:         process.env.TWITTER_CONSUMER_KEY
    , consumer_secret:      process.env.TWITTER_CONSUMER_SECRET
    , access_token:         process.env.TWITTER_ACCESS_TOKEN
    , access_token_secret:  process.env.TWITTER_ACCESS_TOKEN_SECRET
    }
);

console.log(`Tweeting tweet:\n${tweet}`);

T.post('statuses/update', { status: tweet }, function(err, data, response) {
    console.log(data)
})
<|endoftext|>


<commit_before>const fs = require('fs');
const exec = require('child_process').exec;
const moment = require('moment');

/*****************************************************************
    0.........1.........2.........3.........4.........5.........
0   ------------------------------------------------------------
1   ---##----##----####-------##------##---#####---#####--------
2   ---####--##---##--##------##-----------##------##-----------
3   ---##-##-##---##--##------##------##---####----####---------
4   ---##--####---##--##------##------##---##------##-----------
5   ---##----##----####-------#####---##---##------#####--------
6   ------------------------------------------------------------
// run in console to draw on github timeline:
a = document.getElementsByClassName('day')
for (let i=0, l=a.length; i<l; i++ ){
  a[i].setAttribute('fill', '#c6e48b')
  a[i].addEventListener('click', ()=>{ a[i].setAttribute('fill', '#196127') })
  a[i].addEventListener('contextmenu', ()=>{ a[i].setAttribute('fill', '#c6e48b') })
}
*****************************************************************/

let days = [
  '------------------------------------------------------------'.split(''),
  '----##--##--###----##-----##--##--##--##--#-#-#-------------'.split(''),
  '----###-##-##-##----#--#--#--####--#--#---#-#-#-------------'.split(''),
  '----######-##-##----##-#-##-##--##-####---#-#-#-------------'.split(''),
  '----##-###-##-##----######--######--##----------------------'.split(''),
  '----##--##--###------##-##-###--###-##----#-#-#-------------'.split(''),
  '------------------------------------------------------------'.split('')
];

let offset = 17; // because the day i wrote this was 12 days after %60 == 0
// find indexes
let x = ( Math.floor((moment().diff(moment().startOf('year'), 'weeks') )-offset) ) % 60;
let y = moment().weekday() % 7;
// define if it s letter day or not
let isPixel = days[y][x] == '#';
log = (...opts) => {
  console.log( (isPixel?'#':'-')+' ['+moment().format('M-D-YY, h:mm a')+'] -', opts.join(' ') );
}

// Randomize:
// if it IS an update day, LOW exit likelyness
if ( isPixel && Math.random()<.15 ) {
  return log('Busy day but not now...');
}
// if it IS NOT an update day, HIGH exit likelyness
if ( !isPixel && Math.random()<.8 ) {
  return log('Not a busy day, not now...');
}

const emos = ["😀","😃","😄","😁","😆","😅","😂","😊","😇","🙂","🙃","😉","😌","😍","😘","😗","😙","😚",
  "😋","😜","😝","😛","🤑","🤗","🤓","😎","😏","😒","😞","😔","😟","😕","🙁","☹","😣","😖","😫","😩","😤",
  "😠","😡","😶","😐","😑","😯","😦","😧","😮","😲","😵","😳","😱","😨","😰","😢","😥","😭","😓","😪","😴",
  "🙄","🤔","😬","🤐","😷","🤒","🤕","😈","👿","👹","👺","💩","👻","💀","☠","👽","👾","🤖","🎃","😺","😸",
  "😹","😻","😼","😽","🙀","😿","😾","👐","🙌","👏","🙏","👍","👎","👊","✊","✌","🤘","👌","👈","👉","👆",
  "👇","☝","✋","🖐","🖖","👋","💪","🖕","✍","💅","🖖","💄","💋","👄","👅","👂","👃","👣","👁","👀","🗣",
  "👤","👥","👶","👦","👧","👨","👩","👱","👱","👴","👵","👲","👳","👳","👮","👮","👷","👷","💂","💂","🕵",
  "🕵","👩","👨","👩","🌾","👨","🌾","🍳","👨","🍳","👩","🎓","👨","👩","👨","🎤","👩","🏫","👨","🏫","👩",
  "🏭","👨","💻","👚","👕","👖","👔","👗","👙","👘","👠","👡","👢","👞","👟","👒","🎩","🎓","👑","⛑","🎒",
  "👝","👛","👜","💼","👓","🕶","🌂","☂"
];

// generate commit message
let n = 10;
let code = '';
let message = ''
while ( n-- > 0 )
  message += emos[Math.floor(Math.random()*emos.length)] + ' '
// generate random code
n = 3 + Math.random() * 10;
while ( n-- > 0 )
  code += emos[Math.floor(Math.random()*emos.length)] + ' '
  if ( Math.random() > .8 ) code += '\r\n';
// save code
fs.writeFileSync('jam.txt', code, 'utf8');
// push changes to github
exec('git pull && git add jam.txt && git commit -m "'+message+'" && git push', (error, stdout, stderr)=>{
  if (error) {
    return log('Error:', error, error.code);
  }
  log('√ Pushed to Git -', message);
})

<commit_msg>Fix year 2018 bug<commit_after>const fs = require('fs');
const exec = require('child_process').exec;
const moment = require('moment');

/*****************************************************************
// run in console to draw on github timeline:
a = document.getElementsByClassName('day')
for (let i=0, l=a.length; i<l; i++ ){
  a[i].setAttribute('fill', '#c6e48b')
  a[i].addEventListener('click', ()=>{ a[i].setAttribute('fill', '#196127') })
  a[i].addEventListener('contextmenu', ()=>{ a[i].setAttribute('fill', '#c6e48b') })
}
*****************************************************************/

let days = [
  '------------------------------------------------------------'.split(''),
  '----##--##--###----##-----##--##--##--##--#-#-#-------------'.split(''),
  '----###-##-##-##----#--#--#--####--#--#---#-#-#-------------'.split(''),
  '----######-##-##----##-#-##-##--##-####---#-#-#-------------'.split(''),
  '----##-###-##-##----######--######--##----------------------'.split(''),
  '----##--##--###------##-##-###--###-##----#-#-#-------------'.split(''),
  '------------------------------------------------------------'.split('')
];

let offset = 17; // because the day i wrote this was 12 days after %60 == 0
// find indexes
let x = ( Math.floor((moment().diff(moment('01-01-2016', 'MM-DD-YYYY').startOf('year'), 'weeks') )-offset) ) % 60;
let y = moment().weekday() % 7;
// define if it s letter day or not
let isPixel = days[y][x] == '#';
log = (...opts) => {
  console.log( (isPixel?'#':'-')+' ['+moment().format('M-D-YY, h:mm a')+'] -', opts.join(' ') );
}

// Randomize:
// if it IS an update day, LOW exit likelyness
if ( isPixel && Math.random()<.15 ) {
  return log('Busy day but not now...');
}
// if it IS NOT an update day, HIGH exit likelyness
if ( !isPixel && Math.random()<.8 ) {
  return log('Not a busy day, not now...');
}

const emos = ["😀","😃","😄","😁","😆","😅","😂","😊","😇","🙂","🙃","😉","😌","😍","😘","😗","😙","😚",
  "😋","😜","😝","😛","🤑","🤗","🤓","😎","😏","😒","😞","😔","😟","😕","🙁","☹","😣","😖","😫","😩","😤",
  "😠","😡","😶","😐","😑","😯","😦","😧","😮","😲","😵","😳","😱","😨","😰","😢","😥","😭","😓","😪","😴",
  "🙄","🤔","😬","🤐","😷","🤒","🤕","😈","👿","👹","👺","💩","👻","💀","☠","👽","👾","🤖","🎃","😺","😸",
  "😹","😻","😼","😽","🙀","😿","😾","👐","🙌","👏","🙏","👍","👎","👊","✊","✌","🤘","👌","👈","👉","👆",
  "👇","☝","✋","🖐","🖖","👋","💪","🖕","✍","💅","🖖","💄","💋","👄","👅","👂","👃","👣","👁","👀","🗣",
  "👤","👥","👶","👦","👧","👨","👩","👱","👱","👴","👵","👲","👳","👳","👮","👮","👷","👷","💂","💂","🕵",
  "🕵","👩","👨","👩","🌾","👨","🌾","🍳","👨","🍳","👩","🎓","👨","👩","👨","🎤","👩","🏫","👨","🏫","👩",
  "🏭","👨","💻","👚","👕","👖","👔","👗","👙","👘","👠","👡","👢","👞","👟","👒","🎩","🎓","👑","⛑","🎒",
  "👝","👛","👜","💼","👓","🕶","🌂","☂"
];

// generate commit message
let n = 10;
let code = '';
let message = ''
while ( n-- > 0 )
  message += emos[Math.floor(Math.random()*emos.length)] + ' '
// generate random code
n = 3 + Math.random() * 10;
while ( n-- > 0 )
  code += emos[Math.floor(Math.random()*emos.length)] + ' '
  if ( Math.random() > .8 ) code += '\r\n';
// save code
fs.writeFileSync('jam.txt', code, 'utf8');
// push changes to github
exec('git pull && git add jam.txt && git commit -m "'+message+'" && git push', (error, stdout, stderr)=>{
  if (error) {
    return log('Error:', error, error.code);
  }
  log('√ Pushed to Git -', message);
})

<|endoftext|>


<commit_before>/* eslint-env node, mocha */
'use strict';

const assert = require('chai').assert
      , utils = require('./index');

describe('Utils Tests', () => {

  it('should return an object that has a send and getCompression functions', () => {
    assert.isObject(utils);
    assert.isFunction(utils.send);
    assert.isFunction(utils.getCompression);
    assert.isFunction(utils.setup);
    assert.isFunction(utils.parsePath);
    assert.isFunction(utils.isDefined);
    assert.isFunction(utils.isUndefined);
    assert.isFunction(utils.not);
    assert.isFunction(utils.redirect);
    assert.isFunction(utils.contains);
  });

  describe('getCompression tests', () => {
    it('should return deflate if the deflate header is passed in', () => {
      assert.strictEqual(utils.getCompression('deflate', { compress: true }), 'deflate');
    });

    it('should return gzip if gzip is in the header passed in', () => {
      assert.strictEqual(utils.getCompression('gzip', { compress: true }), 'gzip');
    });

    it('should return br if brotli is in the header passed in', () => {
      assert.strictEqual(utils.getCompression('br', { compress: true }), 'br');
    });

    it('should return gzip if both gzip and deflate are in the header', () => {
      assert.strictEqual(utils.getCompression('deflate gzip', { compress: true }), 'gzip');
    });

    it('should return brotli if brotli, gzip and deflate are in the header', () => {
      assert.strictEqual(utils.getCompression('deflate gzip br', { compress: true }), 'br');
    });

    it('should return none if no header is passed in', () => {
      let header; // has no value... just exists

      assert.strictEqual(utils.getCompression(header, { compress: true }), 'none');
    });

    it('should return none if an empty header is passed in', () => {
      assert.strictEqual(utils.getCompression('', { compress: true }), 'none');
    });

    it('should return none if compression is turned off no matter what the header is', () => {
      assert.strictEqual(utils.getCompression('gzip', { compress: false }), 'none');
    });

    it('should return correct compression if compression is not in the config', () => {
      assert.strictEqual(utils.getCompression('gzip', {}), 'gzip');
    });
  });

  describe('send tests', () => {
    it('should have a send function', () => {
      assert.isFunction(utils.send);
    });
  });

  describe('setup tests', () => {
    it('utils should have a setup function', () => {
      assert.isFunction(utils.setup);
    });
  });
});
<commit_msg>added test for stated log<commit_after>/* eslint-env node, mocha */
'use strict';

const assert = require('chai').assert
      , utils = require('./index');

describe('Utils Tests', () => {

  it('should return an object that has a send and getCompression functions', () => {
    assert.isObject(utils);
    assert.isFunction(utils.send);
    assert.isFunction(utils.getCompression);
    assert.isFunction(utils.setup);
    assert.isFunction(utils.parsePath);
    assert.isFunction(utils.isDefined);
    assert.isFunction(utils.isUndefined);
    assert.isFunction(utils.not);
    assert.isFunction(utils.redirect);
    assert.isFunction(utils.contains);
  });

  describe('getCompression tests', () => {
    it('should return deflate if the deflate header is passed in', () => {
      assert.strictEqual(utils.getCompression('deflate', { compress: true }), 'deflate');
    });

    it('should return gzip if gzip is in the header passed in', () => {
      assert.strictEqual(utils.getCompression('gzip', { compress: true }), 'gzip');
    });

    it('should return br if brotli is in the header passed in', () => {
      assert.strictEqual(utils.getCompression('br', { compress: true }), 'br');
    });

    it('should return gzip if both gzip and deflate are in the header', () => {
      assert.strictEqual(utils.getCompression('deflate gzip', { compress: true }), 'gzip');
    });

    it('should return brotli if brotli, gzip and deflate are in the header', () => {
      assert.strictEqual(utils.getCompression('deflate gzip br', { compress: true }), 'br');
    });

    it('should return none if no header is passed in', () => {
      let header; // has no value... just exists

      assert.strictEqual(utils.getCompression(header, { compress: true }), 'none');
    });

    it('should return none if an empty header is passed in', () => {
      assert.strictEqual(utils.getCompression('', { compress: true }), 'none');
    });

    it('should return none if compression is turned off no matter what the header is', () => {
      assert.strictEqual(utils.getCompression('gzip', { compress: false }), 'none');
    });

    it('should return correct compression if compression is not in the config', () => {
      assert.strictEqual(utils.getCompression('gzip', {}), 'gzip');
    });
  });

  describe('send tests', () => {
    it('should have a send function', () => {
      assert.isFunction(utils.send);
    });
  });

  describe('setup tests', () => {
    it('utils should have a setup function', () => {
      assert.isFunction(utils.setup);
    });

    it('utils should log info about statsd', () => {
      let logMessage;
      const config = {
        log: {
          info: (msg) => {
            logMessage = msg;
          }
        }
        , statsd: {
          host: 'test'
          , port: '8080'
        }
      };

      utils.setup(config);
      assert.include(logMessage, config.statsd.host);
      assert.include(logMessage, config.statsd.port);
    });
  });
});
<|endoftext|>


<commit_before>"use strict";

const debug = require("debug")("bot");
import co from "co";

import util from "./libs/util"
import YokohamaArena from "./libs/yokohama-arena"
const arena = new YokohamaArena();
import NissanStadium from "./libs/nissan-stadium"
const nissan = new NissanStadium();
import twitterClient from "./libs/twitter-client";

co(function *(){

  const schedules = yield {
    arena: [arena.getTodaySchedule()],
    nissan: nissan.getMajorSchedules()
  };
  const events_today = [];
  for(let where in schedules){
    for(let schedule of schedules[where]){
      if(util.isScheduleToday(schedule)){
        events_today.push(schedule);
      }
    }
  }

  let msgs = [ "本日のイベントは" ];
  msgs = msgs.concat(
    events_today.map((event) => { return `${event.title}(${event.where})`})
  );
  const tweetText = msgs.join("\n");
  debug(tweetText);
  const result = yield twitterClient.update(tweetText);
  console.log(result);

}).catch(console.error);
<commit_msg>print stack trace<commit_after>"use strict";

const debug = require("debug")("bot");
import co from "co";

import util from "./libs/util"
import YokohamaArena from "./libs/yokohama-arena"
const arena = new YokohamaArena();
import NissanStadium from "./libs/nissan-stadium"
const nissan = new NissanStadium();
import twitterClient from "./libs/twitter-client";

co(function *(){

  const schedules = yield {
    arena: [arena.getTodaySchedule()],
    nissan: nissan.getMajorSchedules()
  };
  const events_today = [];
  for(let where in schedules){
    for(let schedule of schedules[where]){
      if(util.isScheduleToday(schedule)){
        events_today.push(schedule);
      }
    }
  }

  let msgs = [ "本日のイベントは" ];
  msgs = msgs.concat(
    events_today.map((event) => { return `${event.title}(${event.where})`})
  );
  const tweetText = msgs.join("\n");
  debug(tweetText);
  const result = yield twitterClient.update(tweetText);
  console.log(result);

}).catch((err) => {
  console.error(err.stack);
});
<|endoftext|>


<commit_before>const Discord = require('discord.js');
var http = require('http');
const yt = require('ytdl-core');
const options = require('./options.json');

const bot = new Discord.Client();
var music_quality = 3; //quality; 1 lowest, 5 highest
const token = options.token; //'Mjc0NzEzMjQ5NDk5NDQ3Mjk4.C22GLQ.toD09kvCfRefjAQADTXsEMsp5WE';

/*TODO

 - implement persistent storage
 - implement admin-only discrimination
 - implement playlist shuffle
 - implement single/playlist loop
 - implement welcome/farewell messages

*/

bot.on('ready', () => {
  bot.user.setGame('.help for, well, help!');
  console.log('Bot is ready!');
});

var errors = '';
let queue = {};

const admCommands = {
  'leave': (msg) => {
    msg.guild.channels.filter(n => {return n.type === 'voice'}).array().forEach(n => {n.leave()});
    msg.channel.sendMessage(`Leaving all voice channels on the server!`);
  },
  'join': (msg) => {
    return new Promise((resolve, reject) => {
      const voiceChannel = msg.member.voiceChannel;
      if (!voiceChannel || voiceChannel.type !== 'voice') return msg.reply('I couldn\'t connect to your voice channel...');
      voiceChannel.join().then(connection => resolve(connection)).catch(err => reject(err));
    });
  }
};

const commands = {
  'clear': (msg) => {
    var authorRoles = msg.guild.member(msg.author).roles;
    var intersectingRoles = authorRoles.keyArray().filter(n => {return msg.guild.member(bot.user).roles.keyArray().indexOf(n) != -1});
    var setRolePromise = msg.guild.member(msg.author).setRoles(authorRoles.filter(n => {return (intersectingRoles.indexOf(n.id) == -1 )}));
    setRolePromise.then(() => {
      var sentMsgPromise = msg.channel.sendMessage('Cleared your color role(s), ' + msg.author.username + '!');
      sentMsgPromise.then(sent => {sent.delete(3000); msg.delete(3000);}).catch(sent => {sent.delete(); console.log('Failed delivery of msg ' + sent.content);});
    })
    .catch(() => {
      var sentMsgPromise = msg.channel.sendMessage('Clearing role failed for unknown reason - likely because of incorrect role hierachy! Please let your moderators know about this failure!');
      sentMsgPromise.then(sent => {sent.delete(3000); msg.delete(3000);}).catch(sent => {sent.delete(); console.log('Failed delivery of message ' + sent.content);});
    });
  },
  'iam': (msg) => {
    var authorRoles = msg.guild.member(msg.author).roles;
    var roleName = msg.content.match(/^.iam (.*)/i)[1];
    var paramRole = msg.guild.roles.find(n => {return n.name.toLowerCase() === roleName.toLowerCase()});
    if (!msg.guild.roles.find(n => {return n.name.toLowerCase() === roleName.toLowerCase()})) {
      var sentMsgPromise = msg.channel.sendMessage('Could not find role ' + roleName + ', ' + msg.author.username + '!');
      sentMsgPromise.then(sent => {sent.delete(3000); msg.delete(3000);}).catch(sent => {sent.delete(); console.log('Failed delivery of message ' + sent.content);});
    } else if (msg.guild.member(bot.user).roles.has(paramRole.id)) {
      var roleId = paramRole.id;
      roleName = paramRole.name;
      var intersectingColorRoles = authorRoles.keyArray().filter(n => {return (msg.guild.member(bot.user).roles.keyArray().indexOf(n) != -1) && (msg.guild.roles.get(n).color)});
      if (intersectingColorRoles.length > 0 && paramRole.color) {
        var setRolePromise = msg.guild.member(msg.author).setRoles(authorRoles.filter(n => {return intersectingColorRoles.indexOf(n.id) == -1}).concat(msg.guild.roles.filter(n => {return n  .id == roleId})));
        setRolePromise.then(() => {
          var sentMsgPromise = msg.channel.sendMessage('Replaced your color role(s) with ' + roleName + ', ' + msg.author.username + '!');
          sentMsgPromise.then(sent => {sent.delete(3000); msg.delete(3000);}).catch(sent => {sent.delete(); console.log('Failed delivery of message ' + sent.content);});
        })
        .catch(() => {
          var sentMsgPromise = msg.channel.sendMessage('Replacing role failed for unknown reason - likely because of incorrect role hierachy! Please let your moderators know about this failure!');
          sentMsgPromise.then(sent => {sent.delete(3000); msg.delete(3000);}).catch(sent => {sent.delete(); console.log('Failed delivery of message ' + sent.content);});
        });
      } else {
        var addRolePromise = msg.guild.member(msg.author).addRole(roleId);
        addRolePromise.then(() => {
          var sentMsgPromise = msg.channel.sendMessage('Gave you role ' + roleName + ', ' + msg.author.username + '!');
          sentMsgPromise.then(sent => {sent.delete(3000); msg.delete(3000);}).catch(sent => {sent.delete(); console.log('Failed delivery of message ' + sent.content);});
        })
        .catch(() => {
          var sentMsgPromise = msg.channel.sendMessage('Assigning role failed for unknown reason - likely because of incorrect role hierachy! Please let your moderators know about this failure!');
          sentMsgPromise.then(sent => {sent.delete(3000); msg.delete(3000);}).catch(sent => {sent.delete(); console.log('Failed delivery of message ' + sent.content);});
        });
      }
    } else {
      var sentMsgPromise = msg.channel.sendMessage('I do not have access to role ' + roleName + ', ' + msg.author.username + '!');
      sentMsgPromise.then(sent => {sent.delete(3000); msg.delete(3000);}).catch(sent => {sent.delete(); console.log('Failed delivery of message ' + sent.content);});
    }
  },
  'play': (msg) => {
    if (queue[msg.guild.id] === undefined) return msg.channel.sendMessage(`Add some songs to the queue first with .add!`);
    if (!msg.guild.voiceConnection) return commands.join(msg).then(() => commands.play(msg));
    if (queue[msg.guild.id].playing) return msg.channel.sendMessage('Already Playing!');
    let dispatcher;
    queue[msg.guild.id].playing = true;
    (function play(song) {
      if (song === undefined) return msg.channel.sendMessage('Queue is empty - add more with `.add <url>`!').then(() => {
        queue[msg.guild.id].playing = false;
        //msg.member.voiceChannel.leave();
      });
      msg.channel.sendMessage(`Playing: **${song.title}** as requested by: **${song.requester}**`);
      dispatcher = msg.guild.voiceConnection.playStream(yt(song.url, { audioonly: true }), { passes : music_quality });
      let collector = msg.channel.createCollector(m => m);
      collector.on('message', m => {
        if (m.content.toLowerCase().startsWith('.pause')) {
          msg.channel.sendMessage('Playback paused!').then(() => {dispatcher.pause();});
        } else if (m.content.toLowerCase().startsWith('.resume')){
          msg.channel.sendMessage('Playback resumed!').then(() => {dispatcher.resume();});
        } else if (m.content.toLowerCase().startsWith('.skip')){
          msg.channel.sendMessage('Current track skipped!').then(() => {dispatcher.end();});
        } else if (m.content.toLowerCase().startsWith('.volume+')){
          if (Math.round(dispatcher.volume*50) >= 100) return msg.channel.sendMessage(`Volume: ${Math.round(dispatcher.volume*50)}%`);
          dispatcher.setVolume(Math.min((dispatcher.volume*50 + (2*(m.content.split('+').length-1)))/50,2));
          msg.channel.sendMessage(`Volume changed to ${Math.round(dispatcher.volume*50)}%!`);
        } else if (m.content.toLowerCase().startsWith('.volume-')){
          if (Math.round(dispatcher.volume*50) <= 0) return msg.channel.sendMessage(`Volume: ${Math.round(dispatcher.volume*50)}%`);
          dispatcher.setVolume(Math.max((dispatcher.volume*50 - (2*(m.content.split('-').length-1)))/50,0));
          msg.channel.sendMessage(`Volume changed to ${Math.round(dispatcher.volume*50)}%!`);
        } else if (m.content.toLowerCase().startsWith('.volume')){
          var param = m.content.split(' ')[1];
          if (param%1 === 0) {
            dispatcher.setVolume(Math.max(Math.min(param,100),0)/50);
            msg.channel.sendMessage(`Volume changed to ${Math.round(dispatcher.volume*50)}%!`);
          } else {
            msg.channel.sendMessage(`Please enter a whole number between 0 and 100 inclusive; Current volume is ${Math.round(dispatcher.volume*50)}%.`);
          }
        } else if (m.content.toLowerCase().startsWith('.time')){
          msg.channel.sendMessage(`Time in track: ${Math.floor(dispatcher.time / 60000)}:${Math.floor((dispatcher.time % 60000)/1000) <10 ? '0'+Math.floor((dispatcher.time % 60000)/1000) : Math.floor((dispatcher.time % 60000)/1000)}`);
        }
      });
      dispatcher.on('end', () => {
        collector.stop();
        queue[msg.guild.id].songs.shift();
        play(queue[msg.guild.id].songs[0]);
      });
      dispatcher.on('error', (err) => {
        return msg.channel.sendMessage('Error: ' + err).then(() => {
          collector.stop();
          queue[msg.guild.id].songs.shift();
          play(queue[msg.guild.id].songs[0]);
        });
      });
    })(queue[msg.guild.id].songs[0]);
  },
  'quality': (msg) => {
    var param = msg.content.split(' ')[1];
    if (param >= 1 && param <= 5 && (param%1)===0) {
      music_quality = param;
      msg.channel.sendMessage(`Music quality set to **${music_quality}**!`)
    } else {
      msg.channel.sendMessage(`Music quality can only be set to a whole number between 1 and 5 inclusive.`)
    }
  },
  'add': (msg) => {
    let url = msg.content.split(' ')[1];
    if (url == '' || url === undefined) return msg.channel.sendMessage(`You must add a url, or youtube video id after .add!`);
    try {
      yt.getInfo(url, (err, info) => {
        if (err) {return;}
        if (!queue.hasOwnProperty(msg.guild.id)) queue[msg.guild.id] = {}, queue[msg.guild.id].playing = false, queue[msg.guild.id].songs = [];
        queue[msg.guild.id].songs.push({url: url, title: info.title, requester: msg.author.username});
        msg.channel.sendMessage(`Successfully added **${info.title}** to the queue!`).then(() => {msg.delete();});
      });
    } catch (e) {
      msg.channel.sendMessage('Invalid YouTube Link: `' + url + '`').then(sent => {sent.delete(3000); msg.delete(3000);});
    }
  },
  'queue': (msg) => {
    if (queue[msg.guild.id] === undefined) return msg.channel.sendMessage(`Add some songs to the queue first with .add!`);
    let tosend = [];
    queue[msg.guild.id].songs.forEach((song, i) => { tosend.push(`${i+1}. ${song.title} - Requested by: ${song.requester}`);});
    msg.channel.sendMessage(`__**${msg.guild.name}'s Music Queue:**__ Currently **${tosend.length}** songs queued ${(tosend.length > 15 ? '*[Only next 15 shown]*' : '')}\n${tosend.length==0?'':'\`\`\`'}${tosend.slice(0,15).join('\n')}${tosend.length==0?'':'\`\`\`'}`).then(() => {msg.delete();});
  },
  'help': (msg) => {
    let tosend = ['```',
    '.iam <role>: Gives you a role. If you have any other roles that the bot possesses, it will attempt to remove the others for you.',
    '.clear: Clears all the roles the bot can take off you.', '.join : The bot will join the voice channel of the message\'s sender.',
    '.leave : The bot will leave all voice channels on the server.',
    '.quality <number>: Sets the music quality. Number must be between 1 and 5 inclusive. 5 is complete lossless.',
    '.add <url>: Adds a valid youtube link to the queue.', '.queue : Shows the current queue, up to 15 songs shown.',
    '.play : Play the music queue.',
    '.help : Displays this menu.',
    '',
    'the following commands only function while the play command is running:'.toUpperCase(),
    '.pause : Pauses the music.',
    '.resume : Resumes the music.',
    '.skip : Skips the current track.',
    '.time : Shows the playtime of the song.',
    '.volume+(+++) : Increases the volume by 2%/+.',
    '.volume-(---) : Decreases the volume by 2%/-.',
    '```'];
    msg.channel.sendMessage(tosend.join('\n')).then(() => {msg.delete();});
  },
};

bot.on('message', msg => {
  if (!msg.content.startsWith('.')) return;
  if (msg.content.startsWith('.!') && msg.member.permissions.hasPermission("ADMINISTRATOR")) {
    try {
      if (admCommands.hasOwnProperty(msg.content.toLowerCase().slice(2).split(' ')[0])) admCommands[msg.content.toLowerCase().slice(2).split(' ')[0]](msg);
    } catch (e) {
      console.err(`\n-------\n${e}\n-------\n`);
      errors = errors + e + '\n-------\n';
    }
  }
  try {
    if (commands.hasOwnProperty(msg.content.toLowerCase().slice(1).split(' ')[0])) commands[msg.content.toLowerCase().slice(1).split(' ')[0]](msg);
  } catch (e) {
    console.error(`\n-------\n${e}\n-------\n`);
    errors = errors + e + '\n-------\n';
  }
});

bot.login(token);

 http.createServer(function (request, response) {
   response.writeHead(200, {'Content-Type': 'text/plain'});
   response.end(errors + '\n');
}).listen(process.env.PORT || 5000);
<commit_msg>fixing .play fall-through to .join<commit_after>const Discord = require('discord.js');
var http = require('http');
const yt = require('ytdl-core');
const options = require('./options.json');

const bot = new Discord.Client();
var music_quality = 3; //quality; 1 lowest, 5 highest
const token = options.token; //'Mjc0NzEzMjQ5NDk5NDQ3Mjk4.C22GLQ.toD09kvCfRefjAQADTXsEMsp5WE';

/*TODO

 - implement persistent storage
 - implement admin-only discrimination
 - implement playlist shuffle
 - implement single/playlist loop
 - implement welcome/farewell messages

*/

bot.on('ready', () => {
  bot.user.setGame('.help for, well, help!');
  console.log('Bot is ready!');
});

var errors = '';
let queue = {};

const admCommands = {
  'leave': (msg) => {
    msg.guild.channels.filter(n => {return n.type === 'voice'}).array().forEach(n => {n.leave()});
    msg.channel.sendMessage(`Leaving all voice channels on the server!`);
  },
  'join': (msg) => {
    return new Promise((resolve, reject) => {
      const voiceChannel = msg.member.voiceChannel;
      if (!voiceChannel || voiceChannel.type !== 'voice') return msg.reply('I couldn\'t connect to your voice channel...');
      voiceChannel.join().then(connection => resolve(connection)).catch(err => reject(err));
    });
  }
};

const commands = {
  'clear': (msg) => {
    var authorRoles = msg.guild.member(msg.author).roles;
    var intersectingRoles = authorRoles.keyArray().filter(n => {return msg.guild.member(bot.user).roles.keyArray().indexOf(n) != -1});
    var setRolePromise = msg.guild.member(msg.author).setRoles(authorRoles.filter(n => {return (intersectingRoles.indexOf(n.id) == -1 )}));
    setRolePromise.then(() => {
      var sentMsgPromise = msg.channel.sendMessage('Cleared your color role(s), ' + msg.author.username + '!');
      sentMsgPromise.then(sent => {sent.delete(3000); msg.delete(3000);}).catch(sent => {sent.delete(); console.log('Failed delivery of msg ' + sent.content);});
    })
    .catch(() => {
      var sentMsgPromise = msg.channel.sendMessage('Clearing role failed for unknown reason - likely because of incorrect role hierachy! Please let your moderators know about this failure!');
      sentMsgPromise.then(sent => {sent.delete(3000); msg.delete(3000);}).catch(sent => {sent.delete(); console.log('Failed delivery of message ' + sent.content);});
    });
  },
  'iam': (msg) => {
    var authorRoles = msg.guild.member(msg.author).roles;
    var roleName = msg.content.match(/^.iam (.*)/i)[1];
    var paramRole = msg.guild.roles.find(n => {return n.name.toLowerCase() === roleName.toLowerCase()});
    if (!msg.guild.roles.find(n => {return n.name.toLowerCase() === roleName.toLowerCase()})) {
      var sentMsgPromise = msg.channel.sendMessage('Could not find role ' + roleName + ', ' + msg.author.username + '!');
      sentMsgPromise.then(sent => {sent.delete(3000); msg.delete(3000);}).catch(sent => {sent.delete(); console.log('Failed delivery of message ' + sent.content);});
    } else if (msg.guild.member(bot.user).roles.has(paramRole.id)) {
      var roleId = paramRole.id;
      roleName = paramRole.name;
      var intersectingColorRoles = authorRoles.keyArray().filter(n => {return (msg.guild.member(bot.user).roles.keyArray().indexOf(n) != -1) && (msg.guild.roles.get(n).color)});
      if (intersectingColorRoles.length > 0 && paramRole.color) {
        var setRolePromise = msg.guild.member(msg.author).setRoles(authorRoles.filter(n => {return intersectingColorRoles.indexOf(n.id) == -1}).concat(msg.guild.roles.filter(n => {return n  .id == roleId})));
        setRolePromise.then(() => {
          var sentMsgPromise = msg.channel.sendMessage('Replaced your color role(s) with ' + roleName + ', ' + msg.author.username + '!');
          sentMsgPromise.then(sent => {sent.delete(3000); msg.delete(3000);}).catch(sent => {sent.delete(); console.log('Failed delivery of message ' + sent.content);});
        })
        .catch(() => {
          var sentMsgPromise = msg.channel.sendMessage('Replacing role failed for unknown reason - likely because of incorrect role hierachy! Please let your moderators know about this failure!');
          sentMsgPromise.then(sent => {sent.delete(3000); msg.delete(3000);}).catch(sent => {sent.delete(); console.log('Failed delivery of message ' + sent.content);});
        });
      } else {
        var addRolePromise = msg.guild.member(msg.author).addRole(roleId);
        addRolePromise.then(() => {
          var sentMsgPromise = msg.channel.sendMessage('Gave you role ' + roleName + ', ' + msg.author.username + '!');
          sentMsgPromise.then(sent => {sent.delete(3000); msg.delete(3000);}).catch(sent => {sent.delete(); console.log('Failed delivery of message ' + sent.content);});
        })
        .catch(() => {
          var sentMsgPromise = msg.channel.sendMessage('Assigning role failed for unknown reason - likely because of incorrect role hierachy! Please let your moderators know about this failure!');
          sentMsgPromise.then(sent => {sent.delete(3000); msg.delete(3000);}).catch(sent => {sent.delete(); console.log('Failed delivery of message ' + sent.content);});
        });
      }
    } else {
      var sentMsgPromise = msg.channel.sendMessage('I do not have access to role ' + roleName + ', ' + msg.author.username + '!');
      sentMsgPromise.then(sent => {sent.delete(3000); msg.delete(3000);}).catch(sent => {sent.delete(); console.log('Failed delivery of message ' + sent.content);});
    }
  },
  'play': (msg) => {
    if (queue[msg.guild.id] === undefined) return msg.channel.sendMessage(`Add some songs to the queue first with .add!`);
    if (!msg.guild.voiceConnection) {msg.channel.sendMessage('I am not in any voice channels! Please have an adminsistrator add me to one with `.!join`.').then(sent => {sent.delete(3000); msg.delete(3000);});};
    if (queue[msg.guild.id].playing) return msg.channel.sendMessage('Already Playing!');
    let dispatcher;
    queue[msg.guild.id].playing = true;
    (function play(song) {
      if (song === undefined) return msg.channel.sendMessage('Queue is empty - add more with `.add <url>`!').then(() => {
        queue[msg.guild.id].playing = false;
        //msg.member.voiceChannel.leave();
      });
      msg.channel.sendMessage(`Playing: **${song.title}** as requested by: **${song.requester}**`);
      dispatcher = msg.guild.voiceConnection.playStream(yt(song.url, { audioonly: true }), { passes : music_quality });
      let collector = msg.channel.createCollector(m => m);
      collector.on('message', m => {
        if (m.content.toLowerCase().startsWith('.pause')) {
          msg.channel.sendMessage('Playback paused!').then(() => {dispatcher.pause();});
        } else if (m.content.toLowerCase().startsWith('.resume')){
          msg.channel.sendMessage('Playback resumed!').then(() => {dispatcher.resume();});
        } else if (m.content.toLowerCase().startsWith('.skip')){
          msg.channel.sendMessage('Current track skipped!').then(() => {dispatcher.end();});
        } else if (m.content.toLowerCase().startsWith('.volume+')){
          if (Math.round(dispatcher.volume*50) >= 100) return msg.channel.sendMessage(`Volume: ${Math.round(dispatcher.volume*50)}%`);
          dispatcher.setVolume(Math.min((dispatcher.volume*50 + (2*(m.content.split('+').length-1)))/50,2));
          msg.channel.sendMessage(`Volume changed to ${Math.round(dispatcher.volume*50)}%!`);
        } else if (m.content.toLowerCase().startsWith('.volume-')){
          if (Math.round(dispatcher.volume*50) <= 0) return msg.channel.sendMessage(`Volume: ${Math.round(dispatcher.volume*50)}%`);
          dispatcher.setVolume(Math.max((dispatcher.volume*50 - (2*(m.content.split('-').length-1)))/50,0));
          msg.channel.sendMessage(`Volume changed to ${Math.round(dispatcher.volume*50)}%!`);
        } else if (m.content.toLowerCase().startsWith('.volume')){
          var param = m.content.split(' ')[1];
          if (param%1 === 0) {
            dispatcher.setVolume(Math.max(Math.min(param,100),0)/50);
            msg.channel.sendMessage(`Volume changed to ${Math.round(dispatcher.volume*50)}%!`);
          } else {
            msg.channel.sendMessage(`Please enter a whole number between 0 and 100 inclusive; Current volume is ${Math.round(dispatcher.volume*50)}%.`);
          }
        } else if (m.content.toLowerCase().startsWith('.time')){
          msg.channel.sendMessage(`Time in track: ${Math.floor(dispatcher.time / 60000)}:${Math.floor((dispatcher.time % 60000)/1000) <10 ? '0'+Math.floor((dispatcher.time % 60000)/1000) : Math.floor((dispatcher.time % 60000)/1000)}`);
        }
      });
      dispatcher.on('end', () => {
        collector.stop();
        queue[msg.guild.id].songs.shift();
        play(queue[msg.guild.id].songs[0]);
      });
      dispatcher.on('error', (err) => {
        return msg.channel.sendMessage('Error: ' + err).then(() => {
          collector.stop();
          queue[msg.guild.id].songs.shift();
          play(queue[msg.guild.id].songs[0]);
        });
      });
    })(queue[msg.guild.id].songs[0]);
  },
  'quality': (msg) => {
    var param = msg.content.split(' ')[1];
    if (param >= 1 && param <= 5 && (param%1)===0) {
      music_quality = param;
      msg.channel.sendMessage(`Music quality set to **${music_quality}**!`)
    } else {
      msg.channel.sendMessage(`Music quality can only be set to a whole number between 1 and 5 inclusive.`)
    }
  },
  'add': (msg) => {
    let url = msg.content.split(' ')[1];
    if (url == '' || url === undefined) return msg.channel.sendMessage(`You must add a url, or youtube video id after .add!`);
    try {
      yt.getInfo(url, (err, info) => {
        if (err) {return;}
        if (!queue.hasOwnProperty(msg.guild.id)) queue[msg.guild.id] = {}, queue[msg.guild.id].playing = false, queue[msg.guild.id].songs = [];
        queue[msg.guild.id].songs.push({url: url, title: info.title, requester: msg.author.username});
        msg.channel.sendMessage(`Successfully added **${info.title}** to the queue!`).then(() => {msg.delete();});
      });
    } catch (e) {
      msg.channel.sendMessage('Invalid YouTube Link: `' + url + '`').then(sent => {sent.delete(3000); msg.delete(3000);});
    }
  },
  'queue': (msg) => {
    if (queue[msg.guild.id] === undefined) return msg.channel.sendMessage(`Add some songs to the queue first with .add!`);
    let tosend = [];
    queue[msg.guild.id].songs.forEach((song, i) => { tosend.push(`${i+1}. ${song.title} - Requested by: ${song.requester}`);});
    msg.channel.sendMessage(`__**${msg.guild.name}'s Music Queue:**__ Currently **${tosend.length}** songs queued ${(tosend.length > 15 ? '*[Only next 15 shown]*' : '')}\n${tosend.length==0?'':'\`\`\`'}${tosend.slice(0,15).join('\n')}${tosend.length==0?'':'\`\`\`'}`).then(() => {msg.delete();});
  },
  'help': (msg) => {
    let tosend = ['```',
    '.iam <role>: Gives you a role. If you have any other roles that the bot possesses, it will attempt to remove the others for you.',
    '.clear: Clears all the roles the bot can take off you.', '.join : The bot will join the voice channel of the message\'s sender.',
    '.leave : The bot will leave all voice channels on the server.',
    '.quality <number>: Sets the music quality. Number must be between 1 and 5 inclusive. 5 is complete lossless.',
    '.add <url>: Adds a valid youtube link to the queue.', '.queue : Shows the current queue, up to 15 songs shown.',
    '.play : Play the music queue.',
    '.help : Displays this menu.',
    '',
    'the following commands only function while the play command is running:'.toUpperCase(),
    '.pause : Pauses the music.',
    '.resume : Resumes the music.',
    '.skip : Skips the current track.',
    '.time : Shows the playtime of the song.',
    '.volume+(+++) : Increases the volume by 2%/+.',
    '.volume-(---) : Decreases the volume by 2%/-.',
    '```'];
    msg.channel.sendMessage(tosend.join('\n')).then(() => {msg.delete();});
  },
};

bot.on('message', msg => {
  if (!msg.content.startsWith('.')) return;
  if (msg.content.startsWith('.!') && msg.member.permissions.hasPermission("ADMINISTRATOR")) {
    try {
      if (admCommands.hasOwnProperty(msg.content.toLowerCase().slice(2).split(' ')[0])) admCommands[msg.content.toLowerCase().slice(2).split(' ')[0]](msg);
    } catch (e) {
      console.err(`\n-------\n${e}\n-------\n`);
      errors = errors + e + '\n-------\n';
    }
  }
  try {
    if (commands.hasOwnProperty(msg.content.toLowerCase().slice(1).split(' ')[0])) commands[msg.content.toLowerCase().slice(1).split(' ')[0]](msg);
  } catch (e) {
    console.error(`\n-------\n${e}\n-------\n`);
    errors = errors + e + '\n-------\n';
  }
});

bot.login(token);

 http.createServer(function (request, response) {
   response.writeHead(200, {'Content-Type': 'text/plain'});
   response.end(errors + '\n');
}).listen(process.env.PORT || 5000);
<|endoftext|>


<commit_before>let Client = require('./src/client');

let client = new Client();
client.on('ready', () => {
    client.setClientGame("WORLD DOMINATION");
});

client.on('server-created', (server) => {
    if(server.name === "Ho-Bokes") {
        let web_str = 'Members online: ';
        client.guilds.all().forEach(server => {
            console.log("NAME " + server.name);
        });
        client.guilds.get("name", "Ho-Bokes").members.all("online", true).forEach(member => {
            web_str += member.username + ", ";
        });
        web_str = web_str.substring(0, web_str.length - 2);
        // Heroku app page
        var http = require('http');
        let port = process.env.PORT || 9000;

        var http_server = http.createServer((request, response) => {
            response.end(`There are no strings on me!\n\n${web_str}`);
        });

        http_server.listen(port, () => {
            console.log("Server listening on: http://localhost:%s", port);
        });
    }
});

client.login("MTkxNTc3NDYwOTI2NTc4Njg5.Cj8T6g.thz8gHSZ1JNNJXHkjJnhgpXXmNM");
<commit_msg>Cleanup bot.js<commit_after>const http = require('http');
const Client = require('./src/client');

let web_str = '';

let client = new Client();
client.on('ready', () => {
    client.setClientGame('WORLD DOMINATION');
});

client.on('server-created', (server) => {
    if(server.name === 'Ho-Bokes') {
        let web_str = 'Members online: ';
        client.guilds.all().forEach(server => {
            console.log('NAME ' + server.name);
        });
        client.guilds.get('name', 'Ho-Bokes').members.all('online', true).forEach(member => {
            web_str += member.username + ', ';
        });
        web_str = web_str.substring(0, web_str.length - 2);
    }
});

client.login('MTkxNTc3NDYwOTI2NTc4Njg5.Cj8T6g.thz8gHSZ1JNNJXHkjJnhgpXXmNM');

// Heroku app page
const port = process.env.PORT || 9000;

var http_server = http.createServer((request, response) => {
    response.end(`There are no strings on me!\n\n${web_str}`);
});

http_server.listen(port, () => {
    console.log('Server listening on: http://localhost:%s', port);
});
<|endoftext|>


<commit_before>var TGBOT = require("./tg");
var config = require("./config");
var bot = new TGBOT({
    token: config.token,
    help: true
});
var db = require("./db");
var DB = new db(config.dbConnectionString);

bot.on('message', function(message) {

    if (message.chat.id == config.consoleGroup) {
        if (message.reply_to_message && message.text && message.reply_to_message.forward_from) {
            DB.findOriginalIdByFwdMsgId(message.reply_to_message.message_id, function(err, doc) {
                if (err) console.log(err);
                if (message.text == "info") {
                    message.replyMsg("```\n"+JSON.stringify(doc, null, 2)+"```",{parse_mode:"Markdown"});
                }
                else if (message.text.slice(0, 5) == "reply") {
                    if (doc) bot.sendMessage(doc.chat.id, message.text.slice(5), {
                        reply_to_message_id: doc.message_id
                    });
                }
            });

        }
    }
    else {
        bot.forwardMessage(config.consoleGroup, message.chat.id, message.message_id, {}, function(err, result) {
            if (err) {
                console.log(err);
                DB.saveMessage(message);
            }
            else {
                message.fwd_id = result.message_id;
                message.mention = [];
                if (message.entities) {
                    message.entities.forEach(function(entity) {
                        switch (entity.type) {
                            case 'mention':
                                message.mention.push(message.text.slice(entity.offset, entity.offset + entity.length));
                                break;
                            case 'text_mention':
                                message.mention.push(entity.user.id.toString());
                                break;
                            default:
                                // code
                        }
                    });
                }
                if (message.reply_to_message) {
                    message.mention.push(message.reply_to_message.from.id.toString());
                }
                DB.saveMessage(message);
            }
        });
    }
});

bot.on('edited_message', function(message) {
    if (message.chat.id != config.consoleGroup) {
        bot.forwardMessage(config.consoleGroup, message.chat.id, message.message_id, {}, function(err, result) {
            if (err) console.log(err);
            if (result) message.fwd_id = result.message_id;
            DB.saveMessage(message);
        });
    }
});

bot.addCmd('wmmm', function(message, args) {
    listView(message, args, DB.findMention(message.from.username, message.from.id.toString()), function(docs) {
        var text = "";
        docs.forEach(function(doc, index) {
            text += (index + 1 + ". " + (doc.from.username || doc.from.first_name) + " : " + (doc.text || "[Not Text]") + "\n");
        });
        text = text || "Nothing";
        return text;
    }, function(i, messages, cbq) {
        if (messages[i]) {
            bot.replyMessage(messages[i].chat.id, messages[i].message_id, (cbq.from.username ? "@" + cbq.from.username : cbq.from.first_name) + " ^", {
                disable_notification: true
            });
            cbq.answer("請至 " + messages[i].chat.title + " 查看");
        }
    });
}, "查看有哪些訊息提到我");

bot.addCmd('mh', function(message, args) {
    if (message.reply_to_message) {

        listView(message, args, DB.findHistory(message.reply_to_message.message_id, message.chat.id), function(docs) {
            var text = "";
            docs.forEach(function(doc, index) {
                var dateString = new Date((doc.edit_date || doc.date) * 1000).toLocaleTimeString();
                text += (index + 1 + ". " + dateString + " : " + (doc.text || "[Not Text]") + "\n");

            });
            text = text || "Nothing";
            return text;
        }, function(i, messages, cbq) {
            if (messages[i]) bot.forwardMessage(cbq.from.id, config.consoleGroup, messages[i].fwd_id);
            cbq.answer();
        });
    }
}, "訊息歷史", "reply要查看的訊息後 打 /mh");

bot.addCmd('wmr', (message, args) => {
    if (message.reply_to_message) DB.findRepliedIdByMessageId(message.reply_to_message.message_id, function(err, doc) {
        if (err) console.log(err);
        if (doc && doc.reply_to_message) {
            listView(message, args, DB.findHistory(doc.reply_to_message.message_id, doc.reply_to_message.chat.id), function(docs) {
                var text = "";
                docs.forEach(function(newdoc, index) {
                    var dateString = new Date((newdoc.edit_date || newdoc.date) * 1000).toLocaleTimeString();
                    text += (index + 1 + ". " + dateString + " : " + (newdoc.text || "[Not Text]") + "\n");

                });
                text = text || "Nothing";
                return text;
            }, function(i, messages, cbq) {
                if (messages[i]) bot.forwardMessage(cbq.from.id, config.consoleGroup, messages[i].fwd_id);
                cbq.answer();
            });
        }
    });
}, "查看該訊息回復了哪則訊息", "reply要查看的訊息後 打 /wmr");

bot.addCmd('search', (message, args) => {
    if (args[1]) {
        var pattern = args[0],
            chatId = message.chat.id;

        if (args[1] == '-g') {
            args.splice(0, 2);
            pattern = args.join(' ');
            chatId = null;
        }

        if (message.chat.type == 'private') chatId = null;

        listView(message, args, DB.listFindMessage(pattern, 'i', chatId), function(docs) {
            var text = "";
            docs.forEach(function(doc, index) {
                text += (index + 1 + ". " + (doc.from.username || doc.from.first_name) + " : " + (doc.text || "[Not Text]") + "\n");

            });
            text = text || "Nothing";
            return text;
        }, function(i, messages, cbq) {
            if (messages[i]) bot.forwardMessage(cbq.from.id, config.consoleGroup, messages[i].fwd_id);
            cbq.answer();
        });
    }
}, "搜尋訊息", "/search (regex)");

function listView(message, args, iterator, processToText, whenClickNumber) {

    var gen = function*() {
        var docs = yield iterator.nextMessage((docs) => gen.next(docs));
        var messages = docs;
        message.sendToUser(processToText(docs), {
            reply_markup: JSON.stringify({
                inline_keyboard: [
                    [{
                        text: "1",
                        callback_data: "1"
                    }, {
                        text: "2",
                        callback_data: "2"
                    }, {
                        text: "3",
                        callback_data: "3"
                    }, {
                        text: "4",
                        callback_data: "4"
                    }, {
                        text: "5",
                        callback_data: "5"
                    }],
                    [{
                        text: "<",
                        callback_data: "previous"
                    }, {
                        text: ">",
                        callback_data: "next"
                    }]
                ],
                disable_notification: true
            })
        }, function(err) {
            if (err) {
                try {
                    console.log(err.message);
                    err = JSON.parse(err.message);
                }
                catch (e) {
                    console.log(e);
                }
                if (err && (err.description == "Forbidden: bot can't initiate conversation with a user" || err.description == "Bot was blocked by the user")) {
                    message.replyMsg("您需要先私訊本機器人！ OwO", {
                        reply_markup: JSON.stringify({
                            inline_keyboard: [
                                [{
                                    text: "Start",
                                    url: "http://telegram.me/" + bot.username
                                }]
                            ]
                        })
                    });
                }
            }
        }).onCallbackQuery(function(cbq) {
            if (cbq.data.match(/^\d$/)) {
                var i = Number(cbq.data) - 1;
                whenClickNumber(i, messages, cbq);
            }
            else if (cbq.data == "previous") {
                iterator.previousMessage(function(docs) {
                    messages = docs;
                    cbq.message.editText(processToText(docs));
                    cbq.answer();
                });
            }
            else if (cbq.data == "next") {
                iterator.nextMessage(function(docs) {
                    messages = docs;
                    cbq.message.editText(processToText(docs));
                    cbq.answer();
                });
            }
        });

    }();

    gen.next();

}

bot.start();
<commit_msg>Fixed #7, add a button to delete /wmmm notify msg<commit_after>var TGBOT = require("./tg");
var config = require("./config");
var bot = new TGBOT({
    token: config.token,
    help: true
});
var db = require("./db");
var DB = new db(config.dbConnectionString);

bot.on('message', function(message) {

    if (message.chat.id == config.consoleGroup) {
        if (message.reply_to_message && message.text && message.reply_to_message.forward_from) {
            DB.findOriginalIdByFwdMsgId(message.reply_to_message.message_id, function(err, doc) {
                if (err) console.log(err);
                if (message.text == "info") {
                    message.replyMsg("```\n" + JSON.stringify(doc, null, 2) + "```", { parse_mode: "Markdown" });
                }
                else if (message.text.slice(0, 5) == "reply") {
                    if (doc) bot.sendMessage(doc.chat.id, message.text.slice(5), {
                        reply_to_message_id: doc.message_id
                    });
                }
            });

        }
    }
    else {
        bot.forwardMessage(config.consoleGroup, message.chat.id, message.message_id, {}, function(err, result) {
            if (err) {
                console.log(err);
                DB.saveMessage(message);
            }
            else {
                message.fwd_id = result.message_id;
                message.mention = [];
                if (message.entities) {
                    message.entities.forEach(function(entity) {
                        switch (entity.type) {
                            case 'mention':
                                message.mention.push(message.text.slice(entity.offset, entity.offset + entity.length));
                                break;
                            case 'text_mention':
                                message.mention.push(entity.user.id.toString());
                                break;
                            default:
                                // code
                        }
                    });
                }
                if (message.reply_to_message) {
                    message.mention.push(message.reply_to_message.from.id.toString());
                }
                DB.saveMessage(message);
            }
        });
    }
});

bot.on('edited_message', function(message) {
    if (message.chat.id != config.consoleGroup) {
        bot.forwardMessage(config.consoleGroup, message.chat.id, message.message_id, {}, function(err, result) {
            if (err) console.log(err);
            if (result) message.fwd_id = result.message_id;
            DB.saveMessage(message);
        });
    }
});

bot.addCmd('wmmm', function(message, args) {
    listView(message, args, DB.findMention(message.from.username, message.from.id.toString()), function(docs) {
        var text = "";
        docs.forEach(function(doc, index) {
            text += (index + 1 + ". " + (doc.from.username || doc.from.first_name) + " : " + (doc.text || "[Not Text]") + "\n");
        });
        text = text || "Nothing";
        return text;
    }, function(i, messages, cbq) {
        if (messages[i]) {
            bot.replyMessage(messages[i].chat.id, messages[i].message_id, (cbq.from.username ? "@" + cbq.from.username : cbq.from.first_name) + " ^", {
                disable_notification: true,
                reply_markup: JSON.stringify({
                    inline_keyboard: [
                        [{
                            text: "已讀",
                            callback_data: "read"
                        }]
                    ]
                })
            }).onCallbackQuery(cbQuery => {
                if (cbQuery.from.id != message.from.id) {
                    return cbQuery.answer("僅供被提醒者使用");
                }
                if (cbQuery.data == "read") {
                    cbQuery.answer("提醒訊息已刪除");
                    cbQuery.message.delete();
                }
            });
            cbq.answer("請至 " + messages[i].chat.title + " 查看");
        } else {
            cbq.answer("無此訊息");
        }
    });
}, "查看有哪些訊息提到我");

bot.addCmd('mh', function(message, args) {
    if (message.reply_to_message) {

        listView(message, args, DB.findHistory(message.reply_to_message.message_id, message.chat.id), function(docs) {
            var text = "";
            docs.forEach(function(doc, index) {
                var dateString = new Date((doc.edit_date || doc.date) * 1000).toLocaleTimeString();
                text += (index + 1 + ". " + dateString + " : " + (doc.text || "[Not Text]") + "\n");

            });
            text = text || "Nothing";
            return text;
        }, function(i, messages, cbq) {
            if (messages[i]) {
                bot.forwardMessage(cbq.from.id, config.consoleGroup, messages[i].fwd_id);
                cbq.answer();
            } else {
                cbq.answer("無此訊息");
            }
        });
    }
}, "訊息歷史", "reply要查看的訊息後 打 /mh");

bot.addCmd('wmr', (message, args) => {
    if (message.reply_to_message) DB.findRepliedIdByMessageId(message.reply_to_message.message_id, function(err, doc) {
        if (err) console.log(err);
        if (doc && doc.reply_to_message) {
            listView(message, args, DB.findHistory(doc.reply_to_message.message_id, doc.reply_to_message.chat.id), function(docs) {
                var text = "";
                docs.forEach(function(newdoc, index) {
                    var dateString = new Date((newdoc.edit_date || newdoc.date) * 1000).toLocaleTimeString();
                    text += (index + 1 + ". " + dateString + " : " + (newdoc.text || "[Not Text]") + "\n");

                });
                text = text || "Nothing";
                return text;
            }, function(i, messages, cbq) {
                if (messages[i]) {
                    bot.forwardMessage(cbq.from.id, config.consoleGroup, messages[i].fwd_id);
                    cbq.answer();
                } else {
                    cbq.answer("無此訊息");
                }
            });
        }
    });
}, "查看該訊息回復了哪則訊息", "reply要查看的訊息後 打 /wmr");

bot.addCmd('search', (message, args) => {
    if (args[1]) {
        var pattern = args[0],
            chatId = message.chat.id;

        if (args[1] == '-g') {
            args.splice(0, 2);
            pattern = args.join(' ');
            chatId = null;
        }

        if (message.chat.type == 'private') chatId = null;

        listView(message, args, DB.listFindMessage(pattern, 'i', chatId), function(docs) {
            var text = "";
            docs.forEach(function(doc, index) {
                text += (index + 1 + ". " + (doc.from.username || doc.from.first_name) + " : " + (doc.text || "[Not Text]") + "\n");

            });
            text = text || "Nothing";
            return text;
        }, function(i, messages, cbq) {
            if (messages[i]) {
                bot.forwardMessage(cbq.from.id, config.consoleGroup, messages[i].fwd_id);
                cbq.answer();
            } else {
                cbq.answer("無此訊息");
            }
        });
    }
}, "搜尋訊息", "/search (regex)");

function listView(message, args, iterator, processToText, whenClickNumber) {

    var gen = function*() {
        var docs = yield iterator.nextMessage((docs) => gen.next(docs));
        var messages = docs;
        message.sendToUser(processToText(docs), {
            reply_markup: JSON.stringify({
                inline_keyboard: [
                    [{
                        text: "1",
                        callback_data: "1"
                    }, {
                        text: "2",
                        callback_data: "2"
                    }, {
                        text: "3",
                        callback_data: "3"
                    }, {
                        text: "4",
                        callback_data: "4"
                    }, {
                        text: "5",
                        callback_data: "5"
                    }],
                    [{
                        text: "<",
                        callback_data: "previous"
                    }, {
                        text: ">",
                        callback_data: "next"
                    }]
                ],
                disable_notification: true
            })
        }, function(err) {
            if (err) {
                try {
                    console.log(err.message);
                    err = JSON.parse(err.message);
                }
                catch (e) {
                    console.log(e);
                }
                if (err && (err.description == "Forbidden: bot can't initiate conversation with a user" || err.description == "Bot was blocked by the user")) {
                    message.replyMsg("您需要先私訊本機器人！ OwO", {
                        reply_markup: JSON.stringify({
                            inline_keyboard: [
                                [{
                                    text: "Start",
                                    url: "http://telegram.me/" + bot.username
                                }]
                            ]
                        })
                    });
                }
            }
        }).onCallbackQuery(function(cbq) {
            if (cbq.data.match(/^\d$/)) {
                var i = Number(cbq.data) - 1;
                whenClickNumber(i, messages, cbq);
            }
            else if (cbq.data == "previous") {
                iterator.previousMessage(function(docs) {
                    messages = docs;
                    cbq.message.editText(processToText(docs));
                    cbq.answer();
                });
            }
            else if (cbq.data == "next") {
                iterator.nextMessage(function(docs) {
                    messages = docs;
                    cbq.message.editText(processToText(docs));
                    cbq.answer();
                });
            }
        });

    }();

    gen.next();

}

bot.start();
<|endoftext|>