<commit_before>const {
  GraphQLObjectType,
  GraphQLList,
  GraphQLString,
  GraphQLInt,
  GraphQLEnumType,
  GraphQLJSON
} = require("gatsby/graphql");
const _ = require("lodash");
const remark = require("remark");
const retext = require("retext");
const visit = require("unist-util-visit");
const remove = require("unist-util-remove");
const toString = require("mdast-util-to-string");
const generateTOC = require("mdast-util-toc");
const stripMarkdown = require("strip-markdown");
const prune = require("underscore.string/prune");

const debug = require("debug")("gatsby-mdx:extend-node-type");
const renderHTML = require("../utils/render-html");
const getTableOfContents = require("../utils/get-table-of-content");
const defaultOptions = require("../utils/default-options");
const genMDX = require("../utils/gen-mdx");

module.exports = (
  { type, store, pathPrefix, getNode, getNodes, cache, reporter },
  pluginOptions
) => {
  if (type.name !== `Mdx`) {
    return {};
  }

  const options = defaultOptions(pluginOptions);

  for (let plugin of options.gatsbyRemarkPlugins) {
    if (!plugin.resolve) {
      throw new Error(
        'gatsby-remark plugins must be configured in the form {resolve: "plugin", options: {}}'
      );
    }
    debug("requiring", plugin.resolve);
    const requiredPlugin = require(plugin.resolve);
    debug("required", plugin);
    if (_.isFunction(requiredPlugin.setParserPlugins)) {
      for (let parserPlugin of requiredPlugin.setParserPlugins(
        plugin.pluginOptions
      )) {
        if (_.isArray(parserPlugin)) {
          const [parser, parserPluginOptions] = parserPlugin;
          debug("adding mdPlugin with options", plugin, parserPluginOptions);
          options.mdPlugins.push([parser, parserPluginOptions]);
        } else {
          debug("adding mdPlugin", plugin);
          options.mdPlugins.push(parserPlugin);
        }
      }
    }
  }

  const processMDX = ({ node }) =>
    genMDX({ node, getNode, getNodes, reporter, cache, pathPrefix, options });
  return new Promise((resolve /*, reject*/) => {
    async function getText(mdxNode) {
      const { mdast } = await processMDX({ node: mdxNode });

      // convert the mdxast to back to mdast
      remove(mdast, "import");
      remove(mdast, "export");
      visit(mdast, "jsx", node => {
        node.type = "html";
      });

      const textAst = await remark()
        .use(stripMarkdown)
        .run(mdast);

      return remark().stringify(textAst);
    }

    const HeadingType = new GraphQLObjectType({
      name: `MdxHeadingMdx`,
      fields: {
        value: {
          type: GraphQLString,
          resolve(heading) {
            return heading.value;
          }
        },
        depth: {
          type: GraphQLInt,
          resolve(heading) {
            return heading.depth;
          }
        }
      }
    });
    const Headings = new GraphQLEnumType({
      name: `HeadingsMdx`,
      values: {
        h1: { value: 1 },
        h2: { value: 2 },
        h3: { value: 3 },
        h4: { value: 4 },
        h5: { value: 5 },
        h6: { value: 6 }
      }
    });

    return resolve({
      code: {
        resolve(mdxNode) {
          return mdxNode;
        },
        type: new GraphQLObjectType({
          name: `MDXCodeMdx`,
          fields: {
            body: {
              type: GraphQLString,
              async resolve(mdxNode) {
                const { body } = await processMDX({ node: mdxNode });
                return body;
              }
            },
            scope: {
              type: GraphQLString,
              async resolve() {
                return "";
              }
            }
          }
        })
      },
      excerpt: {
        type: GraphQLString,
        args: {
          pruneLength: {
            type: GraphQLInt,
            defaultValue: 140
          }
        },
        async resolve(mdxNode, { pruneLength }) {
          if (mdxNode.excerpt) {
            return Promise.resolve(mdxNode.excerpt);
          }
          const { mdast } = await processMDX({ node: mdxNode });

          const excerptNodes = [];
          visit(mdast, node => {
            if (node.type === "text" || node.type === "inlineCode") {
              excerptNodes.push(node.value);
            }
            return;
          });

          return prune(excerptNodes.join(" "), pruneLength, "…");
        }
      },
      headings: {
        type: new GraphQLList(HeadingType),
        args: {
          depth: {
            type: Headings
          }
        },
        async resolve(mdxNode, { depth }) {
          // TODO: change this to operate on html instead of mdast
          const { mdast } = await processMDX({ node: mdxNode });
          let headings = [];
          visit(mdast, "heading", heading => {
            headings.push({
              value: toString(heading),
              depth: heading.depth
            });
          });
          if (typeof depth === `number`) {
            headings = headings.filter(heading => heading.depth === depth);
          }
          return headings;
        }
      },
      html: {
        type: GraphQLString,
        async resolve(mdxNode) {
          if (mdxNode.html) {
            return Promise.resolve(mdxNode.html);
          }
          const { body } = await processMDX({ node: mdxNode });
          try {
            const withMDX = renderHTML(body);
            return withMDX(store.getState().webpack);
          } catch (e) {
            throw new Error(
              "Error querying the `html` field. This field is inded for use with RSS feed generation.\n" +
                "If you're trying to use it in application-level code, try querying for code.body instead.\n" +
                "Original error: " +
                e
            );
          }
        }
      },
      tableOfContents: {
        type: GraphQLJSON,
        args: {
          maxDepth: {
            type: GraphQLInt,
            default: 6
          }
        },
        async resolve(mdxNode, { maxDepth }) {
          const { mdast } = await processMDX({ node: mdxNode });
          const toc = generateTOC(mdast, maxDepth);

          return getTableOfContents(toc.map, {});
        }
      },
      timeToRead: {
        type: GraphQLInt,
        async resolve(mdxNode) {
          const text = await getText(mdxNode);
          let timeToRead = 0;
          const avgWPM = 265;
          const wordCount = _.words(text).length;
          timeToRead = Math.round(wordCount / avgWPM);
          if (timeToRead === 0) {
            timeToRead = 1;
          }
          return timeToRead;
        }
      },
      wordCount: {
        type: new GraphQLObjectType({
          name: `wordCountsMdx`,
          fields: {
            paragraphs: {
              type: GraphQLInt
            },
            sentences: {
              type: GraphQLInt
            },
            words: {
              type: GraphQLInt
            }
          }
        }),
        async resolve(mdxNode) {
          let counts = {};

          const text = await getText(mdxNode);

          await retext()
            .use(count)
            .process(text);

          return {
            paragraphs: counts.ParagraphNode,
            sentences: counts.SentenceNode,
            words: counts.WordNode
          };

          function count() {
            return counter;
            function counter(tree) {
              visit(tree, visitor);
              function visitor(node) {
                counts[node.type] = (counts[node.type] || 0) + 1;
              }
            }
          }
        }
      }
    });
  });
};
<commit_msg>fixing typo in error message<commit_after>const {
  GraphQLObjectType,
  GraphQLList,
  GraphQLString,
  GraphQLInt,
  GraphQLEnumType,
  GraphQLJSON
} = require("gatsby/graphql");
const _ = require("lodash");
const remark = require("remark");
const retext = require("retext");
const visit = require("unist-util-visit");
const remove = require("unist-util-remove");
const toString = require("mdast-util-to-string");
const generateTOC = require("mdast-util-toc");
const stripMarkdown = require("strip-markdown");
const prune = require("underscore.string/prune");

const debug = require("debug")("gatsby-mdx:extend-node-type");
const renderHTML = require("../utils/render-html");
const getTableOfContents = require("../utils/get-table-of-content");
const defaultOptions = require("../utils/default-options");
const genMDX = require("../utils/gen-mdx");

module.exports = (
  { type, store, pathPrefix, getNode, getNodes, cache, reporter },
  pluginOptions
) => {
  if (type.name !== `Mdx`) {
    return {};
  }

  const options = defaultOptions(pluginOptions);

  for (let plugin of options.gatsbyRemarkPlugins) {
    if (!plugin.resolve) {
      throw new Error(
        'gatsby-remark plugins must be configured in the form {resolve: "plugin", options: {}}'
      );
    }
    debug("requiring", plugin.resolve);
    const requiredPlugin = require(plugin.resolve);
    debug("required", plugin);
    if (_.isFunction(requiredPlugin.setParserPlugins)) {
      for (let parserPlugin of requiredPlugin.setParserPlugins(
        plugin.pluginOptions
      )) {
        if (_.isArray(parserPlugin)) {
          const [parser, parserPluginOptions] = parserPlugin;
          debug("adding mdPlugin with options", plugin, parserPluginOptions);
          options.mdPlugins.push([parser, parserPluginOptions]);
        } else {
          debug("adding mdPlugin", plugin);
          options.mdPlugins.push(parserPlugin);
        }
      }
    }
  }

  const processMDX = ({ node }) =>
    genMDX({ node, getNode, getNodes, reporter, cache, pathPrefix, options });
  return new Promise((resolve /*, reject*/) => {
    async function getText(mdxNode) {
      const { mdast } = await processMDX({ node: mdxNode });

      // convert the mdxast to back to mdast
      remove(mdast, "import");
      remove(mdast, "export");
      visit(mdast, "jsx", node => {
        node.type = "html";
      });

      const textAst = await remark()
        .use(stripMarkdown)
        .run(mdast);

      return remark().stringify(textAst);
    }

    const HeadingType = new GraphQLObjectType({
      name: `MdxHeadingMdx`,
      fields: {
        value: {
          type: GraphQLString,
          resolve(heading) {
            return heading.value;
          }
        },
        depth: {
          type: GraphQLInt,
          resolve(heading) {
            return heading.depth;
          }
        }
      }
    });
    const Headings = new GraphQLEnumType({
      name: `HeadingsMdx`,
      values: {
        h1: { value: 1 },
        h2: { value: 2 },
        h3: { value: 3 },
        h4: { value: 4 },
        h5: { value: 5 },
        h6: { value: 6 }
      }
    });

    return resolve({
      code: {
        resolve(mdxNode) {
          return mdxNode;
        },
        type: new GraphQLObjectType({
          name: `MDXCodeMdx`,
          fields: {
            body: {
              type: GraphQLString,
              async resolve(mdxNode) {
                const { body } = await processMDX({ node: mdxNode });
                return body;
              }
            },
            scope: {
              type: GraphQLString,
              async resolve() {
                return "";
              }
            }
          }
        })
      },
      excerpt: {
        type: GraphQLString,
        args: {
          pruneLength: {
            type: GraphQLInt,
            defaultValue: 140
          }
        },
        async resolve(mdxNode, { pruneLength }) {
          if (mdxNode.excerpt) {
            return Promise.resolve(mdxNode.excerpt);
          }
          const { mdast } = await processMDX({ node: mdxNode });

          const excerptNodes = [];
          visit(mdast, node => {
            if (node.type === "text" || node.type === "inlineCode") {
              excerptNodes.push(node.value);
            }
            return;
          });

          return prune(excerptNodes.join(" "), pruneLength, "…");
        }
      },
      headings: {
        type: new GraphQLList(HeadingType),
        args: {
          depth: {
            type: Headings
          }
        },
        async resolve(mdxNode, { depth }) {
          // TODO: change this to operate on html instead of mdast
          const { mdast } = await processMDX({ node: mdxNode });
          let headings = [];
          visit(mdast, "heading", heading => {
            headings.push({
              value: toString(heading),
              depth: heading.depth
            });
          });
          if (typeof depth === `number`) {
            headings = headings.filter(heading => heading.depth === depth);
          }
          return headings;
        }
      },
      html: {
        type: GraphQLString,
        async resolve(mdxNode) {
          if (mdxNode.html) {
            return Promise.resolve(mdxNode.html);
          }
          const { body } = await processMDX({ node: mdxNode });
          try {
            const withMDX = renderHTML(body);
            return withMDX(store.getState().webpack);
          } catch (e) {
            throw new Error(
              "Error querying the `html` field. This field is intended for use with RSS feed generation.\n" +
                "If you're trying to use it in application-level code, try querying for code.body instead.\n" +
                "Original error: " +
                e
            );
          }
        }
      },
      tableOfContents: {
        type: GraphQLJSON,
        args: {
          maxDepth: {
            type: GraphQLInt,
            default: 6
          }
        },
        async resolve(mdxNode, { maxDepth }) {
          const { mdast } = await processMDX({ node: mdxNode });
          const toc = generateTOC(mdast, maxDepth);

          return getTableOfContents(toc.map, {});
        }
      },
      timeToRead: {
        type: GraphQLInt,
        async resolve(mdxNode) {
          const text = await getText(mdxNode);
          let timeToRead = 0;
          const avgWPM = 265;
          const wordCount = _.words(text).length;
          timeToRead = Math.round(wordCount / avgWPM);
          if (timeToRead === 0) {
            timeToRead = 1;
          }
          return timeToRead;
        }
      },
      wordCount: {
        type: new GraphQLObjectType({
          name: `wordCountsMdx`,
          fields: {
            paragraphs: {
              type: GraphQLInt
            },
            sentences: {
              type: GraphQLInt
            },
            words: {
              type: GraphQLInt
            }
          }
        }),
        async resolve(mdxNode) {
          let counts = {};

          const text = await getText(mdxNode);

          await retext()
            .use(count)
            .process(text);

          return {
            paragraphs: counts.ParagraphNode,
            sentences: counts.SentenceNode,
            words: counts.WordNode
          };

          function count() {
            return counter;
            function counter(tree) {
              visit(tree, visitor);
              function visitor(node) {
                counts[node.type] = (counts[node.type] || 0) + 1;
              }
            }
          }
        }
      }
    });
  });
};
<|endoftext|>


