<commit_before>/**
 * Issue: http://i.imgur.com/5LEb4IH.jpg, Could not convert gif. Key already in use.  Please choose unique key or do not specify
 */

let { Cu } = require("chrome");
let self = require("sdk/self");
let PageMod = require("sdk/page-mod").PageMod;
let Request = require("sdk/request").Request;
let properties = require("packages/properties");
let urlHelper = require("packages/urlHelper");
let resImageBlocker = require("./resImageBlocker");

Cu.import("resource://gre/modules/AddonManager.jsm");

exports.enable = (enable) => {
  return doEnable(enable);
};

let pageMod = null;
let gWorker = null;

function doEnable(enable) {
  resImageBlocker.enable(enable);
  if (!enable) {
    try {
      pageMod.destroy();
      gWorker.port.emit("resImageViewerSupportDisabled");
    }
    catch(ex) {
    }
    return;
  }
  AddonManager.getAddonByID(properties.res.addOnId, (addOn) => {
    if (addOn && addOn.isActive) {
      enableResPageMod();
    }
  });
}

function checkContentTypeBeforeRequestingGfyTranscoder(gifUrl, gifKey, worker) {
  console.log("checking content type", gifUrl);

  let isGifCallback = () => {
    requestGfyTranscoder(gifUrl, gifKey, worker);
  };

  let isNotGifCallback = () => {
    onTranscodeError(gifKey, worker, "Could not transform " + urlHelper.getFileExtension(gifUrl) + " to gfycat video. Displaying original image", false);
  };

  urlHelper.asyncIsContentTypeGif(gifUrl, isGifCallback, isNotGifCallback);
}

function requestGfyTranscoder(gifUrl, gifKey, worker) {
  let url = properties.gfycat.transcodeEndpoint +  createPsudoRandomStr(5) + "?fetchUrl=" + gifUrl;
  worker.port.emit("transcodeStart", gifUrl, gifKey);

  Request({
    url: url,
    onComplete: (response) => {
      resolveTranscodeResponse(response, gifUrl, gifKey, worker);
    }
  }).get();
}

function resolveTranscodeResponse(response, requestedUrl, gifKey, worker) {
  console.log("Transcode response " + response.status, response.json);

  if (response.status >= 400) {
    onTranscodeError(gifKey, worker, "Something went wrong. Server responded with: Status " + repsonse.status + ", " + response.statusText, false);
  } else if (response.json.error) {
    onTranscodeError(gifKey, worker, "Could not convert gif. " + response.json.error, true);
  } else {
    // Success
    let transcodingJson = response.json;
    let bytesSaved = getBandwidthSavedInMB(transcodingJson);
    let message = "About " + bytesSaved.toPrecision(2) + " MB of bandwidth was saved";
    if (bytesSaved < 0) {
      message = "The gfycat video file size (" + transcodingJson.gfysize + " Bytes) is actually larger than the gif (" + transcodingJson.gifSize + " Bytes)";
    }
    onTranscodeSuccess(response, gifKey, worker, message);
  }
}

function onTranscodeSuccess(response, gifKey, worker, loadingMessage) {
  worker.port.emit("transcodeSuccess", response.json, gifKey, loadingMessage);
}

function onTranscodeError(gifKey, worker, errorMessage, showErrorMessage) {
  worker.port.emit("transcodeError", gifKey, errorMessage, showErrorMessage);
}

function enableResPageMod() {
  pageMod = PageMod({
    include: ["*.reddit.com"],
    attachTo: ["existing", "top"],
    contentScriptFile: self.data.url("pagemod/resImageViewerMod.js"),
    contentStyleFile: self.data.url("pagemod/resImageViewerMod.css"),
    onAttach: function(worker) {
      gWorker = worker;
      worker.port.on("requestGfyTranscoder", (gifUrl, gifKey) => {
        checkContentTypeBeforeRequestingGfyTranscoder(gifUrl, gifKey, worker);
      });
    },
    contentScriptWhen: "ready",
    contentScriptOptions: {
      spinnerFile: self.data.url("images/spinner.gif")
    }
  });
}

function createPsudoRandomStr(stringLength) {
  let text = "";
  let possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  for( let i=0; i < stringLength; i++ ) {
    text += possible.charAt(Math.floor(Math.random() * possible.length));
  }
  return text;
}

function getBandwidthSavedInMB(gfyInfo) {
  let gifSize = gfyInfo.gifSize;
  let gfySize = gfyInfo.gfysize;
  return (gifSize - gfySize) / 1024 / 1024;
}<commit_msg>refactoring<commit_after>/**
 * Issue: http://i.imgur.com/5LEb4IH.jpg, Could not convert gif. Key already in use.  Please choose unique key or do not specify
 */

let { Cu } = require("chrome");
let self = require("sdk/self");
let PageMod = require("sdk/page-mod").PageMod;
let Request = require("sdk/request").Request;
let properties = require("packages/properties");
let urlHelper = require("packages/urlHelper");
let resImageBlocker = require("./resImageBlocker");

Cu.import("resource://gre/modules/AddonManager.jsm");

exports.enable = (enable) => {
  return doEnable(enable);
};

let pageMod = null;
let gWorker = null;

function doEnable(enable) {
  resImageBlocker.enable(enable);
  if (!enable) {
    try {
      pageMod.destroy();
      gWorker.port.emit("resImageViewerSupportDisabled");
    }
    catch(ex) {
    }
    return;
  }
  AddonManager.getAddonByID(properties.res.addOnId, (addOn) => {
    if (addOn && addOn.isActive) {
      enableResPageMod();
    }
  });
}

function checkContentTypeBeforeRequestingGfyTranscoder(gifUrl, gifKey, worker) {
  console.log("checking content type", gifUrl);

  let isGifCallback = () => {
    requestGfyTranscoder(gifUrl, gifKey, worker);
  };

  let isNotGifCallback = () => {
    onTranscodeError(gifKey, worker, "Could not transform " + urlHelper.getFileExtension(gifUrl) + " to gfycat video. Displaying original image", false);
  };

  urlHelper.asyncIsContentTypeGif(gifUrl, isGifCallback, isNotGifCallback);
}

function requestGfyTranscoder(gifUrl, gifKey, worker) {
  let url = properties.gfycat.transcodeEndpoint +  createPsudoRandomStr(5) + "?fetchUrl=" + gifUrl;
  worker.port.emit("transcodeStart", gifUrl, gifKey);

  Request({
    url: url,
    onComplete: (response) => {
      resolveTranscodeResponse(response, gifUrl, gifKey, worker);
    }
  }).get();
}

function resolveTranscodeResponse(response, requestedUrl, gifKey, worker) {
  console.log("Transcode response " + response.status, response.json);

  let gfyErrorMessage = response.json.error;

  if (gfyErrorMessage) {
    onTranscodeError(gifKey, worker, "Could not convert gif. " + gfyErrorMessage, gfyErrorMessage.length < 100);
  } else if (response.status >= 400) {
    onTranscodeError(gifKey, worker, "Something went wrong. Server responded with: Status " + repsonse.status + ", " + response.statusText, false);
  } else {
    // Success
    let transcodingJson = response.json;
    let bytesSaved = getBandwidthSavedInMB(transcodingJson);
    let message = "About " + bytesSaved.toPrecision(2) + " MB of bandwidth was saved";
    if (bytesSaved < 0) {
      message = "The gfycat video file size (" + transcodingJson.gfysize + " Bytes) is actually larger than the gif (" + transcodingJson.gifSize + " Bytes)";
    }
    onTranscodeSuccess(response, gifKey, worker, message);
  }
}

function onTranscodeSuccess(response, gifKey, worker, loadingMessage) {
  worker.port.emit("transcodeSuccess", response.json, gifKey, loadingMessage);
}

function onTranscodeError(gifKey, worker, errorMessage, showErrorMessage) {
  worker.port.emit("transcodeError", gifKey, errorMessage, showErrorMessage);
}

function enableResPageMod() {
  pageMod = PageMod({
    include: ["*.reddit.com"],
    attachTo: ["existing", "top"],
    contentScriptFile: self.data.url("pagemod/resImageViewerMod.js"),
    contentStyleFile: self.data.url("pagemod/resImageViewerMod.css"),
    onAttach: function(worker) {
      gWorker = worker;
      worker.port.on("requestGfyTranscoder", (gifUrl, gifKey) => {
        checkContentTypeBeforeRequestingGfyTranscoder(gifUrl, gifKey, worker);
      });
    },
    contentScriptWhen: "ready",
    contentScriptOptions: {
      spinnerFile: self.data.url("images/spinner.gif")
    }
  });
}

function createPsudoRandomStr(stringLength) {
  let text = "";
  let possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  for( let i=0; i < stringLength; i++ ) {
    text += possible.charAt(Math.floor(Math.random() * possible.length));
  }
  return text;
}

function getBandwidthSavedInMB(gfyInfo) {
  let gifSize = gfyInfo.gifSize;
  let gfySize = gfyInfo.gfysize;
  return (gifSize - gfySize) / 1024 / 1024;
}<|endoftext|>


