<commit_before>if (typeof window !== 'undefined') {
  var waitSeconds = 100;

  var head = document.getElementsByTagName('head')[0];

  // get all link tags in the page
  var links = document.getElementsByTagName('link');
  var linkHrefs = [];
  for (var i = 0; i < links.length; i++) {
    linkHrefs.push(links[i].href);
  }

  var isWebkit = !!window.navigator.userAgent.match(/AppleWebKit\/([^ ;]*)/);
  var webkitLoadCheck = function(link, callback) {
    setTimeout(function() {
      for (var i = 0; i < document.styleSheets.length; i++) {
        var sheet = document.styleSheets[i];
        if (sheet.href == link.href)
          return callback();
      }
      webkitLoadCheck(link, callback);
    }, 10);
  };

  var noop = function() {};

  var loadCSS = function(url) {
    return new Promise(function(resolve, reject) {
      var timeout = setTimeout(function() {
        reject('Unable to load CSS');
      }, waitSeconds * 1000);
      var _callback = function(error) {
        clearTimeout(timeout);
        link.onload = link.onerror = noop;
        setTimeout(function() {
          if (error)
            reject(error);
          else
            resolve('');
        }, 7);
      };
      var link = document.createElement('link');
      link.type = 'text/css';
      link.rel = 'stylesheet';
      link.href = url;
      if (!isWebkit) {
        link.onload = function() {
          _callback();
        }
        link.onerror = function(event) {
          _callback(event.error);
        }
      } else {
        webkitLoadCheck(link, _callback);
      }
      head.appendChild(link);
    });
  };

  exports.fetch = function(load) {
    // dont reload styles loaded in the head
    for (var i = 0; i < linkHrefs.length; i++)
      if (load.address == linkHrefs[i])
        return '';
    return loadCSS(load.address);
  };
}
else {
  exports.fetch = function(load) {
    // individually mark loads as not built for buildCSS false
    if (this.buildCSS === false)
      load.metadata.build = false;
    // setting format = 'defined' means we're managing our own output
    load.metadata.format = 'defined';
    // don't load the CSS at all until build time
    return '';
  };
  exports.bundle = function(loads, opts) {
    var loader = this;
    if (loader.buildCSS === false)
      return '';
    return loader['import']('./css-builder', { name: module.id }).then(function(builder) {
      return builder.call(loader, loads, opts);
    });
  };
}
<commit_msg>server execution bug<commit_after>if (typeof window !== 'undefined') {
  var waitSeconds = 100;

  var head = document.getElementsByTagName('head')[0];

  // get all link tags in the page
  var links = document.getElementsByTagName('link');
  var linkHrefs = [];
  for (var i = 0; i < links.length; i++) {
    linkHrefs.push(links[i].href);
  }

  var isWebkit = !!window.navigator.userAgent.match(/AppleWebKit\/([^ ;]*)/);
  var webkitLoadCheck = function(link, callback) {
    setTimeout(function() {
      for (var i = 0; i < document.styleSheets.length; i++) {
        var sheet = document.styleSheets[i];
        if (sheet.href == link.href)
          return callback();
      }
      webkitLoadCheck(link, callback);
    }, 10);
  };

  var noop = function() {};

  var loadCSS = function(url) {
    return new Promise(function(resolve, reject) {
      var timeout = setTimeout(function() {
        reject('Unable to load CSS');
      }, waitSeconds * 1000);
      var _callback = function(error) {
        clearTimeout(timeout);
        link.onload = link.onerror = noop;
        setTimeout(function() {
          if (error)
            reject(error);
          else
            resolve('');
        }, 7);
      };
      var link = document.createElement('link');
      link.type = 'text/css';
      link.rel = 'stylesheet';
      link.href = url;
      if (!isWebkit) {
        link.onload = function() {
          _callback();
        }
        link.onerror = function(event) {
          _callback(event.error);
        }
      } else {
        webkitLoadCheck(link, _callback);
      }
      head.appendChild(link);
    });
  };

  exports.fetch = function(load) {
    // dont reload styles loaded in the head
    for (var i = 0; i < linkHrefs.length; i++)
      if (load.address == linkHrefs[i])
        return '';
    return loadCSS(load.address);
  };
}
else {
  exports.fetch = function(load) {
    // individually mark loads as not built for buildCSS false
    if (this.buildCSS === false)
      load.metadata.build = false;
    // setting format = 'defined' means we're managing our own output
    load.metadata.format = 'defined';
    // don't load the CSS at all until build time
    return '';
  };
  exports.instantiate = function() {};
  exports.bundle = function(loads, opts) {
    var loader = this;
    if (loader.buildCSS === false)
      return '';
    return loader['import']('./css-builder', { name: module.id }).then(function(builder) {
      return builder.call(loader, loads, opts);
    });
  };
}
<|endoftext|>