<commit_before>import {day, sunday, monday, year} from "d3-time";
import UtcDate from "./UtcDate";

var LocalDate = Date;

export default function(locale) {
  var locale_dateTime = locale.dateTime,
      locale_date = locale.date,
      locale_time = locale.time,
      locale_periods = locale.periods,
      locale_days = locale.days,
      locale_shortDays = locale.shortDays,
      locale_months = locale.months,
      locale_shortMonths = locale.shortMonths;

  var periodLookup = formatLookup(locale_periods),
      dayRe = formatRe(locale_days),
      dayLookup = formatLookup(locale_days),
      dayAbbrevRe = formatRe(locale_shortDays),
      dayAbbrevLookup = formatLookup(locale_shortDays),
      monthRe = formatRe(locale_months),
      monthLookup = formatLookup(locale_months),
      monthAbbrevRe = formatRe(locale_shortMonths),
      monthAbbrevLookup = formatLookup(locale_shortMonths);

  var formats = {
    "a": function(d) { return locale_shortDays[d.getDay()]; },
    "A": function(d) { return locale_days[d.getDay()]; },
    "b": function(d) { return locale_shortMonths[d.getMonth()]; },
    "B": function(d) { return locale_months[d.getMonth()]; },
    "c": newFormat(locale_dateTime),
    "d": function(d, p) { return pad(d.getDate(), p, 2); },
    "e": function(d, p) { return pad(d.getDate(), p, 2); },
    "H": function(d, p) { return pad(d.getHours(), p, 2); },
    "I": function(d, p) { return pad(d.getHours() % 12 || 12, p, 2); },
    "j": function(d, p) { return pad(1 + day.count(year(d), d), p, 3); },
    "L": function(d, p) { return pad(d.getMilliseconds(), p, 3); },
    "m": function(d, p) { return pad(d.getMonth() + 1, p, 2); },
    "M": function(d, p) { return pad(d.getMinutes(), p, 2); },
    "p": function(d) { return locale_periods[+(d.getHours() >= 12)]; },
    "S": function(d, p) { return pad(d.getSeconds(), p, 2); },
    "U": function(d, p) { return pad(sunday.count(year(d), d), p, 2); },
    "w": function(d) { return d.getDay(); },
    "W": function(d, p) { return pad(monday.count(year(d), d), p, 2); },
    "x": newFormat(locale_date),
    "X": newFormat(locale_time),
    "y": function(d, p) { return pad(d.getFullYear() % 100, p, 2); },
    "Y": function(d, p) { return pad(d.getFullYear() % 10000, p, 4); },
    "Z": formatZone,
    "%": function() { return "%"; }
  };

  var parses = {
    "a": parseWeekdayAbbrev,
    "A": parseWeekday,
    "b": parseMonthAbbrev,
    "B": parseMonth,
    "c": parseLocaleDateTime,
    "d": parseDay,
    "e": parseDay,
    "H": parseHour24,
    "I": parseHour24,
    "j": parseDayOfYear,
    "L": parseMilliseconds,
    "m": parseMonthNumber,
    "M": parseMinutes,
    "p": parseAmPm,
    "S": parseSeconds,
    "U": parseWeekNumberSunday,
    "w": parseWeekdayNumber,
    "W": parseWeekNumberMonday,
    "x": parseLocaleDate,
    "X": parseLocaleTime,
    "y": parseYear,
    "Y": parseFullYear,
    "Z": parseZone,
    "%": parseLiteralPercent
  };

  function newFormat(template) {
    template += "";

    function format(date) {
      var string = [],
          i = -1,
          j = 0,
          n = template.length,
          c,
          pad,
          format;

      while (++i < n) {
        if (template.charCodeAt(i) === 37) {
          string.push(template.slice(j, i));
          if ((pad = pads[c = template.charAt(++i)]) != null) c = template.charAt(++i);
          if (format = formats[c]) c = format(date, pad == null ? (c === "e" ? " " : "0") : pad);
          string.push(c);
          j = i + 1;
        }
      }

      string.push(template.slice(j, i));
      return string.join("");
    }

    format.parse = function(string) {
      var d = {y: 1900, m: 0, d: 1, H: 0, M: 0, S: 0, L: 0, Z: null},
          i = parseTemplate(d, template, string, 0);
      if (i != string.length) return null;

      // The am-pm flag is 0 for AM, and 1 for PM.
      if ("p" in d) d.H = d.H % 12 + d.p * 12;

      // If a time zone is specified, it is always relative to UTC;
      // we need to use UtcDate if we aren’t already.
      var localZ = d.Z != null && Date !== UtcDate,
          date = new (localZ ? UtcDate : Date);

      // Set year, month, date.
      if ("j" in d) {
        date.setFullYear(d.y, 0, d.j);
      } else if ("w" in d && ("W" in d || "U" in d)) {
        date.setFullYear(d.y, 0, 1);
        date.setFullYear(d.y, 0, "W" in d
            ? (d.w + 6) % 7 + d.W * 7 - (date.getDay() + 5) % 7
            :  d.w          + d.U * 7 - (date.getDay() + 6) % 7);
      } else {
        date.setFullYear(d.y, d.m, d.d);
      }

      // Set hours, minutes, seconds and milliseconds.
      date.setHours(d.H + (d.Z / 100 | 0), d.M + d.Z % 100, d.S, d.L);

      return localZ ? date._ : date;
    };

    format.toString = function() {
      return template;
    };

    return format;
  }

  function newUtcFormat(template) {
    var local = newFormat(template);

    function format(date) {
      try {
        Date = UtcDate;
        var utc = new Date;
        utc._ = date;
        return local(utc);
      } finally {
        Date = LocalDate;
      }
    }

    format.parse = function(string) {
      try {
        Date = UtcDate;
        var date = local.parse(string);
        return date && date._;
      } finally {
        Date = LocalDate;
      }
    };

    format.toString = local.toString;

    return format;
  }

  function parseTemplate(date, template, string, j) {
    var i = 0,
        n = template.length,
        m = string.length,
        c,
        parse;

    while (i < n) {
      if (j >= m) return -1;
      c = template.charCodeAt(i++);
      if (c === 37) {
        c = template.charAt(i++);
        parse = parses[c in pads ? template.charAt(i++) : c];
        if (!parse || ((j = parse(date, string, j)) < 0)) return -1;
      } else if (c != string.charCodeAt(j++)) {
        return -1;
      }
    }

    return j;
  }

  function parseWeekdayAbbrev(date, string, i) {
    dayAbbrevRe.lastIndex = 0;
    var n = dayAbbrevRe.exec(string.slice(i));
    return n ? (date.w = dayAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
  }

  function parseWeekday(date, string, i) {
    dayRe.lastIndex = 0;
    var n = dayRe.exec(string.slice(i));
    return n ? (date.w = dayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
  }

  function parseMonthAbbrev(date, string, i) {
    monthAbbrevRe.lastIndex = 0;
    var n = monthAbbrevRe.exec(string.slice(i));
    return n ? (date.m = monthAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
  }

  function parseMonth(date, string, i) {
    monthRe.lastIndex = 0;
    var n = monthRe.exec(string.slice(i));
    return n ? (date.m = monthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
  }

  function parseLocaleDateTime(date, string, i) {
    return parseTemplate(date, locale_dateTime, string, i);
  }

  function parseLocaleDate(date, string, i) {
    return parseTemplate(date, locale_date, string, i);
  }

  function parseLocaleTime(date, string, i) {
    return parseTemplate(date, locale_time, string, i);
  }

  function parseAmPm(date, string, i) {
    var n = periodLookup.get(string.slice(i, i += 2).toLowerCase());
    return n == null ? -1 : (date.p = n, i);
  }

  return {
    format: newFormat,
    utcFormat: newUtcFormat
  };
};

var pads = {"-": "", "_": " ", "0": "0"},
    numberRe = /^\s*\d+/, // note: ignores next directive
    percentRe = /^%/,
    requoteRe = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;

function pad(value, fill, width) {
  var sign = value < 0 ? "-" : "",
      string = (sign ? -value : value) + "",
      length = string.length;
  return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string);
}

function requote(s) {
  return s.replace(requoteRe, "\\$&");
}

function formatRe(names) {
  return new RegExp("^(?:" + names.map(requote).join("|") + ")", "i");
}

function formatLookup(names) {
  var map = new Map, i = -1, n = names.length;
  while (++i < n) map.set(names[i].toLowerCase(), i);
  return map;
}

function parseWeekdayNumber(date, string, i) {
  numberRe.lastIndex = 0;
  var n = numberRe.exec(string.slice(i, i + 1));
  return n ? (date.w = +n[0], i + n[0].length) : -1;
}

function parseWeekNumberSunday(date, string, i) {
  numberRe.lastIndex = 0;
  var n = numberRe.exec(string.slice(i));
  return n ? (date.U = +n[0], i + n[0].length) : -1;
}

function parseWeekNumberMonday(date, string, i) {
  numberRe.lastIndex = 0;
  var n = numberRe.exec(string.slice(i));
  return n ? (date.W = +n[0], i + n[0].length) : -1;
}

function parseFullYear(date, string, i) {
  numberRe.lastIndex = 0;
  var n = numberRe.exec(string.slice(i, i + 4));
  return n ? (date.y = +n[0], i + n[0].length) : -1;
}

function parseYear(date, string, i) {
  numberRe.lastIndex = 0;
  var n = numberRe.exec(string.slice(i, i + 2));
  return n ? (date.y = +n[0] + (+n[0] > 68 ? 1900 : 2000), i + n[0].length) : -1;
}

function parseZone(date, string, i) {
  return /^[+-]\d{4}$/.test(string = string.slice(i, i + 5))
      ? (date.Z = -string, i + 5) // sign differs from getTimezoneOffset!
      : -1;
}

function parseMonthNumber(date, string, i) {
  numberRe.lastIndex = 0;
  var n = numberRe.exec(string.slice(i, i + 2));
  return n ? (date.m = n[0] - 1, i + n[0].length) : -1;
}

function parseDay(date, string, i) {
  numberRe.lastIndex = 0;
  var n = numberRe.exec(string.slice(i, i + 2));
  return n ? (date.d = +n[0], i + n[0].length) : -1;
}

function parseDayOfYear(date, string, i) {
  numberRe.lastIndex = 0;
  var n = numberRe.exec(string.slice(i, i + 3));
  return n ? (date.j = +n[0], i + n[0].length) : -1;
}

// Note: we don't validate that the hour is in the range [0,23] or [1,12].
function parseHour24(date, string, i) {
  numberRe.lastIndex = 0;
  var n = numberRe.exec(string.slice(i, i + 2));
  return n ? (date.H = +n[0], i + n[0].length) : -1;
}

function parseMinutes(date, string, i) {
  numberRe.lastIndex = 0;
  var n = numberRe.exec(string.slice(i, i + 2));
  return n ? (date.M = +n[0], i + n[0].length) : -1;
}

function parseSeconds(date, string, i) {
  numberRe.lastIndex = 0;
  var n = numberRe.exec(string.slice(i, i + 2));
  return n ? (date.S = +n[0], i + n[0].length) : -1;
}

function parseMilliseconds(date, string, i) {
  numberRe.lastIndex = 0;
  var n = numberRe.exec(string.slice(i, i + 3));
  return n ? (date.L = +n[0], i + n[0].length) : -1;
}

function parseLiteralPercent(date, string, i) {
  percentRe.lastIndex = 0;
  var n = percentRe.exec(string.slice(i, i + 1));
  return n ? i + n[0].length : -1;
}

function formatZone(d) {
  var z = d.getTimezoneOffset();
  return (z > 0 ? "-" : (z *= -1, "+"))
      + pad(z / 60 | 0, "0", 2)
      + pad(z % 60, "0", 2);
}
<commit_msg>Readability.<commit_after>import {day, sunday, monday, year} from "d3-time";
import UtcDate from "./UtcDate";

var LocalDate = Date;

export default function(locale) {
  var locale_dateTime = locale.dateTime,
      locale_date = locale.date,
      locale_time = locale.time,
      locale_periods = locale.periods,
      locale_days = locale.days,
      locale_shortDays = locale.shortDays,
      locale_months = locale.months,
      locale_shortMonths = locale.shortMonths;

  var periodLookup = formatLookup(locale_periods),
      dayRe = formatRe(locale_days),
      dayLookup = formatLookup(locale_days),
      dayAbbrevRe = formatRe(locale_shortDays),
      dayAbbrevLookup = formatLookup(locale_shortDays),
      monthRe = formatRe(locale_months),
      monthLookup = formatLookup(locale_months),
      monthAbbrevRe = formatRe(locale_shortMonths),
      monthAbbrevLookup = formatLookup(locale_shortMonths);

  var formats = {
    "a": function(d) { return locale_shortDays[d.getDay()]; },
    "A": function(d) { return locale_days[d.getDay()]; },
    "b": function(d) { return locale_shortMonths[d.getMonth()]; },
    "B": function(d) { return locale_months[d.getMonth()]; },
    "c": newFormat(locale_dateTime),
    "d": function(d, p) { return pad(d.getDate(), p, 2); },
    "e": function(d, p) { return pad(d.getDate(), p, 2); },
    "H": function(d, p) { return pad(d.getHours(), p, 2); },
    "I": function(d, p) { return pad(d.getHours() % 12 || 12, p, 2); },
    "j": function(d, p) { return pad(1 + day.count(year(d), d), p, 3); },
    "L": function(d, p) { return pad(d.getMilliseconds(), p, 3); },
    "m": function(d, p) { return pad(d.getMonth() + 1, p, 2); },
    "M": function(d, p) { return pad(d.getMinutes(), p, 2); },
    "p": function(d) { return locale_periods[+(d.getHours() >= 12)]; },
    "S": function(d, p) { return pad(d.getSeconds(), p, 2); },
    "U": function(d, p) { return pad(sunday.count(year(d), d), p, 2); },
    "w": function(d) { return d.getDay(); },
    "W": function(d, p) { return pad(monday.count(year(d), d), p, 2); },
    "x": newFormat(locale_date),
    "X": newFormat(locale_time),
    "y": function(d, p) { return pad(d.getFullYear() % 100, p, 2); },
    "Y": function(d, p) { return pad(d.getFullYear() % 10000, p, 4); },
    "Z": formatZone,
    "%": function() { return "%"; }
  };

  var parses = {
    "a": parseWeekdayAbbrev,
    "A": parseWeekday,
    "b": parseMonthAbbrev,
    "B": parseMonth,
    "c": parseLocaleDateTime,
    "d": parseDay,
    "e": parseDay,
    "H": parseHour24,
    "I": parseHour24,
    "j": parseDayOfYear,
    "L": parseMilliseconds,
    "m": parseMonthNumber,
    "M": parseMinutes,
    "p": parseAmPm,
    "S": parseSeconds,
    "U": parseWeekNumberSunday,
    "w": parseWeekdayNumber,
    "W": parseWeekNumberMonday,
    "x": parseLocaleDate,
    "X": parseLocaleTime,
    "y": parseYear,
    "Y": parseFullYear,
    "Z": parseZone,
    "%": parseLiteralPercent
  };

  function newFormat(template) {
    template += "";

    function format(date) {
      var string = [],
          i = -1,
          j = 0,
          n = template.length,
          c,
          pad,
          format;

      while (++i < n) {
        if (template.charCodeAt(i) === 37) {
          string.push(template.slice(j, i));
          if ((pad = pads[c = template.charAt(++i)]) != null) c = template.charAt(++i);
          if (format = formats[c]) c = format(date, pad == null ? (c === "e" ? " " : "0") : pad);
          string.push(c);
          j = i + 1;
        }
      }

      string.push(template.slice(j, i));
      return string.join("");
    }

    format.parse = function(string) {
      var d = {y: 1900, m: 0, d: 1, H: 0, M: 0, S: 0, L: 0, Z: null},
          i = parseTemplate(d, template, string, 0);
      if (i != string.length) return null;

      // The am-pm flag is 0 for AM, and 1 for PM.
      if ("p" in d) d.H = d.H % 12 + d.p * 12;

      // If a time zone is specified, it is always relative to UTC;
      // we need to use UtcDate if we aren’t already.
      var localZ = d.Z != null && Date !== UtcDate,
          date = new (localZ ? UtcDate : Date);

      // Set year, month, date.
      if ("j" in d) {
        date.setFullYear(d.y, 0, d.j);
      } else if ("w" in d && ("W" in d || "U" in d)) {
        date.setFullYear(d.y, 0, 1);
        date.setFullYear(d.y, 0, "W" in d
            ? (d.w + 6) % 7 + d.W * 7 - (date.getDay() + 5) % 7
            :  d.w          + d.U * 7 - (date.getDay() + 6) % 7);
      } else {
        date.setFullYear(d.y, d.m, d.d);
      }

      // Set hours, minutes, seconds and milliseconds.
      date.setHours(d.H + (d.Z / 100 | 0), d.M + d.Z % 100, d.S, d.L);

      return localZ ? date._ : date;
    };

    format.toString = function() {
      return template;
    };

    return format;
  }

  function newUtcFormat(template) {
    var local = newFormat(template);

    function format(date) {
      try {
        Date = UtcDate;
        var utc = new Date;
        utc._ = date;
        return local(utc);
      } finally {
        Date = LocalDate;
      }
    }

    format.parse = function(string) {
      try {
        Date = UtcDate;
        var date = local.parse(string);
        return date && date._;
      } finally {
        Date = LocalDate;
      }
    };

    format.toString = local.toString;

    return format;
  }

  function parseTemplate(d, template, string, j) {
    var i = 0,
        n = template.length,
        m = string.length,
        c,
        parse;

    while (i < n) {
      if (j >= m) return -1;
      c = template.charCodeAt(i++);
      if (c === 37) {
        c = template.charAt(i++);
        parse = parses[c in pads ? template.charAt(i++) : c];
        if (!parse || ((j = parse(d, string, j)) < 0)) return -1;
      } else if (c != string.charCodeAt(j++)) {
        return -1;
      }
    }

    return j;
  }

  function parseWeekdayAbbrev(d, string, i) {
    dayAbbrevRe.lastIndex = 0;
    var n = dayAbbrevRe.exec(string.slice(i));
    return n ? (d.w = dayAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
  }

  function parseWeekday(d, string, i) {
    dayRe.lastIndex = 0;
    var n = dayRe.exec(string.slice(i));
    return n ? (d.w = dayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
  }

  function parseMonthAbbrev(d, string, i) {
    monthAbbrevRe.lastIndex = 0;
    var n = monthAbbrevRe.exec(string.slice(i));
    return n ? (d.m = monthAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
  }

  function parseMonth(d, string, i) {
    monthRe.lastIndex = 0;
    var n = monthRe.exec(string.slice(i));
    return n ? (d.m = monthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
  }

  function parseLocaleDateTime(d, string, i) {
    return parseTemplate(d, locale_dateTime, string, i);
  }

  function parseLocaleDate(d, string, i) {
    return parseTemplate(d, locale_date, string, i);
  }

  function parseLocaleTime(d, string, i) {
    return parseTemplate(d, locale_time, string, i);
  }

  function parseAmPm(d, string, i) {
    var n = periodLookup.get(string.slice(i, i += 2).toLowerCase());
    return n == null ? -1 : (d.p = n, i);
  }

  return {
    format: newFormat,
    utcFormat: newUtcFormat
  };
};

var pads = {"-": "", "_": " ", "0": "0"},
    numberRe = /^\s*\d+/, // note: ignores next directive
    percentRe = /^%/,
    requoteRe = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;

function pad(value, fill, width) {
  var sign = value < 0 ? "-" : "",
      string = (sign ? -value : value) + "",
      length = string.length;
  return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string);
}

function requote(s) {
  return s.replace(requoteRe, "\\$&");
}

function formatRe(names) {
  return new RegExp("^(?:" + names.map(requote).join("|") + ")", "i");
}

function formatLookup(names) {
  var map = new Map, i = -1, n = names.length;
  while (++i < n) map.set(names[i].toLowerCase(), i);
  return map;
}

function parseWeekdayNumber(d, string, i) {
  numberRe.lastIndex = 0;
  var n = numberRe.exec(string.slice(i, i + 1));
  return n ? (d.w = +n[0], i + n[0].length) : -1;
}

function parseWeekNumberSunday(d, string, i) {
  numberRe.lastIndex = 0;
  var n = numberRe.exec(string.slice(i));
  return n ? (d.U = +n[0], i + n[0].length) : -1;
}

function parseWeekNumberMonday(d, string, i) {
  numberRe.lastIndex = 0;
  var n = numberRe.exec(string.slice(i));
  return n ? (d.W = +n[0], i + n[0].length) : -1;
}

function parseFullYear(d, string, i) {
  numberRe.lastIndex = 0;
  var n = numberRe.exec(string.slice(i, i + 4));
  return n ? (d.y = +n[0], i + n[0].length) : -1;
}

function parseYear(d, string, i) {
  numberRe.lastIndex = 0;
  var n = numberRe.exec(string.slice(i, i + 2));
  return n ? (d.y = +n[0] + (+n[0] > 68 ? 1900 : 2000), i + n[0].length) : -1;
}

function parseZone(d, string, i) {
  return /^[+-]\d{4}$/.test(string = string.slice(i, i + 5))
      ? (d.Z = -string, i + 5) // sign differs from getTimezoneOffset!
      : -1;
}

function parseMonthNumber(d, string, i) {
  numberRe.lastIndex = 0;
  var n = numberRe.exec(string.slice(i, i + 2));
  return n ? (d.m = n[0] - 1, i + n[0].length) : -1;
}

function parseDay(d, string, i) {
  numberRe.lastIndex = 0;
  var n = numberRe.exec(string.slice(i, i + 2));
  return n ? (d.d = +n[0], i + n[0].length) : -1;
}

function parseDayOfYear(d, string, i) {
  numberRe.lastIndex = 0;
  var n = numberRe.exec(string.slice(i, i + 3));
  return n ? (d.j = +n[0], i + n[0].length) : -1;
}

// Note: we don't validate that the hour is in the range [0,23] or [1,12].
function parseHour24(d, string, i) {
  numberRe.lastIndex = 0;
  var n = numberRe.exec(string.slice(i, i + 2));
  return n ? (d.H = +n[0], i + n[0].length) : -1;
}

function parseMinutes(d, string, i) {
  numberRe.lastIndex = 0;
  var n = numberRe.exec(string.slice(i, i + 2));
  return n ? (d.M = +n[0], i + n[0].length) : -1;
}

function parseSeconds(d, string, i) {
  numberRe.lastIndex = 0;
  var n = numberRe.exec(string.slice(i, i + 2));
  return n ? (d.S = +n[0], i + n[0].length) : -1;
}

function parseMilliseconds(d, string, i) {
  numberRe.lastIndex = 0;
  var n = numberRe.exec(string.slice(i, i + 3));
  return n ? (d.L = +n[0], i + n[0].length) : -1;
}

function parseLiteralPercent(d, string, i) {
  percentRe.lastIndex = 0;
  var n = percentRe.exec(string.slice(i, i + 1));
  return n ? i + n[0].length : -1;
}

function formatZone(d) {
  var z = d.getTimezoneOffset();
  return (z > 0 ? "-" : (z *= -1, "+"))
      + pad(z / 60 | 0, "0", 2)
      + pad(z % 60, "0", 2);
}
<|endoftext|>


<commit_before>/* http://github.com/avih/nopromise MIT */
(function(G){

var globalQ,
    async,
    staticNativePromise,
    FULFILLED = 1,
    REJECTED  = 2,
    FUNCTION  = "function";

// Try to find the fastest asynchronous scheduler for this environment:
// setImmediate -> native Promise scheduler -> setTimeout
async = this.setImmediate; // nodejs, IE 10+
try {
    staticNativePromise = Promise.resolve();
    async = async || function(f) { staticNativePromise.then(f) }; // Firefox/Chrome
} catch (e) {}
async = async || setTimeout; // IE < 10, others

// The invariant between internalAsync and dequeue is that if globalQ is thuthy,
// then a dequeue is already scheduled and will execute globalQ asynchronously,
// otherwise, globalQ needs to be created and dequeue needs to be scheduled.
// The elements (functions) of the globalQ array need to be invoked in order.
function dequeue() {
    var f, tmp = globalQ.reverse();
    globalQ = 0;
    while (f = tmp.pop())
        f();
}

// This is used throughout the implementation as the asynchronous scheduler.
// While satisfying the contract to invoke f asynchronously, it combines
// individual f's into a single group which is later iterated synchronously.
function internalAsync(f) {
    if (globalQ) {
        globalQ.push(f);
    } else {
        globalQ = [f];
        async(dequeue);
    }
}

// Fulfil/reject a promise if it's pending, else no-op.
function unpend(p, state, value) {
    if (!p._state) {
        p._state = state;
        p._output = value;

        var f, arr = p._resolvers;
        if (arr) {
            // The case where `then` is called many times for the same promise
            // is rare, so for simplicity, we're not optimizing for it, or else
            // if globalQ is empty, we can just do: globalQ = p._resolvers;
            arr.reverse();
            while (f = arr.pop())
                internalAsync(f);
        }
    }
}

// Besides 'then' (+ resolve/reject in legacy interface), the object may have:
// ._state    : 1 if fulfilled, 2 if rejected (doesn't exist otherwise).
// ._output   : value if fulfilled, reason if rejected (doesn't exist otherwise).
// ._resolvers: array of functions (closures) for each .then call while pending (if there were any).

NoPromise.prototype = {
    // Each call to `then` returns a new NoPromise object and creates a closure
    // which is used to resolve it after then's this is fulfilled/rejected.
    then: function(onFulfilled, onRejected) {
        var _self    = this,
            promise2 = new NoPromise;

        _self._state ? internalAsync(promise2Resolver)
                     : _self._resolvers ? _self._resolvers.push(promise2Resolver)
                                        : _self._resolvers = [promise2Resolver];
        return promise2;

        // Invoked asynchronously to `then` and after _self is fulfilled/rejected.
        // _self._state here is FULFILLED/REJECTED
        function promise2Resolver() {
            var handler = _self._state == FULFILLED ? onFulfilled : onRejected;

            if (typeof handler != FUNCTION) {
                unpend(promise2, _self._state, _self._output);
            } else {
                promise2Resolution(0, 1);
            }

            function promise2Resolution(x, isFirstTime) {
                var then,
                    done = 0;

                try {
                    if (isFirstTime)
                        x = handler(_self._output);

                    if (x == promise2) {
                        unpend(promise2, REJECTED, TypeError());

                    // Check for generic thenable... which includes NoPromise.
                    } else if ((x && typeof x == "object" || typeof x == FUNCTION)
                               && typeof (then = x.then) == FUNCTION) {
                        then.call(x, function(y) { done++ || promise2Resolution(y) },
                                     function(r) { done++ || unpend(promise2, REJECTED, r)});

                    } else {
                        unpend(promise2, FULFILLED, x);
                    }

                } catch (e) {
                    done++ || unpend(promise2, REJECTED, e);
                }
            }
        }
    }
}

// Interfaces
// ----------

// Modern - with CTOR:
//   return new NoPromise(function(resolve, reject) { setTimeout(function() { resolve(42); }, 100); });
function NoPromise(executor) {
    var self = this;
    if (executor) {  // not used by the legacy interface
        executor(function(v) { unpend(self, FULFILLED, v); }, // bind is slower
                 function(r) { unpend(self, REJECTED,  r); });
    }
}

// Legacy - with static CTOR (can be commented out if not used):
//   var d = NoPromise.defer(); setTimeout(function() { d.resolve(42); }, 100); return d.promise;

NoPromise.defer = NoPromise.deferred = function() {
    var d = new NoPromise;
    return d.promise = d;
};

NoPromise.prototype.resolve = function(value) {
    unpend(this, FULFILLED, value);
}

NoPromise.prototype.reject = function(reason) {
    unpend(this, REJECTED, reason);
}

// End of legacy interface

// Static interface - resolved/rejected promise with specified value/reason
NoPromise.resolve = function(v) {
    return new NoPromise(function(res, rej) { res(v); });
};

NoPromise.reject  = function(r) {
    return new NoPromise(function(res, rej) { rej(r); });
};

// export/set-global
try {
    module.exports = NoPromise;
} catch (e) {
    G.NoPromise = NoPromise;
}

})( // used to setup a global NoPromise - not when using require("nopromise")
    typeof global != "undefined" ? global :
    typeof window != "undefined" ? window : this)
<commit_msg>add static .all/.race and dynamic .catch/.finally<commit_after>/* http://github.com/avih/nopromise MIT */
(function(G){

// Note: NoPromise[.prototype].resolve() are the only places where "resolve"
// actually means "fulfill". Everywhere else, and specifically at the comments,
// "resolved" means "not pending" - which can be either fulfilled or rejected.
// The variable names also reflect this "resolved" == "not-pending" notion.

var globalQ,
    async,
    staticNativePromise,
    FULFILLED = 1,
    REJECTED  = 2,
    FUNCTION  = "function";

// Try to find the fastest asynchronous scheduler for this environment:
// setImmediate -> native Promise scheduler -> setTimeout
async = this.setImmediate; // nodejs, IE 10+
try {
    staticNativePromise = Promise.resolve();
    async = async || function(f) { staticNativePromise.then(f) }; // Firefox/Chrome
} catch (e) {}
async = async || setTimeout; // IE < 10, others

// The invariant between internalAsync and dequeue is that if globalQ is thuthy,
// then a dequeue is already scheduled and will execute globalQ asynchronously,
// otherwise, globalQ needs to be created and dequeue needs to be scheduled.
// The elements (functions) of the globalQ array need to be invoked in order.
function dequeue() {
    var f, tmp = globalQ.reverse();
    globalQ = 0;
    while (f = tmp.pop())
        f();
}

// This is used throughout the implementation as the asynchronous scheduler.
// While satisfying the contract to invoke f asynchronously, it batches
// individual f's into a single group which is later iterated synchronously.
function internalAsync(f) {
    if (globalQ) {
        globalQ.push(f);
    } else {
        globalQ = [f];
        async(dequeue);
    }
}

// Fulfil/reject a promise if it's pending, else no-op.
function unpend(p, state, value) {
    if (!p._state) {
        p._state = state;
        p._output = value;

        var f, arr = p._resolvers;
        if (arr) {
            // The case where `then` is called many times for the same promise
            // is rare, so for simplicity, we're not optimizing for it, or else
            // if globalQ is empty, we can just do: globalQ = p._resolvers;
            arr.reverse();
            while (f = arr.pop())
                internalAsync(f);
        }
    }
}

// Other than the prototype methods, the object may also have:
// ._state    : 1 if fulfilled, 2 if rejected (doesn't exist otherwise).
// ._output   : value if fulfilled, reason if rejected (doesn't exist otherwise).
// ._resolvers: array of functions (closures) for each .then call while pending (if there were any).

NoPromise.prototype = {
    // Each call to `then` returns a new NoPromise object and creates a closure
    // which is used to resolve it after then's this is fulfilled/rejected.
    then: function(onFulfilled, onRejected) {
        var _self    = this,
            promise2 = new NoPromise;

        _self._state ? internalAsync(promise2Resolver)
                     : _self._resolvers ? _self._resolvers.push(promise2Resolver)
                                        : _self._resolvers = [promise2Resolver];
        return promise2;

        // Invoked asynchronously to `then` and after _self is fulfilled/rejected.
        // _self._state here is FULFILLED/REJECTED
        function promise2Resolver() {
            var handler = _self._state == FULFILLED ? onFulfilled : onRejected;

            if (typeof handler != FUNCTION) {
                unpend(promise2, _self._state, _self._output);
            } else {
                promise2Resolution(0, 1);
            }

            function promise2Resolution(x, isFirstTime) {
                var then,
                    done = 0;

                try {
                    if (isFirstTime)
                        x = handler(_self._output);

                    if (x == promise2) {
                        unpend(promise2, REJECTED, TypeError());

                    // Check for generic thenable... which includes NoPromise.
                    } else if ((x && typeof x == "object" || typeof x == FUNCTION)
                               && typeof (then = x.then) == FUNCTION) {
                        then.call(x, function(y) { done++ || promise2Resolution(y) },
                                     function(r) { done++ || unpend(promise2, REJECTED, r)});

                    } else {
                        unpend(promise2, FULFILLED, x);
                    }

                } catch (e) {
                    done++ || unpend(promise2, REJECTED, e);
                }
            }
        }
    },

    catch: function(onRejected) {
        return this.then(undefined, onRejected);
    },

    // P.finaly(fn) returns a promise X, and calls fn after P resolves to T.
    // if fn throws E: X is rejected with E.
    // Else if fn returns a promise F: X is resolved once F is resolved:
    //   If F is rejected with FJ: X is rejected with FJ.
    // Else: X mirrors T [ignoring fn's retval or F's fulfillment value]
    finally: function(onFinally) {
        function fin_noargs() { return onFinally() }
        var fn;
        return this
            .then(function(v) { fn = function() { return v } },
                  function(r) { fn = function() { throw r } })
            .then(fin_noargs, fin_noargs)
            .then(function finallyOK() { return fn() });
    },
}

// CTOR:
//   return new NoPromise(function(fulfill, reject) { setTimeout(function() { fulfill(42); }, 100); });
function NoPromise(executor) {
    var self = this;
    if (executor) {  // not used inside 'then' nor by the legacy interface
        executor(function(v) { unpend(self, FULFILLED, v); }, // bind is slower
                 function(r) { unpend(self, REJECTED,  r); });
    }
}

// Static methods
// --------------

// Returns an already fulfilled/rejected promise with specified value/reason
NoPromise.resolve = function(v) {
    return new NoPromise(function(ful, rej) { ful(v); });
};

NoPromise.reject  = function(r) {
    return new NoPromise(function(ful, rej) { rej(r); });
};

// Duplicates the logic used in NoPromise to detect a generic thenable
function is_promise(x) {
    return ((x && typeof x == "object") || typeof x == FUNCTION)
           && typeof x.then == FUNCTION;
}

// For .all and .race: we support iterators as array or array-like, and slack
// when it comes to throwing on invalid iterators (we only try [].slice.call).

// Static NoPromise.all(iter) returns a promise X.
// If iter is empty: X fulfills synchronously to an empty array.
// Else for the first promise in iter which rejects with J: X rejects a-sync with J.
// Else (all fulfill): X fulfills a-sync to an array of iter's fulfilled-values
// (non-promise values are considered already fulfilled with that value).
NoPromise.all = function(iter) {
    Array.isArray(iter) || (iter = [].slice.call(iter));
    var len = iter.length;
    if (!len)
        return NoPromise.resolve([]);  // empty fulfills synchronously

    return new NoPromise(function(allful, allrej) {
        var rv = [], pending = 0;
        function fulOne(i, val) { rv[i] = val; --pending || allful(rv); }

        iter.forEach(function(v, i) {
            if (is_promise(v)) {
                pending++;
                v.then(fulOne.bind(null, i), allrej);
            } else {
                rv[i] = v;
            }
        });

        // Non empty but without promises - fulfills a-sync
        if (!pending)
            NoPromise.resolve(rv).then(allful);
    });
}

// Static NoPromise.race(iter) returns a promise X:
// If iter is empty: X never resolves.
// Else: X resolves always a-sync to mirror the first promise in iter which resolves.
// (non-promise values are considered already fulfilled with that value).
NoPromise.race = function(iter) {
    return new NoPromise(function(allful, allrej) {
        Array.isArray(iter) || (iter = [].slice.call(iter));
        iter.some(function(v, i) {
            if (is_promise(v)) {
                v.then(allful, allrej);
            } else {
                NoPromise.resolve(v).then(allful);
                return true;  // continuing would end up no-op
            }
        });
    });
}

// Legacy interface - not used by any NoPromise code, provided as legacy:
//   var d = NoPromise.defer(); setTimeout(function() { d.resolve(42); }, 100); return d.promise;
// d.promise is indistinguishable from a promise created as "new NoPromise(executor)"
NoPromise.defer = NoPromise.deferred = function() {
    var d = new NoPromise;
    return d.promise = d;
};

NoPromise.prototype.resolve = function(value) {
    unpend(this, FULFILLED, value);
}

NoPromise.prototype.reject = function(reason) {
    unpend(this, REJECTED, reason);
}
// End of legacy interface

// export/set-global
try {
    module.exports = NoPromise;
} catch (e) {
    G.NoPromise = NoPromise;
}

})( // used to setup a global NoPromise - not when using require("nopromise")
    typeof global != "undefined" ? global :
    typeof window != "undefined" ? window : this)
<|endoftext|>


<commit_before>function Elevator() {
  // body...
  this.floors = Math.floor(Math.random() * 100) + 1 ;
  this.currentFloor = Math.floor(this.floors / 2);
  this. startingFloor = Math.floor(this.floors / 2);
  this.child = new Plucky;
  this.player = new Player;
  this.rollcount = 0;
  this.diff = Math.abs(this.player.desiredFloor - this.startingFloor);
  this.yourtrys = this.diff * 2
}

Elevator.prototype.go_up = function () {
  // body...
  this.currentFloor += 1;
};

Elevator.prototype.go_down = function () {
  // body...
  this.currentFloor -= 1;
};

Elevator.prototype.myInfo = function () {
  // body...
  getElementById('results').innerHTML =  console.log('You were trying to get to floor', this.player.desiredFloor);
};

Elevator.prototype.roll = function () {
  // body...
  if(this.currentFloor != this.player.desiredFloor && this.rollcount < this.yourtrys){
    this.child.reroll();

    if (this.player.desiredFloor < this.currentFloor) {

      if (this.child.chanceOfPushingButton > 75) {
        this.go_up();
        this.rollcount += 1;
        this.roll();
      } else {
        this.go_down();
        this.roll();

      }
    } else {
      if(this.child.chanceOfPushingButton > 75) {
        this.go_down();
        this.rollcount += 1;
        this.roll();
      } else {
        this.go_up();
        this.roll();
      }
    }

  } else if(this.currentFloor == this.player.desiredFloor){
    console.log('The player has won!');
    console.log('you started on floor', this.startingFloor);
    console.log('You made it through', this.rollcount , 'floors');
  } else if(this.rollcount >= this.diff){
    var mytest = Math.abs(this.diff - this.rollcount);
    console.log('Sorry. You died of starvation.');
    console.log('you started on floor', this.startingFloor);
    console.log('Your current floor was:', this.currentFloor);
    console.log('You made it through', this.rollcount , 'floors');
  }

};

function Player(number){
  this.desiredFloor = Math.floor((Math.random() * 100) + 1);
};

function Plucky(){
  this.chanceOfPushingButton = Math.floor((Math.random() * 100) + 20);
};

Plucky.prototype.reroll = function () {
  // body...
  this.chanceOfPushingButton = Math.floor((Math.random() * 100) + 20);
};

function trypage(){
game = new Elevator();
game.roll();
game.myInfo();
};
<commit_msg>Create callable function<commit_after>function Elevator() {
  // body...
  this.floors = Math.floor(Math.random() * 100) + 1 ;
  this.currentFloor = Math.floor(this.floors / 2);
  this. startingFloor = Math.floor(this.floors / 2);
  this.child = new Plucky;
  this.player = new Player;
  this.rollcount = 0;
  this.diff = Math.abs(this.player.desiredFloor - this.startingFloor);
  this.yourtrys = this.diff * 2
}

Elevator.prototype.go_up = function () {
  // body...
  this.currentFloor += 1;
};

Elevator.prototype.go_down = function () {
  // body...
  this.currentFloor -= 1;
};

Elevator.prototype.myInfo = function () {
  // body...
  document.getElementById('results').innerHTML =  console.log('You were trying to get to floor', this.player.desiredFloor);
};

Elevator.prototype.roll = function () {
  // body...
  if(this.currentFloor != this.player.desiredFloor && this.rollcount < this.yourtrys){
    this.child.reroll();

    if (this.player.desiredFloor < this.currentFloor) {

      if (this.child.chanceOfPushingButton > 75) {
        this.go_up();
        this.rollcount += 1;
        this.roll();
      } else {
        this.go_down();
        this.roll();

      }
    } else {
      if(this.child.chanceOfPushingButton > 75) {
        this.go_down();
        this.rollcount += 1;
        this.roll();
      } else {
        this.go_up();
        this.roll();
      }
    }

  } else if(this.currentFloor == this.player.desiredFloor){
    console.log('The player has won!');
    console.log('you started on floor', this.startingFloor);
    console.log('You made it through', this.rollcount , 'floors');
  } else if(this.rollcount >= this.diff){
    var mytest = Math.abs(this.diff - this.rollcount);
    console.log('Sorry. You died of starvation.');
    console.log('you started on floor', this.startingFloor);
    console.log('Your current floor was:', this.currentFloor);
    console.log('You made it through', this.rollcount , 'floors');
  }

};

function Player(number){
  this.desiredFloor = Math.floor((Math.random() * 100) + 1);
};

function Plucky(){
  this.chanceOfPushingButton = Math.floor((Math.random() * 100) + 20);
};

Plucky.prototype.reroll = function () {
  // body...
  this.chanceOfPushingButton = Math.floor((Math.random() * 100) + 20);
};

function trypage(){
game = new Elevator();
game.roll();
game.myInfo();
};
<|endoftext|>


<commit_before>// @flow
import path from 'path'

const platform = process.platform
export const isMobile = false
export const isAndroid = false
export const isIOS = false
export const isLargeScreen = true
export const isIPhoneX = false
export const isElectron = true
export const isDarwin = platform === 'darwin'
export const isWindows = platform === 'win32'
export const isLinux = platform === 'linux'
export const isAndroidNewerThanN = false
export const shortcutSymbol = isDarwin ? '⌘' : '^'

// For storyshots, we only want to test macOS
export const fileUIName = isDarwin || __STORYBOOK__ ? 'Finder' : isWindows ? 'Explorer' : 'File Explorer'

const runMode = process.env['KEYBASE_RUN_MODE'] || 'prod'
const homeEnv = process.env['HOME'] || ''

if (__DEV__ && !__STORYBOOK__) {
  console.log(`Run mode: ${runMode}`)
}

const socketName = 'keybased.sock'

const getLinuxPaths = () => {
  // If XDG_RUNTIME_DIR is defined use that, else use $HOME/.config.
  const homeConfigDir = path.join(homeEnv, '.config')
  const runtimeDir = process.env['XDG_RUNTIME_DIR'] || ''
  const cacheDir = runtimeDir || homeConfigDir
  const appName = `keybase${runMode === 'prod' ? '' : `.${runMode}`}`

  if (!runtimeDir && !homeEnv) {
    console.warn(
      "You don't have $HOME or $XDG_RUNTIME_DIR defined, so we can't find the Keybase service path."
    )
  }

  const logDir = `${process.env['XDG_CACHE_HOME'] || `${homeEnv}/.cache`}/${appName}/`

  return {
    cacheRoot: logDir,
    dataRoot: `${process.env['XDG_DATA_HOME'] || `${homeEnv}/.local/share`}/${appName}/`,
    jsonDebugFileName: `${logDir}keybase.app.debug`,
    logDir,
    logFileName: `${logDir}Keybase.app.log`,
    serverConfigFileName: `${logDir}keybase.app.serverConfig`,
    socketPath: path.join(cacheDir, appName, socketName),
  }
}

const getWindowsPaths = () => {
  const appName = `Keybase${runMode === 'prod' ? '' : runMode[0].toUpperCase() + runMode.slice(1)}`
  let appdata = process.env['LOCALAPPDATA'] || ''
  // Remove leading drive letter e.g. C:
  if (/^[a-zA-Z]:/.test(appdata)) {
    appdata = appdata.slice(2)
  }
  let dir = `\\\\.\\pipe\\kbservice${appdata}\\${appName}`
  const logDir = `${process.env['LOCALAPPDATA'] || ''}\\${appName}\\`
  return {
    cacheRoot: `${process.env['APPDATA'] || ''}\\${appName}\\`,
    dataRoot: `${process.env['LOCALAPPDATA'] || ''}\\${appName}\\`,
    jsonDebugFileName: `${logDir}keybase.app.debug`,
    logDir,
    logFileName: `${logDir}keybase.app.log`,
    serverConfigFileName: `${logDir}keybase.app.serverConfig`,
    socketPath: path.join(dir, socketName),
  }
}

const getDarwinPaths = () => {
  const appName = `Keybase${runMode === 'prod' ? '' : runMode[0].toUpperCase() + runMode.slice(1)}`
  const libraryDir = `${homeEnv}/Library/`
  const logDir = `${libraryDir}Logs/`

  return {
    cacheRoot: `${libraryDir}Caches/${appName}/`,
    dataRoot: `${libraryDir}Application Support/${appName}/`,
    jsonDebugFileName: `${logDir}${appName}.app.debug`,
    logDir,
    logFileName: `${logDir}${appName}.app.log`,
    serverConfigFileName: `${logDir}${appName}.app.serverConfig`,
    socketPath: path.join(`${libraryDir}Group Containers/keybase/Library/Caches/${appName}/`, socketName),
  }
}

const paths =
  (isLinux && getLinuxPaths()) || (isWindows && getWindowsPaths()) || (isDarwin && getDarwinPaths())
if (!paths) {
  throw new Error('Unknown OS')
}

export const {dataRoot, cacheRoot, socketPath, jsonDebugFileName, serverConfigFileName, logFileName} = paths

// Empty string means let the service figure out the right directory.
export const pprofDir = ''
export const version = 'TODO'
export {runMode}
<commit_msg>Update shortcut text. (#15954)<commit_after>// @flow
import path from 'path'

const platform = process.platform
export const isMobile = false
export const isAndroid = false
export const isIOS = false
export const isLargeScreen = true
export const isIPhoneX = false
export const isElectron = true
export const isDarwin = platform === 'darwin'
export const isWindows = platform === 'win32'
export const isLinux = platform === 'linux'
export const isAndroidNewerThanN = false
export const shortcutSymbol = isDarwin ? '⌘' : 'Ctrl-'

// For storyshots, we only want to test macOS
export const fileUIName = isDarwin || __STORYBOOK__ ? 'Finder' : isWindows ? 'Explorer' : 'File Explorer'

const runMode = process.env['KEYBASE_RUN_MODE'] || 'prod'
const homeEnv = process.env['HOME'] || ''

if (__DEV__ && !__STORYBOOK__) {
  console.log(`Run mode: ${runMode}`)
}

const socketName = 'keybased.sock'

const getLinuxPaths = () => {
  // If XDG_RUNTIME_DIR is defined use that, else use $HOME/.config.
  const homeConfigDir = path.join(homeEnv, '.config')
  const runtimeDir = process.env['XDG_RUNTIME_DIR'] || ''
  const cacheDir = runtimeDir || homeConfigDir
  const appName = `keybase${runMode === 'prod' ? '' : `.${runMode}`}`

  if (!runtimeDir && !homeEnv) {
    console.warn(
      "You don't have $HOME or $XDG_RUNTIME_DIR defined, so we can't find the Keybase service path."
    )
  }

  const logDir = `${process.env['XDG_CACHE_HOME'] || `${homeEnv}/.cache`}/${appName}/`

  return {
    cacheRoot: logDir,
    dataRoot: `${process.env['XDG_DATA_HOME'] || `${homeEnv}/.local/share`}/${appName}/`,
    jsonDebugFileName: `${logDir}keybase.app.debug`,
    logDir,
    logFileName: `${logDir}Keybase.app.log`,
    serverConfigFileName: `${logDir}keybase.app.serverConfig`,
    socketPath: path.join(cacheDir, appName, socketName),
  }
}

const getWindowsPaths = () => {
  const appName = `Keybase${runMode === 'prod' ? '' : runMode[0].toUpperCase() + runMode.slice(1)}`
  let appdata = process.env['LOCALAPPDATA'] || ''
  // Remove leading drive letter e.g. C:
  if (/^[a-zA-Z]:/.test(appdata)) {
    appdata = appdata.slice(2)
  }
  let dir = `\\\\.\\pipe\\kbservice${appdata}\\${appName}`
  const logDir = `${process.env['LOCALAPPDATA'] || ''}\\${appName}\\`
  return {
    cacheRoot: `${process.env['APPDATA'] || ''}\\${appName}\\`,
    dataRoot: `${process.env['LOCALAPPDATA'] || ''}\\${appName}\\`,
    jsonDebugFileName: `${logDir}keybase.app.debug`,
    logDir,
    logFileName: `${logDir}keybase.app.log`,
    serverConfigFileName: `${logDir}keybase.app.serverConfig`,
    socketPath: path.join(dir, socketName),
  }
}

const getDarwinPaths = () => {
  const appName = `Keybase${runMode === 'prod' ? '' : runMode[0].toUpperCase() + runMode.slice(1)}`
  const libraryDir = `${homeEnv}/Library/`
  const logDir = `${libraryDir}Logs/`

  return {
    cacheRoot: `${libraryDir}Caches/${appName}/`,
    dataRoot: `${libraryDir}Application Support/${appName}/`,
    jsonDebugFileName: `${logDir}${appName}.app.debug`,
    logDir,
    logFileName: `${logDir}${appName}.app.log`,
    serverConfigFileName: `${logDir}${appName}.app.serverConfig`,
    socketPath: path.join(`${libraryDir}Group Containers/keybase/Library/Caches/${appName}/`, socketName),
  }
}

const paths =
  (isLinux && getLinuxPaths()) || (isWindows && getWindowsPaths()) || (isDarwin && getDarwinPaths())
if (!paths) {
  throw new Error('Unknown OS')
}

export const {dataRoot, cacheRoot, socketPath, jsonDebugFileName, serverConfigFileName, logFileName} = paths

// Empty string means let the service figure out the right directory.
export const pprofDir = ''
export const version = 'TODO'
export {runMode}
<|endoftext|>


<commit_before>describe('ionicInfiniteScroll directive', function() {
  beforeEach(module('ionic'));

  var scrollTopValue  = 50;
  var scrollTopMaxValue = 60;
  var scrollLeftValue = 101;
  var scrollLeftMaxValue = 121;
  var ctrl;
  function setupJS(attrs, scopeProps, options) {
    var element;
    inject(function($rootScope, $compile) {
      var scope = $rootScope.$new();
      angular.extend(scope, scopeProps || {});
      element = angular.element('<ion-infinite-scroll ' + (attrs || '') + '></ion-infinite-scroll>');
      ionic.animationFrameThrottle = function(cb) { return function() { cb(); }; };
      element.data('$$ionicScrollController', {
        scrollView: {
          options: angular.extend({
            scrollingX: true,
            scrollingY: true
          }, options || {}),
          getValues: jasmine.createSpy('getValues').andCallFake(function() {
            return {
              left: scrollLeftValue,
              top: scrollTopValue
            };
          }),
          getScrollMax: jasmine.createSpy('getScrollMax').andCallFake(function() {
            return {
              left: scrollLeftMaxValue,
              top: scrollTopMaxValue
            };
          }),
          resize: jasmine.createSpy('resize')
        },
        resize: jasmine.createSpy('resize'),
        $element: angular.element('<div>')
      });
      $compile(element)(scope);
      ctrl = element.controller('ionInfiniteScroll');
      scope.$apply();
    });
    return element;
  }

  function setupNative(attrs, scopeProps, options) {
    var element, parent;
    inject(function($rootScope, $compile, $document) {
      var scope = $rootScope.$new();
      angular.extend(scope, scopeProps || {});
      parent = angular.element('<ion-content class="overflow-scroll"><ion-infinite-scroll ' + (attrs || '') +
                               '></ion-infinite-scroll></ion-content></ion-content>');
      if (options && !!options.scrollingX) parent[0].style['overflow-x'] ='scroll';
      if (options && !!options.scrollingY) parent[0].style['overflow-y'] ='scroll';
      element = parent.find('ion-infinite-scroll');
      ionic.animationFrameThrottle = function(cb) { return function() { cb(); }; };
      $compile(element)(scope);
      ctrl = element.controller('ionInfiniteScroll');
      // create a fake scrollEl since they can't be faked if we're passing in scroll data
      if (options) {
        ctrl.scrollEl = {style:{
          'overflow-x':'hidden',
          'overflow-y':'hidden'
        }};
        if (!!options.scrollingX) ctrl.scrollEl.style['overflow-x'] ='scroll';
        if (!!options.scrollingY) ctrl.scrollEl.style['overflow-y'] ='scroll';
        ctrl.scrollEl.clientWidth = ctrl.scrollEl.scrollLeft = scrollLeftValue;
        ctrl.scrollEl.clientHeight = ctrl.scrollEl.scrollTop = scrollTopValue;
        ctrl.scrollEl.scrollWidth = scrollLeftMaxValue;
        ctrl.scrollEl.scrollHeight = scrollTopMaxValue;
      }

      scope.$apply();
    });

    return element;
  }

  it('should error if no ionicScroll or native scroll parent', function() {
    expect(function() {
      inject(function($compile, $rootScope) {
        $compile('<ion-infinite-scroll></ion-infinite-scroll>')($rootScope.$new());
      });
    }).toThrow();
  });

  it('should not have class or be loading by default', function() {
    var el = setupJS();
    expect(el.hasClass('active')).toBe(false);
    expect(ctrl.isLoading).toBe(false);

    el = setupNative();
    expect(el.hasClass('active')).toBe(false);
    expect(ctrl.isLoading).toBe(false);
  });

  it('should unbind scroll event on destroy', function() {
    var el = setupJS();
    spyOn(el.controller('$ionicScroll').$element, 'off');
    el.scope().$destroy();
    expect(el.controller('$ionicScroll').$element.off).toHaveBeenCalledWith('scroll', jasmine.any(Function));

    el = setupNative();
    spyOn(ctrl.scrollEl, 'removeEventListener');
    el.scope().$destroy();
    expect(ctrl.scrollEl.removeEventListener).toHaveBeenCalled();
  });

  describe('icon', function() {
    it('should have default icon ion-loading-d', function() {
      var el = setupJS();
      var icon = angular.element(el[0].querySelector('.icon'));
      expect(icon.hasClass('ion-loading-d')).toBe(true);
    });

    it('should allow icon attr blank', function() {
      var el = setupJS('icon=""');
      var icon = angular.element(el[0].querySelector('.icon'));
      expect(icon.hasClass('ion-loading-d')).toBe(false);
    });

    it('should allow interpolated icon attr', function() {
      var el = setupJS('icon="{{someIcon}}"');
      var icon = angular.element(el[0].querySelector('.icon'));
      expect(icon.hasClass('ion-loading-d')).toBe(false);
      el.scope().$apply('someIcon = "super-icon"');
      expect(icon.hasClass('super-icon')).toBe(true);
    });
  });

  describe('getMaxScroll', function() {
    [{ scrollingX: true,  scrollingY: true },
     { scrollingX: false, scrollingY: true },
     { scrollingX: true,  scrollingY: false }
    ].forEach(function(opts) {

      describe('with scrollingX=' + opts.scrollingX + ', scrollingY=' + opts.scrollingY, function() {
        it('should default to 2.5%', function() {
          setupJS('', {}, opts);
          expect(ctrl.getJSMaxScroll()).toEqual({
            left: opts.scrollingX ? scrollLeftMaxValue * 0.975 : -1,
            top: opts.scrollingY ? scrollTopMaxValue * 0.975 : -1
          });

          setupNative('', {}, opts);
          expect(ctrl.getNativeMaxScroll()).toEqual({
            left: opts.scrollingX ? scrollLeftMaxValue * 0.975 : -1,
            top: opts.scrollingY ? scrollTopMaxValue * 0.975 : -1
          });
        });

        it('should use attr.distance as number', function() {
          setupJS('distance=3', {}, opts);
          expect(ctrl.getJSMaxScroll()).toEqual({
            left: opts.scrollingX ? scrollLeftMaxValue - 3 : -1,
            top: opts.scrollingY ? scrollTopMaxValue - 3 : -1
          });

          setupNative('distance=3', {}, opts);
          expect(ctrl.getNativeMaxScroll()).toEqual({
            left: opts.scrollingX ? scrollLeftMaxValue - 3 : -1,
            top: opts.scrollingY ? scrollTopMaxValue - 3 : -1
          });
        });

        it('should use attr.distance as percent', function() {
          setupJS('distance=5%', {}, opts);
          expect(ctrl.getJSMaxScroll()).toEqual({
            left: opts.scrollingX ? scrollLeftMaxValue * 0.95 : -1,
            top: opts.scrollingY ? scrollTopMaxValue * 0.95 : -1
          });

          setupNative('distance=5%', {}, opts);
          expect(ctrl.getNativeMaxScroll()).toEqual({
            left: opts.scrollingX ? scrollLeftMaxValue * 0.95 : -1,
            top: opts.scrollingY ? scrollTopMaxValue * 0.95 : -1
          });
        });
      });

    });
  });

  describe('scroll event', function() {

    it('should do nothing if < left and top', function() {
      var el = setupJS('on-infinite="foo=1"');
      el.controller('$ionicScroll').$element.triggerHandler('scroll');

      expect(el.hasClass('active')).toBe(false);
      expect(ctrl.isLoading).toBe(false);
      expect(el.scope().foo).not.toBe(1);

      var el = setupNative('on-infinite="foo=1"');
      var scrollEvent = new Event('scroll');
      ctrl.scrollEl.dispatchEvent(scrollEvent);

      expect(el.hasClass('active')).toBe(false);
      expect(ctrl.isLoading).toBe(false);
      expect(el.scope().foo).not.toBe(1);
    });
    it('should add active and call attr.onInfinite if >= top', function() {
      var el = setupJS('on-infinite="foo=1"');
      scrollTopValue = scrollTopMaxValue;
      el.controller('$ionicScroll').$element.triggerHandler('scroll');

      expect(el.hasClass('active')).toBe(true);
      expect(ctrl.isLoading).toBe(true);
      expect(el.scope().foo).toBe(1);

      scrollTopValue = scrollTopMaxValue;
      var el = setupNative('on-infinite="foo=1"', {}, { scrollingX: true, scrollingY: true });
      ctrl.checkBounds();
      expect(el.hasClass('active')).toBe(true);
      expect(ctrl.isLoading).toBe(true);
      expect(el.scope().foo).toBe(1);
    });
    it('should add active and call attr.onInfinite if >= left', function() {
      var el = setupJS('on-infinite="foo=1"');
      scrollLeftValue = scrollLeftMaxValue;
      el.controller('$ionicScroll').$element.triggerHandler('scroll');

      expect(el.hasClass('active')).toBe(true);
      expect(ctrl.isLoading).toBe(true);
      expect(el.scope().foo).toBe(1);

      scrollLeftValue = scrollLeftMaxValue;
      var el = setupNative('on-infinite="foo=1"', {}, { scrollingX: true, scrollingY: true });
      ctrl.checkBounds();

      expect(el.hasClass('active')).toBe(true);
      expect(ctrl.isLoading).toBe(true);
      expect(el.scope().foo).toBe(1);
    });
    it('should not run the event twice if isLoading is true', function() {
      var onScrollSpy = jasmine.createSpy('onInfiniteScroll');
      var el = setupJS('', { $onInfiniteScroll: onScrollSpy });
      scrollTopValue = scrollTopMaxValue;
      el.controller('$ionicScroll').$element.triggerHandler('scroll');

      expect(el.hasClass('active')).toBe(true);
      el.removeClass('active');
      expect(el.hasClass('active')).toBe(false);

      el.controller('$ionicScroll').$element.triggerHandler('scroll');
      expect(el.hasClass('active')).toBe(false);
    });

  });

  it('should checkbounds on launch', inject(function($timeout) {
    var el = setupJS();
    spyOn(el.controller('ionInfiniteScroll'),'checkBounds');
    expect(el.controller('ionInfiniteScroll').checkBounds).not.toHaveBeenCalled();
    $timeout.flush();
    expect(el.controller('ionInfiniteScroll').checkBounds).toHaveBeenCalled();
  }));

  it('should not checkbounds on launch if immediate-check=false', inject(function($timeout) {
    var el = setupJS('immediate-check="false"');
    spyOn(el.controller('ionInfiniteScroll'),'checkBounds');
    expect(el.controller('ionInfiniteScroll').checkBounds).not.toHaveBeenCalled();
    $timeout.flush();
    expect(el.controller('ionInfiniteScroll').checkBounds).not.toHaveBeenCalled();
  }));

  it('scroll.infiniteScrollComplete should work', inject(function($timeout) {
    var el = setupJS();
    ctrl.isLoading = true;
    el.addClass('active');
    el.scope().$broadcast('scroll.infiniteScrollComplete');
    expect(ctrl.isLoading).toBe(false);
    expect(el.hasClass('active')).toBe(false);
    expect(el.controller('$ionicScroll').scrollView.resize).not.toHaveBeenCalled();
    $timeout.flush();
    expect(el.controller('$ionicScroll').scrollView.resize).toHaveBeenCalled();
  }));
});
<commit_msg>test(infiniteScroll): Fix unit test for PhantomJS bug<commit_after>describe('ionicInfiniteScroll directive', function() {
  beforeEach(module('ionic'));

  var scrollTopValue  = 50;
  var scrollTopMaxValue = 60;
  var scrollLeftValue = 101;
  var scrollLeftMaxValue = 121;
  var ctrl;
  function setupJS(attrs, scopeProps, options) {
    var element;
    inject(function($rootScope, $compile) {
      var scope = $rootScope.$new();
      angular.extend(scope, scopeProps || {});
      element = angular.element('<ion-infinite-scroll ' + (attrs || '') + '></ion-infinite-scroll>');
      ionic.animationFrameThrottle = function(cb) { return function() { cb(); }; };
      element.data('$$ionicScrollController', {
        scrollView: {
          options: angular.extend({
            scrollingX: true,
            scrollingY: true
          }, options || {}),
          getValues: jasmine.createSpy('getValues').andCallFake(function() {
            return {
              left: scrollLeftValue,
              top: scrollTopValue
            };
          }),
          getScrollMax: jasmine.createSpy('getScrollMax').andCallFake(function() {
            return {
              left: scrollLeftMaxValue,
              top: scrollTopMaxValue
            };
          }),
          resize: jasmine.createSpy('resize')
        },
        resize: jasmine.createSpy('resize'),
        $element: angular.element('<div>')
      });
      $compile(element)(scope);
      ctrl = element.controller('ionInfiniteScroll');
      scope.$apply();
    });
    return element;
  }

  function setupNative(attrs, scopeProps, options) {
    var element, parent;
    inject(function($rootScope, $compile, $document) {
      var scope = $rootScope.$new();
      angular.extend(scope, scopeProps || {});
      parent = angular.element('<ion-content class="overflow-scroll"><ion-infinite-scroll ' + (attrs || '') +
                               '></ion-infinite-scroll></ion-content></ion-content>');
      if (options && !!options.scrollingX) parent[0].style['overflow-x'] ='scroll';
      if (options && !!options.scrollingY) parent[0].style['overflow-y'] ='scroll';
      element = parent.find('ion-infinite-scroll');
      ionic.animationFrameThrottle = function(cb) { return function() { cb(); }; };
      $compile(element)(scope);
      ctrl = element.controller('ionInfiniteScroll');
      // create a fake scrollEl since they can't be faked if we're passing in scroll data
      if (options) {
        ctrl.scrollEl = {style:{
          'overflow-x':'hidden',
          'overflow-y':'hidden'
        }};
        if (!!options.scrollingX) ctrl.scrollEl.style['overflow-x'] ='scroll';
        if (!!options.scrollingY) ctrl.scrollEl.style['overflow-y'] ='scroll';
        ctrl.scrollEl.clientWidth = ctrl.scrollEl.scrollLeft = scrollLeftValue;
        ctrl.scrollEl.clientHeight = ctrl.scrollEl.scrollTop = scrollTopValue;
        ctrl.scrollEl.scrollWidth = scrollLeftMaxValue;
        ctrl.scrollEl.scrollHeight = scrollTopMaxValue;
      }

      scope.$apply();
    });

    return element;
  }

  it('should error if no ionicScroll or native scroll parent', function() {
    expect(function() {
      inject(function($compile, $rootScope) {
        $compile('<ion-infinite-scroll></ion-infinite-scroll>')($rootScope.$new());
      });
    }).toThrow();
  });

  it('should not have class or be loading by default', function() {
    var el = setupJS();
    expect(el.hasClass('active')).toBe(false);
    expect(ctrl.isLoading).toBe(false);

    el = setupNative();
    expect(el.hasClass('active')).toBe(false);
    expect(ctrl.isLoading).toBe(false);
  });

  it('should unbind scroll event on destroy', function() {
    var el = setupJS();
    spyOn(el.controller('$ionicScroll').$element, 'off');
    el.scope().$destroy();
    expect(el.controller('$ionicScroll').$element.off).toHaveBeenCalledWith('scroll', jasmine.any(Function));

    el = setupNative();
    spyOn(ctrl.scrollEl, 'removeEventListener');
    el.scope().$destroy();
    expect(ctrl.scrollEl.removeEventListener).toHaveBeenCalled();
  });

  describe('icon', function() {
    it('should have default icon ion-loading-d', function() {
      var el = setupJS();
      var icon = angular.element(el[0].querySelector('.icon'));
      expect(icon.hasClass('ion-loading-d')).toBe(true);
    });

    it('should allow icon attr blank', function() {
      var el = setupJS('icon=""');
      var icon = angular.element(el[0].querySelector('.icon'));
      expect(icon.hasClass('ion-loading-d')).toBe(false);
    });

    it('should allow interpolated icon attr', function() {
      var el = setupJS('icon="{{someIcon}}"');
      var icon = angular.element(el[0].querySelector('.icon'));
      expect(icon.hasClass('ion-loading-d')).toBe(false);
      el.scope().$apply('someIcon = "super-icon"');
      expect(icon.hasClass('super-icon')).toBe(true);
    });
  });

  describe('getMaxScroll', function() {
    [{ scrollingX: true,  scrollingY: true },
     { scrollingX: false, scrollingY: true },
     { scrollingX: true,  scrollingY: false }
    ].forEach(function(opts) {

      describe('with scrollingX=' + opts.scrollingX + ', scrollingY=' + opts.scrollingY, function() {
        it('should default to 2.5%', function() {
          setupJS('', {}, opts);
          expect(ctrl.getJSMaxScroll()).toEqual({
            left: opts.scrollingX ? scrollLeftMaxValue * 0.975 : -1,
            top: opts.scrollingY ? scrollTopMaxValue * 0.975 : -1
          });

          setupNative('', {}, opts);
          expect(ctrl.getNativeMaxScroll()).toEqual({
            left: opts.scrollingX ? scrollLeftMaxValue * 0.975 : -1,
            top: opts.scrollingY ? scrollTopMaxValue * 0.975 : -1
          });
        });

        it('should use attr.distance as number', function() {
          setupJS('distance=3', {}, opts);
          expect(ctrl.getJSMaxScroll()).toEqual({
            left: opts.scrollingX ? scrollLeftMaxValue - 3 : -1,
            top: opts.scrollingY ? scrollTopMaxValue - 3 : -1
          });

          setupNative('distance=3', {}, opts);
          expect(ctrl.getNativeMaxScroll()).toEqual({
            left: opts.scrollingX ? scrollLeftMaxValue - 3 : -1,
            top: opts.scrollingY ? scrollTopMaxValue - 3 : -1
          });
        });

        it('should use attr.distance as percent', function() {
          setupJS('distance=5%', {}, opts);
          expect(ctrl.getJSMaxScroll()).toEqual({
            left: opts.scrollingX ? scrollLeftMaxValue * 0.95 : -1,
            top: opts.scrollingY ? scrollTopMaxValue * 0.95 : -1
          });

          setupNative('distance=5%', {}, opts);
          expect(ctrl.getNativeMaxScroll()).toEqual({
            left: opts.scrollingX ? scrollLeftMaxValue * 0.95 : -1,
            top: opts.scrollingY ? scrollTopMaxValue * 0.95 : -1
          });
        });
      });

    });
  });

  describe('scroll event', function() {

    it('should do nothing if < left and top', function() {
      var el = setupJS('on-infinite="foo=1"');
      el.controller('$ionicScroll').$element.triggerHandler('scroll');

      expect(el.hasClass('active')).toBe(false);
      expect(ctrl.isLoading).toBe(false);
      expect(el.scope().foo).not.toBe(1);

      var el = setupNative('on-infinite="foo=1"');
      var evObj = document.createEvent('HTMLEvents');
      evObj.initEvent('scroll', true, true, window, 1, 12, 345, 7, 220, false, false, true, false, 0, null);
      ctrl.scrollEl.dispatchEvent(evObj);

      expect(el.hasClass('active')).toBe(false);
      expect(ctrl.isLoading).toBe(false);
      expect(el.scope().foo).not.toBe(1);
    });
    it('should add active and call attr.onInfinite if >= top', function() {
      var el = setupJS('on-infinite="foo=1"');
      scrollTopValue = scrollTopMaxValue;
      el.controller('$ionicScroll').$element.triggerHandler('scroll');

      expect(el.hasClass('active')).toBe(true);
      expect(ctrl.isLoading).toBe(true);
      expect(el.scope().foo).toBe(1);

      scrollTopValue = scrollTopMaxValue;
      var el = setupNative('on-infinite="foo=1"', {}, { scrollingX: true, scrollingY: true });
      ctrl.checkBounds();
      expect(el.hasClass('active')).toBe(true);
      expect(ctrl.isLoading).toBe(true);
      expect(el.scope().foo).toBe(1);
    });
    it('should add active and call attr.onInfinite if >= left', function() {
      var el = setupJS('on-infinite="foo=1"');
      scrollLeftValue = scrollLeftMaxValue;
      el.controller('$ionicScroll').$element.triggerHandler('scroll');

      expect(el.hasClass('active')).toBe(true);
      expect(ctrl.isLoading).toBe(true);
      expect(el.scope().foo).toBe(1);

      scrollLeftValue = scrollLeftMaxValue;
      var el = setupNative('on-infinite="foo=1"', {}, { scrollingX: true, scrollingY: true });
      ctrl.checkBounds();

      expect(el.hasClass('active')).toBe(true);
      expect(ctrl.isLoading).toBe(true);
      expect(el.scope().foo).toBe(1);
    });
    it('should not run the event twice if isLoading is true', function() {
      var onScrollSpy = jasmine.createSpy('onInfiniteScroll');
      var el = setupJS('', { $onInfiniteScroll: onScrollSpy });
      scrollTopValue = scrollTopMaxValue;
      el.controller('$ionicScroll').$element.triggerHandler('scroll');

      expect(el.hasClass('active')).toBe(true);
      el.removeClass('active');
      expect(el.hasClass('active')).toBe(false);

      el.controller('$ionicScroll').$element.triggerHandler('scroll');
      expect(el.hasClass('active')).toBe(false);
    });

  });

  it('should checkbounds on launch', inject(function($timeout) {
    var el = setupJS();
    spyOn(el.controller('ionInfiniteScroll'),'checkBounds');
    expect(el.controller('ionInfiniteScroll').checkBounds).not.toHaveBeenCalled();
    $timeout.flush();
    expect(el.controller('ionInfiniteScroll').checkBounds).toHaveBeenCalled();
  }));

  it('should not checkbounds on launch if immediate-check=false', inject(function($timeout) {
    var el = setupJS('immediate-check="false"');
    spyOn(el.controller('ionInfiniteScroll'),'checkBounds');
    expect(el.controller('ionInfiniteScroll').checkBounds).not.toHaveBeenCalled();
    $timeout.flush();
    expect(el.controller('ionInfiniteScroll').checkBounds).not.toHaveBeenCalled();
  }));

  it('scroll.infiniteScrollComplete should work', inject(function($timeout) {
    var el = setupJS();
    ctrl.isLoading = true;
    el.addClass('active');
    el.scope().$broadcast('scroll.infiniteScrollComplete');
    expect(ctrl.isLoading).toBe(false);
    expect(el.hasClass('active')).toBe(false);
    expect(el.controller('$ionicScroll').scrollView.resize).not.toHaveBeenCalled();
    $timeout.flush();
    expect(el.controller('$ionicScroll').scrollView.resize).toHaveBeenCalled();
  }));
});
<|endoftext|>


<commit_before>//DEPENDENCIES
fs = require('fs');
moment = require('moment');
var n = 3;
//CONFIG PARAMETERS
var minutes = 0.1; //minutes between every check
var path_file = "./capture.txt"; //watched file
var verbose = true; //do you want dates and event printed?

//AUX FUNCTIONS

//COMMENT, filtering log if unnecessary
var Comment = function(comment){
if(verbose) console.log("["+moment(new Date()).format("hh:mm")+"] [interval.js:log] "+comment);
}

//CALLBACK, the function looking for modifications.
var callback = function(){
	Comment("Checking...");
	var old = new Date(fecham).getTime();
	var newone = new Date(fs.statSync(path_file).mtime).getTime();
	if(old!=newone){
		Comment("File has been modified");
		fecham = newone;
		Comment("New last modified date: "+ moment(fecham).format('MMMM Do YYYY, h:mm:ss a'));

		//DO HERE WHATEVER YOU WANT,
		//SENDING MEASURES FOR INSTANCE.

		guardarMedicion();

	}else{
		Comment("Nothing has changed.");
		Comment("LastMeasure: ");
		//ultimaMedicion();
	}
};

////PROGRAM

console.log("\n\n\n");
var fecham = fs.statSync(path_file).mtime;
Comment('Original last modification date: '+moment(fecham).format('MMMM Do YYYY, h:mm:ss a'));

setInterval(callback, minutes*60*1000);

//CONSULTA UTILS
var http = require("http"); //para hacer peticiones http
var moment = require("moment");
var events = require('events'); //para poder lanzar eventos personalizados
var eventEmitter = new events.EventEmitter();

function imprimeBody(current_time, body){
Comment("IMPRIMIENDO BODY del evento: "+current_time );
Comment(body.replace(/[^\x20-\x7E]+/g, ''));
eventEmitter.removeListener(current_time, imprimeBody);

};

//GUARDARMEDICION
function guardarMedicion(){

	fs.readFile(path_file, 'utf8', function(err, data) {
			  if (err) throw err;
			  Comment('OK: ' + path_file);
			  //Comment(data);
var pieces = data.split("\n");

var send="";
for(i=0;i<=n;i++){
send+=pieces.pop()+'*';
}

send = send.substring(0, send.length-1);
send= send.replace('\n','');

Comment(send);

		});

};

//ULTIMAMEDICION
function ultimaMedicion(){
	var parametros = {
			plantID: 3,
			numero: 1
		};

		var miConsulta = "obtenerMediciones";
		consultaPHP(miConsulta,parametros);

};<commit_msg>javascript funciona bien, sube medidas y las consulta(puede comentarse para que no compruebe cada dos por tres)<commit_after>//DEPENDENCIES
fs = require('fs');
moment = require('moment');

//CONFIG PARAMETERS

var n = 3;
var interv = 1; //tiempo entre medidas, en minutos
var minutes = 0.1; //minutes between every check
var path_file = "./capture.txt"; //watched file
var verbose = true; //do you want dates and event printed?

//AUX FUNCTIONS

//COMMENT, filtering log if unnecessary
var Comment = function(comment){
if(verbose) console.log("["+moment(new Date()).format("hh:mm")+"] [interval.js:log] "+comment);
}

//CALLBACK, the function looking for modifications.
var callback = function(){
	Comment("Checking...");
	var old = new Date(fecham).getTime();
	var newone = new Date(fs.statSync(path_file).mtime).getTime();
	if(old!=newone){
		Comment("File has been modified");
		fecham = newone;
		Comment("New last modified date: "+ moment(fecham).format('MMMM Do YYYY, h:mm:ss a'));

		//DO HERE WHATEVER YOU WANT,
		//SENDING MEASURES FOR INSTANCE.

		guardarMedicion();

	}else{
		Comment("Nothing has changed.");
		Comment("LastMeasure: ");
		ultimaMedicion();
	}
};

////PROGRAM

Comment("\n\n\n");
var fecham = fs.statSync(path_file).mtime;
//Comment('Original last modification date: '+moment(fecham).format('MMMM Do YYYY, h:mm:ss a'));

setInterval(callback, minutes*60*1000);

//CONSULTA UTILS
var http = require("http"); //para hacer peticiones http
var moment = require("moment");
var events = require('events'); //para poder lanzar eventos personalizados
var eventEmitter = new events.EventEmitter();

function imprimeBody(current_time, body){
Comment("IMPRIMIENDO BODY del evento: "+current_time );
Comment(body.replace(/[^\x20-\x7E]+/g, ''));
eventEmitter.removeListener(current_time, imprimeBody);

};

//CONSULTA GENÉRICA
function consultaPHP(consulta,parametros){
	var current_time = Date.now();
	eventEmitter.on(current_time, imprimeBody);

	var options = {
  		host: '193.146.210.69',
  		port: 80,
  		path: '/consultas.php?consulta='+consulta,
  		method: 'GET'
		};

	for (key in parametros) {
    		if (parametros.hasOwnProperty(key)) {
        		options.path = options.path + "&"+key+"="+parametros[key];
    		}
	}
	Comment("Iniciando consulta: "+ options.path);
	var req = http.request(options, function(res) {
  		Comment('RESPUESTA: ' + res.statusCode);
  		//Comment('HEADERS: ' + JSON.stringify(res.headers));
  		res.setEncoding('utf8');
  		res.on('data', function (chunk) {
    			//Comment('BODY: ' + chunk);
			eventEmitter.emit(current_time, current_time, chunk);
  		});

	});

	req.on('error', function(e) {
  		Comment('problem with request: ' + e.message);
	});
	req.end();
}

//GUARDARMEDICION
function guardarMedicion(){

	fs.readFile(path_file, 'utf8', function(err, data) {
			  if (err) throw err;

var pieces = data.split("\n");

var send="";
for(i=0;i<=n;i++){
send+=pieces.pop()+'*';
}

send = send.substring(1, send.length-1);
send= send.replace('\n','');

Comment("DATOS A ENVIAR: "+send);
var parametros = {
			datos: send,
			intervalo: interv
		};
		Comment(parametros.toString());
		var miConsulta = "guardarMedicion";
		consultaPHP(miConsulta,parametros);

		});

};

//ULTIMAMEDICION
function ultimaMedicion(){
	var parametros = {
			plantID: 3,
			numero: n
		};

		var miConsulta = "obtenerMediciones";
		Comment("Últimas "+ n+ " medidas:\n");
		consultaPHP(miConsulta,parametros);

};
<|endoftext|>