<commit_before>locale.da = {
    modes: {
        add_area: {
            title: "Område",
            description: "Tilføj parker, bygninger, søer, eller andre områder til kortet.",
            tail: "Klik på kortet for at indtegne et område fx en park, sø eller bygning."
        },
        add_line: {
            title: "Linje",
            description: "Linjer kan være veje, gader eller stier selv kanaler kan være linjer.",
            tail: "Klik på koret for at indtegne en vej, sti eller rute."
        },
        add_point: {
            title: "Punkt",
            description: "Restauranter, mindesmærker og postkasser er punkter.",
            tail: "Klik på kortet for at tilføje et punkt."
        },
        browse: {
            title: "Browse",
            description: "Træk rundt og zoom på kortet."
        },
        draw_area: {
            tail: "Klik her for at tilføje punkter til dit område. Click the first point to finish the area."
        },
        draw_line: {
            tail: "Click to add more points to the line. Click on other lines to connect to them, and double-click to end the line."
        }
    },

    operations: {
        add: {
            annotation: {
                point: "Tilføjede et punkt.",
                vertex: "Tilføjede en node til en vej."
            }
        },
        start: {
            annotation: {
                line: "Startede en linje.",
                area: "Startede et område."
            }
        },
        'continue': {
            annotation: {
                line: "Forsatte en linje.",
                area: "Forsatte et område."
            }
        },
        cancel_draw: {
            annotation: "Annulleret indtegning."
        },
        change_tags: {
            annotation: "Ændret tags."
        },
        circularize: {
            title: "Circularize",
            description: "Make this round.",
            key: "O",
            annotation: {
                line: "Made a line circular.",
                area: "Made an area circular."
            }
        },
        orthogonalize: {
            title: "Orthogonalize",
            description: "Square these corners.",
            key: "Q",
            annotation: {
                line: "Squared the corners of a line.",
                area: "Squared the corners of an area."
            }
        },
        'delete': {
            title: "Slet",
            description: "Fjern dette fra kortet.",
            key: "⌫",
            annotation: {
                point: "Slettede et punkt.",
                vertex: "Slettede en node fra en vej.",
                line: "Slettede en linje.",
                area: "Slettede et område.",
                relation: "Sletede en relation.",
                multiple: "Slettede {n} objekter."
            }
        },
        connect: {
            annotation: {
                point: "Connected a way to a point.",
                vertex: "Connected a way to another.",
                line: "Connected a way to a line.",
                area: "Connected a way to an area."
            }
        },
        disconnect: {
            title: "Disconnect",
            description: "Disconnect these ways from each other.",
            key: "D",
            annotation: "Disconnected ways."
        },
        merge: {
            title: "Merge",
            description: "Merge these lines.",
            key: "C",
            annotation: "Merged {n} lines."
        },
        move: {
            title: "Flyt",
            description: "Flyt dette til anden lokation.",
            key: "M",
            annotation: {
                point: "Flyttede et punktMoved.",
                vertex: "Flyttede en node i en vej.",
                line: "Flyttede en linje.",
                area: "Flyttede et område."
            }
        },
        reverse: {
            title: "Reverse",
            description: "Make this line go in the opposite direction.",
            key: "V",
            annotation: "Reversed a line."
        },
        split: {
            title: "Del op",
            description: "Del op i to vej ved dette punkt.",
            key: "X",
            annotation: "Del op en vej."
        }
    },

    nothing_to_undo: "Nothing to undo.",
    nothing_to_redo: "Nothing to redo.",

    just_edited: "Du har lige rettede i OpenStreetMap!",
    browser_notice: "This editor is supported in Firefox, Chrome, Safari, Opera, and Internet Explorer 9 and above. Please upgrade your browser or use Potlatch 2 to edit the map.",
    view_on_osm: "Vis på OSM",
    zoom_in_edit: "zoom ind for at rette kortet",
    logout: "log ud",
    report_a_bug: "report a bug",

    layerswitcher: {
        title: "Background",
        description: "Background Settings",
        percent_brightness: "{opacity}% brightness",
        fix_misalignment: "Fix misalignment",
        reset: "nulstill"
    },

    commit: {
        title: "Save Changes",
        description_placeholder: "Brief description of your contributions",
        upload_explanation: "The changes you upload as {user} will be visible on all maps that use OpenStreetMap data.",
        save: "Save",
        cancel: "Cancel",
        warnings: "Warnings",
        modified: "Modified",
        deleted: "Deleted",
        created: "Created"
    },

    contributors: {
        list: "Vis bidrag fra {users}",
        truncated_list: "Vis bidrag fra {users} og {count} andre"
    },

    geocoder: {
        title: "Find  et sted",
        placeholder: "find et sted",
        no_results: "Kunne ikke finde '{name}'"
    },

    geolocate: {
        title: "Show My Location"
    },

    inspector: {
        no_documentation_combination:  "Der er ingen dokumentation for denne tag kombination",
        no_documentation_key: "Der er ingen dokumenation tilgængelig for denne nøgle",
        new_tag: "Nyt Tag",
        edit_tags: "Ret tags",
        okay: "Ok",
        view_on_osm: "View on OSM"
    },

    restore: {
        description: "You have unsaved changes from a previous editing session. Do you wish to restore these changes?",
        restore: "Restore",
        reset: "Reset"
    },

    save: {
        title: "Gem",
        help: "Gem ændringer til OpenStreetMap gør dem synlige for andre brugere",
        error: "Der skete en fejl da du prøvede at gemme",
        uploading: "Gemmer nu ændringer til OpenStreetMap.",
        unsaved_changes: "Du har ændringer der ikke er gemt endnu",
    },

    splash: {
        welcome: "Welcome to the iD OpenStreetMap editor",
        text: "This is development version {version}. For more information see {website} and report bugs at {github}."
    },

    source_switch: {
        live: "live",
        dev: "dev"
    },

    tag_reference: {
        description: "Description",
        on_wiki: "{tag} on wiki.osm.org",
        used_with: "used with {type}"
    },

    zoom: {
        in: "Zoom ind",
        out: "Zoom ud"
    },

    validations: {
        untagged_point: "Untagged point which is not part of a line or area",
        untagged_line: "Untagged line",
        untagged_area: "Untagged area",
        tag_suggests_area: "The tag {tag} suggests line should be area, but it is not an area",
        deprecated_tags: "Deprecated tags: {tags}"
    }
};
<commit_msg>Update locale/da.js<commit_after>locale.da = {
    modes: {
        add_area: {
            title: "Område",
            description: "Tilføj parker, bygninger, søer, eller andre områder til kortet.",
            tail: "Klik på kortet for at indtegne et område fx en park, sø eller bygning."
        },
        add_line: {
            title: "Linje",
            description: "Linjer kan være veje, gader eller stier selv kanaler kan være linjer.",
            tail: "Klik på koret for at indtegne en vej, sti eller rute."
        },
        add_point: {
            title: "Punkt",
            description: "Restauranter, mindesmærker og postkasser er punkter.",
            tail: "Klik på kortet for at tilføje et punkt."
        },
        browse: {
            title: "Browse",
            description: "Træk rundt og zoom på kortet."
        },
        draw_area: {
            tail: "Klik her for at tilføje punkter til dit område. Klik på første punkt igen for at færdiggøre området."
        },
        draw_line: {
            tail: "Klik her for at tilføje flere punkter til linjen. Klik på andre linjer for at forbinde dem og dobbeltklik for at afslutte linjen."
        }
    },

    operations: {
        add: {
            annotation: {
                point: "Tilføjede et punkt.",
                vertex: "Tilføjede en node til en vej."
            }
        },
        start: {
            annotation: {
                line: "Startede en linje.",
                area: "Startede et område."
            }
        },
        'continue': {
            annotation: {
                line: "Fortsatte en linje.",
                area: "Fortsatte et område."
            }
        },
        cancel_draw: {
            annotation: "Annullerede indtegning."
        },
        change_tags: {
            annotation: "Ændret tags."
        },
        circularize: {
            title: "Cirkularisere",
            description: "Lav denne rund.",
            key: "O",
            annotation: {
                line: "Lavede en linje rund.",
                area: "Lave et område rundt."
            }
        },
        orthogonalize: {
            title: "Ortogonalisering",
            description: "Gør disse hjørner firkantet.",
            key: "Q",
            annotation: {
                line: "Lavede hjørner på en linje firkantet.",
                area: "Lavede hjørner på et område firkantet."
            }
        },
        'delete': {
            title: "Slet",
            description: "Fjern dette fra kortet.",
            key: "⌫",
            annotation: {
                point: "Slettede et punkt.",
                vertex: "Slettede en node fra en vej.",
                line: "Slettede en linje.",
                area: "Slettede et område.",
                relation: "Sletede en relation.",
                multiple: "Slettede {n} objekter."
            }
        },
        connect: {
            annotation: {
                point: "Forbandt en vej til et punkt.",
                vertex: "Forbandt en vej til en anden vej.",
                line: "Forbandt en vej til en linje.",
                area: "Forbandt en vej til et område."
            }
        },
        disconnect: {
            title: "Afbryd",
            description: "Afbryd disse veje fra hinanden.",
            key: "D",
            annotation: "Afbrød vejene."
        },
        merge: {
            title: "Flet",
            description: "Flet disse linjer.",
            key: "C",
            annotation: "Flettede {n} linjer."
        },
        move: {
            title: "Flyt",
            description: "Flyt dette til en anden lokation.",
            key: "M",
            annotation: {
                point: "Flyttede et punkt.",
                vertex: "Flyttede en node i en vej.",
                line: "Flyttede en linje.",
                area: "Flyttede et område."
            }
        },
        reverse: {
            title: "Omvendt",
            description: "Lad denne linje gå i modsat retning.",
            key: "V",
            annotation: "Omvendte en linje."
        },
        split: {
            title: "Del op",
            description: "Del op i to veje ved dette punkt.",
            key: "X",
            annotation: "Del en vej op."
        }
    },

    nothing_to_undo: "Ingenting at fortryde.",
    nothing_to_redo: "Ingenting at gendanne.",

    just_edited: "Du har lige rettet i OpenStreetMap!",
    browser_notice: "Dette værktøj er understøttet i Firefox, Chrome, Safari, Opera og Internet Explorer 9 og højere. Vær venlig at opgradere din browser eller benyt Potlatch 2 for at rette i kortet.",
    view_on_osm: "Vis på OSM",
    zoom_in_edit: "zoom ind for at rette på kortet",
    logout: "log ud",
    report_a_bug: "rapportere en fejl",

    layerswitcher: {
        title: "Baggrund",
        description: "Baggrundsindstillinger",
        percent_brightness: "{opacity}% lysstyrke",
        fix_misalignment: "Lav fejljustering",
        reset: "nulstil"
    },

    commit: {
        title: "Gem ændringer",
        description_placeholder: "Kort beskrivelse af dine bidrag",
        upload_explanation: "Dine ændringer vil som brugernavn {user} blive synligt på alle kort der bruger OpenStreetMap data.",
        save: "Gem",
        cancel: "Fortryd",
        warnings: "Advarsler",
        modified: "Modificeret",
        deleted: "Slettede",
        created: "Lavede"
    },

    contributors: {
        list: "Vis bidrag fra {users}",
        truncated_list: "Vis bidrag fra {users} og {count} andre"
    },

    geocoder: {
        title: "Find et sted",
        placeholder: "find et sted",
        no_results: "Kunne ikke finde '{name}'"
    },

    geolocate: {
        title: "Vis min lokalitet"
    },

    inspector: {
        no_documentation_combination:  "Der er ingen dokumentation for denne tag kombination",
        no_documentation_key: "Der er ingen dokumentation tilgængelig for denne nøgle",
        new_tag: "Nyt tag",
        edit_tags: "Ret tags",
        okay: "Ok",
        view_on_osm: "Vis på OSM"
    },

    restore: {
        description: "Du har ændringer fra forrige session som ikke er gemt. Ønsker du at gendanne disse ændringer?",
        restore: "Gendan",
        reset: "Nulstil"
    },

    save: {
        title: "Gem",
        help: "Gem ændringer til OpenStreetMap vil gøre dem synlige for andre brugere",
        error: "Der skete en fejl da du prøvede at gemme",
        uploading: "Gemmer nu ændringer til OpenStreetMap.",
        unsaved_changes: "Du har ændringer der ikke er gemt endnu",
    },

    splash: {
        welcome: "Velkommen til iD OpenStreetMap værktøjet",
        text: "Dette er udviklingsversion {version}. Mere information se {website} og rapportere fejl på {github}."
    },

    source_switch: {
        live: "live",
        dev: "dev"
    },

    tag_reference: {
        description: "Beskrivelse",
        on_wiki: "{tag} på wiki.osm.org",
        used_with: "brugt med {type}"
    },

    zoom: {
        in: "Zoom ind",
        out: "Zoom ud"
    },

    validations: {
        untagged_point: "Mangler et tag på punkt som ikke er del af en linje eller område",
        untagged_line: "Mangler tag på linje",
        untagged_area: "Mangler tag på område",
        tag_suggests_area: "Dette tag {tag} mener denne linje skule være et område, men dette er ikke et område",
        deprecated_tags: "Uønskede tags: {tags}"
    }
};
<|endoftext|>


<commit_before>module.exports = chaiStyle