<commit_before>(function(context) {

  var Lazy = context.Lazy;

  // Define a custom type of sequence that recursively walks the nodes of an
  // AST.
  Lazy.Sequence.define('nodes', {
    each: function(fn) {
      var self = this;

      self.parent.each(function(node) {
        if (fn(node) === false) {
          return false;
        }

        var children = self.getNodeChildren(node);
        if (children.length > 0) {
          return Lazy(children).nodes().each(fn);
        }
      });
    },

    getNodeChildren: function(node) {
      switch (node.type) {
        case 'FunctionDeclaration':
        case 'FunctionExpression':
          return [node.body];

        case 'BlockStatement':
          return node.body;

        case 'ExpressionStatement':
          return [node.expression];

        case 'AssignmentExpression':
          return node.right.type === 'FunctionExpression' ? [node.right] : [];

        case 'CallExpression':
          return node.callee.type === 'FunctionExpression' ? [node.callee] : [];

        default: return [];
      }
    }
  });

  /**
   * @namespace Breakneck
   */
  var Breakneck = {};

  /**
   * Parses an arbitrary blob of JavaScript code and returns an object
   * containing all of the data necessary to generate a project website with
   * docs, specs, and performance benchmarks.
   *
   * @param {string} code The JavaScript code to parse.
   * @param {Object=} options
   * @returns {Object}
   */
  Breakneck.parse = function(code, options) {
    options = options || {};

    var codeParser     = options.codeParser     || context.esprima,
        commentParser  = options.commentParser  || context.doctrine,
        markdownParser = options.markdownParser || defaultMarkdownParser();

    // Generate the abstract syntax tree.
    var ast = codeParser.parse(code, {
      comment: true,
      loc: true
    });

    // Extract all of the function from the AST, and map them to their location
    // in the code (this is so that we can associate each function with its
    // accompanying doc comments, if any).
    var functions = Lazy(ast.body).nodes()
      .filter(function(node) {
        if (node.type === 'FunctionDeclaration') {
          return true;
        }
        if (node.type === 'AssignmentExpression' && node.right.type === 'FunctionExpression') {
          return true;
        }
        return false;
      })
      .groupBy(function(node) {
        return node.loc.start.line;
      })
      .toObject();

    // Go through all of of the comments in the AST, attempting to associate
    // each with a function.
    var docs = Lazy(ast.comments)
      .map(function(comment) {

        // Find the function right after this comment. If none exists, skip it.
        var fn = functions[comment.loc.end.line + 1];
        if (typeof fn === 'undefined') {
          return null;
        }

        // Attempt to parse the comment. If it can't be parsed, or it appears to
        // be basically empty, then skip it.
        var doc = Breakneck.parseComment(comment, commentParser);
        if (typeof doc === 'undefined' || (!doc.description && (!doc.examples || doc.examples.length === 0))) {
          return null;
        }

        var name        = Breakneck.getIdentifierName(fn[0]),
            description = markdownParser.parse(doc.description),
            params      = Breakneck.getParams(doc),
            returns     = Breakneck.getReturns(doc),
            signature   = Breakneck.getSignature(name, params),
            examples    = Breakneck.getExamples(doc),
            benchmarks  = Breakneck.getBenchmarks(doc);

        return {
          name: name,
          description: description,
          params: params,
          returns: returns,
          hasSignature: params.length > 0 || !!returns,
          signature: signature,
          examples: examples,
          hasExamples: examples.length > 0,
          benchmarks: benchmarks,
          hasBenchmarks: benchmarks.length > 0
        };
      })
      .compact()
      .toArray();

    // This is kind of stupid... for now, I'm just assuming the library will
    // have a @fileOverview tag and @name tag in the header comments.
    var libraryInfo = Breakneck.getLibraryInfo(ast.comments, commentParser);

    return {
      name: libraryInfo.name,
      description: libraryInfo.description,
      code: code,
      docs: docs
    };
  };

  /**
   * Gets the name of whatever identifier is associated with this node (if any).
   *
   * @param {Object} object
   * @return {Object}
   */
  Breakneck.getIdentifierName = function(node) {
    switch (node.type) {
      case 'Identifier': return node.name;
      case 'AssignmentExpression': return Breakneck.getIdentifierName(node.left);
      case 'MemberExpression': return Breakneck.getIdentifierName(node.property);
      case 'FunctionDeclaration': return node.id.name;
      case 'VariableDeclaration': return node.declarations[0].id.name;
      case 'VariableDeclarator': return node.id.name;

      case 'ExpressionStatement': return Breakneck.getIdentifierName(node.expression);

      default: return null;
    }
  };

  /**
   * @typedef {Object} ParameterInfo
   * @property {string} name
   * @property {string} type
   * @property {string} description
   */

  /**
   * Gets an array of { name, type, description } objects representing the
   * parameters of a function definition.
   *
   * @param {Object} doc The doclet for the function.
   * @returns {Array.<ParameterInfo>} An array of { name, type, description } objects.
   */
  Breakneck.getParams = function(doc) {
    var Lazy = context.Lazy;

    return Lazy(doc.tags)
      .where({ title: 'param' })
      .map(function(tag) {
        return {
          name: tag.name,
          type: Breakneck.formatType(tag.type),
          description: tag.description || ''
        };
      })
      .toArray();
  };

  /**
   * @typedef {Object} ReturnInfo
   * @property {string} type
   * @property {string} description
   */

  /**
   * Get a { type, description } object representing the return value of a
   * function definition.
   *
   * @param {Object} doc The doclet for the function.
   * @returns {ReturnInfo} A { type, description } object.
   */
  Breakneck.getReturns = function(doc) {
    var Lazy      = context.Lazy,
        returnTag = Lazy(doc.tags).findWhere({ title: 'returns' });

    if (typeof returnTag === 'undefined') {
      return {};
    }

    return {
      type: Breakneck.formatType(returnTag.type),
      description: returnTag.description || ''
    };
  };

  /**
   * Produces a string representing the signature of a function.
   *
   * @param {string} name
   * @param {Array.<ParameterInfo>} params
   * @returns {string}
   */
  Breakneck.getSignature = function(name, params) {
    return 'function ' + name + '(' + Lazy(params).pluck('name').join(', ') + ')';
  };

  /**
   * @typedef LibraryInfo
   * @property {string} name
   * @property {string} description
   */

  /**
   * Returns a { name, description } object describing an entire library.
   *
   * @param {Array.<string>} comments
   * @param {Object} commentParser
   * @returns {LibraryInfo}
   */
  Breakneck.getLibraryInfo = function(comments, commentParser) {
    var Lazy = context.Lazy;

    var docWithFileOverview = Lazy(comments)
      .map(function(comment) {
        return Breakneck.parseComment(comment, commentParser);
      })
      .compact()
      .filter(function(doc) {
        return Lazy(doc.tags).where({ title: 'fileOverview' }).any();
      })
      .first();

    var libraryName = 'Untitled Library',
        libraryDesc = '[No description]';

    if (docWithFileOverview) {
      libraryDesc = Lazy(docWithFileOverview.tags).findWhere({ title: 'fileOverview' }).description;

      var libraryNameTag = Lazy(docWithFileOverview.tags).findWhere({ title: 'name' });
      if (libraryNameTag) {
        libraryName = libraryNameTag.description;
      }
    }

    return {
      name: libraryName,
      description: marked(libraryDesc)
    };
  };

  /**
   * @callback PairCallback
   * @param {string} left
   * @param {string} right
   * @returns {*}
   */

  /**
   * Takes a doclet and a tag name, then reads all of the lines from that tag
   * and splits them across '=>', finally calling a callback on each left/right
   * pair. (Does that make any sense? Whatever.)
   *
   * @param {Object} doc
   * @param {string} tagName
   * @param {PairCallback} callback
   * @returns {Array.<*>} An array of whatever the callback returns.
   */
  Breakneck.splitCommentLines = function(doc, tagName, callback) {
    var Lazy = context.Lazy,
        tag  = Lazy(doc.tags).findWhere({ title: tagName });

    if (typeof tag === 'undefined') {
      return [];
    }

    return Lazy(tag.description.split('\n'))
      .map(function(line) {
        return line.match(/^(.*)\s*=>\s*(.*)$/);
      })
      .compact()
      .map(function(match) {
        return callback(
          match[1],
          match[2]
        );
      })
      .toArray();
  };

  /**
   * Gets the text from a given comment tag and splits it into lines.
   *
   * @param {Object} doc
   * @param {string} tagName
   * @returns {Array.<string>}
   */
  Breakneck.getCommentLines = function(doc, tagName) {
    var Lazy = context.Lazy,
        tag  = Lazy(doc.tags).findWhere({ title: tagName });

    if (typeof tag === 'undefined') {
      return [];
    }

    return tag.description.split('\n');
  };

  /**
   * @typedef {Object} ExampleInfo
   * @property {number} id
   * @property {string} input
   * @property {string} output
   */

  /**
   * Produces an array of { id, input, output } objects representing simple examples of a function.
   *
   * @param {Object} doc
   * @returns {Array.<ExampleInfo>}
   */
  Breakneck.getExamples = function(doc) {
    var Lazy = context.Lazy;

    var commentLines = Breakneck.getCommentLines(doc, 'examples');

    return Lazy(commentLines)
      .map(Breakneck.parseExample)
      .compact()
      .toArray();
  };

  /**
   * Given a line like 'input => output', parses this into a { id, input, output } object.
   *
   * @param {string} line
   * @returns {ExampleInfo|null}
   */
  Breakneck.parseExample = function(line) {
    var parts = line.match(/^(.*)\s*=>\s*(.*)$/);

    if (!parts) {
      return null;
    }

    return {
      input: trim(parts[1]),
      output: trim(parts[2])
    };
  };

  /**
   * @typedef {Object} BenchmarkInfo
   * @property {number} id
   * @property {string} name
   * @property {string} impl
   */

  /**
   * Produces an array of { id, name, impl } objects representing benchmarks for a function.
   *
   * @param {Object} doc
   * @returns {Array.<BenchmarkInfo>}
   */
  Breakneck.getBenchmarks = function(doc) {
    var benchmarkIdCounter = 1;
    return Breakneck.splitCommentLines(doc, 'benchmarks', function(left, right) {
      return {
        id: benchmarkIdCounter++,
        name: left,
        impl: right
      };
    });
  };

  /**
   * Produces a string representation of a type object.
   *
   * @param {Object} type
   * @returns {string}
   */
  Breakneck.formatType = function(type) {
    switch (type.type) {
      case 'NameExpression':
        return type.name;

      case 'TypeApplication':
        return Breakneck.formatType(type.expression) + '.<' + Lazy(type.applications).map(Breakneck.formatType).join('|') + '>';

      case 'AllLiteral':
        return '*';

      case 'OptionalType':
        return Breakneck.formatType(type.expression) + '?';

      case 'FunctionType':
        return 'function(' + Lazy(type.params).map(Breakneck.formatType).join(', ') + '):' + Breakneck.formatType(type.result);

      default:
        throw 'Unable to format type ' + type.type + '!\n\n' + JSON.stringify(type, null, 2);
    }
  };

  /**
   * Parses a comment.
   *
   * @param {string} comment The comment to parse.
   * @param {Object} commentParser The parser to use. For now this will just
   *     use Doctrine.
   * @returns {Object}
   */
  Breakneck.parseComment = function(comment, commentParser) {
    return commentParser.parse('/*' + comment.value + '*/', { unwrap: true });
  };

  function defaultMarkdownParser() {
    return {
      parse: function(markdown) {
        return context.marked(markdown);
      }
    };
  }

  function trim(string) {
    return string.replace(/^\s+/, '').replace(/\s+$/, '');
  }

  if (typeof module === 'object') {
    module.exports = Breakneck;
  } else {
    context.Breakneck = Breakneck;
  }

}(typeof global !== 'undefined' ? global : this));
<commit_msg>not sure what that was about<commit_after>(function(context) {

  var Lazy = context.Lazy;

  // Define a custom type of sequence that recursively walks the nodes of an
  // AST.
  Lazy.Sequence.define('nodes', {
    each: function(fn) {
      var self = this;

      self.parent.each(function(node) {
        if (fn(node) === false) {
          return false;
        }

        var children = self.getNodeChildren(node);
        if (children.length > 0) {
          return Lazy(children).nodes().each(fn);
        }
      });
    },

    getNodeChildren: function(node) {
      switch (node.type) {
        case 'FunctionDeclaration':
        case 'FunctionExpression':
          return [node.body];

        case 'BlockStatement':
          return node.body;

        case 'ExpressionStatement':
          return [node.expression];

        case 'AssignmentExpression':
          return node.right.type === 'FunctionExpression' ? [node.right] : [];

        case 'CallExpression':
          return node.callee.type === 'FunctionExpression' ? [node.callee] : [];

        default: return [];
      }
    }
  });

  /**
   * @namespace Breakneck
   */
  var Breakneck = {};

  /**
   * Parses an arbitrary blob of JavaScript code and returns an object
   * containing all of the data necessary to generate a project website with
   * docs, specs, and performance benchmarks.
   *
   * @param {string} code The JavaScript code to parse.
   * @param {Object=} options
   * @returns {Object}
   */
  Breakneck.parse = function(code, options) {
    options = options || {};

    var codeParser     = options.codeParser     || context.esprima,
        commentParser  = options.commentParser  || context.doctrine,
        markdownParser = options.markdownParser || defaultMarkdownParser();

    // Generate the abstract syntax tree.
    var ast = codeParser.parse(code, {
      comment: true,
      loc: true
    });

    // Extract all of the function from the AST, and map them to their location
    // in the code (this is so that we can associate each function with its
    // accompanying doc comments, if any).
    var functions = Lazy(ast.body).nodes()
      .filter(function(node) {
        if (node.type === 'FunctionDeclaration') {
          return true;
        }
        if (node.type === 'AssignmentExpression' && node.right.type === 'FunctionExpression') {
          return true;
        }
        return false;
      })
      .groupBy(function(node) {
        return node.loc.start.line;
      })
      .toObject();

    // Go through all of of the comments in the AST, attempting to associate
    // each with a function.
    var docs = Lazy(ast.comments)
      .map(function(comment) {

        // Find the function right after this comment. If none exists, skip it.
        var fn = functions[comment.loc.end.line + 1];
        if (typeof fn === 'undefined') {
          return null;
        }

        // Attempt to parse the comment. If it can't be parsed, or it appears to
        // be basically empty, then skip it.
        var doc = Breakneck.parseComment(comment, commentParser);
        if (typeof doc === 'undefined' || !doc.description) {
          return null;
        }

        var name        = Breakneck.getIdentifierName(fn[0]),
            description = markdownParser.parse(doc.description),
            params      = Breakneck.getParams(doc),
            returns     = Breakneck.getReturns(doc),
            signature   = Breakneck.getSignature(name, params),
            examples    = Breakneck.getExamples(doc),
            benchmarks  = Breakneck.getBenchmarks(doc);

        return {
          name: name,
          description: description,
          params: params,
          returns: returns,
          hasSignature: params.length > 0 || !!returns,
          signature: signature,
          examples: examples,
          hasExamples: examples.length > 0,
          benchmarks: benchmarks,
          hasBenchmarks: benchmarks.length > 0
        };
      })
      .compact()
      .toArray();

    // This is kind of stupid... for now, I'm just assuming the library will
    // have a @fileOverview tag and @name tag in the header comments.
    var libraryInfo = Breakneck.getLibraryInfo(ast.comments, commentParser);

    return {
      name: libraryInfo.name,
      description: libraryInfo.description,
      code: code,
      docs: docs
    };
  };

  /**
   * Gets the name of whatever identifier is associated with this node (if any).
   *
   * @param {Object} object
   * @return {Object}
   */
  Breakneck.getIdentifierName = function(node) {
    switch (node.type) {
      case 'Identifier': return node.name;
      case 'AssignmentExpression': return Breakneck.getIdentifierName(node.left);
      case 'MemberExpression': return Breakneck.getIdentifierName(node.property);
      case 'FunctionDeclaration': return node.id.name;
      case 'VariableDeclaration': return node.declarations[0].id.name;
      case 'VariableDeclarator': return node.id.name;

      case 'ExpressionStatement': return Breakneck.getIdentifierName(node.expression);

      default: return null;
    }
  };

  /**
   * @typedef {Object} ParameterInfo
   * @property {string} name
   * @property {string} type
   * @property {string} description
   */

  /**
   * Gets an array of { name, type, description } objects representing the
   * parameters of a function definition.
   *
   * @param {Object} doc The doclet for the function.
   * @returns {Array.<ParameterInfo>} An array of { name, type, description } objects.
   */
  Breakneck.getParams = function(doc) {
    var Lazy = context.Lazy;

    return Lazy(doc.tags)
      .where({ title: 'param' })
      .map(function(tag) {
        return {
          name: tag.name,
          type: Breakneck.formatType(tag.type),
          description: tag.description || ''
        };
      })
      .toArray();
  };

  /**
   * @typedef {Object} ReturnInfo
   * @property {string} type
   * @property {string} description
   */

  /**
   * Get a { type, description } object representing the return value of a
   * function definition.
   *
   * @param {Object} doc The doclet for the function.
   * @returns {ReturnInfo} A { type, description } object.
   */
  Breakneck.getReturns = function(doc) {
    var Lazy      = context.Lazy,
        returnTag = Lazy(doc.tags).findWhere({ title: 'returns' });

    if (typeof returnTag === 'undefined') {
      return {};
    }

    return {
      type: Breakneck.formatType(returnTag.type),
      description: returnTag.description || ''
    };
  };

  /**
   * Produces a string representing the signature of a function.
   *
   * @param {string} name
   * @param {Array.<ParameterInfo>} params
   * @returns {string}
   */
  Breakneck.getSignature = function(name, params) {
    return 'function ' + name + '(' + Lazy(params).pluck('name').join(', ') + ')';
  };

  /**
   * @typedef LibraryInfo
   * @property {string} name
   * @property {string} description
   */

  /**
   * Returns a { name, description } object describing an entire library.
   *
   * @param {Array.<string>} comments
   * @param {Object} commentParser
   * @returns {LibraryInfo}
   */
  Breakneck.getLibraryInfo = function(comments, commentParser) {
    var Lazy = context.Lazy;

    var docWithFileOverview = Lazy(comments)
      .map(function(comment) {
        return Breakneck.parseComment(comment, commentParser);
      })
      .compact()
      .filter(function(doc) {
        return Lazy(doc.tags).where({ title: 'fileOverview' }).any();
      })
      .first();

    var libraryName = 'Untitled Library',
        libraryDesc = '[No description]';

    if (docWithFileOverview) {
      libraryDesc = Lazy(docWithFileOverview.tags).findWhere({ title: 'fileOverview' }).description;

      var libraryNameTag = Lazy(docWithFileOverview.tags).findWhere({ title: 'name' });
      if (libraryNameTag) {
        libraryName = libraryNameTag.description;
      }
    }

    return {
      name: libraryName,
      description: marked(libraryDesc)
    };
  };

  /**
   * @callback PairCallback
   * @param {string} left
   * @param {string} right
   * @returns {*}
   */

  /**
   * Takes a doclet and a tag name, then reads all of the lines from that tag
   * and splits them across '=>', finally calling a callback on each left/right
   * pair. (Does that make any sense? Whatever.)
   *
   * @param {Object} doc
   * @param {string} tagName
   * @param {PairCallback} callback
   * @returns {Array.<*>} An array of whatever the callback returns.
   */
  Breakneck.splitCommentLines = function(doc, tagName, callback) {
    var Lazy = context.Lazy,
        tag  = Lazy(doc.tags).findWhere({ title: tagName });

    if (typeof tag === 'undefined') {
      return [];
    }

    return Lazy(tag.description.split('\n'))
      .map(function(line) {
        return line.match(/^(.*)\s*=>\s*(.*)$/);
      })
      .compact()
      .map(function(match) {
        return callback(
          match[1],
          match[2]
        );
      })
      .toArray();
  };

  /**
   * Gets the text from a given comment tag and splits it into lines.
   *
   * @param {Object} doc
   * @param {string} tagName
   * @returns {Array.<string>}
   */
  Breakneck.getCommentLines = function(doc, tagName) {
    var Lazy = context.Lazy,
        tag  = Lazy(doc.tags).findWhere({ title: tagName });

    if (typeof tag === 'undefined') {
      return [];
    }

    return tag.description.split('\n');
  };

  /**
   * @typedef {Object} ExampleInfo
   * @property {number} id
   * @property {string} input
   * @property {string} output
   */

  /**
   * Produces an array of { id, input, output } objects representing simple examples of a function.
   *
   * @param {Object} doc
   * @returns {Array.<ExampleInfo>}
   */
  Breakneck.getExamples = function(doc) {
    var Lazy = context.Lazy;

    var commentLines = Breakneck.getCommentLines(doc, 'examples');

    return Lazy(commentLines)
      .map(Breakneck.parseExample)
      .compact()
      .toArray();
  };

  /**
   * Given a line like 'input => output', parses this into a { id, input, output } object.
   *
   * @param {string} line
   * @returns {ExampleInfo|null}
   */
  Breakneck.parseExample = function(line) {
    var parts = line.match(/^(.*)\s*=>\s*(.*)$/);

    if (!parts) {
      return null;
    }

    return {
      input: trim(parts[1]),
      output: trim(parts[2])
    };
  };

  /**
   * @typedef {Object} BenchmarkInfo
   * @property {number} id
   * @property {string} name
   * @property {string} impl
   */

  /**
   * Produces an array of { id, name, impl } objects representing benchmarks for a function.
   *
   * @param {Object} doc
   * @returns {Array.<BenchmarkInfo>}
   */
  Breakneck.getBenchmarks = function(doc) {
    var benchmarkIdCounter = 1;
    return Breakneck.splitCommentLines(doc, 'benchmarks', function(left, right) {
      return {
        id: benchmarkIdCounter++,
        name: left,
        impl: right
      };
    });
  };

  /**
   * Produces a string representation of a type object.
   *
   * @param {Object} type
   * @returns {string}
   */
  Breakneck.formatType = function(type) {
    switch (type.type) {
      case 'NameExpression':
        return type.name;

      case 'TypeApplication':
        return Breakneck.formatType(type.expression) + '.<' + Lazy(type.applications).map(Breakneck.formatType).join('|') + '>';

      case 'AllLiteral':
        return '*';

      case 'OptionalType':
        return Breakneck.formatType(type.expression) + '?';

      case 'FunctionType':
        return 'function(' + Lazy(type.params).map(Breakneck.formatType).join(', ') + '):' + Breakneck.formatType(type.result);

      default:
        throw 'Unable to format type ' + type.type + '!\n\n' + JSON.stringify(type, null, 2);
    }
  };

  /**
   * Parses a comment.
   *
   * @param {string} comment The comment to parse.
   * @param {Object} commentParser The parser to use. For now this will just
   *     use Doctrine.
   * @returns {Object}
   */
  Breakneck.parseComment = function(comment, commentParser) {
    return commentParser.parse('/*' + comment.value + '*/', { unwrap: true });
  };

  function defaultMarkdownParser() {
    return {
      parse: function(markdown) {
        return context.marked(markdown);
      }
    };
  }

  function trim(string) {
    return string.replace(/^\s+/, '').replace(/\s+$/, '');
  }

  if (typeof module === 'object') {
    module.exports = Breakneck;
  } else {
    context.Breakneck = Breakneck;
  }

}(typeof global !== 'undefined' ? global : this));
<|endoftext|>


<commit_before>const AsyncComputation = require('./asynccomputation.js');
const AsyncHandler = require('./asynchandler.js');
const AsyncFirst = require('./asyncfirst.js');
const Free = require('../free');

/**
 *	Monadic.Async
 *	written by Joel Dentici
 *	on 6/25/2017
 *
 *	The Async monad represents computations
 *	that run in an asynchronous context.
 *
 *	Unlike Promises, an Async computation is
 *	lazily evaluated, so it won't be executed
 *	immediately.
 *
 *	Async provides an Interpreter to be used
 *	with the Free.createInterpreter function so it
 *	can be used with other Free monads. It maps to
 *	Async, as it is expected that most interpreters
 *	will do the same. Because of this, it essentially
 *	doesn't do anything.
 *
 *	A method called run is also provided to
 *	interpret an Async into a Promise.
 */

class Async {
	/**
	 *	create :: ((a -> ()) -> (b -> ()) -> ()) -> Async b a
	 *
	 *	Creates an Async computation. Takes a function that
	 *	accepts two functions, one for a successful computation
	 *	an one for a failed computation. This function is not
	 *	executed until the Async is ran.
	 */
	static create(thunk) {
		return Free.liftF(new AsyncComputation(thunk, x => x));
	}

	/**
	 *	catch :: Async b a -> (b -> Async c d) -> Async c d
	 *
	 *	Creates an Async handler. This takes an Async computation
	 *	and an error handler function.
	 */
	static catch(asyncVal, handler) {
		return Free.liftF(new AsyncHandler(asyncVal, handler, x => x));
	}

	/**
	 *	try :: Async b a -> Async b a
	 *
	 *	Adds a "catch" method to the provided Async computation.
	 *	This is a convenience method to allow Async.catch to be
	 *	infix, and make monadic code look more imperative.
	 */
	static try(asyncVal) {
		asyncVal.catch = function(handler) {
			return Async.catch(asyncVal, handler);
		};

		return asyncVal;
	}

	/**
	 *	wrap :: (...any -> (b -> c -> ()) -> ()) -> ...any -> Async b c
	 *
	 *	Wraps a callback taking async function so it becomes a function
	 *	that returns Async computations.
	 */
	static wrap(fn) {
		return function(...args) {
			return Async.create((succ, fail) => {
				const allArgs = args.concat([(err, val) => {
					if (err) fail(err);
					else succ(val);
				}]);

				fn(...allArgs);
			});
		}
	}

	/**
	 *	unit :: a -> Async () a
	 *
	 *	Puts a value into the context of
	 *	an Async computation.
	 */
	static unit(v) {
		return Free.unit(v);
	}

	/**
	 *	fail :: a -> Async a ()
	 *
	 *	Returns an Async computation that failed
	 *	for the specified reason.
	 */
	static fail(e) {
		return Async.create((succ, fail) => fail(e));
	}

	/**
	 *	run :: Async b a -> Promise a b
	 *
	 *	Runs the asynchronous computation and
	 *	returns a promise for the result.
	 *
	 *	run only runs the Async on the first application.
	 *	Any subsequent applications will return the promise
	 *	from the first application.
	 */
	static run(comp) {
		if (!comp.__res__) {
			const res = comp.case({
				Free: x => x.case({
					AsyncComputation: (t, n) => new Promise(t).then(v => Async.run(n(v))),
					AsyncHandler: (a, h, n) => Async.run(a)
						.catch(e => Async.run(h(e)))
						.then(v => Async.run(n(v))),
					AsyncFirst: (cs, n) => Promise
						.race(cs.map(c => Async.run(c)))
						.then(v => Async.run(n(v))),
					default: () => Promise.reject(new Error(
						"Expected Async computation, got: " + x.__type__)),
				}),
				Return: x => Promise.resolve(x),
			});

			comp.__res__ = res;
		}

		return comp.__res__;
	}

	/**
	 *	sleep :: int -> Async ()
	 *
	 *	Creates an Async computation that sleeps for the specified
	 *	timespan in milliseconds and returns no result.
	 */
	static sleep(ms) {
		return Async.create((succ, fail) => setTimeout(succ, ms));
	}

	/**
	 *	first :: ...Async e a -> Async e a
	 *
	 *	Returns an Async computation whose result is
	 *	the result of the first provided computation to
	 *	finish.
	 */
	static first(...comps) {
		return Free.liftF(new AsyncFirst(comps, x => x));
	}
}

/* The Async interpreter doesn't do anything,
it just exists so Async can be used with other
Free monads. It literally maps Asyncs back onto Asyncs.

Other Free monads will provide interpreters to
*/
Async.interpreter = () => ({
	/**
	 *	prepare :: Interpreter -> () -> Async ()
	 *
	 *	Prepares interpretation context for Async.
	 */
	prepare() {
		return Async.unit();
	},

	/**
	 *	map :: Interpreter -> AsyncComputation ((a -> ()) -> (b -> ()) -> ()) -> Async b a
	 *
	 *	Maps an AsyncComputation into a new Async, essentially doing
	 *	nothing.
	 */
	map(comp) {
		return comp.case({
			AsyncComputation: (t, n) => [Async.create(t), n],
			AsyncHandler: (a, h, n) => [Async.catch(a, h), n],
			AsyncFirst: (cs, n) => [Async.first(...cs), n],
			default: () => null,
		});
	},

	/**
	 *	cleanup :: Interpreter -> a -> Async () a
	 *
	 *	We don't need to clean up anything.
	 */
	cleanup(result) {
		return Async.unit(result);
	},

	/**
	 *	cleanupErr :: Interpreter -> b -> Async b ()
	 *
	 *	We don't need to clean up anything.
	 */
	cleanupErr(err) {
		return Async.fail(err);
	}
});

module.exports = Async;<commit_msg>Added throwE alias to fail, fixed interpreter<commit_after>const AsyncComputation = require('./asynccomputation.js');
const AsyncHandler = require('./asynchandler.js');
const AsyncFirst = require('./asyncfirst.js');
const Free = require('../free');

/**
 *	Monadic.Async
 *	written by Joel Dentici
 *	on 6/25/2017
 *
 *	The Async monad represents computations
 *	that run in an asynchronous context.
 *
 *	Unlike Promises, an Async computation is
 *	lazily evaluated, so it won't be executed
 *	immediately.
 *
 *	Async provides an Interpreter to be used
 *	with the Free.createInterpreter function so it
 *	can be used with other Free monads. It maps to
 *	Async, as it is expected that most interpreters
 *	will do the same. Because of this, it essentially
 *	doesn't do anything.
 *
 *	A method called run is also provided to
 *	interpret an Async into a Promise.
 */