function chaiStyle(chai, utils) {
  const {Assertion} = chai
  const {flag} = utils
  const color = require('onecolor')

  Assertion.addMethod('style', function(property, value = '') {
    const element = flag(this, 'object')
    const style = window.getComputedStyle(element)
    value = value.trim()
    const propertyValue = style[property]

    const propertyValueIsColor = color(propertyValue) instanceof color.RGB
    const isColor = color.namedColors[value]
      || color(value) instanceof color.RGB
      || color(value) instanceof color.HSL

    const cssUnit = /(px|em|rem|vh|vw)$/ // |vw|vh|vmin|vmax|%|pt
    const isCSSUnit = cssUnit.test(value) || /\d/.test(value)

    const assertion = value
      ? isColor
        ? color(propertyValue).equals(color(value))
        : isCSSUnit
          ? compareCSSValue(propertyValue, value)
          : propertyValue === value
      : propertyValueIsColor
        ? color(propertyValue).alpha() === 1
        : Boolean(propertyValue)

    const elementTag = element.tagName.toLowerCase()

    const throwMessage = `expect ${elementTag} to have {${property}: ${value}}, is receiving {${property}: ${propertyValue}}`
    const throwMessageNegative = `expect ${elementTag} to not have {${property}: ${value}}, is receiving {${property}: ${propertyValue}}`

    this.assert(assertion, throwMessage, throwMessageNegative, value)

    function compareCSSValue(a, b) {
      const rootFontSize = window
        .getComputedStyle(document.documentElement)['font-size'].replace('px', '')
        || '16'

      a = a
        .split(' ')
        .map(parseToPixel)
        .join(' ')

      b = b
        .split(' ')
        .map(parseToPixel)
        .join(' ')

      if (b.includes('auto')) {
        const reg = new RegExp(b.replace('auto', '(\\d+(.\\d+)?px|auto)'))
        return reg.test(a)
      } else {
        return a === b
      }

      function parseToPixel(value) {
        const elementFontSize = style.fontSize.replace(cssUnit, '')// || rootFontSize

        const number = Number(value.replace(cssUnit, ''))
        const isNumber = !isNaN(value) || !isNaN(number)

        if (isNumber) {
          switch (true) {
            case /\dem$/.test(value):
              value = number * elementFontSize
              break
            case /\drem$/.test(value):
              value = number * rootFontSize
              break
            case /\dvh$/.test(value):
              value = parseInt((number / 100) * document.documentElement.clientHeight)
              break
            case /\dvw$/.test(value):
              value = parseInt((number / 100) * document.documentElement.clientWidth)
              break
            default:
              value = number
          }
          return `${value}px`
        }

        return value
      }
    }
  })
}

<commit_msg>replace all auto in regex<commit_after>module.exports = chaiStyle

function chaiStyle(chai, utils) {
  const {Assertion} = chai
  const {flag} = utils
  const color = require('onecolor')

  Assertion.addMethod('style', function(property, value = '') {
    const element = flag(this, 'object')
    const style = window.getComputedStyle(element)
    value = value.trim()
    const propertyValue = style[property]

    const propertyValueIsColor = color(propertyValue) instanceof color.RGB
    const isColor = color.namedColors[value]
      || color(value) instanceof color.RGB
      || color(value) instanceof color.HSL

    const cssUnit = /(px|em|rem|vh|vw)$/ // |vw|vh|vmin|vmax|%|pt
    const isCSSUnit = cssUnit.test(value) || /\d/.test(value)

    const assertion = value
      ? isColor
        ? color(propertyValue).equals(color(value))
        : isCSSUnit
          ? compareCSSValue(propertyValue, value)
          : propertyValue === value
      : propertyValueIsColor
        ? color(propertyValue).alpha() === 1
        : Boolean(propertyValue)

    const elementTag = element.tagName.toLowerCase()

    const throwMessage = `expect ${elementTag} to have {${property}: ${value}}, is receiving {${property}: ${propertyValue}}`
    const throwMessageNegative = `expect ${elementTag} to not have {${property}: ${value}}, is receiving {${property}: ${propertyValue}}`

    this.assert(assertion, throwMessage, throwMessageNegative, value)

    function compareCSSValue(a, b) {
      const rootFontSize = window
        .getComputedStyle(document.documentElement)['font-size'].replace('px', '')
        || '16'

      a = a
        .split(' ')
        .map(parseToPixel)
        .join(' ')

      b = b
        .split(' ')
        .map(parseToPixel)
        .join(' ')

      if (b.includes('auto')) {
        const reg = new RegExp(b.replace(/auto/g, '(\\d+(.\\d+)?px|auto)'))
        return reg.test(a)
      } else {
        return a === b
      }

      function parseToPixel(value) {
        const elementFontSize = style.fontSize.replace(cssUnit, '')// || rootFontSize

        const number = Number(value.replace(cssUnit, ''))
        const isNumber = !isNaN(value) || !isNaN(number)

        if (isNumber) {
          switch (true) {
            case /\dem$/.test(value):
              value = number * elementFontSize
              break
            case /\drem$/.test(value):
              value = number * rootFontSize
              break
            case /\dvh$/.test(value):
              value = parseInt((number / 100) * document.documentElement.clientHeight)
              break
            case /\dvw$/.test(value):
              value = parseInt((number / 100) * document.documentElement.clientWidth)
              break
            default:
              value = number
          }
          return `${value}px`
        }

        return value
      }
    }
  })
}

<|endoftext|>


<commit_before>const _ = require('lodash');

const {isNumber} = require('../../lib/utils');
const {CURRENT_SEASON} = require('../../lib/constants');

const RECORD_REGEX = /^\d{1,2}-\d{1,2}$/;
const RECORD_REGEX_WITH_TIES = /^\d{1,2}-\d{1,2}-\d{1,2}$/;

const _parseRecord = (record) => {
  const recordTokens = record.split('-');

  const winCount = Number(recordTokens[0]);
  const lossCount = Number(recordTokens[1]);
  const tieCount = recordTokens.length === 2 ? 0 : Number(recordTokens[2]);

  return [winCount, lossCount, tieCount];
};

module.exports = (
  {records, season, isHomeGame, weekIndex, completedGameCountForSeason},
  assert,
  ignoredAssert
) => {
  const wrappedAssert = (statement, message) => {
    assert(statement, message, {
      records,
      isHomeGame,
      weekIndex,
      completedGameCountForSeason,
    });
  };

  const wrappedIgnoredAssert = (statement, message) => {
    ignoredAssert(statement, message, {
      records,
      isHomeGame,
      weekIndex,
      completedGameCountForSeason,
    });
  };

  if (season <= CURRENT_SEASON) {
    if (season < 2018) {
      // TODO: Fully enable this assert when all completed games have records.
      wrappedIgnoredAssert(
        typeof records !== 'undefined',
        `Current or former season game should have records object.`
      );
    } else {
      wrappedAssert(
        typeof records !== 'undefined',
        `Current or former season game should have records object.`
      );

      if (typeof records !== 'undefined') {
        wrappedAssert(
          _.isEqual(_.keys(records).sort(), ['home', 'away'].sort()),
          'Records object has unexpected keys.'
        );

        ['home', 'away'].forEach((homeOrAway) => {
          const isNdRecord = isHomeGame ? homeOrAway === 'home' : homeOrAway === 'away';
          const homeOrAwayRecords = records[homeOrAway];
          if (typeof homeOrAwayRecords !== 'undefined') {
            // TODO: Backfill neutral site records and make this a strict equality check.
            wrappedAssert(
              Object.keys(homeOrAwayRecords).every((val) =>
                ['home', 'away', 'neutral', 'overall'].includes(val)
              ),
              `${_.capitalize(homeOrAway)} record has unexpected keys.`
            );

            // Validate home, away, neutral, and overall records.
            _.forEach(homeOrAwayRecords, (currentRecord, homeAwayNeutralOrOverall) => {
              wrappedAssert(
                currentRecord.match(RECORD_REGEX) || currentRecord.match(RECORD_REGEX_WITH_TIES),
                `${_.capitalize(homeOrAway)} ${homeAwayNeutralOrOverall} record has invalid format.`
              );

              const [winCount, lossCount, tieCount] = _parseRecord(currentRecord);

              wrappedAssert(
                isNumber(winCount) && winCount >= 0,
                `${_.capitalize(
                  homeOrAway
                )} ${homeAwayNeutralOrOverall} record has unexpected wins value.`
              );

              wrappedAssert(
                isNumber(lossCount) && lossCount >= 0,
                `${_.capitalize(
                  homeOrAway
                )} ${homeAwayNeutralOrOverall} record has unexpected losses value.`
              );

              wrappedAssert(
                isNumber(tieCount) && tieCount >= 0,
                `${_.capitalize(
                  homeOrAway
                )} ${homeAwayNeutralOrOverall} record has unexpected ties value.`
              );

              if (homeAwayNeutralOrOverall === 'overall') {
                // The number of games Notre Dame has played should be the minimum of the week
                // index (which is 0-indexed; for weeks with completed games) or the completed
                // game count (for upcoming games).
                const ndExpectedGamesPlayed = Math.min(weekIndex + 1, completedGameCountForSeason);

                const gamesPlayedCountFromRecord = winCount + lossCount + tieCount;

                if (isNdRecord) {
                  // ND's actual games played count from their record should equal their expected
                  // games played count.
                  wrappedAssert(
                    gamesPlayedCountFromRecord === ndExpectedGamesPlayed,
                    `${_.capitalize(
                      homeOrAway
                    )} (ND) overall record has unexpected number of games.`
                  );
                } else {
                  // Opponent's actual games played count from their record should be no more than
                  // 1 away from the ND's expected games played count.
                  wrappedAssert(
                    Math.abs(gamesPlayedCountFromRecord - ndExpectedGamesPlayed) <= 1,
                    `${_.capitalize(
                      homeOrAway
                    )} (opponent) overall record has unexpected number of games.`
                  );
                }

                const [awayWinCount, awayLossCount, awayTieCount] = _parseRecord(
                  records[homeOrAway].away
                );
                const [homeWinCount, homeLossCount, homeTieCount] = _parseRecord(
                  records[homeOrAway].home
                );
                const [neutralWinCount, neutralLossCount, neutralTieCount] = _parseRecord(
                  // TODO: Backfill neutral site records and remove the hardcoded 0-0 record.
                  records[homeOrAway].neutral || '0-0'
                );

                wrappedAssert(
                  gamesPlayedCountFromRecord ===
                    awayWinCount +
                      awayLossCount +
                      awayTieCount +
                      homeWinCount +
                      homeLossCount +
                      homeTieCount +
                      neutralWinCount +
                      neutralLossCount +
                      neutralTieCount,
                  `${_.capitalize(
                    homeOrAway
                  )} overall record has different games played count than their away, home, and neutral records combined.`
                );
              }
            });
          }
        });
      }
    }
  } else {
    wrappedAssert(
      typeof records === 'undefined',
      'Future season game should not have records object.'
    );
  }
};
<commit_msg>Exclude some validation which is failing due to COVID<commit_after>const _ = require('lodash');

const {isNumber} = require('../../lib/utils');
const {CURRENT_SEASON} = require('../../lib/constants');

const RECORD_REGEX = /^\d{1,2}-\d{1,2}$/;
const RECORD_REGEX_WITH_TIES = /^\d{1,2}-\d{1,2}-\d{1,2}$/;

const _parseRecord = (record) => {
  const recordTokens = record.split('-');

  const winCount = Number(recordTokens[0]);
  const lossCount = Number(recordTokens[1]);
  const tieCount = recordTokens.length === 2 ? 0 : Number(recordTokens[2]);

  return [winCount, lossCount, tieCount];
};