class Async {
	/**
	 *	create :: ((a -> ()) -> (b -> ()) -> ()) -> Async b a
	 *
	 *	Creates an Async computation. Takes a function that
	 *	accepts two functions, one for a successful computation
	 *	an one for a failed computation. This function is not
	 *	executed until the Async is ran.
	 */
	static create(thunk) {
		return Free.liftF(new AsyncComputation(thunk, x => x));
	}

	/**
	 *	catch :: Async b a -> (b -> Async c d) -> Async c d
	 *
	 *	Creates an Async handler. This takes an Async computation
	 *	and an error handler function.
	 */
	static catch(asyncVal, handler) {
		return Free.liftF(new AsyncHandler(asyncVal, handler, x => x));
	}

	/**
	 *	try :: Async b a -> Async b a
	 *
	 *	Adds a "catch" method to the provided Async computation.
	 *	This is a convenience method to allow Async.catch to be
	 *	infix, and make monadic code look more imperative.
	 */
	static try(asyncVal) {
		asyncVal.catch = function(handler) {
			return Async.catch(asyncVal, handler);
		};

		return asyncVal;
	}

	/**
	 *	wrap :: (...any -> (b -> c -> ()) -> ()) -> ...any -> Async b c
	 *
	 *	Wraps a callback taking async function so it becomes a function
	 *	that returns Async computations.
	 */
	static wrap(fn) {
		return function(...args) {
			return Async.create((succ, fail) => {
				const allArgs = args.concat([(err, val) => {
					if (err) fail(err);
					else succ(val);
				}]);

				fn(...allArgs);
			});
		}
	}

	/**
	 *	unit :: a -> Async () a
	 *
	 *	Puts a value into the context of
	 *	an Async computation.
	 */
	static unit(v) {
		return Free.unit(v);
	}

	/**
	 *	fail :: a -> Async a ()
	 *
	 *	Returns an Async computation that failed
	 *	for the specified reason.
	 */
	static fail(e) {
		return Async.create((succ, fail) => fail(e));
	}

	/**
	 *	run :: Async b a -> Promise a b
	 *
	 *	Runs the asynchronous computation and
	 *	returns a promise for the result.
	 *
	 *	run only runs the Async on the first application.
	 *	Any subsequent applications will return the promise
	 *	from the first application.
	 */
	static run(comp) {
		if (!comp.__res__) {
			const res = comp.case({
				Free: x => x.case({
					AsyncComputation: (t, n) => new Promise(t).then(v => Async.run(n(v))),
					AsyncHandler: (a, h, n) => Async.run(a)
						.catch(e => Async.run(h(e)))
						.then(v => Async.run(n(v))),
					AsyncFirst: (cs, n) => Promise
						.race(cs.map(c => Async.run(c)))
						.then(v => Async.run(n(v))),
					default: () => Promise.reject(new Error(
						"Expected Async computation, got: " + x.__type__)),
				}),
				Return: x => Promise.resolve(x),
			});

			comp.__res__ = res;
		}

		return comp.__res__;
	}

	/**
	 *	sleep :: int -> Async ()
	 *
	 *	Creates an Async computation that sleeps for the specified
	 *	timespan in milliseconds and returns no result.
	 */
	static sleep(ms) {
		return Async.create((succ, fail) => setTimeout(succ, ms));
	}

	/**
	 *	first :: ...Async e a -> Async e a
	 *
	 *	Returns an Async computation whose result is
	 *	the result of the first provided computation to
	 *	finish.
	 */
	static first(...comps) {
		return Free.liftF(new AsyncFirst(comps, x => x));
	}

	/**
	 *	throwE :: e -> Async e ()
	 *
	 *	Alias of fail
	 */
	static throwE(e) {
		return Async.fail(e);
	}
}

/* The Async interpreter doesn't do anything,
it just exists so Async can be used with other
Free monads. It literally maps Asyncs back onto Asyncs.

Other Free monads will provide interpreters to map to
Async as well
*/
Async.interpreter = (execute) => ({
	/**
	 *	prepare :: Interpreter -> () -> Async ()
	 *
	 *	Prepares interpretation context for Async.
	 */
	prepare() {
		return Async.unit();
	},

	/**
	 *	map :: Interpreter -> AsyncFunctor b a -> [Async b a, (a -> Free f a | Free f a)]
	 *
	 *	Maps an AsyncComputation into a new Async, essentially doing
	 *	nothing.
	 */
	map(comp) {
		return comp.case({
			AsyncComputation: (t, n) => [Async.create(t), n],
			AsyncHandler: (a, h, n) => [Async.catch(execute(a), h), n],
			AsyncFirst: (cs, n) => [Async.first(cs.map(execute)), n],
			default: () => null,
		});
	},

	/**
	 *	cleanup :: Interpreter -> a -> Async () a
	 *
	 *	We don't need to clean up anything.
	 */
	cleanup(result) {
		return Async.unit(result);
	},

	/**
	 *	cleanupErr :: Interpreter -> b -> Async b ()
	 *
	 *	We don't need to clean up anything.
	 */
	cleanupErr(err) {
		return Async.fail(err);
	}
});

module.exports = Async;<|endoftext|>


<commit_before>'use strict';

/**
 * @license
 * Copyright SOAJS All Rights Reserved.
 *
 * Use of this source code is governed by an Apache license that can be
 * found in the LICENSE file at the root of this repository
 */

const get = (p, o) => p.reduce((xs, x) => (xs && xs[x]) ? xs[x] : null, o);

const async = require('async');
const coreLibs = require("soajs.core.libs");

const registryModule = require("./../../modules/registry");

let param = null;
let timeout = null;
let regEnvironment = (process.env.SOAJS_ENV || "dev");
regEnvironment = regEnvironment.toLowerCase();

let awarenessCache = {};

let lib = {
	"getInfraToken": (envCode, cb) => {
		registryModule.loadByEnv({envCode: envCode}, (err, envRecord) => {
			if (err) {
				return cb(err);
			}
			if (!envRecord) {
				return cb(new Error("loadByEnv empty. Unable to find healthy configuration in registry"));
			}
			let registry = envRecord;
			let depType = get(["deployer", "type"], registry);
			let regConf = null;
			if (depType === "container") {
				let depSeleted = get(["deployer", "selected"], registry);
				if (depSeleted && depSeleted.includes("kubernetes")) {
					regConf = get(["deployer"].concat(depSeleted.split(".")), registry);
				}
			}
			if (regConf) {
				let protocol = regConf.configuration.protocol || "https";
				let port = regConf.configuration.port ? ":" + regConf.configuration.port : "";
				let config = {
					"namespace": regConf.namespace,
					"token": regConf.configuration.token,
					"url": protocol + "://" + regConf.configuration.url + port
				};
				return cb(null, config);
			} else {
				return cb(new Error("Unable to find healthy configuration in registry"));
			}
		});
	},

	"getHostFromCache": function (serviceName, version) {
		if (awarenessCache[serviceName] &&
			awarenessCache[serviceName][version] &&
			awarenessCache[serviceName][version].host) {
			param.log.debug('Got ' + serviceName + ' - ' + version + ' - ' + awarenessCache[serviceName][version].host + ' from awareness cache');
			return awarenessCache[serviceName][version].host;
		}

		return null;
	},

	"getHostFromAPI": function (serviceName, version, cb) {
		if (!version) {
			lib.getInfraToken(regEnvironment, (error, configuration) => {
				if (error) {
					param.log.error(error.message);
					return cb(null);
				}
				let options = null;
				let input = {
					"configuration": {"configuration": configuration},
					"itemName": serviceName
				};
				param.infraModule.kubernetes.get.item_latestVersion(param, input, options, (error, obtainedVersion) => {
					if (error) {
						param.log.error(error.message);
						return cb(null);
					}
					getHost(obtainedVersion);
				});
			});
		} else {
			getHost(version);
		}

		function getHost(version) {
			lib.getInfraToken(regEnvironment, (error, configuration) => {
				if (error) {
					param.log.error(error.message);
					return cb(null);
				}
				param.log.debug('Getting host for ' + serviceName + ' - ' + version + ' ....');
				let options = null;
				let input = {
					"configuration": {"configuration": configuration},
					"item": {"name": serviceName, "version": version, "env": regEnvironment}
				};
				param.infraModule.kubernetes.get.host(param, input, options, (error, host) => {
					if (error) {
						param.log.error(error.message);
						return cb(null);
					}
					if (!awarenessCache[serviceName]) {
						awarenessCache[serviceName] = {};
					}
					if (!awarenessCache[serviceName][version]) {
						awarenessCache[serviceName][version] = {};
					}
					awarenessCache[serviceName][version].host = host;
					return cb(host);
				});
			});
		}
	},

	"rebuildAwarenessCache": function () {
		lib.getInfraToken(regEnvironment, (error, configuration) => {
			if (error) {
				param.log.error(error.message);
				return;
			}
			let myCache = {};
			let options = null;
			let input = {
				"configuration": {"configuration": configuration},
			};
			param.infraModule.kubernetes.get.all(param, input, options, (error, services) => {
				if (error) {
					param.log.error(error.message);
					return;
				}
				async.each(services, function (oneService, callback) {
					let version, serviceName;
					if (oneService.metadata.labels['soajs.service.type'] !== "service" && oneService.metadata.labels['soajs.service.type'] !== "mdaemon") {
						return callback();
					}
					if (oneService.metadata.labels && oneService.metadata.labels['soajs.service.version']) {
						version = oneService.metadata.labels['soajs.service.version'];
					}

					if (oneService.metadata.labels && oneService.metadata.labels['soajs.service.name']) {
						serviceName = oneService.metadata.labels['soajs.service.name'];
					}

					if (!serviceName) {
						return callback();
					}
					if (oneService.spec.clusterIP) {
						if (!myCache[serviceName]) {
							myCache[serviceName] = {};
						}
						if (!myCache[serviceName][version]) {
							myCache[serviceName][version] = {};
						}
						myCache[serviceName][version].host = oneService.spec.clusterIP;
					}
					return callback();
				}, function () {
					awarenessCache = myCache;
					param.log.debug("Awareness cache rebuilt successfully");
					param.log.debug(awarenessCache);

					let cacheTTL = registryModule.get().serviceConfig.awareness.cacheTTL;
					if (cacheTTL) {
						if (timeout) {
							clearTimeout(timeout);
						}
						param.log.debug("rebuilding cache in: " + cacheTTL);
						timeout = setTimeout(lib.rebuildAwarenessCache, cacheTTL);
					}
				});
			});
		});
	}
};

let ha = {
	"init": function (_param) {
		param = _param;
		lib.rebuildAwarenessCache();
	},

	"getServiceHost": function () {
		let env = regEnvironment;
		let serviceName = param.serviceName, version = null, cb = arguments[arguments.length - 1];
		switch (arguments.length) {
			//controller, cb
			case 2:
				serviceName = arguments[0];
				break;

			//controller, 1, cb
			case 3:
				serviceName = arguments[0];
				version = arguments[1];
				break;

			//controller, 1, dash, cb [dash is ignored]
			case 4:
				serviceName = arguments[0];
				version = arguments[1];
				break;
		}

		if (serviceName === param.serviceName) {
			if (process.env.SOAJS_DEPLOY_HA === 'kubernetes') {
				serviceName += "-v" + param.serviceVersion + "-service";
			}
			let info = registryModule.get().deployer.selected.split('.');
			let deployerConfig = registryModule.get().deployer.container[info[1]][info[2]];
			let namespace = '';
			if (deployerConfig && deployerConfig.namespace && deployerConfig.namespace.default) {
				namespace = '.' + deployerConfig.namespace.default;
				if (deployerConfig.namespace.perService) {
					namespace += '-' + env + '-' + param.serviceName + '-v' + param.serviceVersion;
				}
			}
			return cb(env + "-" + serviceName + namespace);
		} else {
			let hostname = lib.getHostFromCache(serviceName, version);
			if (hostname) {
				return cb(hostname);
			} else {
				lib.getHostFromAPI(serviceName, version, cb);
			}
		}
	},

	"getLatestVersion": function (name, cb) {
		if (!awarenessCache[name]) {
			return cb(null);
		}

		let serviceVersions = Object.keys(awarenessCache[name]);
		if (serviceVersions.length === 0) {
			return cb(null);
		}
		let latestVersion = null;
		for (let i = 0; i < serviceVersions.length; i++) {
			latestVersion = coreLibs.version.getLatest(latestVersion, serviceVersions[i]);
		}
		if (latestVersion) {
			return cb(latestVersion);
		} else {
			return cb(null);
		}
	},

	"getLatestVersionFromCluster": function (name, cb) {
		lib.getInfraToken(regEnvironment, (error, configuration) => {
			if (error) {
				param.log.error(error.message);
				return cb(null);
			}
			let options = null;
			let input = {
				"configuration": {"configuration": configuration},
				"itemName": name
			};
			param.infraModule.kubernetes.get.item_latestVersion(param, input, options, (error, obtainedVersion) => {
				if (error) {
					param.log.error(error.message);
					return cb(null);
				}
				return cb(obtainedVersion);
			});
		});
	}
};

module.exports = ha;
<commit_msg>handled awareness ha driver error<commit_after>'use strict';

/**
 * @license
 * Copyright SOAJS All Rights Reserved.
 *
 * Use of this source code is governed by an Apache license that can be
 * found in the LICENSE file at the root of this repository
 */

const get = (p, o) => p.reduce((xs, x) => (xs && xs[x]) ? xs[x] : null, o);

const async = require('async');
const coreLibs = require("soajs.core.libs");

const registryModule = require("./../../modules/registry");

let param = null;
let timeout = null;
let regEnvironment = (process.env.SOAJS_ENV || "dev");
regEnvironment = regEnvironment.toLowerCase();

let awarenessCache = {};

let lib = {
	"getInfraToken": (envCode, cb) => {
		registryModule.loadByEnv({envCode: envCode}, (err, envRecord) => {
			if (err) {
				return cb(err);
			}
			if (!envRecord) {
				return cb(new Error("loadByEnv empty. Unable to find healthy configuration in registry"));
			}
			let registry = envRecord;
			let depType = get(["deployer", "type"], registry);
			let regConf = null;
			if (depType === "container") {
				let depSeleted = get(["deployer", "selected"], registry);
				if (depSeleted && depSeleted.includes("kubernetes")) {
					regConf = get(["deployer"].concat(depSeleted.split(".")), registry);
				}
			}
			if (regConf) {
				let protocol = regConf.configuration.protocol || "https";
				let port = regConf.configuration.port ? ":" + regConf.configuration.port : "";
				let config = {
					"namespace": regConf.namespace,
					"token": regConf.configuration.token,
					"url": protocol + "://" + regConf.configuration.url + port
				};
				return cb(null, config);
			} else {
				return cb(new Error("Unable to find healthy configuration in registry"));
			}
		});
	},

	"getHostFromCache": function (serviceName, version) {
		if (awarenessCache[serviceName] &&
			awarenessCache[serviceName][version] &&
			awarenessCache[serviceName][version].host) {
			param.log.debug('Got ' + serviceName + ' - ' + version + ' - ' + awarenessCache[serviceName][version].host + ' from awareness cache');
			return awarenessCache[serviceName][version].host;
		}

		return null;
	},

	"getHostFromAPI": function (serviceName, version, cb) {
		if (!version) {
			lib.getInfraToken(regEnvironment, (error, configuration) => {
				if (error) {
					param.log.error(error.message);
					return cb(null);
				}
				let options = null;
				let input = {
					"configuration": {"configuration": configuration},
					"itemName": serviceName
				};
				param.infraModule.kubernetes.get.item_latestVersion(param, input, options, (error, obtainedVersion) => {
					if (error) {
						if (error.message) {
							param.log.error(error.message);
						} else {
							param.log.error(error);
						}
						return cb(null);
					}
					getHost(obtainedVersion);
				});
			});
		} else {
			getHost(version);
		}

		function getHost(version) {
			lib.getInfraToken(regEnvironment, (error, configuration) => {
				if (error) {
					param.log.error(error.message);
					return cb(null);
				}
				param.log.debug('Getting host for ' + serviceName + ' - ' + version + ' ....');
				let options = null;
				let input = {
					"configuration": {"configuration": configuration},
					"item": {"name": serviceName, "version": version, "env": regEnvironment}
				};
				param.infraModule.kubernetes.get.host(param, input, options, (error, host) => {
					if (error) {
						if (error.message) {
							param.log.error(error.message);
						} else {
							param.log.error(error);
						}
						return cb(null);
					}
					if (!awarenessCache[serviceName]) {
						awarenessCache[serviceName] = {};
					}
					if (!awarenessCache[serviceName][version]) {
						awarenessCache[serviceName][version] = {};
					}
					awarenessCache[serviceName][version].host = host;
					return cb(host);
				});
			});
		}
	},

	"rebuildAwarenessCache": function () {
		lib.getInfraToken(regEnvironment, (error, configuration) => {
			if (error) {
				param.log.error(error.message);
				return;
			}
			let myCache = {};
			let options = null;
			let input = {
				"configuration": {"configuration": configuration},
			};
			param.infraModule.kubernetes.get.all(param, input, options, (error, services) => {
				if (error) {
					if (error.message) {
						param.log.error(error.message);
					} else {
						param.log.error(error);
					}
					return;
				}
				async.each(services, function (oneService, callback) {
					let version, serviceName;
					if (oneService.metadata.labels['soajs.service.type'] !== "service" && oneService.metadata.labels['soajs.service.type'] !== "mdaemon") {
						return callback();
					}
					if (oneService.metadata.labels && oneService.metadata.labels['soajs.service.version']) {
						version = oneService.metadata.labels['soajs.service.version'];
					}

					if (oneService.metadata.labels && oneService.metadata.labels['soajs.service.name']) {
						serviceName = oneService.metadata.labels['soajs.service.name'];
					}

					if (!serviceName) {
						return callback();
					}
					if (oneService.spec.clusterIP) {
						if (!myCache[serviceName]) {
							myCache[serviceName] = {};
						}
						if (!myCache[serviceName][version]) {
							myCache[serviceName][version] = {};
						}
						myCache[serviceName][version].host = oneService.spec.clusterIP;
					}
					return callback();
				}, function () {
					awarenessCache = myCache;
					param.log.debug("Awareness cache rebuilt successfully");
					param.log.debug(awarenessCache);

					let cacheTTL = registryModule.get().serviceConfig.awareness.cacheTTL;
					if (cacheTTL) {
						if (timeout) {
							clearTimeout(timeout);
						}
						param.log.debug("rebuilding cache in: " + cacheTTL);
						timeout = setTimeout(lib.rebuildAwarenessCache, cacheTTL);
					}
				});
			});
		});
	}
};

let ha = {
	"init": function (_param) {
		param = _param;
		lib.rebuildAwarenessCache();
	},

	"getServiceHost": function () {
		let env = regEnvironment;
		let serviceName = param.serviceName, version = null, cb = arguments[arguments.length - 1];
		switch (arguments.length) {
			//controller, cb
			case 2:
				serviceName = arguments[0];
				break;

			//controller, 1, cb
			case 3:
				serviceName = arguments[0];
				version = arguments[1];
				break;

			//controller, 1, dash, cb [dash is ignored]
			case 4:
				serviceName = arguments[0];
				version = arguments[1];
				break;
		}

		if (serviceName === param.serviceName) {
			if (process.env.SOAJS_DEPLOY_HA === 'kubernetes') {
				serviceName += "-v" + param.serviceVersion + "-service";
			}
			let info = registryModule.get().deployer.selected.split('.');
			let deployerConfig = registryModule.get().deployer.container[info[1]][info[2]];
			let namespace = '';
			if (deployerConfig && deployerConfig.namespace && deployerConfig.namespace.default) {
				namespace = '.' + deployerConfig.namespace.default;
				if (deployerConfig.namespace.perService) {
					namespace += '-' + env + '-' + param.serviceName + '-v' + param.serviceVersion;
				}
			}
			return cb(env + "-" + serviceName + namespace);
		} else {
			let hostname = lib.getHostFromCache(serviceName, version);
			if (hostname) {
				return cb(hostname);
			} else {
				lib.getHostFromAPI(serviceName, version, cb);
			}
		}
	},

	"getLatestVersion": function (name, cb) {
		if (!awarenessCache[name]) {
			return cb(null);
		}

		let serviceVersions = Object.keys(awarenessCache[name]);
		if (serviceVersions.length === 0) {
			return cb(null);
		}
		let latestVersion = null;
		for (let i = 0; i < serviceVersions.length; i++) {
			latestVersion = coreLibs.version.getLatest(latestVersion, serviceVersions[i]);
		}
		if (latestVersion) {
			return cb(latestVersion);
		} else {
			return cb(null);
		}
	},

	"getLatestVersionFromCluster": function (name, cb) {
		lib.getInfraToken(regEnvironment, (error, configuration) => {
			if (error) {
				param.log.error(error.message);
				return cb(null);
			}
			let options = null;
			let input = {
				"configuration": {"configuration": configuration},
				"itemName": name
			};
			param.infraModule.kubernetes.get.item_latestVersion(param, input, options, (error, obtainedVersion) => {
				if (error) {
					if (error.message) {
						param.log.error(error.message);
					} else {
						param.log.error(error);
					}
					return cb(null);
				}
				return cb(obtainedVersion);
			});
		});
	}
};

module.exports = ha;
<|endoftext|>


<commit_before>const {escapeRegExp, sample, sampleSize, chunk, uniq, sortBy, shuffle} = require('lodash');
const scrapeIt = require('scrape-it');
const levenshtein = require('fast-levenshtein');
const {Mutex} = require('async-mutex');
const {hiraganize} = require('japanese');
const {Deferred} = require('../lib/utils.ts');
const {unlock, increment} = require('../achievements');
const {loadSheet} = require('./index.js');
const {getSongInfo, getMovieInfo} = require('../lyrics/index.ts');
const {tokenize} = require('kuromojin');
const {promises: fs} = require('fs');
const path = require('path');

const freqDeferred = new Deferred();
const mutex = new Mutex();

const loadFreq = async () => {
	if (freqDeferred.isResolved) {
		return freqDeferred.promise;
	}

	const data = await fs.readFile(path.resolve(__dirname, '../vocabwar/data/frequency.txt'));
	const freq = new Map(data.toString().split('\n').filter((line) => line).map((line) => {
		const [word, frequency] = line.split(' ');
		return [word, parseFloat(frequency)];
	}));
	freqDeferred.resolve(freq);
	return freq;
};

const getHintText = (n) => {
	if (n <= 1) {
		return 'しょうがないにゃあ、ヒントだよ';
	}
	if (n <= 2) {
		return 'もう一つヒントだよ、早く答えてね';
	}
	if (n <= 3) {
		return 'まだわからないの？ヒント追加するからね';
	}
	return '最後のヒントだよ！もうわかるよね？';
};