module.exports = (
  {records, season, isHomeGame, weekIndex, completedGameCountForSeason},
  assert,
  ignoredAssert
) => {
  const wrappedAssert = (statement, message) => {
    assert(statement, message, {
      records,
      isHomeGame,
      weekIndex,
      completedGameCountForSeason,
    });
  };

  const wrappedIgnoredAssert = (statement, message) => {
    ignoredAssert(statement, message, {
      records,
      isHomeGame,
      weekIndex,
      completedGameCountForSeason,
    });
  };

  if (season <= CURRENT_SEASON) {
    if (season < 2018) {
      // TODO: Fully enable this assert when all completed games have records.
      wrappedIgnoredAssert(
        typeof records !== 'undefined',
        `Current or former season game should have records object.`
      );
    } else {
      wrappedAssert(
        typeof records !== 'undefined',
        `Current or former season game should have records object.`
      );

      if (typeof records !== 'undefined') {
        wrappedAssert(
          _.isEqual(_.keys(records).sort(), ['home', 'away'].sort()),
          'Records object has unexpected keys.'
        );

        ['home', 'away'].forEach((homeOrAway) => {
          const isNdRecord = isHomeGame ? homeOrAway === 'home' : homeOrAway === 'away';
          const homeOrAwayRecords = records[homeOrAway];
          if (typeof homeOrAwayRecords !== 'undefined') {
            // TODO: Backfill neutral site records and make this a strict equality check.
            wrappedAssert(
              Object.keys(homeOrAwayRecords).every((val) =>
                ['home', 'away', 'neutral', 'overall'].includes(val)
              ),
              `${_.capitalize(homeOrAway)} record has unexpected keys.`
            );

            // Validate home, away, neutral, and overall records.
            _.forEach(homeOrAwayRecords, (currentRecord, homeAwayNeutralOrOverall) => {
              wrappedAssert(
                currentRecord.match(RECORD_REGEX) || currentRecord.match(RECORD_REGEX_WITH_TIES),
                `${_.capitalize(homeOrAway)} ${homeAwayNeutralOrOverall} record has invalid format.`
              );

              const [winCount, lossCount, tieCount] = _parseRecord(currentRecord);

              wrappedAssert(
                isNumber(winCount) && winCount >= 0,
                `${_.capitalize(
                  homeOrAway
                )} ${homeAwayNeutralOrOverall} record has unexpected wins value.`
              );

              wrappedAssert(
                isNumber(lossCount) && lossCount >= 0,
                `${_.capitalize(
                  homeOrAway
                )} ${homeAwayNeutralOrOverall} record has unexpected losses value.`
              );

              wrappedAssert(
                isNumber(tieCount) && tieCount >= 0,
                `${_.capitalize(
                  homeOrAway
                )} ${homeAwayNeutralOrOverall} record has unexpected ties value.`
              );

              if (homeAwayNeutralOrOverall === 'overall') {
                // The number of games Notre Dame has played should be the minimum of the week
                // index (which is 0-indexed; for weeks with completed games) or the completed
                // game count (for upcoming games).
                const ndExpectedGamesPlayed = Math.min(weekIndex + 1, completedGameCountForSeason);

                const gamesPlayedCountFromRecord = winCount + lossCount + tieCount;

                if (isNdRecord) {
                  // ND's actual games played count from their record should equal their expected
                  // games played count.
                  wrappedAssert(
                    gamesPlayedCountFromRecord === ndExpectedGamesPlayed,
                    `${_.capitalize(
                      homeOrAway
                    )} (ND) overall record has unexpected number of games.`
                  );
                } else {
                  // Opponent's actual games played count from their record should be no more than
                  // 1 away from the ND's expected games played count.
                  // Exlude 2020 because COVID caused so many postponements.
                  if (season !== 2020) {
                    wrappedAssert(
                      Math.abs(gamesPlayedCountFromRecord - ndExpectedGamesPlayed) <= 1,
                      `${_.capitalize(
                        homeOrAway
                      )} (opponent) overall record has unexpected number of games.`
                    );
                  }
                }

                const [awayWinCount, awayLossCount, awayTieCount] = _parseRecord(
                  records[homeOrAway].away
                );
                const [homeWinCount, homeLossCount, homeTieCount] = _parseRecord(
                  records[homeOrAway].home
                );
                const [neutralWinCount, neutralLossCount, neutralTieCount] = _parseRecord(
                  // TODO: Backfill neutral site records and remove the hardcoded 0-0 record.
                  records[homeOrAway].neutral || '0-0'
                );

                wrappedAssert(
                  gamesPlayedCountFromRecord ===
                    awayWinCount +
                      awayLossCount +
                      awayTieCount +
                      homeWinCount +
                      homeLossCount +
                      homeTieCount +
                      neutralWinCount +
                      neutralLossCount +
                      neutralTieCount,
                  `${_.capitalize(
                    homeOrAway
                  )} overall record has different games played count than their away, home, and neutral records combined.`
                );
              }
            });
          }
        });
      }
    }
  } else {
    wrappedAssert(
      typeof records === 'undefined',
      'Future season game should not have records object.'
    );
  }
};
<|endoftext|>


<commit_before>const messages = {
    after: (field, [target]) => `${field}는 ${target} 뒤에 와야 합니다.`,
    alpha_dash: (field) => `${field}는 영문자와 숫자 그리고 대시, 언더스코어를 사용할 수 있습니다.`,
    alpha_num: (field) => `${field}는 영문자와 숫자만 사용할 수 있습니다.`,
    alpha_spaces: (field) => `${field}는 영문자와 공백만 사용할 수 있습니다.`,
    alpha: (field) => `${field}는 영문자만 사용할 수 있습니다.`,
    before: (field, [target]) => `${field}는 ${target} 앞에 와야 합니다.`,
    between: (field, [min, max]) => `${field}는 ${min} 와 ${max} 사이 값이어야 합니다.`,
    confirmed: (field, [confirmedField]) => `${field}는 ${confirmedField}와 일치하지 않습니다.`,
    date_between: (field, [min, max]) => `${field}는 ${min}와 ${max} 사이의 날짜이어야 합니다.`,
    date_format: (field, [format]) => `${field}는 ${format} 형식이어야 합니다.`,
    decimal: (field, [decimals] = ['*']) => `${field}는 숫자이어야 하고 ${decimals === '*' ? '' : decimals} 소숫점을 가질 수 있습니다.`,
    digits: (field, [length]) => `${field}는 숫자이고 ${length} 길이를 필요합니다.`,
    dimensions: (field, [width, height]) => `${field}는 ${width}px과 ${height}px 이어야 합니다.`,
    email: (field) => `${field}는 올바른 이메일 형식이어야 합니다.`,
    ext: (field) => `${field}는 올바른 파일 형식이어야 합니다.`,
    image: (field) => `${field}는 이미지 파일이어야 합니다.`,
    in: (field) => `${field}는 올바른 값이어야 합니다.`,
    ip: (field) => `${field}는 올바른 IP 주소이어야 합니다.`,
    max: (field, [length]) => `${field}는 ${length}보다 길어야 합니다.`,
    max_value: (field, [max]) => `${field}는 최대한 ${max} 보다 작어야 합니다.`,
    mimes: (field) => `${field}는 올바른 파일이어야 합니다.`,
    min: (field, [length]) => `${field}는 최소한 ${length} 보다 커야 합니다.`,
    min_value: (field, [min]) => `${field} ${min} 보다 커야합니다.`,
    not_in: (field) => `${field}는 올바른 값이어야 합니다.`,
    numeric: (field) => `${field}는 영문자이어야 합니다.`,
    regex: (field) => `${field}는 형식에 맞지 않습니다.`,
    required: (field) => `${field}가 필요합니다.`,
    size: (field, [size]) => `${field}는 ${size} KB 보다 작아야 합니다.`,
    url: (field) => `${field}는 올바른 URL이 아닙니다.`
};

const locale = {
    name: 'ko',
    messages,
    attributes: {}
};

if (typeof VeeValidate !== 'undefined' && VeeValidate && typeof VeeValidate.Validator) {
    VeeValidate.Validator.addLocale(locale);
}

export default locale;
<commit_msg>Update ko.js<commit_after>const messages = {
    after: (field, [target]) => `${field}항목은 ${target}항목 뒤에 와야 합니다.`,
    alpha_dash: (field) => `${field}항목은 문자와 숫자 그리고 대시, 언더스코어를 사용할 수 있습니다.`,
    alpha_num: (field) => `${field}항목은 영문자와 숫자만 사용할 수 있습니다.`,
    alpha_spaces: (field) => `${field}항목은 영문자와 공백만 사용할 수 있습니다.`,
    alpha: (field) => `${field}항목은 영문자만 사용할 수 있습니다.`,
    before: (field, [target]) => `${field}항목은 ${target}항목의 앞에 와야 합니다.`,
    between: (field, [min, max]) => `${field}항목은 ${min} 와 ${max} 사이 값이어야 합니다.`,
    confirmed: (field, [confirmedField]) => `${field}의 항목이 ${confirmedField}와 일치하지 않습니다.`,
    date_between: (field, [min, max]) => `${field}항목은 ${min}와 ${max} 사이의 날짜이어야 합니다.`,
    date_format: (field, [format]) => `${field}항목은 ${format} 형식이어야 합니다.`,
    decimal: (field, [decimals] = ['*']) => `${field}항목은 숫자이어야 하고 ${decimals === '*' ? '' : decimals} 소숫점을 가질 수 있습니다.`,
    digits: (field, [length]) => `${field}항목은 숫자이고 ${length}글자를 필요합니다.`,
    dimensions: (field, [width, height]) => `${field}의 사진 크기는 ${width}px과 ${height}px 이어야 합니다.`,
    email: (field) => `${field}항목은 올바른 이메일 형식이어야 합니다.`,
    ext: (field) => `${field}항목은 올바른 파일 형식이어야 합니다.`,
    image: (field) => `${field}항목은 이미지 파일이어야 합니다.`,
    in: (field) => `${field}항목은 올바른 값이어야 합니다.`,
    ip: (field) => `${field}항목은 올바른 IP 주소이어야 합니다.`,
    max: (field, [length]) => `${field}항목은 ${length}글자보다 작아야 합니다.`,
    max_value: (field, [max]) => `${field}는 최대한 ${max} 보다 작어야 합니다.`,
    mimes: (field) => `${field}는 올바른 파일이어야 합니다.`,
    min: (field, [length]) => `${field}는 최소한 ${length}글자보다 커야 합니다.`,
    min_value: (field, [min]) => `${field} ${min} 보다 커야합니다.`,
    not_in: (field) => `${field}항목은 올바른 값이어야 합니다.`,
    numeric: (field) => `${field}항목은 영문자이어야 합니다.`,
    regex: (field) => `${field}항목은 형식에 맞지 않습니다.`,
    required: (field) => `${field}항목이 필요합니다.`,
    size: (field, [size]) => `${field}항목의 크기는 ${size} KB 보다 작아야 합니다.`,
    url: (field) => `${field}항목은 올바른 주소(URL)가 아닙니다.`
};

const locale = {
    name: 'ko',
    messages,
    attributes: {}
};

if (typeof VeeValidate !== 'undefined' && VeeValidate && typeof VeeValidate.Validator) {
    VeeValidate.Validator.addLocale(locale);
}

export default locale;
<|endoftext|>


<commit_before>// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview The module loader which uses the BulkLoader to load the URIs.
 *
 *
 */

goog.provide('goog.module.ModuleLoader');

goog.require('goog.array');
goog.require('goog.debug.Logger');
goog.require('goog.dom');
goog.require('goog.events.EventHandler');
goog.require('goog.module.BaseModuleLoader');
goog.require('goog.net.BulkLoader');
goog.require('goog.net.EventType');
goog.require('goog.userAgent');

/**
 * A class that loads Javascript modules.
 * @constructor
 * @extends {goog.module.BaseModuleLoader}
 */
goog.module.ModuleLoader = function() {
  goog.module.BaseModuleLoader.call(this);

  /**
   * Event handler for managing handling events.
   * @type {goog.events.EventHandler}
   * @private
   */
  this.eventHandler_ = new goog.events.EventHandler(this);
};
goog.inherits(goog.module.ModuleLoader, goog.module.BaseModuleLoader);

/**
 * A logger.
 * @type {goog.debug.Logger}
 * @protected
 */
goog.module.ModuleLoader.prototype.logger = goog.debug.Logger.getLogger(
    'goog.module.ModuleLoader');