const getSongInfos = async (title) => {
	const {animeInfos} = await loadSheet();
	const anime = animeInfos.find(({name}) => name === title);
	if (!anime || !anime.utanetId) {
		return [];
	}
	const utanetUrl = `https://www.uta-net.com/user/search/anime_list_2.html?tno=${anime.utanetId}`;
	const {data: {songs}} = await scrapeIt(utanetUrl, {
		songs: {
			listItem: '.list_title + table + table tr',
			data: {
				title: 'td:nth-child(1)',
				link: {
					selector: 'td:nth-child(1) a',
					attr: 'href',
					convert: (link) => new URL(link, utanetUrl).href,
				},
				artist: 'td:nth-child(2)',
				type: 'td:nth-child(3)',
			},
		},
	});
	const songInfos = [];
	for (const song of shuffle(songs)) {
		if (song.type !== 'OP' && song.type !== 'ED') {
			continue;
		}
		const songInfo = await getSongInfo(song.link, '');
		const movieInfos = await getMovieInfo(songInfo.utaNetUrl.replace('song', 'movie'));
		songInfo.tokens = await tokenize(songInfo.paragraphs.join('\n'));
		songInfo.type = song.type;
		songInfo.movie = `https://youtu.be/${movieInfos[0].id}`;
		songInfo.animeTitle = title;

		songInfo.forbiddenWords = uniq([
			...songInfo.title.split(/[\s\P{Letter}]+/),
			...songInfo.animeTitle.split(/[\s\P{Letter}]+/),
		]).filter((word) => word.length > 2).sort((a, b) => b.length - a.length);

		songInfos.push(songInfo);
		break;
	}
	return songInfos;
};

const mask = (text, words) => {
	let response = text;
	for (const word of words) {
		response = response.replace(new RegExp(escapeRegExp(word), 'igu'), '█'.repeat(word.length));
	}
	return response;
};

const getHint = async (songInfos, n) => {
	const songInfo = sample(songInfos);

	if (n === 0) {
		const nouns = songInfo.tokens.filter((token) => (
			token.pos === '名詞' &&
			!songInfo.forbiddenWords.includes(token.surface_form)
		));
		return chunk(sampleSize(uniq(nouns.map((noun) => noun.basic_form)), 10), 5)
			.map((hints) => hints.map((hint) => `＊${hint}＊`).join(' / '))
			.join('\n');
	}
	if (n === 1) {
		const freq = await loadFreq();
		const words = songInfo.tokens.filter((token) => (
			token.word_type === 'KNOWN' &&
			['名詞', '動詞', '形容詞'].includes(token.pos) &&
			!songInfo.forbiddenWords.includes(token.surface_form)
		));
		const sortedWords = sortBy(uniq(words.map((word) => word.basic_form)), (word) => {
			if (freq.has(word)) {
				return freq.get(word);
			}
			return Infinity;
		}).reverse();
		return chunk(sortedWords.slice(0, 20), 5)
			.map((hints) => hints.map((hint) => `＊${hint}＊`).join(' / '))
			.join('\n');
	}
	if (n === 2) {
		const sentences = sampleSize(songInfo.paragraphs.join('\n').split(/\s+/), 5);
		return sentences.map((sentence) => `＊${mask(sentence, songInfo.forbiddenWords)}＊`).join('\n');
	}
	if (n === 3 || n === 4) {
		const paragraph = sample(songInfo.paragraphs);
		return paragraph.split('\n').map((line) => `＊${mask(line, songInfo.forbiddenWords)}＊`).join('\n');
	}
	return '';
};

module.exports = ({rtmClient: rtm, webClient: slack}) => {
	const state = {
		answer: null,
		previousTick: 0,
		previousHint: 0,
		hints: [],
		songInfos: [],
		thread: null,
		difficulty: null,
	};

	const onTick = () => {
		mutex.runExclusive(async () => {
			const now = Date.now();
			const nextHint = state.previousHint + (state.hints.length === 5 ? 30 : 15) * 1000;

			if (state.answer !== null && nextHint <= now) {
				state.previousHint = now;
				if (state.hints.length < 5) {
					const hintText = getHintText(state.hints.length);
					const hint = await getHint(state.songInfos, state.hints.length);

					await slack.chat.postMessage({
						channel: process.env.CHANNEL_SANDBOX,
						text: `${hintText}\n\n${hint}`,
						username: 'anime',
						icon_emoji: ':tv:',
						thread_ts: state.thread,
					});

					state.hints.push({});
				} else {
					const anger = sample([
						'これくらい常識だよね？',
						'なんでこんな簡単なこともわからないの？',
						'次は絶対正解してよ？',
						'やる気が足りないんじゃない？',
						'もっと集中して！',
					]);
					const songInfo = state.songInfos[0];
					await slack.chat.postMessage({
						channel: process.env.CHANNEL_SANDBOX,
						text: `もう、しっかりして！\n答えは ＊${songInfo.title}＊ (${state.answer} ${songInfo.type}) だよ:anger:\n${anger}\n\n${songInfo.movie}`,
						username: 'anime',
						icon_emoji: ':tv:',
						thread_ts: state.thread,
						reply_broadcast: true,
						unfurl_links: true,
					});
					await slack.chat.postMessage({
						channel: process.env.CHANNEL_SANDBOX,
						text: songInfo.utaNetUrl,
						username: 'anime',
						icon_emoji: ':tv:',
						thread_ts: state.thread,
						unfurl_links: true,
					});
					state.answer = null;
					state.previousHint = 0;
					state.hints = [];
					state.thread = null;
					state.difficulty = null;
				}
			}
			state.previousTick = now;
		});
	};

	setInterval(onTick, 1000);

	rtm.on('message', (message) => {
		if (message.channel !== process.env.CHANNEL_SANDBOX) {
			return;
		}

		let matches = null;

		if (message.text && (matches = message.text.match(/^アニソン当てクイズ(?<difficulty>easy|normal|hard)?$/)) && state.answer === null) {
			const difficulty = matches.groups.difficulty || 'easy';

			mutex.runExclusive(async () => {
				const {animes, easyAnimes, normalAnimes} = await loadSheet();
				const animeTitles = uniq(animes.map(({animeTitle}) => animeTitle).filter((title) => title));
				let answer = null;
				if (difficulty === 'easy' || difficulty === 'extreme') {
					answer = sample(easyAnimes);
				} else if (difficulty === 'normal') {
					answer = sample(normalAnimes);
				} else {
					answer = sample(animeTitles);
				}

				const songInfos = await getSongInfos(answer);

				if (songInfos.length === 0) {
					await slack.chat.postMessage({
						channel: process.env.CHANNEL_SANDBOX,
						text: `エラー:cry:\nアニメ: ${answer}`,
						username: 'anime',
						icon_emoji: ':tv:',
					});
					return;
				}

				const {ts} = await slack.chat.postMessage({
					channel: process.env.CHANNEL_SANDBOX,
					text: `このアニソンなーんだ\n\n${await getHint(songInfos, 0)}`,
					username: 'anime',
					icon_emoji: ':tv:',
				});

				state.songInfos = songInfos;
				state.thread = ts;
				state.hints.push({});
				state.previousHint = Date.now();
				state.difficulty = difficulty;

				await slack.chat.postMessage({
					channel: process.env.CHANNEL_SANDBOX,
					text: '15秒経過でヒントを出すよ♫',
					username: 'anime',
					icon_emoji: ':tv:',
					thread_ts: ts,
				});

				state.answer = answer;
			});
		}

		if (state.answer !== null && message.text && message.thread_ts === state.thread && message.username !== 'anime') {
			mutex.runExclusive(async () => {
				if (state.answer === null) {
					return;
				}
				const songInfo = state.songInfos[0];
				const answer = hiraganize(state.answer.replace(/\P{Letter}/gu, '').toLowerCase());
				const songName = hiraganize(songInfo.title.replace(/\P{Letter}/gu, '').toLowerCase());
				const userAnswer = hiraganize(message.text.replace(/\P{Letter}/gu, '').toLowerCase());

				const distance1 = levenshtein.get(answer, userAnswer);
				const distance2 = levenshtein.get(songName, userAnswer);

				if (distance1 <= answer.length / 3 || distance2 <= songName.length / 3) {
					await slack.chat.postMessage({
						channel: process.env.CHANNEL_SANDBOX,
						text: `<@${message.user}> 正解:tada:\n答えは ＊${songInfo.title}＊ (${state.answer} ${songInfo.type}) だよ:muscle:\n\n${songInfo.movie}`,
						username: 'anime',
						icon_emoji: ':tv:',
						thread_ts: state.thread,
						reply_broadcast: true,
						unfurl_links: true,
					});
					await slack.chat.postMessage({
						channel: process.env.CHANNEL_SANDBOX,
						text: songInfo.utaNetUrl,
						username: 'anime',
						icon_emoji: ':tv:',
						thread_ts: state.thread,
						unfurl_links: true,
					});
					state.answer = null;
					state.previousHint = 0;
					state.hints = [];
					state.thread = null;
					state.difficulty = null;
				} else {
					await slack.reactions.add({
						name: 'no_good',
						channel: message.channel,
						timestamp: message.ts,
					});
				}
			});
		}
	});
};
<commit_msg>anime: guegue<commit_after>const {escapeRegExp, sample, sampleSize, chunk, uniq, sortBy, shuffle} = require('lodash');
const scrapeIt = require('scrape-it');
const levenshtein = require('fast-levenshtein');
const {Mutex} = require('async-mutex');
const {hiraganize} = require('japanese');
const {Deferred} = require('../lib/utils.ts');
const {unlock, increment} = require('../achievements');
const {loadSheet} = require('./index.js');
const {getSongInfo, getMovieInfo} = require('../lyrics/index.ts');
const {tokenize} = require('kuromojin');
const {promises: fs} = require('fs');
const path = require('path');

const freqDeferred = new Deferred();
const mutex = new Mutex();

const loadFreq = async () => {
	if (freqDeferred.isResolved) {
		return freqDeferred.promise;
	}

	const data = await fs.readFile(path.resolve(__dirname, '../vocabwar/data/frequency.txt'));
	const freq = new Map(data.toString().split('\n').filter((line) => line).map((line) => {
		const [word, frequency] = line.split(' ');
		return [word, parseFloat(frequency)];
	}));
	freqDeferred.resolve(freq);
	return freq;
};

const getHintText = (n) => {
	if (n <= 1) {
		return 'しょうがないにゃあ、ヒントだよ';
	}
	if (n <= 2) {
		return 'もう一つヒントだよ、早く答えてね';
	}
	if (n <= 3) {
		return 'まだわからないの？ヒント追加するからね';
	}
	return '最後のヒントだよ！もうわかるよね？';
};

const getSongInfos = async (title) => {
	const {animeInfos} = await loadSheet();
	const anime = animeInfos.find(({name}) => name === title);
	if (!anime || !anime.utanetId) {
		return [];
	}
	const utanetUrl = `https://www.uta-net.com/user/search/anime_list_2.html?tno=${anime.utanetId}`;
	const {data: {songs}} = await scrapeIt(utanetUrl, {
		songs: {
			listItem: '.list_title + table + table tr',
			data: {
				title: 'td:nth-child(1)',
				link: {
					selector: 'td:nth-child(1) a',
					attr: 'href',
					convert: (link) => new URL(link, utanetUrl).href,
				},
				artist: 'td:nth-child(2)',
				type: 'td:nth-child(3)',
			},
		},
	});
	const songInfos = [];
	for (const song of shuffle(songs)) {
		if (song.type !== 'OP' && song.type !== 'ED') {
			continue;
		}
		const songInfo = await getSongInfo(song.link, '');
		const movieInfos = await getMovieInfo(songInfo.utaNetUrl.replace('song', 'movie'));
		songInfo.tokens = await tokenize(songInfo.paragraphs.join('\n'));
		songInfo.type = song.type;
		songInfo.movie = `https://youtu.be/${movieInfos[0].id}`;
		songInfo.animeTitle = title;

		songInfo.forbiddenWords = uniq([
			...songInfo.title.split(/\P{Letter}+/u),
			...songInfo.animeTitle.split(/\P{Letter}+/u),
		]).filter((word) => word.length > 2).sort((a, b) => b.length - a.length);

		songInfos.push(songInfo);
		break;
	}
	return songInfos;
};