/** @inheritDoc */
goog.module.ModuleLoader.prototype.loadModulesInternal = function(
    ids, moduleInfoMap, opt_successFn, opt_errorFn, opt_timeoutFn,
    opt_forceReload) {
  var uris = [];
  for (var i = 0; i < ids.length; i++) {
    goog.array.extend(uris, moduleInfoMap[ids[i]].getUris());
  }
  this.logger.info('loadModules ids:' + ids + ' uris:' + uris);

  // In prod, we don't load via a script tag because it is difficult to
  // determine if the script has been loaded and to handle errors conditions.
  if (this.getDebugMode()) {
    this.loadModulesInDebugMode_(uris);
  } else {
    var bulkLoader = new goog.net.BulkLoader(uris);
    var eventHandler = this.eventHandler_;
    eventHandler.listen(
        bulkLoader,
        goog.net.EventType.SUCCESS,
        goog.bind(this.handleSuccess, this, bulkLoader, ids,
            opt_successFn, opt_errorFn),
        false,
        null);
    eventHandler.listen(
        bulkLoader,
        goog.net.EventType.ERROR,
        goog.bind(this.handleError, this, bulkLoader, ids, opt_errorFn),
        false,
        null);
    // TODO(user): Need to handle timeouts in the module loading code.

    bulkLoader.load();
  }
};

/**
 * Loads and evaluates the JavaScript files at the specified URIs, in order.
 * This method uses <script> tags rather than XHRs to load the files. This
 * makes it possible to debug and inspect stack traces more easily. It's also
 * possible to use it to load JavaScript files that are hosted on another
 * domain.
 * @param {Array.<string>} uris The URIs to load.
 * @private
 */
goog.module.ModuleLoader.prototype.loadModulesInDebugMode_ = function(uris) {
  if (!uris.length) {
    return;
  }

  var createScript = function(uri) {
    var scriptEl = goog.dom.createElement('script');
    scriptEl.src = uri;
    scriptEl.type = 'text/javascript';
    return scriptEl;
  };

  var documentElement = document.documentElement;
  if (goog.userAgent.GECKO) {
    // For <script> tags that are loaded in this manner, Gecko ensures that
    // tag order is consistent with evaluation order. Unfortunately, other
    // browsers do not make that guarantee. So the other browsers need a slower
    // and more complex implementation.
    for (var i = 0; i < uris.length; i++) {
      var scriptEl = createScript(uris[i]);
      documentElement.appendChild(scriptEl);
    }
  } else {
    var popAndLoadNextScript = function() {
      var uri = uris.shift();
      var scriptEl = createScript(uri);
      if (uris.length) {
        if (goog.userAgent.IE) {
          scriptEl.onreadystatechange = function() {
            if (!this.readyState || this.readyState == 'loaded' ||
                this.readyState == 'complete') {
              // Guard against redundant state changes.
              scriptEl.onreadystatechange = goog.nullFunction;
              popAndLoadNextScript();
            }
          };
        } else {
          scriptEl.onload = popAndLoadNextScript;
        }
      }
      documentElement.appendChild(scriptEl);
    };
    popAndLoadNextScript();
  }
};

/**
 * Handles a successful response to a request for one or more modules.
 *
 * @param {goog.net.BulkLoader} bulkLoader The bulk loader.
 * @param {Array.<string>} moduleIds The ids of the modules requested.
 * @param {function()} successFn The callback for success.
 * @param {function(?number)} errorFn The callback for error.
 */
goog.module.ModuleLoader.prototype.handleSuccess = function(
    bulkLoader, moduleIds, successFn, errorFn) {
  var jsCode = bulkLoader.getResponseTexts().join('\n');

  this.handleRequestSuccess(jsCode, moduleIds, successFn, errorFn);

  // NOTE: A bulk loader instance is used for loading a set of module ids. Once
  // these modules have been loaded succesfully or in error the bulk loader
  // should be disposed as it is not needed anymore. A new bulk loader is
  // instantiated for any new modules to be loaded. The dispose is called
  // on a timer so that the bulkloader has a chance to release its
  // objects.
  goog.Timer.callOnce(bulkLoader.dispose, 5, bulkLoader);
};

/**
 * Handles an error during a request for one or more modules.
 * @param {goog.net.BulkLoader} bulkLoader The bulk loader.
 * @param {Array.<string>} moduleIds The ids of the modules requested.
 * @param {function(?number)} errorFn The function to call on failure.
 * @param {number} status The response status.
 */
goog.module.ModuleLoader.prototype.handleError = function(
    bulkLoader, moduleIds, errorFn, status) {
  this.handleRequestError(moduleIds, errorFn, status);

  // NOTE: A bulk loader instance is used for loading a set of module ids. Once
  // these modules have been loaded succesfully or in error the bulk loader
  // should be disposed as it is not needed anymore. A new bulk loader is
  // instantiated for any new modules to be loaded. The dispose is called
  // on another thread so that the bulkloader has a chance to release its
  // objects.
  goog.Timer.callOnce(bulkLoader.dispose, 5, bulkLoader);
};

/** @inheritDoc */
goog.module.ModuleLoader.prototype.disposeInternal = function() {
  goog.module.ModuleLoader.superClass_.disposeInternal.call(this);

  this.eventHandler_.dispose();
  this.eventHandler_ = null;
};
<commit_msg><commit_after>// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview The module loader which uses the BulkLoader to load the URIs.
 *
 *
 */

goog.provide('goog.module.ModuleLoader');

goog.require('goog.array');
goog.require('goog.debug.Logger');
goog.require('goog.dom');
goog.require('goog.events.EventHandler');
goog.require('goog.module.BaseModuleLoader');
goog.require('goog.net.BulkLoader');
goog.require('goog.net.EventType');
goog.require('goog.userAgent');

/**
 * A class that loads Javascript modules.
 * @constructor
 * @extends {goog.module.BaseModuleLoader}
 */
goog.module.ModuleLoader = function() {
  goog.module.BaseModuleLoader.call(this);

  /**
   * Event handler for managing handling events.
   * @type {goog.events.EventHandler}
   * @private
   */
  this.eventHandler_ = new goog.events.EventHandler(this);
};
goog.inherits(goog.module.ModuleLoader, goog.module.BaseModuleLoader);

/**
 * A logger.
 * @type {goog.debug.Logger}
 * @protected
 */
goog.module.ModuleLoader.prototype.logger = goog.debug.Logger.getLogger(
    'goog.module.ModuleLoader');

/** @inheritDoc */
goog.module.ModuleLoader.prototype.loadModulesInternal = function(
    ids, moduleInfoMap, opt_successFn, opt_errorFn, opt_timeoutFn,
    opt_forceReload) {
  var uris = [];
  for (var i = 0; i < ids.length; i++) {
    goog.array.extend(uris, moduleInfoMap[ids[i]].getUris());
  }
  this.logger.info('loadModules ids:' + ids + ' uris:' + uris);

  // In prod, we don't load via a script tag because it is difficult to
  // determine if the script has been loaded and to handle errors conditions.
  if (this.getDebugMode()) {
    this.loadModulesInDebugMode_(uris);
  } else {
    var bulkLoader = new goog.net.BulkLoader(uris);
    var eventHandler = this.eventHandler_;
    eventHandler.listen(
        bulkLoader,
        goog.net.EventType.SUCCESS,
        goog.bind(this.handleSuccess, this, bulkLoader, ids,
            opt_successFn, opt_errorFn),
        false,
        null);
    eventHandler.listen(
        bulkLoader,
        goog.net.EventType.ERROR,
        goog.bind(this.handleError, this, bulkLoader, ids, opt_errorFn),
        false,
        null);
    // TODO(user): Need to handle timeouts in the module loading code.

    bulkLoader.load();
  }
};

/**
 * Loads and evaluates the JavaScript files at the specified URIs, in order.
 * This method uses <script> tags rather than XHRs to load the files. This
 * makes it possible to debug and inspect stack traces more easily. It's also
 * possible to use it to load JavaScript files that are hosted on another
 * domain.
 * @param {Array.<string>} uris The URIs to load.
 * @private
 */
goog.module.ModuleLoader.prototype.loadModulesInDebugMode_ = function(uris) {
  if (!uris.length) {
    return;
  }

  var createScript = function(uri) {
    var scriptEl = goog.dom.createElement('script');
    scriptEl.src = uri;
    scriptEl.type = 'text/javascript';
    return scriptEl;
  };

  // If IE6 or 7 is still parsing the document, appending to the document
  // element will lead to an operation aborted alert. If possible, try to find
  // a head element to append on to make this a bit more idiot-proof.
  var scriptParent = document.getElementsByTagName('head')[0] ||
      document.documentElement;
  if (goog.userAgent.GECKO) {
    // For <script> tags that are loaded in this manner, Gecko ensures that
    // tag order is consistent with evaluation order. Unfortunately, other
    // browsers do not make that guarantee. So the other browsers need a slower
    // and more complex implementation.
    for (var i = 0; i < uris.length; i++) {
      var scriptEl = createScript(uris[i]);
      scriptParent.appendChild(scriptEl);
    }
  } else {
    var popAndLoadNextScript = function() {
      var uri = uris.shift();
      var scriptEl = createScript(uri);
      if (uris.length) {
        if (goog.userAgent.IE) {
          scriptEl.onreadystatechange = function() {
            if (!this.readyState || this.readyState == 'loaded' ||
                this.readyState == 'complete') {
              // Guard against redundant state changes.
              scriptEl.onreadystatechange = goog.nullFunction;
              popAndLoadNextScript();
            }
          };
        } else {
          scriptEl.onload = popAndLoadNextScript;
        }
      }
      scriptParent.appendChild(scriptEl);
    };
    popAndLoadNextScript();
  }
};

/**
 * Handles a successful response to a request for one or more modules.
 *
 * @param {goog.net.BulkLoader} bulkLoader The bulk loader.
 * @param {Array.<string>} moduleIds The ids of the modules requested.
 * @param {function()} successFn The callback for success.
 * @param {function(?number)} errorFn The callback for error.
 */
goog.module.ModuleLoader.prototype.handleSuccess = function(
    bulkLoader, moduleIds, successFn, errorFn) {
  var jsCode = bulkLoader.getResponseTexts().join('\n');

  this.handleRequestSuccess(jsCode, moduleIds, successFn, errorFn);

  // NOTE: A bulk loader instance is used for loading a set of module ids. Once
  // these modules have been loaded succesfully or in error the bulk loader
  // should be disposed as it is not needed anymore. A new bulk loader is
  // instantiated for any new modules to be loaded. The dispose is called
  // on a timer so that the bulkloader has a chance to release its
  // objects.
  goog.Timer.callOnce(bulkLoader.dispose, 5, bulkLoader);
};

/**
 * Handles an error during a request for one or more modules.
 * @param {goog.net.BulkLoader} bulkLoader The bulk loader.
 * @param {Array.<string>} moduleIds The ids of the modules requested.
 * @param {function(?number)} errorFn The function to call on failure.
 * @param {number} status The response status.
 */
goog.module.ModuleLoader.prototype.handleError = function(
    bulkLoader, moduleIds, errorFn, status) {
  this.handleRequestError(moduleIds, errorFn, status);

  // NOTE: A bulk loader instance is used for loading a set of module ids. Once
  // these modules have been loaded succesfully or in error the bulk loader
  // should be disposed as it is not needed anymore. A new bulk loader is
  // instantiated for any new modules to be loaded. The dispose is called
  // on another thread so that the bulkloader has a chance to release its
  // objects.
  goog.Timer.callOnce(bulkLoader.dispose, 5, bulkLoader);
};

/** @inheritDoc */
goog.module.ModuleLoader.prototype.disposeInternal = function() {
  goog.module.ModuleLoader.superClass_.disposeInternal.call(this);

  this.eventHandler_.dispose();
  this.eventHandler_ = null;
};
<|endoftext|>


<commit_before>// Database data, should not be changed except when refreshing
var database = null;

// Tracking data
var currentQuestions = [];
var currentSpecies = [];
var currentAnswers = {};
var newAnswers = {};
var currentBug = {};

function start() {
    reset();
    fetchData(nextQuestion);
}

function reset() {
    $('#main').empty();
    database = null;
    currentQuestions = [];
    currentSpecies = [];
    currentBug = {};
    currentAnswers = {};
    newAnswers = {};
}