const mask = (text, words) => {
	let response = text;
	for (const word of words) {
		response = response.replace(new RegExp(escapeRegExp(word), 'igu'), '█'.repeat(word.length));
	}
	return response;
};

const getHint = async (songInfos, n) => {
	const songInfo = sample(songInfos);

	if (n === 0) {
		const nouns = songInfo.tokens.filter((token) => (
			token.pos === '名詞' &&
			!songInfo.forbiddenWords.includes(token.surface_form)
		));
		return chunk(sampleSize(uniq(nouns.map((noun) => noun.basic_form)), 10), 5)
			.map((hints) => hints.map((hint) => `＊${hint}＊`).join(' / '))
			.join('\n');
	}
	if (n === 1) {
		const freq = await loadFreq();
		const words = songInfo.tokens.filter((token) => (
			token.word_type === 'KNOWN' &&
			['名詞', '動詞', '形容詞'].includes(token.pos) &&
			!songInfo.forbiddenWords.includes(token.surface_form)
		));
		const sortedWords = sortBy(uniq(words.map((word) => word.basic_form)), (word) => {
			if (freq.has(word)) {
				return freq.get(word);
			}
			return Infinity;
		}).reverse();
		return chunk(sortedWords.slice(0, 20), 5)
			.map((hints) => hints.map((hint) => `＊${hint}＊`).join(' / '))
			.join('\n');
	}
	if (n === 2) {
		const sentences = sampleSize(songInfo.paragraphs.join('\n').split(/\s+/), 5);
		return sentences.map((sentence) => `＊${mask(sentence, songInfo.forbiddenWords)}＊`).join('\n');
	}
	if (n === 3 || n === 4) {
		const paragraph = sample(songInfo.paragraphs);
		return paragraph.split('\n').map((line) => `＊${mask(line, songInfo.forbiddenWords)}＊`).join('\n');
	}
	return '';
};

module.exports = ({rtmClient: rtm, webClient: slack}) => {
	const state = {
		answer: null,
		previousTick: 0,
		previousHint: 0,
		hints: [],
		songInfos: [],
		thread: null,
		difficulty: null,
	};

	const onTick = () => {
		mutex.runExclusive(async () => {
			const now = Date.now();
			const nextHint = state.previousHint + (state.hints.length === 5 ? 30 : 15) * 1000;

			if (state.answer !== null && nextHint <= now) {
				state.previousHint = now;
				if (state.hints.length < 5) {
					const hintText = getHintText(state.hints.length);
					const hint = await getHint(state.songInfos, state.hints.length);

					await slack.chat.postMessage({
						channel: process.env.CHANNEL_SANDBOX,
						text: `${hintText}\n\n${hint}`,
						username: 'anime',
						icon_emoji: ':tv:',
						thread_ts: state.thread,
					});

					state.hints.push({});
				} else {
					const anger = sample([
						'これくらい常識だよね？',
						'なんでこんな簡単なこともわからないの？',
						'次は絶対正解してよ？',
						'やる気が足りないんじゃない？',
						'もっと集中して！',
					]);
					const songInfo = state.songInfos[0];
					await slack.chat.postMessage({
						channel: process.env.CHANNEL_SANDBOX,
						text: `もう、しっかりして！\n答えは ＊${songInfo.title}＊ (${state.answer} ${songInfo.type}) だよ:anger:\n${anger}\n\n${songInfo.movie}`,
						username: 'anime',
						icon_emoji: ':tv:',
						thread_ts: state.thread,
						reply_broadcast: true,
						unfurl_links: true,
					});
					await slack.chat.postMessage({
						channel: process.env.CHANNEL_SANDBOX,
						text: songInfo.utaNetUrl,
						username: 'anime',
						icon_emoji: ':tv:',
						thread_ts: state.thread,
						unfurl_links: true,
					});
					state.answer = null;
					state.previousHint = 0;
					state.hints = [];
					state.thread = null;
					state.difficulty = null;
				}
			}
			state.previousTick = now;
		});
	};

	setInterval(onTick, 1000);

	rtm.on('message', (message) => {
		if (message.channel !== process.env.CHANNEL_SANDBOX) {
			return;
		}

		let matches = null;

		if (message.text && (matches = message.text.match(/^アニソン当てクイズ(?<difficulty>easy|normal|hard)?$/)) && state.answer === null) {
			const difficulty = matches.groups.difficulty || 'easy';

			mutex.runExclusive(async () => {
				const {animes, easyAnimes, normalAnimes} = await loadSheet();
				const animeTitles = uniq(animes.map(({animeTitle}) => animeTitle).filter((title) => title));
				let answer = null;
				if (difficulty === 'easy' || difficulty === 'extreme') {
					answer = sample(easyAnimes);
				} else if (difficulty === 'normal') {
					answer = sample(normalAnimes);
				} else {
					answer = sample(animeTitles);
				}

				const songInfos = await getSongInfos(answer);

				if (songInfos.length === 0) {
					await slack.chat.postMessage({
						channel: process.env.CHANNEL_SANDBOX,
						text: `エラー:cry:\nアニメ: ${answer}`,
						username: 'anime',
						icon_emoji: ':tv:',
					});
					return;
				}

				const {ts} = await slack.chat.postMessage({
					channel: process.env.CHANNEL_SANDBOX,
					text: `このアニソンなーんだ\n\n${await getHint(songInfos, 0)}`,
					username: 'anime',
					icon_emoji: ':tv:',
				});

				state.songInfos = songInfos;
				state.thread = ts;
				state.hints.push({});
				state.previousHint = Date.now();
				state.difficulty = difficulty;

				await slack.chat.postMessage({
					channel: process.env.CHANNEL_SANDBOX,
					text: '15秒経過でヒントを出すよ♫',
					username: 'anime',
					icon_emoji: ':tv:',
					thread_ts: ts,
				});

				state.answer = answer;
			});
		}

		if (state.answer !== null && message.text && message.thread_ts === state.thread && message.username !== 'anime') {
			mutex.runExclusive(async () => {
				if (state.answer === null) {
					return;
				}
				const songInfo = state.songInfos[0];
				const answer = hiraganize(state.answer.replace(/\P{Letter}/gu, '').toLowerCase());
				const songName = hiraganize(songInfo.title.replace(/\P{Letter}/gu, '').toLowerCase());
				const userAnswer = hiraganize(message.text.replace(/\P{Letter}/gu, '').toLowerCase());

				const distance1 = levenshtein.get(answer, userAnswer);
				const distance2 = levenshtein.get(songName, userAnswer);

				if (distance1 <= answer.length / 3 || distance2 <= songName.length / 3) {
					await slack.chat.postMessage({
						channel: process.env.CHANNEL_SANDBOX,
						text: `<@${message.user}> 正解:tada:\n答えは ＊${songInfo.title}＊ (${state.answer} ${songInfo.type}) だよ:muscle:\n\n${songInfo.movie}`,
						username: 'anime',
						icon_emoji: ':tv:',
						thread_ts: state.thread,
						reply_broadcast: true,
						unfurl_links: true,
					});
					await slack.chat.postMessage({
						channel: process.env.CHANNEL_SANDBOX,
						text: songInfo.utaNetUrl,
						username: 'anime',
						icon_emoji: ':tv:',
						thread_ts: state.thread,
						unfurl_links: true,
					});
					state.answer = null;
					state.previousHint = 0;
					state.hints = [];
					state.thread = null;
					state.difficulty = null;
				} else {
					await slack.reactions.add({
						name: 'no_good',
						channel: message.channel,
						timestamp: message.ts,
					});
				}
			});
		}
	});
};
<|endoftext|>


<commit_before>
  'use strict';
  var Bird = require('../prefabs/bird');
  var Ground = require('../prefabs/ground');
  var PipeGroup = require('../prefabs/pipeGroup');

  function Play() {}
  Play.prototype = {
    create: function() {
      // Set physics
      this.game.physics.startSystem(Phaser.Physics.ARCADE);
      this.game.physics.arcade.gravity.y = 1200;

      this.background = this.game.add.sprite(0, 0, 'background');

      // Create a new bird object
      this.bird = new Bird(this.game, 100, this.game.height/2);
      // and add it to the game
      this.game.add.existing(this.bird);

      // create and add a group to hold our pipeGroup prefabs
      this.pipes = this.game.add.group();

      // create and add a new Ground object
      this.ground = new Ground(this.game, 0, 400, 335, 112);
      this.game.add.existing(this.ground);

      // add mouse/touch controls
      this.input.onDown.add(this.bird.flap, this.bird);

      // add a timer
      this.pipeGenerator = this.game.time.events.loop(Phaser.Timer.SECOND * 1.25, this.generatePipes, this);
      this.pipeGenerator.timer.start();
    },
    generatePipes: function() {
      var pipeY = this.game.rnd.integerInRange(-100, 100);
      var pipeGroup = this.pipes.getFirstExists(false);
      if(!pipeGroup) {
          pipeGroup = new PipeGroup(this.game, this.pipes);
      }
      pipeGroup.reset(this.game.width + pipeGroup.width/2, pipeY);
    },
    update: function() {
      this.game.physics.arcade.collide(this.bird, this.ground);
    }
  };

  module.exports = Play;
<commit_msg>enables collisions with pipes<commit_after>
  'use strict';
  var Bird = require('../prefabs/bird');
  var Ground = require('../prefabs/ground');
  var PipeGroup = require('../prefabs/pipeGroup');

  function Play() {}
  Play.prototype = {
    create: function() {
      // Set physics
      this.game.physics.startSystem(Phaser.Physics.ARCADE);
      this.game.physics.arcade.gravity.y = 1200;

      this.background = this.game.add.sprite(0, 0, 'background');

      // Create a new bird object
      this.bird = new Bird(this.game, 100, this.game.height/2);
      // and add it to the game
      this.game.add.existing(this.bird);

      // create and add a group to hold our pipeGroup prefabs
      this.pipes = this.game.add.group();

      // create and add a new Ground object
      this.ground = new Ground(this.game, 0, 400, 335, 112);
      this.game.add.existing(this.ground);

      // add mouse/touch controls
      this.input.onDown.add(this.bird.flap, this.bird);

      // add a timer
      this.pipeGenerator = this.game.time.events.loop(Phaser.Timer.SECOND * 1.25, this.generatePipes, this);
      this.pipeGenerator.timer.start();
    },
    generatePipes: function() {
      var pipeY = this.game.rnd.integerInRange(-100, 100);
      var pipeGroup = this.pipes.getFirstExists(false);
      if(!pipeGroup) {
          pipeGroup = new PipeGroup(this.game, this.pipes);
      }
      pipeGroup.reset(this.game.width + pipeGroup.width/2, pipeY);
    },
    update: function() {
      // enable collisions between the bird and the ground
      this.game.physics.arcade.collide(this.bird, this.ground, this.deathHandler, null, this);

      // enable collisions between the bird and each group in the pipes group
      this.pipes.forEach(function(pipeGroup) {
        this.game.physics.arcade.collide(this.bird, pipeGroup, this.deathHandler, null, this);
      }, this);
    },
    deathHandler: function() {
      this.game.state.start('gameover');
    },
    shutdown: function() {
      this.bird.destroy();
      this.pipes.destroy();
    }
  };

  module.exports = Play;
<|endoftext|>


<commit_before>var loader = require("@loader");

var isNode = typeof process === "object" && {}.toString.call(process) ===
	"[object process]";
var importRegEx = /@import [^uU]['"]?([^'"\)]*)['"]?/g;
var resourceRegEx =  /url\(['"]?([^'"\)]*)['"]?\)/g;

var waitSeconds = (loader.cssOptions && loader.cssOptions.timeout)
	? parseInt(loader.cssOptions.timeout, 10) : 60;
var noop = function () {};
var onloadCss = function(link, cb){
	debugger;
	var styleSheets = document.styleSheets,
		i = styleSheets.length;
	while( i-- ){
		if( styleSheets[ i ].href === link.href ){
			return cb();
		}
	}
	setTimeout(function() {
		onloadCss(link, cb);
	});
};

if(isProduction()) {
	exports.fetch = function(load) {
		// inspired by https://github.com/filamentgroup/loadCSS

		var styleSheets = document.styleSheets;

		// wait until the css file is loaded
		return new Promise(function(resolve, reject) {
			var timeout = setTimeout(function() {
				reject('Unable to load CSS');
			}, waitSeconds * 1000);

			// if found a stylesheet with the same address
			// resolve this promise without adding a link element to the page.
			for (var i = 0; i < styleSheets.length; ++i) {
				if(load.address === styleSheets[i].href){
					resolve('');
					return;
				}
			}

			var link = document.createElement('link');
			link.type = 'text/css';
			link.rel = 'stylesheet';
			link.href = load.address;

			var loadCB = function(event) {
				clearTimeout(timeout);
				link.removeEventListener("load", loadCB);
				link.removeEventListener("error", loadCB);

				if(event && event.type === "error"){
					reject('Unable to load CSS');
				} else {
					resolve('');
				}
			};

			// This code is for browsers that don’t support onload
			// No support for onload (it'll bind but never fire):
			//	* Android 4.3 (Samsung Galaxy S4, Browserstack)
			//	* Android 4.2 Browser (Samsung Galaxy SIII Mini GT-I8200L)
			//	* Android 2.3 (Pantech Burst P9070)
			// Weak inference targets Android < 4.4 and
			// a fallback for IE 8 and beneath
			if( "isApplicationInstalled" in navigator || !link.addEventListener) {
				// fallback, polling styleSheets
				onloadCss(link, loadCB);
			} else {
				// attach onload event for all modern browser
				link.addEventListener( "load", loadCB );
				link.addEventListener( "error", loadCB );
			}

			document.head.appendChild(link);

		});
	};

} else {

	exports.instantiate = function(load) {
		var loader = this;

		// Replace @import's that don't start with a "u" or "U" and do start
		// with a single or double quote with a path wrapped in "url()"
		// relative to the page
		load.source = load.source.replace(importRegEx, function(whole, part) {
			if(isNode) {
				return "@import url(" + part + ")";
			}else{
				return "@import url(" + steal.joinURIs( load.address, part) + ")";
			}
		});

		load.metadata.deps = [];
		load.metadata.execute = function(){

			var source = load.source+"/*# sourceURL="+load.address+" */";
			source = source.replace(resourceRegEx, function(whole, part) {
				return "url(" + steal.joinURIs( load.address, part) + ")";
			});

			if(load.source && typeof document !== "undefined") {
				var doc = document.head ? document : document.getElementsByTagName ?
					document : document.documentElement;

				var head = doc.head || doc.getElementsByTagName('head')[0],
					style = document.createElement('style');

				if(!head) {
					var docEl = doc.documentElement || doc;
					head = document.createElement("head");
					docEl.insertBefore(head, docEl.firstChild);
				}

				// make source load relative to the current page
				style.type = 'text/css';

				if (style.styleSheet){
					style.styleSheet.cssText = source;
				} else {
					style.appendChild(document.createTextNode(source));
				}
				head.appendChild(style);

				if(loader.has("live-reload")) {
					var cssReload = loader["import"]("live-reload", { name: "$css" });
					Promise.resolve(cssReload).then(function(reload){
						loader["import"](load.name).then(function(){
							reload.once(load.name, function(){
								head.removeChild(style);
							});
						});
					});
				}
			}

			return System.newModule({source: source});
		};
		load.metadata.format = "css";
	};

}

function isProduction(){
	return (loader.isEnv && loader.isEnv("production")) ||
		loader.env === "production";
}
exports.locateScheme = true;
exports.buildType = "css";
exports.includeInBuild = true;
<commit_msg>remove debugger<commit_after>var loader = require("@loader");

var isNode = typeof process === "object" && {}.toString.call(process) ===
	"[object process]";
var importRegEx = /@import [^uU]['"]?([^'"\)]*)['"]?/g;
var resourceRegEx =  /url\(['"]?([^'"\)]*)['"]?\)/g;

var waitSeconds = (loader.cssOptions && loader.cssOptions.timeout)
	? parseInt(loader.cssOptions.timeout, 10) : 60;
var noop = function () {};
var onloadCss = function(link, cb){
	var styleSheets = document.styleSheets,
		i = styleSheets.length;
	while( i-- ){
		if( styleSheets[ i ].href === link.href ){
			return cb();
		}
	}
	setTimeout(function() {
		onloadCss(link, cb);
	});
};

if(isProduction()) {
	exports.fetch = function(load) {
		// inspired by https://github.com/filamentgroup/loadCSS

		var styleSheets = document.styleSheets;

		// wait until the css file is loaded
		return new Promise(function(resolve, reject) {
			var timeout = setTimeout(function() {
				reject('Unable to load CSS');
			}, waitSeconds * 1000);

			// if found a stylesheet with the same address
			// resolve this promise without adding a link element to the page.
			for (var i = 0; i < styleSheets.length; ++i) {
				if(load.address === styleSheets[i].href){
					resolve('');
					return;
				}
			}

			var link = document.createElement('link');
			link.type = 'text/css';
			link.rel = 'stylesheet';
			link.href = load.address;

			var loadCB = function(event) {
				clearTimeout(timeout);
				link.removeEventListener("load", loadCB);
				link.removeEventListener("error", loadCB);

				if(event && event.type === "error"){
					reject('Unable to load CSS');
				} else {
					resolve('');
				}
			};

			// This code is for browsers that don’t support onload
			// No support for onload (it'll bind but never fire):
			//	* Android 4.3 (Samsung Galaxy S4, Browserstack)
			//	* Android 4.2 Browser (Samsung Galaxy SIII Mini GT-I8200L)
			//	* Android 2.3 (Pantech Burst P9070)
			// Weak inference targets Android < 4.4 and
			// a fallback for IE 8 and beneath
			if( "isApplicationInstalled" in navigator || !link.addEventListener) {
				// fallback, polling styleSheets
				onloadCss(link, loadCB);
			} else {
				// attach onload event for all modern browser
				link.addEventListener( "load", loadCB );
				link.addEventListener( "error", loadCB );
			}

			document.head.appendChild(link);

		});
	};

} else {

	exports.instantiate = function(load) {
		var loader = this;

		// Replace @import's that don't start with a "u" or "U" and do start
		// with a single or double quote with a path wrapped in "url()"
		// relative to the page
		load.source = load.source.replace(importRegEx, function(whole, part) {
			if(isNode) {
				return "@import url(" + part + ")";
			}else{
				return "@import url(" + steal.joinURIs( load.address, part) + ")";
			}
		});

		load.metadata.deps = [];
		load.metadata.execute = function(){

			var source = load.source+"/*# sourceURL="+load.address+" */";
			source = source.replace(resourceRegEx, function(whole, part) {
				return "url(" + steal.joinURIs( load.address, part) + ")";
			});

			if(load.source && typeof document !== "undefined") {
				var doc = document.head ? document : document.getElementsByTagName ?
					document : document.documentElement;

				var head = doc.head || doc.getElementsByTagName('head')[0],
					style = document.createElement('style');

				if(!head) {
					var docEl = doc.documentElement || doc;
					head = document.createElement("head");
					docEl.insertBefore(head, docEl.firstChild);
				}

				// make source load relative to the current page
				style.type = 'text/css';

				if (style.styleSheet){
					style.styleSheet.cssText = source;
				} else {
					style.appendChild(document.createTextNode(source));
				}
				head.appendChild(style);

				if(loader.has("live-reload")) {
					var cssReload = loader["import"]("live-reload", { name: "$css" });
					Promise.resolve(cssReload).then(function(reload){
						loader["import"](load.name).then(function(){
							reload.once(load.name, function(){
								head.removeChild(style);
							});
						});
					});
				}
			}

			return System.newModule({source: source});
		};
		load.metadata.format = "css";
	};

}

function isProduction(){
	return (loader.isEnv && loader.isEnv("production")) ||
		loader.env === "production";
}
exports.locateScheme = true;
exports.buildType = "css";
exports.includeInBuild = true;
<|endoftext|>


<commit_before>$(document).ready(function () {

  var sidebarInner = $('.sidebar-inner');

  initAffix();
  resizeListener();

  function initAffix () {
    var headerOffset = getHeaderOffset(),
        footerOffset = getFooterOffset();

    sidebarInner.affix({
      offset: {
        top: headerOffset - CONFIG.sidebar.offset,
        bottom: footerOffset
      }
    });

    setSidebarMarginTop(headerOffset).show();
  }

  function resizeListener () {
    var mql = window.matchMedia('(min-width: 991px)');
    mql.addListener(function(e){
      if(e.matches){
        recalculateAffixPosition();
      }
    });
  }

  function getHeaderOffset () {
    return $('.header-inner').height() + CONFIG.sidebar.offset;
  }

  function getFooterOffset () {
    var footerInner = $('.footer-inner'),
        footerMargin = footerInner.outerHeight(true) - footerInner.outerHeight(),
        footerOffset = footerInner.outerHeight(true) + footerMargin;
    return footerOffset;
  }

  function setSidebarMarginTop (headerOffset) {
    return $('#sidebar').css({ 'margin-top': headerOffset });
  }

  function recalculateAffixPosition () {
    $(window).off('.affix');
    sidebarInner.removeData('bs.affix').removeClass('affix affix-top affix-bottom');
    initAffix();
  }

});
<commit_msg>FIX: sidebar scrollable in all schemes [22].<commit_after>$(document).ready(function () {

  var sidebarInner = $('.sidebar-inner');

  initAffix();
  resizeListener();

  function initAffix () {
    var headerOffset = getHeaderOffset(),
        footerOffset = getFooterOffset(),
        sidebarHeight = $('#sidebar').height() + NexT.utils.getSidebarb2tHeight(),
        contentHeight = $('#content').height();

    // Not affix if sidebar taller then content (to prevent bottom jumping).
    if (headerOffset + sidebarHeight < contentHeight) {
      sidebarInner.affix({
        offset: {
          top: headerOffset - CONFIG.sidebar.offset,
          bottom: footerOffset
        }
      });
    }

    setSidebarMarginTop(headerOffset).css({ 'margin-left': 'initial' });
  }

  function resizeListener () {
    var mql = window.matchMedia('(min-width: 991px)');
    mql.addListener(function(e){
      if(e.matches){
        recalculateAffixPosition();
      }
    });
  }

  function getHeaderOffset () {
    return $('.header-inner').height() + CONFIG.sidebar.offset;
  }

  function getFooterOffset () {
    var footerInner = $('.footer-inner'),
        footerMargin = footerInner.outerHeight(true) - footerInner.outerHeight(),
        footerOffset = footerInner.outerHeight(true) + footerMargin;
    return footerOffset;
  }

  function setSidebarMarginTop (headerOffset) {
    return $('#sidebar').css({ 'margin-top': headerOffset });
  }

  function recalculateAffixPosition () {
    $(window).off('.affix');
    sidebarInner.removeData('bs.affix').removeClass('affix affix-top affix-bottom');
    initAffix();
  }

});
<|endoftext|>