function fetchData(callback) {
    $('body').addClass("loading");
    $.ajax({
        url: "data.php",
        dataType: 'json'
    })
    .done(function(data) {
        if (!data || !data.success) {
            showRetry("Error loading data from database, sorry!", data.message);
        } else {
            setDatabase(data);
            callback();
        }
    })
    .fail(function() {
        showRetry("Error loading data from database, sorry!", 'Communications Failure');
    })
    .always(function() {
        $('body').removeClass("loading");
    });
}

function showRetry(message, title) {
    var mainDiv = $('#main');
    mainDiv.empty();
    mainDiv.append($('
').text(message).prop('title', title));
    var retryButton = $('<button type="button"/>').text("Try Again").click(function() {
        start();
    });
    var retryDiv = $('
');
    retryDiv.append(retryButton);
    mainDiv.append(retryDiv);
}

function showStartOver(message) {
    var mainDiv = $('#main');
    mainDiv.empty();
    mainDiv.append($('
').text(message));
    var retryButton = $('<button type="button"/>').text("Start Over").click(function() {
        start();
    });
    var retryDiv = $('
');
    retryDiv.append(retryButton);
    mainDiv.append(retryDiv);
}

function setDatabase(data) {
    database = data;
    currentQuestions = database.questions.slice();
    currentSpecies = database.species.slice();
}

function nextQuestion() {
    var mainDiv = $('#main');
    mainDiv.empty();
    if (currentQuestions.length == 0 || currentSpecies.length <= 1) {
        foundMatch();
        return;
    }

    var instructionsSpan = $('
').text("Let's answer some questions so I can learn about your bug! I may be able to guess what you have.");
    mainDiv.append(instructionsSpan);

    var questionIndex = Math.floor(Math.random() * currentQuestions.length);
    var question = currentQuestions[questionIndex];
    currentQuestions.splice(questionIndex, 1);

    // This should never happen, but you know.
    if (!question.hasOwnProperty('answers')) {
        nextQuestion();
        return;
    }

    var questionSpan = $('
').text(question.question);
    mainDiv.append(questionSpan);
    var remainingAnswers = jQuery.extend({}, database.answers);
    for (var i = 0; i < question.answers.length; i++) {
        var answer = database.answers[question.answers[i]];
        delete remainingAnswers[question.answers[i]];
        var answerSpan = $('
').text(answer.answer);
        answerSpan.click(function(answerId) {
            return function() { answerQuestion(question.id, answerId); };
        }(answer.id));
        mainDiv.append(answerSpan);
    }
    var customAnswers = [];
    for (var key in remainingAnswers) {
        if (remainingAnswers.hasOwnProperty(key)) {
            customAnswers.push(remainingAnswers[key].answer);
        }
    }
    var customAnswerSpan = $('
');
    var answerInput = $('<input id="newAnswer" type="text" size="30" placeholder="(Other Answer)"/>')
        .autocomplete({source: customAnswers})
        .keypress(function(e) {
            if (e.keyCode == $.ui.keyCode.ENTER) {
                newAnswer(question.id, $('#newAnswer').val());
            }
        });
    var answerButton = $('<button type="button"/>').text("Answer").click(function() {
        newAnswer(question.id, $('#newAnswer').val());
    });
    customAnswerSpan.append(answerInput);
    customAnswerSpan.append(answerButton);
    mainDiv.append(customAnswerSpan);
}

function newAnswer(questionId, answer) {
    if (answer.length < 2) {
        showAlert('Please enter an answer');
        return;
    }
    if (answer.length > 255) {
        showAlert('That answer is too long, please shorten it');
        return;
    }
    var oldSpecies = currentSpecies;
    currentSpecies = [];
    for (var i = 0; i < oldSpecies.length;i++) {
        var species = oldSpecies[i];
        if (!species.questions.hasOwnProperty(questionId)) {
            currentSpecies.push(species);
        }
    }
    newAnswers[questionId] = answer;
    nextQuestion();
}

function answerQuestion(questionId, answerId) {
    var oldSpecies = currentSpecies;
    currentSpecies = [];
    for (var i = 0; i < oldSpecies.length;i++) {
        var species = oldSpecies[i];
        if (species.questions.hasOwnProperty(questionId) && species.questions[questionId] == answerId) {
            currentSpecies.push(species);
        }
    }
    currentAnswers[questionId] = answerId;
    nextQuestion();
}

function foundMatch() {
    if (currentSpecies.length > 0) {
        var species = currentSpecies[0];
        var speciesDiv = $('
');
        var speciesName = species.name;
        if (species.common_name) {
            speciesName = species.common_name + ' (' + speciesName + ')';
        }
        var nameDiv = $('
').text(speciesName);
        speciesDiv.append(nameDiv);

        if (species.image_url) {
            var imageLink = $('');
            var imageDiv = $('
');
            imageLink.append($(''));
            imageDiv.append(imageLink);
            speciesDiv.append(imageDiv);
        }
        if (species.wiki_url) {
            var wikiDiv = $('
').append($('').text("Full Wikipedia Article"));
            speciesDiv.append(wikiDiv);
        }
        if (species.description) {
            var descriptionDiv = $('
').html(species.description);
            speciesDiv.append(descriptionDiv);
        }

        var askContainer = $('
');
        var askDiv = $('
').text("Is this your bug?");
        askContainer.append(askDiv);

        var yesButton = $('<button type="button"/>').text("Yes").click(function() {
            alert("COOL!");
        });
        var noButton = $('<button type="button"/>').text("No").click(function() {
            noMoreQuestions();
        });
        askContainer.append(yesButton);
        askContainer.append(noButton);
        speciesDiv.append(askContainer);

        $('#main').append(speciesDiv);
    } else {
        noMoreQuestions();
    }
}

function noMoreQuestions() {
    var mainDiv = $('#main');
    mainDiv.empty();
    var introMessage = database.questions.length == 0 ? "I don't know anything yet! Can you help me learn?" : "I've run out of questions! Can you help me learn?";
    var askDiv = $('
').text(introMessage);
    mainDiv.append(askDiv);

    var nameDiv = $('
').text("What is the name of your bug?");
    mainDiv.append(nameDiv);

    var nameInput = $('<input id="name" size="50" placeholder="(Type Name Here)"/>');
    mainDiv.append(nameInput);
    nameInput.keypress(function(e) {
        if (e.keyCode == $.ui.keyCode.ENTER) {
            nameBug();
        }
    });

    var submitButton = $('<button type="button"/>').text("Name My Bug").click(function() {
        nameBug();
    });
    var submitDiv = $('
');
    submitDiv.append(submitButton);
    mainDiv.append(submitDiv);
    appendFactSection(mainDiv);
}

function appendFactSection(mainDiv)
{
    var answerCount = 0;
    var answers = {};
    for (var currentAnswerKey in currentAnswers) {
        if (currentAnswers.hasOwnProperty(currentAnswerKey)) {
            answerCount++;
            answers[database.question_map[currentAnswerKey].question] = database.answers[currentAnswers[currentAnswerKey]].answer;
        }
    }
    for (var newAnswerKey in newAnswers) {
        if (newAnswers.hasOwnProperty(newAnswerKey)) {
            answerCount++;
            answers[database.question_map[newAnswerKey].question] = newAnswers[newAnswerKey];
        }
    }
    if (answerCount > 0) {
        var plural = answerCount > 1 ? 's' : '';
        var factsLabel = $('
').text(numberToWord(answerCount) + ' fact' + plural + ' about your bug:');
        var factsTable = $('
');
        for (var question in answers) {
            if (answers.hasOwnProperty(question)) {
                var factsRow = $('
');
                var questionCell = $('').text(question);
                var answerCell = $('').text(answers[question]);
                factsRow.append(questionCell);
                factsRow.append(answerCell);
                factsTable.append(factsRow);
            }
        }
        mainDiv.append(factsLabel);
        mainDiv.append(factsTable);
    }
}

function numberToWord(number) {
    switch (number) {
        case 0: return 'Zero';
        case 1: return 'One';
        case 2: return 'Two';
        case 3: return 'Three';
        case 4: return 'Four';
        case 5: return 'Five';
        case 6: return 'Six';
        case 7: return 'Seven';
        case 8: return 'Eight';
        case 9: return 'Nine';
        case 10: return 'Ten';
        case 11: return 'Eleven';
        case 12: return 'Twelve';
        case 13: return 'Thirteen';
        case 14: return 'Fourteen';
        case 15: return 'Fifteen';
    }
    return number;
}

function nameBug() {
    var nameInput = $('#name');
    var bugName = nameInput.val();
    if (bugName.length < 2) {
        showAlert("Please enter a bug name");
        return;
    }
    if (bugName.length > 255) {
        showAlert("Please enter a shorter bug name");
        return;
    }
    loadBug(bugName);
}

function loadBug(title) {
    $('body').addClass("loading");
    $.ajax({
        url: "wiki.php",
        dataType: 'json',
        data: {
            title: title
        }
    })
    .done(function(data) {
        if (!data || !data.success) {
            showAlert("Error loading wiki data - can't save bug, sorry! (" + data.message + ")");
        } else {
            showNewBug(title, data);
        }
    })
    .fail(function() {
        showAlert("Error loading wiki data - can't save bug, sorry!");
    })
    .always(function() {
        $('body').removeClass("loading");
    });
}

function showNewBug(title, wikiData) {
    var currentBug = {
        name: title,
        commonName: null,
        description: null,
        image: null,
        wikiUrl: null
    };

    var mainDiv = $('#main');
    mainDiv.empty();
    var speciesDiv = $('
');
    var nameText = title;
    if (wikiData.hasOwnProperty('redirect')) {
        currentBug.name = wikiData['redirect'];
        currentBug.commonName = title;
        nameText = nameText + " (" + wikiData['redirect'] + ")";
    }
    if (wikiData.hasOwnProperty('wiki')) {
        currentBug.wikiUrl = 'https://en.wikipedia.org/wiki/' + wikiData['wiki'];
    }
    var nameDiv = $('
').text(nameText);
    speciesDiv.append(nameDiv);

    if (wikiData.hasOwnProperty('extract')) {
        var extractDiv = $('
');
        extractDiv.html(wikiData['extract']);
        speciesDiv.append(extractDiv);
        currentBug.description = wikiData['extract'];
    }

    var pickImageDiv = $('
').text("Please choose an image:");
    speciesDiv.append(pickImageDiv);

    var imageContainer = $('
');
    for (var i = 0; i < wikiData.images.length; i++) {
        var imageData = wikiData.images[i];
        var imageDiv = $('
');
        var imageUrl = $('');
        imageDiv.append(imageUrl);
        imageContainer.append(imageDiv);
        imageDiv.click(function(url) {
             return function() {
                 $('.image').removeClass('selected');
                 $(this).addClass('selected');
                 currentBug.image = url;
             }
        }(imageData.url));
    }
    speciesDiv.append(imageContainer);

    var pickQuestionDiv = $('
').text("Please type a question to help me identify this bug:");
    speciesDiv.append(pickQuestionDiv);
    var questionDiv = $('
');
    var questionLabel = $('').text("Question:");
    var questionInput = $('<input id="newQuestion" size="150" placeholder="(Type a Question)"/>');
    questionDiv.append(questionLabel).append(questionInput);
    speciesDiv.append(questionDiv);
    var answerDiv = $('
');
    var answerLabel = $('').text("Answer:");
    var answerInput = $('<input id="newAnswer" size="50" placeholder="(Type an Answer)"/>');
    var allAnswers = [];
    for (var key in database.answers) {
        if (database.answers.hasOwnProperty(key)) {
            allAnswers.push(database.answers[key].answer);
        }
    }
    answerInput.autocomplete({source: allAnswers});

    answerDiv.append(answerLabel).append(answerInput);
    speciesDiv.append(answerDiv);

    appendFactSection(speciesDiv);

    var submitButton = $('<button type="button"/>').text("Save My Bug").click(function() {
        saveNewBug(currentBug);
    });
    var submitDiv = $('
');
    submitDiv.append(submitButton);
    speciesDiv.append(submitDiv);

    mainDiv.append(speciesDiv);
}

function saveNewBug(bug) {
    var question = $('#newQuestion').val();
    var answer = $('#newAnswer').val();
    if (question.length < 2 || answer.length < 1) {
        showAlert("Please enter a question and answer so I can identify this bug");
        return;
    }
    if (question.length > 255) {
        showAlert("Please enter a shorter question");
        return;
    }
    if (answer.length > 255) {
        showAlert("Please enter a shorter answer");
        return;
    }
    newAnswers[question] = answer;
    $('body').addClass("loading");
    $.ajax({
        url: "add.php",
        dataType: 'json',
        type: 'POST',
        data: {
            name: bug.name,
            description: bug.description,
            common_name: bug.commonName,
            new_answers: newAnswers,
            answers: currentAnswers,
            image_url: bug.image,
            wiki_url: bug.wikiUrl
        }
    })
    .done(function(data) {
        if (!data || !data.success) {
            showAlert("Error saving bug, sorry! (" + data.message + ")");
        } else {
            showStartOver("Thank you, I've learned a little bit about " + bug.name + "!");
        }
    })
    .fail(function() {
        showAlert("Error saving bug, sorry!");
    })
    .always(function() {
        $('body').removeClass("loading");
    });
}

function showAlert(message, icon, title) {
    title = title ? title : 'Bug-O-Pedia';
    icon = icon ? icon : 'alert';

    var alertDiv = jQuery('
')
        .append(jQuery(''))
        .append(jQuery('').append(message));

    alertDiv.dialog
    ({
        resizable: false,
        modal: true,
        buttons : { "Ok" : function() { jQuery(this).dialog("close"); } }
    });
}<commit_msg>Start over after identifying a bug<commit_after>// Database data, should not be changed except when refreshing
var database = null;

// Tracking data
var currentQuestions = [];
var currentSpecies = [];
var currentAnswers = {};
var newAnswers = {};
var currentBug = {};

function start() {
    reset();
    fetchData(nextQuestion);
}

function reset() {
    $('#main').empty();
    database = null;
    currentQuestions = [];
    currentSpecies = [];
    currentBug = {};
    currentAnswers = {};
    newAnswers = {};
}

function fetchData(callback) {
    $('body').addClass("loading");
    $.ajax({
        url: "data.php",
        dataType: 'json'
    })
    .done(function(data) {
        if (!data || !data.success) {
            showRetry("Error loading data from database, sorry!", data.message);
        } else {
            setDatabase(data);
            callback();
        }
    })
    .fail(function() {
        showRetry("Error loading data from database, sorry!", 'Communications Failure');
    })
    .always(function() {
        $('body').removeClass("loading");
    });
}

function showRetry(message, title) {
    var mainDiv = $('#main');
    mainDiv.empty();
    mainDiv.append($('
').text(message).prop('title', title));
    var retryButton = $('<button type="button"/>').text("Try Again").click(function() {
        start();
    });
    var retryDiv = $('
');
    retryDiv.append(retryButton);
    mainDiv.append(retryDiv);
}

function showStartOver(message) {
    var mainDiv = $('#main');
    mainDiv.empty();
    mainDiv.append($('
').text(message));
    var retryButton = $('<button type="button"/>').text("Start Over").click(function() {
        start();
    });
    var retryDiv = $('
');
    retryDiv.append(retryButton);
    mainDiv.append(retryDiv);
}

function setDatabase(data) {
    database = data;
    currentQuestions = database.questions.slice();
    currentSpecies = database.species.slice();
}

function nextQuestion() {
    var mainDiv = $('#main');
    mainDiv.empty();
    if (currentQuestions.length == 0 || currentSpecies.length <= 1) {
        foundMatch();
        return;
    }

    var instructionsSpan = $('
').text("Let's answer some questions so I can learn about your bug! I may be able to guess what you have.");
    mainDiv.append(instructionsSpan);

    var questionIndex = Math.floor(Math.random() * currentQuestions.length);
    var question = currentQuestions[questionIndex];
    currentQuestions.splice(questionIndex, 1);

    // This should never happen, but you know.
    if (!question.hasOwnProperty('answers')) {
        nextQuestion();
        return;
    }

    var questionSpan = $('
').text(question.question);
    mainDiv.append(questionSpan);
    var remainingAnswers = jQuery.extend({}, database.answers);
    for (var i = 0; i < question.answers.length; i++) {
        var answer = database.answers[question.answers[i]];
        delete remainingAnswers[question.answers[i]];
        var answerSpan = $('
').text(answer.answer);
        answerSpan.click(function(answerId) {
            return function() { answerQuestion(question.id, answerId); };
        }(answer.id));
        mainDiv.append(answerSpan);
    }
    var customAnswers = [];
    for (var key in remainingAnswers) {
        if (remainingAnswers.hasOwnProperty(key)) {
            customAnswers.push(remainingAnswers[key].answer);
        }
    }
    var customAnswerSpan = $('
');
    var answerInput = $('<input id="newAnswer" type="text" size="30" placeholder="(Other Answer)"/>')
        .autocomplete({source: customAnswers})
        .keypress(function(e) {
            if (e.keyCode == $.ui.keyCode.ENTER) {
                newAnswer(question.id, $('#newAnswer').val());
            }
        });
    var answerButton = $('<button type="button"/>').text("Answer").click(function() {
        newAnswer(question.id, $('#newAnswer').val());
    });
    customAnswerSpan.append(answerInput);
    customAnswerSpan.append(answerButton);
    mainDiv.append(customAnswerSpan);
}

function newAnswer(questionId, answer) {
    if (answer.length < 2) {
        showAlert('Please enter an answer');
        return;
    }
    if (answer.length > 255) {
        showAlert('That answer is too long, please shorten it');
        return;
    }
    var oldSpecies = currentSpecies;
    currentSpecies = [];
    for (var i = 0; i < oldSpecies.length;i++) {
        var species = oldSpecies[i];
        if (!species.questions.hasOwnProperty(questionId)) {
            currentSpecies.push(species);
        }
    }
    newAnswers[questionId] = answer;
    nextQuestion();
}

function answerQuestion(questionId, answerId) {
    var oldSpecies = currentSpecies;
    currentSpecies = [];
    for (var i = 0; i < oldSpecies.length;i++) {
        var species = oldSpecies[i];
        if (species.questions.hasOwnProperty(questionId) && species.questions[questionId] == answerId) {
            currentSpecies.push(species);
        }
    }
    currentAnswers[questionId] = answerId;
    nextQuestion();
}

function foundMatch() {
    if (currentSpecies.length > 0) {
        var species = currentSpecies[0];
        var speciesDiv = $('
');
        var speciesName = species.name;
        if (species.common_name) {
            speciesName = species.common_name + ' (' + speciesName + ')';
        }
        var nameDiv = $('
').text(speciesName);
        speciesDiv.append(nameDiv);

        if (species.image_url) {
            var imageLink = $('');
            var imageDiv = $('
');
            imageLink.append($(''));
            imageDiv.append(imageLink);
            speciesDiv.append(imageDiv);
        }
        if (species.wiki_url) {
            var wikiDiv = $('
').append($('').text("Full Wikipedia Article"));
            speciesDiv.append(wikiDiv);
        }
        if (species.description) {
            var descriptionDiv = $('
').html(species.description);
            speciesDiv.append(descriptionDiv);
        }

        var askContainer = $('
');
        var askDiv = $('
').text("Is this your bug?");
        askContainer.append(askDiv);

        var yesButton = $('<button type="button"/>').text("Yes").click(function() {
            askContainer.empty();
            var startOverDiv = $('
').text("Hooray!");
            askContainer.append(startOverDiv);

            var startOverButton = $('<button type="button"/>').text("Start Over").click(function() {
                start();
            });
            askContainer.append(startOverButton);
        });
        var noButton = $('<button type="button"/>').text("No").click(function() {
            noMoreQuestions();
        });
        askContainer.append(yesButton);
        askContainer.append(noButton);
        speciesDiv.append(askContainer);

        $('#main').append(speciesDiv);
    } else {
        noMoreQuestions();
    }
}

function noMoreQuestions() {
    var mainDiv = $('#main');
    mainDiv.empty();
    var introMessage = database.questions.length == 0 ? "I don't know anything yet! Can you help me learn?" : "I've run out of questions! Can you help me learn?";
    var askDiv = $('
').text(introMessage);
    mainDiv.append(askDiv);

    var nameDiv = $('
').text("What is the name of your bug?");
    mainDiv.append(nameDiv);

    var nameInput = $('<input id="name" size="50" placeholder="(Type Name Here)"/>');
    mainDiv.append(nameInput);
    nameInput.keypress(function(e) {
        if (e.keyCode == $.ui.keyCode.ENTER) {
            nameBug();
        }
    });

    var submitButton = $('<button type="button"/>').text("Name My Bug").click(function() {
        nameBug();
    });
    var submitDiv = $('
');
    submitDiv.append(submitButton);
    mainDiv.append(submitDiv);
    appendFactSection(mainDiv);
}

function appendFactSection(mainDiv)
{
    var answerCount = 0;
    var answers = {};
    for (var currentAnswerKey in currentAnswers) {
        if (currentAnswers.hasOwnProperty(currentAnswerKey)) {
            answerCount++;
            answers[database.question_map[currentAnswerKey].question] = database.answers[currentAnswers[currentAnswerKey]].answer;
        }
    }
    for (var newAnswerKey in newAnswers) {
        if (newAnswers.hasOwnProperty(newAnswerKey)) {
            answerCount++;
            answers[database.question_map[newAnswerKey].question] = newAnswers[newAnswerKey];
        }
    }
    if (answerCount > 0) {
        var plural = answerCount > 1 ? 's' : '';
        var factsLabel = $('
').text(numberToWord(answerCount) + ' fact' + plural + ' about your bug:');
        var factsTable = $('
');
        for (var question in answers) {
            if (answers.hasOwnProperty(question)) {
                var factsRow = $('
');
                var questionCell = $('').text(question);
                var answerCell = $('').text(answers[question]);
                factsRow.append(questionCell);
                factsRow.append(answerCell);
                factsTable.append(factsRow);
            }
        }
        mainDiv.append(factsLabel);
        mainDiv.append(factsTable);
    }
}

function numberToWord(number) {
    switch (number) {
        case 0: return 'Zero';
        case 1: return 'One';
        case 2: return 'Two';
        case 3: return 'Three';
        case 4: return 'Four';
        case 5: return 'Five';
        case 6: return 'Six';
        case 7: return 'Seven';
        case 8: return 'Eight';
        case 9: return 'Nine';
        case 10: return 'Ten';
        case 11: return 'Eleven';
        case 12: return 'Twelve';
        case 13: return 'Thirteen';
        case 14: return 'Fourteen';
        case 15: return 'Fifteen';
    }
    return number;
}

function nameBug() {
    var nameInput = $('#name');
    var bugName = nameInput.val();
    if (bugName.length < 2) {
        showAlert("Please enter a bug name");
        return;
    }
    if (bugName.length > 255) {
        showAlert("Please enter a shorter bug name");
        return;
    }
    loadBug(bugName);
}

function loadBug(title) {
    $('body').addClass("loading");
    $.ajax({
        url: "wiki.php",
        dataType: 'json',
        data: {
            title: title
        }
    })
    .done(function(data) {
        if (!data || !data.success) {
            showAlert("Error loading wiki data - can't save bug, sorry! (" + data.message + ")");
        } else {
            showNewBug(title, data);
        }
    })
    .fail(function() {
        showAlert("Error loading wiki data - can't save bug, sorry!");
    })
    .always(function() {
        $('body').removeClass("loading");
    });
}

function showNewBug(title, wikiData) {
    var currentBug = {
        name: title,
        commonName: null,
        description: null,
        image: null,
        wikiUrl: null
    };

    var mainDiv = $('#main');
    mainDiv.empty();
    var speciesDiv = $('
');
    var nameText = title;
    if (wikiData.hasOwnProperty('redirect')) {
        currentBug.name = wikiData['redirect'];
        currentBug.commonName = title;
        nameText = nameText + " (" + wikiData['redirect'] + ")";
    }
    if (wikiData.hasOwnProperty('wiki')) {
        currentBug.wikiUrl = 'https://en.wikipedia.org/wiki/' + wikiData['wiki'];
    }
    var nameDiv = $('
').text(nameText);
    speciesDiv.append(nameDiv);

    if (wikiData.hasOwnProperty('extract')) {
        var extractDiv = $('
');
        extractDiv.html(wikiData['extract']);
        speciesDiv.append(extractDiv);
        currentBug.description = wikiData['extract'];
    }

    var pickImageDiv = $('
').text("Please choose an image:");
    speciesDiv.append(pickImageDiv);

    var imageContainer = $('
');
    for (var i = 0; i < wikiData.images.length; i++) {
        var imageData = wikiData.images[i];
        var imageDiv = $('
');
        var imageUrl = $('');
        imageDiv.append(imageUrl);
        imageContainer.append(imageDiv);
        imageDiv.click(function(url) {
             return function() {
                 $('.image').removeClass('selected');
                 $(this).addClass('selected');
                 currentBug.image = url;
             }
        }(imageData.url));
    }
    speciesDiv.append(imageContainer);

    var pickQuestionDiv = $('
').text("Please type a question to help me identify this bug:");
    speciesDiv.append(pickQuestionDiv);
    var questionDiv = $('
');
    var questionLabel = $('').text("Question:");
    var questionInput = $('<input id="newQuestion" size="150" placeholder="(Type a Question)"/>');
    questionDiv.append(questionLabel).append(questionInput);
    speciesDiv.append(questionDiv);
    var answerDiv = $('
');
    var answerLabel = $('').text("Answer:");
    var answerInput = $('<input id="newAnswer" size="50" placeholder="(Type an Answer)"/>');
    var allAnswers = [];
    for (var key in database.answers) {
        if (database.answers.hasOwnProperty(key)) {
            allAnswers.push(database.answers[key].answer);
        }
    }
    answerInput.autocomplete({source: allAnswers});

    answerDiv.append(answerLabel).append(answerInput);
    speciesDiv.append(answerDiv);

    appendFactSection(speciesDiv);

    var submitButton = $('<button type="button"/>').text("Save My Bug").click(function() {
        saveNewBug(currentBug);
    });
    var submitDiv = $('
');
    submitDiv.append(submitButton);
    speciesDiv.append(submitDiv);

    mainDiv.append(speciesDiv);
}

function saveNewBug(bug) {
    var question = $('#newQuestion').val();
    var answer = $('#newAnswer').val();
    if (question.length < 2 || answer.length < 1) {
        showAlert("Please enter a question and answer so I can identify this bug");
        return;
    }
    if (question.length > 255) {
        showAlert("Please enter a shorter question");
        return;
    }
    if (answer.length > 255) {
        showAlert("Please enter a shorter answer");
        return;
    }
    newAnswers[question] = answer;
    $('body').addClass("loading");
    $.ajax({
        url: "add.php",
        dataType: 'json',
        type: 'POST',
        data: {
            name: bug.name,
            description: bug.description,
            common_name: bug.commonName,
            new_answers: newAnswers,
            answers: currentAnswers,
            image_url: bug.image,
            wiki_url: bug.wikiUrl
        }
    })
    .done(function(data) {
        if (!data || !data.success) {
            showAlert("Error saving bug, sorry! (" + data.message + ")");
        } else {
            showStartOver("Thank you, I've learned a little bit about " + bug.name + "!");
        }
    })
    .fail(function() {
        showAlert("Error saving bug, sorry!");
    })
    .always(function() {
        $('body').removeClass("loading");
    });
}

function showAlert(message, icon, title) {
    title = title ? title : 'Bug-O-Pedia';
    icon = icon ? icon : 'alert';

    var alertDiv = jQuery('
')
        .append(jQuery(''))
        .append(jQuery('').append(message));

    alertDiv.dialog
    ({
        resizable: false,
        modal: true,
        buttons : { "Ok" : function() { jQuery(this).dialog("close"); } }
    });
}<|endoftext|>


<commit_before><commit_msg>adding ability to set the server from .use<commit_after><|endoftext|>


<commit_before>'use strict';

let angular = require('angular');

module.exports =  angular.module('spinnaker.pipelines.stage.executionWindows.transformer', [])
  .service('executionWindowsTransformer', function() {

    /**
     * Overrides "running" status, setting it to "suspended"
     */
    function transformRunningExecutionWindows(execution) {
      execution.stages
        .filter(function (stage) {
          return stage.type === 'restrictExecutionDuringTimeWindow' && stage.status === 'RUNNING';
        })
        .forEach(function (stage) {
          stage.status = 'SUSPENDED';
          stage.tasks.forEach(function(task) { task.status = 'SUSPENDED'; });
        });
    }

    this.transform = function(application, execution) {
      transformRunningExecutionWindows(execution);
    };
  })
  .name;
<commit_msg>trying to fix module resolution on jenkins.<commit_after>'use strict';
let angular = require('angular');
module.exports =  angular.module('spinnaker.pipelines.stage.executionWindows.transformer', [])
  .service('executionWindowsTransformer', function() {
    /**
     * Overrides "running" status, setting it to "suspended"
     */
    function transformRunningExecutionWindows(execution) {
      execution.stages
        .filter(function (stage) {
          return stage.type === 'restrictExecutionDuringTimeWindow' && stage.status === 'RUNNING';
        })
        .forEach(function (stage) {
          stage.status = 'SUSPENDED';
          stage.tasks.forEach(function(task) { task.status = 'SUSPENDED'; });
        });
    }
    this.transform = function(application, execution) {
      transformRunningExecutionWindows(execution);
    };
  })
  .name;
<|endoftext|>


<commit_before>/*
* @Author: ben_cripps
* @Date:   2015-08-25 21:20:55
* @Last Modified by:   ben_cripps
* @Last Modified time: 2015-10-14 11:44:23
*/

var TextObject = require('./textClass');

Array.prototype.getUnique = function(){
   var u = {}, a = [];
   for(var i = 0, l = this.length; i < l; ++i){
      if(u.hasOwnProperty(this[i])) {
         continue;
      }
      a.push(this[i]);
      u[this[i]] = 1;
   }
   return a;
};

module.exports = function(textSchema, appMessages) {

    var exporter = {
        export: function(query, server) {
            textSchema.find({'tag.id': query.tag}).sort({'textInformation.date': 1}).exec().then(function(resp) {
                server.setHeader('Content-Type', 'application/json');
                server.send(JSON.stringify(exporter.utils.getJSON(resp)));
            });
        },
        utils: {
            getJSON: function(arr) {
                var ret = [],
                    numbers = arr.map(function(ob) { return ob.userInformation.phoneNumber.string; }).getUnique(),
                    userTexts = [],
                    textObj,
                    zipCode;

                numbers.forEach(function(num) {

                    userTexts = arr.filter(function(ob) { return ob.userInformation.phoneNumber.string === num; });

                    zipCode = userTexts[0].textInformation.location.fromZip;

                    textObj = new TextObject(num, zipCode);

                    userTexts.forEach(function(text, i) {
                        textObj.addResponse(text.textInformation.body, i + 1);
                    });

                    ret.push(textObj.values);
                });

                return ret;
            }
        }
    };

    return exporter;
};
<commit_msg>export stuff<commit_after>/*
* @Author: ben_cripps
* @Date:   2015-08-25 21:20:55
* @Last Modified by:   ben_cripps
* @Last Modified time: 2015-10-16 09:54:07
*/

var TextObject = require('./textClass');

Array.prototype.getUnique = function(){
   var u = {}, a = [];
   for(var i = 0, l = this.length; i < l; ++i){
      if(u.hasOwnProperty(this[i])) {
         continue;
      }
      a.push(this[i]);
      u[this[i]] = 1;
   }
   return a;
};

module.exports = function(textSchema, appMessages) {

    var exporter = {
        export: function(query, server) {
            textSchema.find({'tag.id': query.tag}).sort({'textInformation.date': 1}).exec().then(function(resp) {
                server.setHeader('Content-Type', 'application/json');
                server.send(JSON.stringify(exporter.utils.getJSON(resp)));
            });
        },
        utils: {
            getJSON: function(arr) {
                var ret = [],
                    numbers = arr.map(function(ob) { return ob.userInformation.phoneNumber.string; }).getUnique(),
                    userTexts = [],
                    textObj,
                    zipCode;

                numbers.forEach(function(num) {

                    userTexts = arr.filter(function(ob) { return ob.userInformation.phoneNumber.string === num; });

                    zipCode = userTexts[0].textInformation.location.fromZip;

                    textObj = new TextObject(num, zipCode);

                    userTexts.forEach(function(text, i) {
                        textObj.addResponse(text.textInformation.body, i + 1);
                    });

                    ret.push(textObj.values);
                });

                return ret;

                // var responses = arr.map(function(ob){ return ob.textInformation.body; }),
                //     zips = responses.filter(function(val){ return Number(val) && val.replace(/\s/g, '').length === 5; }),
                //     formattedZips = zips.map(function(z) { return z.replace(/\s/g, ''); }),
                //     retForAsher = {};

                // formattedZips.forEach(function(num) {

                //   if (!retForAsher[num]) {
                //     retForAsher[num] = 1;
                //   }

                //   else {
                //     retForAsher[num]+= 1;
                //   }

                // });

                // return retForAsher;
            }
        }
    };

    return exporter;
};
<|endoftext|>


<commit_before>function checkPerms() {
 if (globalCode == 2639301) {
  document.getElementById('loadVideo').src = "https://darkheart527.github.io/domain-storage/XiaoYing - James.mp4";
  document.getElementById('gCArea').style.visibility = 'hidden';
  alert("Successful Login - Page Ex's Page Logged Into")
  localStorage.globalCode001 = globalCode;
 } else {
  document.getElementById('gCArea').style.visibility = 'hidden';
  alert('Your Gc is incorrect');
 }
}

function loadGlobal() {
 if (localStorage.globalCode001 == null) {
  alert('There Is A Global On This Page');
 } else
 document.getElementById('gcBox').value = Number(localStorage.globalCode001);
 globalCode = Number(localStorage.globalCode001);
 checkPerms();
}
<commit_msg>Update exPage.js<commit_after>function checkPerms() {
 if (globalCode == 2639301) {
  document.getElementById('loadVideo').src = "https://darkheart527.github.io/domain-storage/XiaoYing - James.mp4";
  document.getElementById('gCArea').style.visibility = 'hidden';
  alert("Successful Login - Page Ex's Page Logged Into")
  localStorage.globalCode001 = globalCode;
 } else {
  document.getElementById('gCArea').style.visibility = 'hidden';
  alert('Your Gc is incorrect');
 }
}

function loadGlobal() {
 if (localStorage.globalCode001 == null) {
  alert('There Is A Global On This Page');
 } else {
 document.getElementById('gcBox').value = Number(localStorage.globalCode001);
 globalCode = Number(localStorage.globalCode001);
 checkPerms();
 }
}
<|endoftext|>