<commit_before>import Utils from "../core/Utils.js";
import FileSaver from "file-saver";

/**
 * Waiter to handle events related to the output.
 *
 * @author n1474335 [n1474335@gmail.com]
 * @copyright Crown Copyright 2016
 * @license Apache-2.0
 *
 * @constructor
 * @param {App} app - The main view object for CyberChef.
 * @param {Manager} manager - The CyberChef event manager.
 */
const OutputWaiter = function(app, manager) {
    this.app = app;
    this.manager = manager;

    this.dishBuffer = null;
    this.dishStr = null;
};

/**
 * Gets the output string from the output textarea.
 *
 * @returns {string}
 */
OutputWaiter.prototype.get = function() {
    return document.getElementById("output-text").value;
};

/**
 * Sets the output in the output textarea.
 *
 * @param {string|ArrayBuffer} data - The output string/HTML/ArrayBuffer
 * @param {string} type - The data type of the output
 * @param {number} duration - The length of time (ms) it took to generate the output
 * @param {boolean} [preserveBuffer=false] - Whether to preserve the dishBuffer
 */
OutputWaiter.prototype.set = function(data, type, duration, preserveBuffer) {
    log.debug("Output type: " + type);
    const outputText = document.getElementById("output-text");
    const outputHtml = document.getElementById("output-html");
    const outputFile = document.getElementById("output-file");
    const outputHighlighter = document.getElementById("output-highlighter");
    const inputHighlighter = document.getElementById("input-highlighter");
    let scriptElements, lines, length;

    if (!preserveBuffer) {
        this.closeFile();
        document.getElementById("show-file-overlay").style.display = "none";
    }

    switch (type) {
        case "html":
            outputText.style.display = "none";
            outputHtml.style.display = "block";
            outputFile.style.display = "none";
            outputHighlighter.display = "none";
            inputHighlighter.display = "none";

            outputText.value = "";
            outputHtml.innerHTML = data;
            this.dishStr = Utils.stripHtmlTags(data, true);
            length = data.length;
            lines = this.dishStr.count("\n") + 1;

            // Execute script sections
            scriptElements = outputHtml.querySelectorAll("script");
            for (let i = 0; i < scriptElements.length; i++) {
                try {
                    eval(scriptElements[i].innerHTML); // eslint-disable-line no-eval
                } catch (err) {
                    log.error(err);
                }
            }
            break;
        case "ArrayBuffer":
            outputText.style.display = "block";
            outputHtml.style.display = "none";
            outputHighlighter.display = "none";
            inputHighlighter.display = "none";

            outputText.value = "";
            outputHtml.innerHTML = "";
            this.dishStr = "";
            length = data.byteLength;

            this.setFile(data);
            break;
        case "string":
        default:
            outputText.style.display = "block";
            outputHtml.style.display = "none";
            outputFile.style.display = "none";
            outputHighlighter.display = "block";
            inputHighlighter.display = "block";

            outputText.value = Utils.printable(data, true);
            outputHtml.innerHTML = "";

            lines = data.count("\n") + 1;
            length = data.length;
            this.dishStr = data;
            break;
    }

    this.manager.highlighter.removeHighlights();
    this.setOutputInfo(length, lines, duration);
};

/**
 * Shows file details.
 *
 * @param {ArrayBuffer} buf
 */
OutputWaiter.prototype.setFile = function(buf) {
    this.dishBuffer = buf;
    const file = new File([buf], "output.dat");

    // Display file overlay in output area with details
    const fileOverlay = document.getElementById("output-file"),
        fileSize = document.getElementById("output-file-size");

    fileOverlay.style.display = "block";
    fileSize.textContent = file.size.toLocaleString() + " bytes";
};

/**
 * Removes the output file and nulls its memory.
 */
OutputWaiter.prototype.closeFile = function() {
    this.dishBuffer = null;
    document.getElementById("output-file").style.display = "none";
};

/**
 * Handler for file download events.
 */
OutputWaiter.prototype.downloadFile = function() {
    this.filename = window.prompt("Please enter a filename:", this.filename || "download.dat");
    const file = new File([this.dishBuffer], this.filename);

    if (this.filename) FileSaver.saveAs(file, this.filename, false);
};

/**
 * Handler for file slice display events.
 */
OutputWaiter.prototype.displayFileSlice = function() {
    const startTime = new Date().getTime(),
        showFileOverlay = document.getElementById("show-file-overlay"),
        sliceFromEl = document.getElementById("output-file-slice-from"),
        sliceToEl = document.getElementById("output-file-slice-to"),
        sliceFrom = parseInt(sliceFromEl.value, 10),
        sliceTo = parseInt(sliceToEl.value, 10),
        str = Utils.arrayBufferToStr(this.dishBuffer.slice(sliceFrom, sliceTo));

    showFileOverlay.style.display = "block";
    this.set(str, "string", new Date().getTime() - startTime, true);
};

/**
 * Handler for show file overlay events.
 *
 * @param {Event} e
 */
OutputWaiter.prototype.showFileOverlayClick = function(e) {
    const outputFile = document.getElementById("output-file"),
        showFileOverlay = e.target;

    outputFile.style.display = "block";
    showFileOverlay.style.display = "none";
    this.setOutputInfo(this.dishBuffer.byteLength, null, 0);
};

/**
 * Displays information about the output.
 *
 * @param {number} length - The length of the current output string
 * @param {number} lines - The number of the lines in the current output string
 * @param {number} duration - The length of time (ms) it took to generate the output
 */
OutputWaiter.prototype.setOutputInfo = function(length, lines, duration) {
    let width = length.toString().length;
    width = width < 4 ? 4 : width;

    const lengthStr = length.toString().padStart(width, " ").replace(/ /g, " ");
    const timeStr = (duration.toString() + "ms").padStart(width, " ").replace(/ /g, " ");

    let msg = "time: " + timeStr + "
length: " + lengthStr;

    if (typeof lines === "number") {
        const linesStr = lines.toString().padStart(width, " ").replace(/ /g, " ");
        msg += "
lines: " + linesStr;
    }

    document.getElementById("output-info").innerHTML = msg;
    document.getElementById("input-selection-info").innerHTML = "";
    document.getElementById("output-selection-info").innerHTML = "";
};

/**
 * Adjusts the display properties of the output buttons so that they fit within the current width
 * without wrapping or overflowing.
 */
OutputWaiter.prototype.adjustWidth = function() {
    const output         = document.getElementById("output");
    const saveToFile     = document.getElementById("save-to-file");
    const copyOutput     = document.getElementById("copy-output");
    const switchIO       = document.getElementById("switch");
    const undoSwitch     = document.getElementById("undo-switch");
    const maximiseOutput = document.getElementById("maximise-output");

    if (output.clientWidth < 680) {
        saveToFile.childNodes[1].nodeValue = "";
        copyOutput.childNodes[1].nodeValue = "";
        switchIO.childNodes[1].nodeValue = "";
        undoSwitch.childNodes[1].nodeValue = "";
        maximiseOutput.childNodes[1].nodeValue = "";
    } else {
        saveToFile.childNodes[1].nodeValue = " Save to file";
        copyOutput.childNodes[1].nodeValue = " Copy output";
        switchIO.childNodes[1].nodeValue = " Move output to input";
        undoSwitch.childNodes[1].nodeValue = " Undo";
        maximiseOutput.childNodes[1].nodeValue =
            maximiseOutput.getAttribute("title") === "Maximise" ? " Max" : " Restore";
    }
};

/**
 * Handler for save click events.
 * Saves the current output to a file.
 */
OutputWaiter.prototype.saveClick = function() {
    if (!this.dishBuffer) {
        this.dishBuffer = new Uint8Array(Utils.strToCharcode(this.dishStr)).buffer;
    }
    this.downloadFile();
};

/**
 * Handler for copy click events.
 * Copies the output to the clipboard.
 */
OutputWaiter.prototype.copyClick = function() {
    // Create invisible textarea to populate with the raw dishStr (not the printable version that
    // contains dots instead of the actual bytes)
    const textarea = document.createElement("textarea");
    textarea.style.position = "fixed";
    textarea.style.top = 0;
    textarea.style.left = 0;
    textarea.style.width = 0;
    textarea.style.height = 0;
    textarea.style.border = "none";

    textarea.value = this.dishStr;
    document.body.appendChild(textarea);

    // Select and copy the contents of this textarea
    let success = false;
    try {
        textarea.select();
        success = this.dishStr && document.execCommand("copy");
    } catch (err) {
        success = false;
    }

    if (success) {
        this.app.alert("Copied raw output successfully.", "success", 2000);
    } else {
        this.app.alert("Sorry, the output could not be copied.", "danger", 2000);
    }

    // Clean up
    document.body.removeChild(textarea);
};

/**
 * Handler for switch click events.
 * Moves the current output into the input textarea.
 */
OutputWaiter.prototype.switchClick = function() {
    this.switchOrigData = this.manager.input.get();
    document.getElementById("undo-switch").disabled = false;
    if (this.dishBuffer) {
        this.manager.input.setFile(new File([this.dishBuffer], "output.dat"));
        this.manager.input.handleLoaderMessage({
            data: {
                progress: 100,
                fileBuffer: this.dishBuffer
            }
        });
    } else {
        this.app.setInput(this.dishStr);
    }
};

/**
 * Handler for undo switch click events.
 * Removes the output from the input and replaces the input that was removed.
 */
OutputWaiter.prototype.undoSwitchClick = function() {
    this.app.setInput(this.switchOrigData);
    document.getElementById("undo-switch").disabled = true;
};

/**
 * Handler for file switch click events.
 * Moves a file's data for items created via Utils.displayFilesAsHTML to the input.
 */
OutputWaiter.prototype.fileSwitch = function(e) {
    e.preventDefault();
    this.switchOrigData = this.manager.input.get();
    this.app.setInput(e.target.getAttribute("fileValue"));
    document.getElementById("undo-switch").disabled = false;
};

/**
 * Handler for maximise output click events.
 * Resizes the output frame to be as large as possible, or restores it to its original size.
 */
OutputWaiter.prototype.maximiseOutputClick = function(e) {
    const el = e.target.id === "maximise-output" ? e.target : e.target.parentNode;

    if (el.getAttribute("title") === "Maximise") {
        this.app.columnSplitter.collapse(0);
        this.app.columnSplitter.collapse(1);
        this.app.ioSplitter.collapse(0);

        el.setAttribute("title", "Restore");
        el.innerHTML = " Restore";
        this.adjustWidth();
    } else {
        el.setAttribute("title", "Maximise");
        el.innerHTML = " Max";
        this.app.resetLayout();
    }
};

/**
 * Shows or hides the loading icon.
 *
 * @param {boolean} value
 */
OutputWaiter.prototype.toggleLoader = function(value) {
    const outputLoader = document.getElementById("output-loader"),
        outputElement = document.getElementById("output-text");

    if (value) {
        this.manager.controls.hideStaleIndicator();
        this.bakingStatusTimeout = setTimeout(function() {
            outputElement.disabled = true;
            outputLoader.style.visibility = "visible";
            outputLoader.style.opacity = 1;
            this.manager.controls.toggleBakeButtonFunction(true);
        }.bind(this), 200);
    } else {
        clearTimeout(this.bakingStatusTimeout);
        outputElement.disabled = false;
        outputLoader.style.opacity = 0;
        outputLoader.style.visibility = "hidden";
        this.manager.controls.toggleBakeButtonFunction(false);
        this.setStatusMsg("");
    }
};

/**
 * Sets the baking status message value.
 *
 * @param {string} msg
 */
OutputWaiter.prototype.setStatusMsg = function(msg) {
    const el = document.querySelector("#output-loader .loading-msg");

    el.textContent = msg;
};

/**
 * Returns true if the output contains carriage returns
 *
 * @returns {boolean}
 */
OutputWaiter.prototype.containsCR = function() {
    return this.dishStr.indexOf("\r") >= 0;
};

export default OutputWaiter;
<commit_msg>HTML outputs are now unescaped correctly when converted to a string<commit_after>import Utils from "../core/Utils.js";
import FileSaver from "file-saver";

/**
 * Waiter to handle events related to the output.
 *
 * @author n1474335 [n1474335@gmail.com]
 * @copyright Crown Copyright 2016
 * @license Apache-2.0
 *
 * @constructor
 * @param {App} app - The main view object for CyberChef.
 * @param {Manager} manager - The CyberChef event manager.
 */
const OutputWaiter = function(app, manager) {
    this.app = app;
    this.manager = manager;

    this.dishBuffer = null;
    this.dishStr = null;
};

/**
 * Gets the output string from the output textarea.
 *
 * @returns {string}
 */
OutputWaiter.prototype.get = function() {
    return document.getElementById("output-text").value;
};

/**
 * Sets the output in the output textarea.
 *
 * @param {string|ArrayBuffer} data - The output string/HTML/ArrayBuffer
 * @param {string} type - The data type of the output
 * @param {number} duration - The length of time (ms) it took to generate the output
 * @param {boolean} [preserveBuffer=false] - Whether to preserve the dishBuffer
 */
OutputWaiter.prototype.set = function(data, type, duration, preserveBuffer) {
    log.debug("Output type: " + type);
    const outputText = document.getElementById("output-text");
    const outputHtml = document.getElementById("output-html");
    const outputFile = document.getElementById("output-file");
    const outputHighlighter = document.getElementById("output-highlighter");
    const inputHighlighter = document.getElementById("input-highlighter");
    let scriptElements, lines, length;

    if (!preserveBuffer) {
        this.closeFile();
        document.getElementById("show-file-overlay").style.display = "none";
    }

    switch (type) {
        case "html":
            outputText.style.display = "none";
            outputHtml.style.display = "block";
            outputFile.style.display = "none";
            outputHighlighter.display = "none";
            inputHighlighter.display = "none";

            outputText.value = "";
            outputHtml.innerHTML = data;
            this.dishStr = Utils.unescapeHtml(Utils.stripHtmlTags(data, true));
            length = data.length;
            lines = this.dishStr.count("\n") + 1;

            // Execute script sections
            scriptElements = outputHtml.querySelectorAll("script");
            for (let i = 0; i < scriptElements.length; i++) {
                try {
                    eval(scriptElements[i].innerHTML); // eslint-disable-line no-eval
                } catch (err) {
                    log.error(err);
                }
            }
            break;
        case "ArrayBuffer":
            outputText.style.display = "block";
            outputHtml.style.display = "none";
            outputHighlighter.display = "none";
            inputHighlighter.display = "none";

            outputText.value = "";
            outputHtml.innerHTML = "";
            this.dishStr = "";
            length = data.byteLength;

            this.setFile(data);
            break;
        case "string":
        default:
            outputText.style.display = "block";
            outputHtml.style.display = "none";
            outputFile.style.display = "none";
            outputHighlighter.display = "block";
            inputHighlighter.display = "block";

            outputText.value = Utils.printable(data, true);
            outputHtml.innerHTML = "";

            lines = data.count("\n") + 1;
            length = data.length;
            this.dishStr = data;
            break;
    }

    this.manager.highlighter.removeHighlights();
    this.setOutputInfo(length, lines, duration);
};

/**
 * Shows file details.
 *
 * @param {ArrayBuffer} buf
 */
OutputWaiter.prototype.setFile = function(buf) {
    this.dishBuffer = buf;
    const file = new File([buf], "output.dat");

    // Display file overlay in output area with details
    const fileOverlay = document.getElementById("output-file"),
        fileSize = document.getElementById("output-file-size");

    fileOverlay.style.display = "block";
    fileSize.textContent = file.size.toLocaleString() + " bytes";
};

/**
 * Removes the output file and nulls its memory.
 */
OutputWaiter.prototype.closeFile = function() {
    this.dishBuffer = null;
    document.getElementById("output-file").style.display = "none";
};

/**
 * Handler for file download events.
 */
OutputWaiter.prototype.downloadFile = function() {
    this.filename = window.prompt("Please enter a filename:", this.filename || "download.dat");
    const file = new File([this.dishBuffer], this.filename);

    if (this.filename) FileSaver.saveAs(file, this.filename, false);
};

/**
 * Handler for file slice display events.
 */
OutputWaiter.prototype.displayFileSlice = function() {
    const startTime = new Date().getTime(),
        showFileOverlay = document.getElementById("show-file-overlay"),
        sliceFromEl = document.getElementById("output-file-slice-from"),
        sliceToEl = document.getElementById("output-file-slice-to"),
        sliceFrom = parseInt(sliceFromEl.value, 10),
        sliceTo = parseInt(sliceToEl.value, 10),
        str = Utils.arrayBufferToStr(this.dishBuffer.slice(sliceFrom, sliceTo));

    showFileOverlay.style.display = "block";
    this.set(str, "string", new Date().getTime() - startTime, true);
};

/**
 * Handler for show file overlay events.
 *
 * @param {Event} e
 */
OutputWaiter.prototype.showFileOverlayClick = function(e) {
    const outputFile = document.getElementById("output-file"),
        showFileOverlay = e.target;

    outputFile.style.display = "block";
    showFileOverlay.style.display = "none";
    this.setOutputInfo(this.dishBuffer.byteLength, null, 0);
};

/**
 * Displays information about the output.
 *
 * @param {number} length - The length of the current output string
 * @param {number} lines - The number of the lines in the current output string
 * @param {number} duration - The length of time (ms) it took to generate the output
 */
OutputWaiter.prototype.setOutputInfo = function(length, lines, duration) {
    let width = length.toString().length;
    width = width < 4 ? 4 : width;

    const lengthStr = length.toString().padStart(width, " ").replace(/ /g, " ");
    const timeStr = (duration.toString() + "ms").padStart(width, " ").replace(/ /g, " ");

    let msg = "time: " + timeStr + "
length: " + lengthStr;

    if (typeof lines === "number") {
        const linesStr = lines.toString().padStart(width, " ").replace(/ /g, " ");
        msg += "
lines: " + linesStr;
    }

    document.getElementById("output-info").innerHTML = msg;
    document.getElementById("input-selection-info").innerHTML = "";
    document.getElementById("output-selection-info").innerHTML = "";
};

/**
 * Adjusts the display properties of the output buttons so that they fit within the current width
 * without wrapping or overflowing.
 */
OutputWaiter.prototype.adjustWidth = function() {
    const output         = document.getElementById("output");
    const saveToFile     = document.getElementById("save-to-file");
    const copyOutput     = document.getElementById("copy-output");
    const switchIO       = document.getElementById("switch");
    const undoSwitch     = document.getElementById("undo-switch");
    const maximiseOutput = document.getElementById("maximise-output");

    if (output.clientWidth < 680) {
        saveToFile.childNodes[1].nodeValue = "";
        copyOutput.childNodes[1].nodeValue = "";
        switchIO.childNodes[1].nodeValue = "";
        undoSwitch.childNodes[1].nodeValue = "";
        maximiseOutput.childNodes[1].nodeValue = "";
    } else {
        saveToFile.childNodes[1].nodeValue = " Save to file";
        copyOutput.childNodes[1].nodeValue = " Copy output";
        switchIO.childNodes[1].nodeValue = " Move output to input";
        undoSwitch.childNodes[1].nodeValue = " Undo";
        maximiseOutput.childNodes[1].nodeValue =
            maximiseOutput.getAttribute("title") === "Maximise" ? " Max" : " Restore";
    }
};

/**
 * Handler for save click events.
 * Saves the current output to a file.
 */
OutputWaiter.prototype.saveClick = function() {
    if (!this.dishBuffer) {
        this.dishBuffer = new Uint8Array(Utils.strToCharcode(this.dishStr)).buffer;
    }
    this.downloadFile();
};

/**
 * Handler for copy click events.
 * Copies the output to the clipboard.
 */
OutputWaiter.prototype.copyClick = function() {
    // Create invisible textarea to populate with the raw dishStr (not the printable version that
    // contains dots instead of the actual bytes)
    const textarea = document.createElement("textarea");
    textarea.style.position = "fixed";
    textarea.style.top = 0;
    textarea.style.left = 0;
    textarea.style.width = 0;
    textarea.style.height = 0;
    textarea.style.border = "none";

    textarea.value = this.dishStr;
    document.body.appendChild(textarea);

    // Select and copy the contents of this textarea
    let success = false;
    try {
        textarea.select();
        success = this.dishStr && document.execCommand("copy");
    } catch (err) {
        success = false;
    }

    if (success) {
        this.app.alert("Copied raw output successfully.", "success", 2000);
    } else {
        this.app.alert("Sorry, the output could not be copied.", "danger", 2000);
    }

    // Clean up
    document.body.removeChild(textarea);
};

/**
 * Handler for switch click events.
 * Moves the current output into the input textarea.
 */
OutputWaiter.prototype.switchClick = function() {
    this.switchOrigData = this.manager.input.get();
    document.getElementById("undo-switch").disabled = false;
    if (this.dishBuffer) {
        this.manager.input.setFile(new File([this.dishBuffer], "output.dat"));
        this.manager.input.handleLoaderMessage({
            data: {
                progress: 100,
                fileBuffer: this.dishBuffer
            }
        });
    } else {
        this.app.setInput(this.dishStr);
    }
};

/**
 * Handler for undo switch click events.
 * Removes the output from the input and replaces the input that was removed.
 */
OutputWaiter.prototype.undoSwitchClick = function() {
    this.app.setInput(this.switchOrigData);
    document.getElementById("undo-switch").disabled = true;
};

/**
 * Handler for file switch click events.
 * Moves a file's data for items created via Utils.displayFilesAsHTML to the input.
 */
OutputWaiter.prototype.fileSwitch = function(e) {
    e.preventDefault();
    this.switchOrigData = this.manager.input.get();
    this.app.setInput(e.target.getAttribute("fileValue"));
    document.getElementById("undo-switch").disabled = false;
};

/**
 * Handler for maximise output click events.
 * Resizes the output frame to be as large as possible, or restores it to its original size.
 */
OutputWaiter.prototype.maximiseOutputClick = function(e) {
    const el = e.target.id === "maximise-output" ? e.target : e.target.parentNode;

    if (el.getAttribute("title") === "Maximise") {
        this.app.columnSplitter.collapse(0);
        this.app.columnSplitter.collapse(1);
        this.app.ioSplitter.collapse(0);

        el.setAttribute("title", "Restore");
        el.innerHTML = " Restore";
        this.adjustWidth();
    } else {
        el.setAttribute("title", "Maximise");
        el.innerHTML = " Max";
        this.app.resetLayout();
    }
};

/**
 * Shows or hides the loading icon.
 *
 * @param {boolean} value
 */
OutputWaiter.prototype.toggleLoader = function(value) {
    const outputLoader = document.getElementById("output-loader"),
        outputElement = document.getElementById("output-text");

    if (value) {
        this.manager.controls.hideStaleIndicator();
        this.bakingStatusTimeout = setTimeout(function() {
            outputElement.disabled = true;
            outputLoader.style.visibility = "visible";
            outputLoader.style.opacity = 1;
            this.manager.controls.toggleBakeButtonFunction(true);
        }.bind(this), 200);
    } else {
        clearTimeout(this.bakingStatusTimeout);
        outputElement.disabled = false;
        outputLoader.style.opacity = 0;
        outputLoader.style.visibility = "hidden";
        this.manager.controls.toggleBakeButtonFunction(false);
        this.setStatusMsg("");
    }
};

/**
 * Sets the baking status message value.
 *
 * @param {string} msg
 */
OutputWaiter.prototype.setStatusMsg = function(msg) {
    const el = document.querySelector("#output-loader .loading-msg");

    el.textContent = msg;
};

/**
 * Returns true if the output contains carriage returns
 *
 * @returns {boolean}
 */
OutputWaiter.prototype.containsCR = function() {
    return this.dishStr.indexOf("\r") >= 0;
};

export default OutputWaiter;
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import { InlineMath, BlockMath } from 'react-katex';
import Typography from '@material-ui/core/Typography';
import { withStyles } from '@material-ui/core/styles';
import Highlight from '../../Highlight';
import styles from '../style';
import { getHelmet } from '../utilities';
import 'highlight.js/styles/ocean.css';

const Post = ({ classes, match }) => {
  const { helmet, title, date } = getHelmet(match.url);
  return (
    <React.Fragment>
      {helmet}
      <React.Fragment>
        <Typography variant="h3">{title}</Typography>
        <Typography variant="subtitle1">{date}</Typography>
        <Typography variant="body1">
          A common preprocessing step when operating on data is standardization. This is
          the procedure of making two data-sets comparable by removing any bias and normalizing the
          variance. This definition may seem arbitrary but the effect is quite easy to understand.
        </Typography>
        <Typography variant="body1">
          Imagine you are working on speech recognition for home automation. The prototype device
          works while the production units have significant issues. The only difference between the
          units is the quality of the microphones. An expensive, but high quality, sensor is in the
          prototype. A more cost-effective sensor is in the production units. The specs are a
          different and the training-set is exclusively generated by the expensive sensor. Can the
          change of sensor cause the issue?
        </Typography>
        <Typography variant="body1">
          This is the kind of issue standardization solves. Lets simplify the problem by analyzing
          the time-series.
        </Typography>
        {/* TODO: Time series comparison */}
        <Typography variant="body1">
          This is the kind of issue standardization solves. Lets simplify the problem by analyzing
          the time-series.
        </Typography>
        <Typography variant="body1">
          First notice that the low-cost sensor has an offset. The time-series recorded is non-zero,
          even at points of silence. This is an example of bias in the low-cost sensor, the effect
          of which is raising the value of each sample. In our speech-recognition example, bias is
          due to a flaw in the low-end sensor. For instance, there could be an added voltage between
          the reference ground and the sampling point. We can remove the bias by subtracting the
          average signal strength from the data.
        </Typography>

          <BlockMath
            math={
              '\\begin{aligned}\
              \\bar y &= \\bar x - {1 \\over N} \\sum_{i}^{N} x_i \\\\\
              \\\\\
              \\      &= \\bar x - \\mathrm{E}\\big[\\bar x\\big] \\\\\
              \\end{aligned}'
            }
          />

        <Typography variant="body1">
          The second effect is subtler. The signal generated by the low-end sensor varies less than
          the original. This is due to the sensitivity of the sensor. In speech recognition, it
          means the speaker will need to be louder to generate a comparable signal. The data
          recorded by the high-end sensor has a higher variance. One way to correct for this is to
          divide both signals by their standard-deviation.
        </Typography>

          <BlockMath
            math={
              '\\begin{aligned}\
              \\bar y &= {\\bar x \\over \\sqrt{ {1 \\over N}  \\sum_i^N(\\bar x - \\mathrm{E}\\big[\\bar x\\big])^2}} \\\\\
              \\\\\
                      &= {\\bar x \\over \\sqrt{ \\mathrm{E}\\bigg[\\bar x - \\mathrm{E}\\big[\\bar x\\big]\\bigg]^2}} \\\\\
              \\\\\
                      &= {\\bar x \\over \\sqrt{ \\mathrm{E}\\big[\\bar x^2\\big] - \\mathrm{E}\\big[\\bar x\\big]^2}} \\\\\
              \\end{aligned}'
            }
          />

        <Typography variant="body1">
          See how a change of bias or variance effects the signal.
        </Typography>
        {/* TODO: Change bias / variance plot */}
        <Typography variant="body1">
          All code in this post can be found on{' '}

            GitHub

          .
        </Typography>
        <Typography variant="h4">Environmental Causes</Typography>
        <Typography variant="body1">
          The above example focuses on flaws in the sensor as a way to make this problem concrete.
          But a change in sensor is not the only reason a data-set requires normalization. For audio
          recordings, variance could be a symptom of a change in the environment. For instance, the
          addition of unwanted noise will create a change in signal variance. Similarly, as the
          speaker walks towards the sensor, the signal strength will increase.
        </Typography>
        <Typography variant="body1">
          As for bias, the electrical characteristics of a circuit change based on temporal factors.
          The electrical bias of a circuit could be dependent on the ambient temperature. This means
          the bias changes as the room heats and cools. It also means as the sensor's
          electronics generate heat, the bias will change.
        </Typography>
        <Typography variant="body1">
          The end result is that the data requires continuous standardization. This is typically
          done in batches of <InlineMath math="M" /> samples The application determines the window
          size <InlineMath math="M" />.
        </Typography>
        <Typography variant="body1">
          Performing this running standardization will reduce the effect of environmental changes.
          As a result, this increases the effectiveness of machine-learning algorithms.
        </Typography>
        <Typography variant="h4">A Naive Approach</Typography>
        <Typography variant="body1">
          Below is a direct, yet inefficient, algorithm for windowed standardization.
        </Typography>
        <Highlight language="python">
          def standardize(x, M):{'\n'}
          {'    '}N = x.size{'\n'}
          {'    '}out = np.zeros(N - M){'\n'}
          {'    '}for i in range(0, N - M):{'\n'}
          {'        '}out[i] = x[i] - np.mean(x[i:i + M]){'\n'}
          {'        '}out[i] = out[i] / np.std(x[i:i + M]){'\n'}
          {'    '}return out
        </Highlight>
        <Typography variant="body1">
          This function is verbose and quite easy to understand. Unfortunately, this comes at the
          cost of efficiency. This naive approach has a complexity of <InlineMath math="O(NM)" />,
          where <InlineMath math="N" /> is the input data size and <InlineMath math="M" /> is the
          window size. When approaching a problem such as this, one of the first things to try is
          vectorization. Vectorization, in this case, can reduce the complexity to{' '}
          <InlineMath math="O(N)" /> and confers a host of other benefits.
        </Typography>
        <Typography variant="h4">Why Choose a Vectorized Implementation?</Typography>
        <Typography variant="body1">
          Vectorizing an algorithm refers to operating uniformly across arrays. In other words,
          vectorizing an algorithm replaces *for loops* with optimized vector operations. These
          vectorized operations rely on the underlying linear-algebra library, such as BLAS.
          Optimized linear-algebra libraries provide the following benefits.
        </Typography>
        <Typography variant="h5">SIMD Instructions</Typography>
        <Typography variant="body1">
          Modern processors have{' '}
          Single Instruction, Multiple Data (SIMD)
          instructions. These specialized instructions perform computations on a vector of data. A
          SIMD instruction loads a single operation (instruction) and a vector of data into an array
          of{' '}
          Arithmetic Logic Units{' '}
          (ALUs). SIMD allows for data-level parallelism that can provide enormous efficiency gains.
          This is in contrast to a traditional Single Instruction, Single Data (SISD) architectures.
        </Typography>
        <Typography variant="h5">Parallel Execution</Typography>
        <Typography variant="body1">
          Vectorized operations can often exploit parallelism. Take, for instance, a vector
          dot-product.
        </Typography>

          <BlockMath math={'x = \\bar u^T \\bar v'} />

        <Typography variant="body1">
          This is easily mapped into to two identical sub-problems.
        </Typography>

          <BlockMath
            math={
              '\\begin{aligned}\
              \\bar u &= \\begin{bmatrix} \
              \\bar u_1 \\\\\
              \\bar u_2 \\\\\
              \\end{bmatrix} \\\\\
              \\\\\
              \\bar v &= \\begin{bmatrix} \
              \\bar v_1 \\\\\
              \\bar v_2 \\\\\
              \\end{bmatrix}\\\\\
              \\\\\
              x_1 &= \\bar u_1^T \\bar v_1 \\\\\
              \\\\\
              x_2 &= \\bar u_2^T \\bar v_2 \\\\\
              \\end{aligned}'
            }
          />

        <Typography variant="body1">
          Combining the results of the sub problems gives the answer to the original query.
        </Typography>

          <BlockMath math="x = x_1 + x_2" />

        <Typography variant="body1">
          The two sub-problems can be further divided to achieve the desired level or parallelism.
          This method, MapReduce, is commonly
          exploited in vectorized operations.
        </Typography>
        <Typography variant="h5">Minimizing Cache Misses</Typography>
        <Typography variant="body1">
          Fetching data from memory is a slow process. For this reason, processors cache data for
          fast access. This is common for operations that exhibit{' '}
          sequential locality.
          When accessing data at sequential addresses, the processor loads the entire block into the
          cache. This avoids repeating costly IO operations.
        </Typography>
        <Typography variant="body1">
          Vectorized operations take advantage of sequential locality. For instance, take
          multiplying a{' '}

            column-major matrix
          {' '}
          by a scalar. A column-major matrix has each column stored in contiguous memory. To
          minimize cache misses, this function will iterate sequentially along the major axis.
        </Typography>

          <BlockMath
            math={
              'A = \\begin{bmatrix} \
              a_{1,1} \\ a_{1,2} \\ a_{1,3} \\\\\
              a_{2,1} \\ a_{2,2} \\ a_{2,3} \\\\\
              a_{3,1} \\ a_{3,2} \\ a_{3,3} \\\\\
              \\ldots \\\\\
              \\end{bmatrix}'
            }
          />

        <Typography variant="body1">
          For instance, if <InlineMath math="A" /> is a column-major matrix, then{' '}
          <InlineMath math="a_{2,1}" /> and <InlineMath math="a_{3,1}" /> are adjacent in memory. If
          the matrix <InlineMath math="A" /> has many rows, then <InlineMath math="a_{1,1}" /> and{' '}
          <InlineMath math="a_{1,2}" /> could be in different memory blocks. Iterating along the
          major axis minimizes the number of memory fetches.
        </Typography>
        <Typography variant="h4">A Vectorized Approach</Typography>
        <Typography variant="body1">
          The first step of standardization is determining the mean of the vector. In the{' '}
          windowed approach, this is a{' '}
          moving average filter.
        </Typography>

          <BlockMath
            math={
              '\\begin{aligned} \
              u_j &= {1 \\over M} \\sum_{i = j}^{M + j - 1} x_i \\\\\
              \\\\\
                  &= {1 \\over M} \\bigg[ \\sum_{i}^{M + j - 1} x_i  - \\sum_{i}^{j-1} x_i \\bigg] \\\\\
              \\end{aligned}'
            }
          />

        <Typography variant="body1">
          Note the similarity to the vectorized operation cumulative-summation.
        </Typography>

          <BlockMath math={'cumsum(x)_j = \\sum_{i}^{j} x_{i}'} />

        <Typography variant="body1">
          Below is a vectorized implementation of the moving average filter. This implementation
          uses the cumulative-summation.
        </Typography>
        <Highlight language="python">
          def moving_average(x, M):{'\n'}
          {'    '}x_sum = np.cumsum(x){'\n'}
          {'    '}return (x_sum[M:] - x_sum[:-M]) / float(M)
        </Highlight>
        <Typography variant="body1">A similar trick vectorizes the standard deviation.</Typography>
        <Highlight language="python">
          def standard_deviation(x, M):{'\n'}
          {'    '}x_sum = np.cumsum(x){'\n'}
          {'    '}x_sq_sum = np.cumsum(np.square(x)){'\n'}
          {'\n'}
          {'    '}mean = (x_sum[M:] - x_sum[:-M]) / float(M){'\n'}
          {'    '}sq_mean = (x_sq_sum[M:] - x_sq_sum[:-M]) / float(M){'\n'}
          {'    '}return np.sqrt(sq_mean - np.square(mean))
        </Highlight>
        <Typography variant="body1">
          Combine both definitions for our vectorized windowed standardization algorithm.
        </Typography>
        <Highlight language="python">
          def standardize_vec(x, M):{'\n'}
          {'    '}x_sum = np.cumsum(x){'\n'}
          {'    '}x_sq_sum = np.cumsum(np.square(x)){'\n'}
          {'\n'}
          {'    '}mean = (x_sum[M:] - x_sum[:-M]) / float(M){'\n'}
          {'    '}sq_mean = (x_sq_sum[M:] - x_sq_sum[:-M]) / float(M){'\n'}
          {'    '}std = np.sqrt(sq_mean - np.square(mean)){'\n'}
          {'    '}return (x[:-M] - mean) / std
        </Highlight>
        <Typography variant="h4">Wrapping Up</Typography>
        <Typography variant="body1">
          There is a pitfall with the vectorized approach, and that is numerical error. The
          cumulative sum will sum together the entire vector, only to later get a subset of that
          summation. If the data has a wide range of values, the summation of large values may
          reduce the precision of the results. 32-bit floats can encode around 7 decimal digits of
          information. If the difference in values is near 7 decimal places, there will be numerical
          error. One solution is to use a larger floating point encoding (doubles / quads). That
          often comes with a significant slowdown in execution speed.
        </Typography>
      </React.Fragment>
    </React.Fragment>
  );
};

Post.propTypes = {
  classes: PropTypes.objectOf(PropTypes.string).isRequired,
  match: PropTypes.shape({
    isExact: PropTypes.bool,
    path: PropTypes.string,
    url: PropTypes.string,
  }).isRequired,
};

Post.defaultProps = {};

export default withStyles(styles)(Post);
<commit_msg>Added timing info to post<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import { InlineMath, BlockMath } from 'react-katex';
import Typography from '@material-ui/core/Typography';
import { withStyles } from '@material-ui/core/styles';
import Highlight from '../../Highlight';
import styles from '../style';
import { getHelmet } from '../utilities';
import 'highlight.js/styles/ocean.css';

const Post = ({ classes, match }) => {
  const { helmet, title, date } = getHelmet(match.url);
  return (
    <React.Fragment>
      {helmet}
      <React.Fragment>
        <Typography variant="h3">{title}</Typography>
        <Typography variant="subtitle1">{date}</Typography>
        <Typography variant="body1">
          A common preprocessing step when operating on data is standardization. This is
          the procedure of making two data-sets comparable by removing any bias and normalizing the
          variance. This definition may seem arbitrary but the effect is quite easy to understand.
        </Typography>
        <Typography variant="body1">
          Imagine you are working on speech recognition for home automation. The prototype device
          works while the production units have significant issues. The only difference between the
          units is the quality of the microphones. An expensive, but high quality, sensor is in the
          prototype. A more cost-effective sensor is in the production units. The specs are a
          different and the training-set is exclusively generated by the expensive sensor. Can the
          change of sensor cause the issue?
        </Typography>
        <Typography variant="body1">
          This is the kind of issue standardization solves. Lets simplify the problem by analyzing
          the time-series.
        </Typography>
        {/* TODO: Time series comparison */}
        <Typography variant="body1">
          This is the kind of issue standardization solves. Lets simplify the problem by analyzing
          the time-series.
        </Typography>
        <Typography variant="body1">
          First notice that the low-cost sensor has an offset. The time-series recorded is non-zero,
          even at points of silence. This is an example of bias in the low-cost sensor, the effect
          of which is raising the value of each sample. In our speech-recognition example, bias is
          due to a flaw in the low-end sensor. For instance, there could be an added voltage between
          the reference ground and the sampling point. We can remove the bias by subtracting the
          average signal strength from the data.
        </Typography>

          <BlockMath
            math={
              '\\begin{aligned}\
              \\bar y &= \\bar x - {1 \\over N} \\sum_{i}^{N} x_i \\\\\
              \\\\\
              \\      &= \\bar x - \\mathrm{E}\\big[\\bar x\\big] \\\\\
              \\end{aligned}'
            }
          />

        <Typography variant="body1">
          The second effect is subtler. The signal generated by the low-end sensor varies less than
          the original. This is due to the sensitivity of the sensor. In speech recognition, it
          means the speaker will need to be louder to generate a comparable signal. The data
          recorded by the high-end sensor has a higher variance. One way to correct for this is to
          divide both signals by their standard-deviation.
        </Typography>

          <BlockMath
            math={
              '\\begin{aligned}\
              \\bar y &= {\\bar x \\over \\sqrt{ {1 \\over N}  \\sum_i^N(\\bar x - \\mathrm{E}\\big[\\bar x\\big])^2}} \\\\\
              \\\\\
                      &= {\\bar x \\over \\sqrt{ \\mathrm{E}\\bigg[\\bar x - \\mathrm{E}\\big[\\bar x\\big]\\bigg]^2}} \\\\\
              \\\\\
                      &= {\\bar x \\over \\sqrt{ \\mathrm{E}\\big[\\bar x^2\\big] - \\mathrm{E}\\big[\\bar x\\big]^2}} \\\\\
              \\end{aligned}'
            }
          />

        <Typography variant="body1">
          See how a change of bias or variance effects the signal.
        </Typography>
        {/* TODO: Change bias / variance plot */}
        <Typography variant="body1">
          All code in this post can be found on{' '}

            GitHub

          .
        </Typography>
        <Typography variant="h4">Environmental Causes</Typography>
        <Typography variant="body1">
          The above example focuses on flaws in the sensor as a way to make this problem concrete.
          But a change in sensor is not the only reason a data-set requires normalization. For audio
          recordings, variance could be a symptom of a change in the environment. For instance, the
          addition of unwanted noise will create a change in signal variance. Similarly, as the
          speaker walks towards the sensor, the signal strength will increase.
        </Typography>
        <Typography variant="body1">
          As for bias, the electrical characteristics of a circuit change based on temporal factors.
          The electrical bias of a circuit could be dependent on the ambient temperature. This means
          the bias changes as the room heats and cools. It also means as the sensor's
          electronics generate heat, the bias will change.
        </Typography>
        <Typography variant="body1">
          The end result is that the data requires continuous standardization. This is typically
          done in batches of <InlineMath math="M" /> samples The application determines the window
          size <InlineMath math="M" />.
        </Typography>
        <Typography variant="body1">
          Performing this running standardization will reduce the effect of environmental changes.
          As a result, this increases the effectiveness of machine-learning algorithms.
        </Typography>
        <Typography variant="h4">A Naive Approach</Typography>
        <Typography variant="body1">
          Below is a direct, yet inefficient, algorithm for windowed standardization.
        </Typography>
        <Highlight language="python">
          def standardize(x, M):{'\n'}
          {'    '}N = x.size{'\n'}
          {'    '}out = np.zeros(N - M){'\n'}
          {'    '}for i in range(0, N - M):{'\n'}
          {'        '}out[i] = x[i] - np.mean(x[i:i + M]){'\n'}
          {'        '}out[i] = out[i] / np.std(x[i:i + M]){'\n'}
          {'    '}return out
        </Highlight>
        <Typography variant="body1">
          This function is verbose and quite easy to understand. Unfortunately, this comes at the
          cost of efficiency. This naive approach has a complexity of <InlineMath math="O(NM)" />,
          where <InlineMath math="N" /> is the input data size and <InlineMath math="M" /> is the
          window size. When approaching a problem such as this, one of the first things to try is
          vectorization. Vectorization, in this case, can reduce the complexity to{' '}
          <InlineMath math="O(N)" /> and confers a host of other benefits.
        </Typography>
        <Typography variant="h4">Why Choose a Vectorized Implementation?</Typography>
        <Typography variant="body1">
          Vectorizing an algorithm refers to operating uniformly across arrays. In other words,
          vectorizing an algorithm replaces *for loops* with optimized vector operations. These
          vectorized operations rely on the underlying linear-algebra library, such as BLAS.
          Optimized linear-algebra libraries provide the following benefits.
        </Typography>
        <Typography variant="h5">SIMD Instructions</Typography>
        <Typography variant="body1">
          Modern processors have{' '}
          Single Instruction, Multiple Data (SIMD)
          instructions. These specialized instructions perform computations on a vector of data. A
          SIMD instruction loads a single operation (instruction) and a vector of data into an array
          of{' '}
          Arithmetic Logic Units{' '}
          (ALUs). SIMD allows for data-level parallelism that can provide enormous efficiency gains.
          This is in contrast to a traditional Single Instruction, Single Data (SISD) architectures.
        </Typography>
        <Typography variant="h5">Parallel Execution</Typography>
        <Typography variant="body1">
          Vectorized operations can often exploit parallelism. Take, for instance, a vector
          dot-product.
        </Typography>

          <BlockMath math={'x = \\bar u^T \\bar v'} />

        <Typography variant="body1">
          This is easily mapped into to two identical sub-problems.
        </Typography>

          <BlockMath
            math={
              '\\begin{aligned}\
              \\bar u &= \\begin{bmatrix} \
              \\bar u_1 \\\\\
              \\bar u_2 \\\\\
              \\end{bmatrix} \\\\\
              \\\\\
              \\bar v &= \\begin{bmatrix} \
              \\bar v_1 \\\\\
              \\bar v_2 \\\\\
              \\end{bmatrix}\\\\\
              \\\\\
              x_1 &= \\bar u_1^T \\bar v_1 \\\\\
              \\\\\
              x_2 &= \\bar u_2^T \\bar v_2 \\\\\
              \\end{aligned}'
            }
          />

        <Typography variant="body1">
          Combining the results of the sub problems gives the answer to the original query.
        </Typography>

          <BlockMath math="x = x_1 + x_2" />

        <Typography variant="body1">
          The two sub-problems can be further divided to achieve the desired level or parallelism.
          This method, MapReduce, is commonly
          exploited in vectorized operations.
        </Typography>
        <Typography variant="h5">Minimizing Cache Misses</Typography>
        <Typography variant="body1">
          Fetching data from memory is a slow process. For this reason, processors cache data for
          fast access. This is common for operations that exhibit{' '}
          sequential locality.
          When accessing data at sequential addresses, the processor loads the entire block into the
          cache. This avoids repeating costly IO operations.
        </Typography>
        <Typography variant="body1">
          Vectorized operations take advantage of sequential locality. For instance, take
          multiplying a{' '}

            column-major matrix
          {' '}
          by a scalar. A column-major matrix has each column stored in contiguous memory. To
          minimize cache misses, this function will iterate sequentially along the major axis.
        </Typography>

          <BlockMath
            math={
              'A = \\begin{bmatrix} \
              a_{1,1} \\ a_{1,2} \\ a_{1,3} \\\\\
              a_{2,1} \\ a_{2,2} \\ a_{2,3} \\\\\
              a_{3,1} \\ a_{3,2} \\ a_{3,3} \\\\\
              \\ldots \\\\\
              \\end{bmatrix}'
            }
          />

        <Typography variant="body1">
          For instance, if <InlineMath math="A" /> is a column-major matrix, then{' '}
          <InlineMath math="a_{2,1}" /> and <InlineMath math="a_{3,1}" /> are adjacent in memory. If
          the matrix <InlineMath math="A" /> has many rows, then <InlineMath math="a_{1,1}" /> and{' '}
          <InlineMath math="a_{1,2}" /> could be in different memory blocks. Iterating along the
          major axis minimizes the number of memory fetches.
        </Typography>
        <Typography variant="h4">A Vectorized Approach</Typography>
        <Typography variant="body1">
          The first step of standardization is determining the mean of the vector. In the{' '}
          windowed approach, this is a{' '}
          moving average filter.
        </Typography>

          <BlockMath
            math={
              '\\begin{aligned} \
              u_j &= {1 \\over M} \\sum_{i = j}^{M + j - 1} x_i \\\\\
              \\\\\
                  &= {1 \\over M} \\bigg[ \\sum_{i}^{M + j - 1} x_i  - \\sum_{i}^{j-1} x_i \\bigg] \\\\\
              \\end{aligned}'
            }
          />

        <Typography variant="body1">
          Note the similarity to the vectorized operation cumulative-summation.
        </Typography>

          <BlockMath math={'cumsum(x)_j = \\sum_{i}^{j} x_{i}'} />

        <Typography variant="body1">
          Below is a vectorized implementation of the moving average filter. This implementation
          uses the cumulative-summation.
        </Typography>
        <Highlight language="python">
          def moving_average(x, M):{'\n'}
          {'    '}x_sum = np.cumsum(x){'\n'}
          {'    '}return (x_sum[M:] - x_sum[:-M]) / float(M)
        </Highlight>
        <Typography variant="body1">A similar trick vectorizes the standard deviation.</Typography>
        <Highlight language="python">
          def standard_deviation(x, M):{'\n'}
          {'    '}x_sum = np.cumsum(x){'\n'}
          {'    '}x_sq_sum = np.cumsum(np.square(x)){'\n'}
          {'\n'}
          {'    '}mean = (x_sum[M:] - x_sum[:-M]) / float(M){'\n'}
          {'    '}sq_mean = (x_sq_sum[M:] - x_sq_sum[:-M]) / float(M){'\n'}
          {'    '}return np.sqrt(sq_mean - np.square(mean))
        </Highlight>
        <Typography variant="body1">
          Combine both definitions for our vectorized windowed standardization algorithm.
        </Typography>
        <Highlight language="python">
          def standardize_vec(x, M):{'\n'}
          {'    '}x_sum = np.cumsum(x){'\n'}
          {'    '}x_sq_sum = np.cumsum(np.square(x)){'\n'}
          {'\n'}
          {'    '}mean = (x_sum[M:] - x_sum[:-M]) / float(M){'\n'}
          {'    '}sq_mean = (x_sq_sum[M:] - x_sq_sum[:-M]) / float(M){'\n'}
          {'    '}std = np.sqrt(sq_mean - np.square(mean)){'\n'}
          {'    '}return (x[:-M] - mean) / std
        </Highlight>
        <Typography variant="h4">Wrapping Up</Typography>
        <Typography variant="body1">
          Below is the results from running the naive and vectorized algorithms on a vector of size
          10000. In both cases, the window-size is 2048. The result is the average execution time
          from 50 iterations.
        </Typography>
        <Highlight language="bash">
          50 loops, best of 5: 11.53 sec per loop{'  '}# standardize{'\n'}
          50 loops, best of 5: 17.58 msec per loop # standardize_vec
        </Highlight>
        <Typography variant="body1">
          There is a pitfall with the vectorized approach, and that is numerical error. The
          cumulative sum will sum together the entire vector, only to later get a subset of that
          summation. If the data has a wide range of values, the summation of large values may
          reduce the precision of the results. 32-bit floats can encode around 7 decimal digits of
          information. If the difference in values is near 7 decimal places, there will be numerical
          error. One solution is to use a larger floating point encoding (doubles / quads). That
          often comes with a significant slowdown in execution speed.
        </Typography>
      </React.Fragment>
    </React.Fragment>
  );
};

Post.propTypes = {
  classes: PropTypes.objectOf(PropTypes.string).isRequired,
  match: PropTypes.shape({
    isExact: PropTypes.bool,
    path: PropTypes.string,
    url: PropTypes.string,
  }).isRequired,
};

Post.defaultProps = {};

export default withStyles(styles)(Post);
<|endoftext|>


<commit_before>import * as THREE from '../node_modules/three/build/three.module.js';
import MeshBVHNode from './MeshBVHNode.js';
import BVHConstructionContext from './BVHConstructionContext.js';
import { arrayToBox, boundsToArray } from './BoundsUtilities.js';

export default class MeshBVH extends MeshBVHNode {

	constructor( geo, options = {} ) {

		super();

		// default options
		options = Object.assign( {

			strategy: 0,
			maxDepth: Infinity,
			maxLeafNodes: 10

		}, options );
		options.strategy = Math.max( 0, Math.min( 2, options.strategy ) );

		if ( geo.isBufferGeometry ) {

			this._root = this._buildTree( geo, options );

		} else {

			throw new Error( 'Only BufferGeometries are supported.' );

		}

	}

	/* Private Functions */
	_buildTree( geo, options ) {

		const ctx = new BVHConstructionContext( geo, options );
		const verticesLength = geo.attributes.position.count;
		const indicesLength = ctx.tris.length * 3;
		const indices = new ( verticesLength < 65536 ? Uint16Array : Uint32Array )( indicesLength );
		const boxtemp = new THREE.Box3();

		const createNode = ( bounds, newNode, offset, count, depth = 0 ) => {

			const node = newNode || new MeshBVHNode();

			// get the bounds of the triangles
			node.boundingData = bounds;

			// early out wif we've met our capacity
			if ( count <= options.maxLeafNodes ) {

				ctx.writeReorderedIndices( offset, count, indices );
				node.offset = offset;
				node.count = count;
				return node;

			}

			// Find where to split the volume
			arrayToBox( bounds, boxtemp );
			const split = ctx.getOptimalSplit( boxtemp, offset, count, options.strategy );
			if ( split.axis === - 1 ) {

				ctx.writeReorderedIndices( offset, count, indices );
				node.offset = offset;
				node.count = count;
				return node;

			}

			const splitOffset = ctx.partition( offset, count, split );

			// create the two new child nodes
			if ( splitOffset === offset || splitOffset === offset + count ) {

				ctx.writeReorderedIndices( offset, count, indices );
				node.offset = offset;
				node.count = count;

			} else if ( depth < options.maxDepth ) {

				node.splitAxis = split.axis;
				node.children = [];

				// create the bounds for the left child, keeping it within the bounds of the parent
				const bl = ctx.shrinkBoundsTo( offset, splitOffset - offset, bounds, new Float32Array( 6 ) );
				node.children.push( createNode( bl, null, offset, splitOffset - offset, depth + 1 ) );

				// repeat for right
				const br = ctx.shrinkBoundsTo( splitOffset, offset + count - splitOffset, bounds, new Float32Array( 6 ) );
				node.children.push( createNode( br, null, splitOffset, offset + count - splitOffset, depth + 1 ) );

			}

			return node;

		};

		if ( ! geo.boundingBox ) geo.computeBoundingBox();

		const n = createNode( boundsToArray( geo.boundingBox ), this, 0, ctx.tris.length );
		n.index = new THREE.BufferAttribute( indices, 1 );
		return n;

	}

}
<commit_msg>Make createNode less strange<commit_after>import * as THREE from '../node_modules/three/build/three.module.js';
import MeshBVHNode from './MeshBVHNode.js';
import BVHConstructionContext from './BVHConstructionContext.js';
import { arrayToBox, boundsToArray } from './BoundsUtilities.js';

export default class MeshBVH extends MeshBVHNode {

	constructor( geo, options = {} ) {

		super();

		// default options
		options = Object.assign( {

			strategy: 0,
			maxDepth: Infinity,
			maxLeafNodes: 10

		}, options );
		options.strategy = Math.max( 0, Math.min( 2, options.strategy ) );

		if ( geo.isBufferGeometry ) {

			this._root = this._buildTree( geo, options );

		} else {

			throw new Error( 'Only BufferGeometries are supported.' );

		}

	}

	/* Private Functions */
	_buildTree( geo, options ) {

		const ctx = new BVHConstructionContext( geo, options );
		const verticesLength = geo.attributes.position.count;
		const indicesLength = ctx.tris.length * 3;
		const indices = new ( verticesLength < 65536 ? Uint16Array : Uint32Array )( indicesLength );
		const boxtemp = new THREE.Box3();

		// either recursively splits the given node, creating left and right subtrees for it, or makes it a leaf node,
		// recording the offset and count of its triangles and writing them into the reordered geometry index.
		const splitNode = ( node, offset, count, depth = 0 ) => {

			// early out wif we've met our capacity
			if ( count <= options.maxLeafNodes ) {

				ctx.writeReorderedIndices( offset, count, indices );
				node.offset = offset;
				node.count = count;
				return node;

			}

			// Find where to split the volume
			arrayToBox( node.boundingData, boxtemp );
			const split = ctx.getOptimalSplit( boxtemp, offset, count, options.strategy );
			if ( split.axis === - 1 ) {

				ctx.writeReorderedIndices( offset, count, indices );
				node.offset = offset;
				node.count = count;
				return node;

			}

			const splitOffset = ctx.partition( offset, count, split );

			// create the two new child nodes
			if ( splitOffset === offset || splitOffset === offset + count ) {

				ctx.writeReorderedIndices( offset, count, indices );
				node.offset = offset;
				node.count = count;

			} else if ( depth < options.maxDepth ) {

				// create the left child, keeping the bounds within the bounds of the parent
				const left = new MeshBVHNode();
				const lstart = offset, lcount = splitOffset - offset;
				left.boundingData = ctx.shrinkBoundsTo( lstart, lcount, node.boundingData, new Float32Array( 6 ) );
				splitNode( left, lstart, lcount, depth + 1 );

				// repeat for right
				const right = new MeshBVHNode();
				const rstart = splitOffset, rcount = count - lcount;
				right.boundingData = ctx.shrinkBoundsTo( rstart, rcount, node.boundingData, new Float32Array( 6 ) );
				splitNode( right, rstart, rcount, depth + 1 );

				node.splitAxis = split.axis;
				node.children = [left, right];

			}

			return node;

		};

		if ( ! geo.boundingBox ) geo.computeBoundingBox();

		this.boundingData = boundsToArray( geo.boundingBox );
		this.index = new THREE.BufferAttribute( indices, 1 );
		splitNode( this, 0, ctx.tris.length );

		return this;

	}

}
<|endoftext|>


<commit_before>var userID;
var authObject;

function checkUserInDatabase(authData){
	userID = authData.google.id;
	var path = "https://tinderpreneurship.firebaseio.com/users/" + userID;
	var userRef = new Firebase(path);
	userRef.once('value', function(snapshot){
		if(!snapshot.exists()){
			var userGoogleData = new Firebase(path + "/google");
			userGoogleData.set({
				uid: userID,
				name: authData.google.displayName,
				email: authData.google.email,
				img: authData.google.profileImageURL
			});
			var userProfileData = new Firebase(path + "/profile");
			userProfileData.set({
				description: "",
				desires: JSON.stringify([]),
				peeves: "",
				secretname: getNewSecretName(),
				strengths: JSON.stringify([])
			});
			displayMessage("Welcome to Tinderpreneurship!
Since this is your first time, fill out this profile to help others learn more about you.")
			openSection('profile');
		}
		else{
			openSection('menu');
		}
	});
}

function googleLogin(){
	var ref = new Firebase("https://tinderpreneurship.firebaseio.com");
	ref.authWithOAuthPopup('google', function(error, authData){
		if(error){
			console.log(error);
		}
		else{
			console.log(authData);
			authObject = authData;
			checkUserInDatabase(authData);
		}
	},
	{
		scope: "email"
	});
}

/*--------------------------------------------*/
/*---> SECRET NAMES <-------------------------*/
/*--------------------------------------------*/

var colors = ["aeneous","albicant","albugineous","amaranthine","argent","atrous","aubergine","aurulent","azuline","azure","badious","beige","brunneous","burnet","caesious","cardinal","castaneous","castory","celadon","celeste","cerulean","cesious","chartreuse","chlorochrous","chrysochlorous","cinerious","cinnabar","citreous","citrine","claret","coccineous","columbine","coquelicot","corbeau","cramoisy","cretaceous","croceate","cyaneous","eburnean","erythraean","ferruginous","filemot","flammeous","flavescent","fuliginous","fulvous","fuscous","gamboge","glaucous","goldenrod","greige","gridelin","griseous","haematic","heliotrope","hoary","hyacinthine","ianthine","ibis","icterine","icteritious","incarnadine","indigo","infuscate","isabelline","jacinthe","jessamy","kermes","khaki","lateritious","leucochroic","liard","lovat","lurid","luteolous","luteous","lutescent","madder","magenta","maroon","mauve","mazarine","melanic","melichrous","meline","miniaceous","minium","modena","morel","nacarat","nankeen","nigricant","nigrine","niveous","ochre","ochroleucous","olivaceous","or","pavonated","periwinkle","perse","phoeniceous","piceous","plumbeous","ponceau","porphyrous","porraceous","prasinous","primrose","puccoon","puce","puniceous","purpure","purpureal","pyrrhous","rhodopsin","rubiginous","rubious","rufous","russet","sable","saffron","sage","sanguineous","sapphire","sarcoline","sepia","sinopia","slate","smalt","smaragdine","solferino","sorrel","spadiceous","stammel","stramineous","suede","sulphureous","tan","taupe","tawny","teal","terracotta","testaceous","tilleul","titian","topaz","turquoise","ultramarine","umber","vermeil","vermilion","vinaceous","vinous","violaceous","violet","virescent","virid","viridian","vitellary","wallflower","watchet","wheaten","whey","willowish","xanthic","zinnober"];

var animals = ["aardwolf","aasvogel","aberdevine","accentor","acipenser","addax","adjutant","adzebill","aepyornis","agouti","amberjack","amphiuma","anhinga","anoa","anole","antechinus","argali","aurochs","avocet","axolotl","aye-aye","babirusa","bandicoot","bangtail","banteng","barasingha","barbet","beira","bharal","binturong","biscacha","bittern","blauwbok","blenny","blesbok","bongo","bontbok","borzoi","brach","brachet","brandling","brocken","bulbul","bullock","cabrilla","caiman","caple","capybara","caracal","caracara","cassowary","chamois","chevrotain","chiru","chital","chuckwalla","civet","cleg","coelacanth","colobus","colocolo","colugo","conure","corella","coypu","culex","culver","curlew","cusk","dabchick","daw","degu","desman","dhole","dibatag","dik-dik","diprotodon","dobbin","dobsonfly","douc","douroucouli","dowitcher","duarf","dugong","duiker","dunnart","earwig","echidna","eland","emmet","eyas","falanouc","falconet","fossa","francolin","froghopper","galago","galah","gannet","gaur","gayal","gelada","gemsbok","genet","gerenuk","gharial","goa","goanna","goral","gowk","graphiure","grayling","grebe","grilse","grison","grivet","grysbok","guenon","guereza","guillemot","gundi","gymnure","hammerkop","harrier","havier","hellbender","hoatzin","hocco","hogget","huemul","hutia","hyrax","ibex","ibis","ichneumon","iguana","iiwi","ipiti","isatis","ithomiid","iulus","izard","jabiru","jacana","jade","jennet","jerboa","jiboya","junco","jurel","kagu","kaka","kea","keffel","kereru","kiang","kine","kinkajou","kleenebok","klipspringer","knobber","kob","kouprey","kudu","kyloe","lammergeier","langur","lechwe","leopon","leveret","limpkin","linsang","lorikeet","loris","lutung","malbrouck","mangabey","markhor","meerkat","morel","muntjac","murre","nightjar","numbat","nutria","nyala","octodont","okapi","olm","onager","onocrotal","oribi","oropendola","oryx","ouzel","oystercatcher","palfrey","pangolin","peccary","percheron","petrel","phalarope","phoenicopter","pichi","pichiciego","pika","porbeagle","potto","pratincole","prion","pudu","puku","quarrion","quaviver","quawk","quelea","querquedule","quetzal","queyock","quickhatch","quinnat","quokka","quoll","raad","rach","ratel","reebok","reedbuck","rooibok","rooirhebok","rorqual","rosella","saiga","saki","sambar","scanderoon","seriema","serow","serval","shearling","siamang","siskin","sitatunga","skink","skua","solenodon","sounder","spatangoid","springbok","springhare","steenbok","stellion","stirk","sumpter","sunbittern","suni","tabanid","tahr","takin","tamandua","tamaraw","tarpan","tayra","teg","tenrec","thamin","thylacine","tinamou","titi","topi","trogon","tsessebe","tuatara","tucutucu","turaco","tuza","uakari","uguisu","uintathere","uraster","urial","urochs","uromastix","urraca","urubu","vaquita","vedalia","vicuna","vireo","viscacha","wapiti","wether","whiffet","whitecoat","widgeon","wisent","woolbird","xanthareel","xeme","xenops","xenurine","xiphias","xiphosuran","yabby","yaffingale","yakow","yapok","yeanling","yelt","yelting","yowie","zander","zebrinny","zebrule","zebu","zemni","zeren","zho","zokor","zonure","zyzzyva"];

function getNewSecretName(){

	/* STILL NOT WORKING - TODO: Ensure that new secret names are unique
	var secretnames = [];

	function getSecretNames(){
		var secretNameRef = new Firebase("https://tinderpreneurship.firebaseio.com/users/secretnames");
		secretNameRef.once('value', function(snapshot){
			snapshot.forEach(function(childSnapshot){
				secretnames.push(childSnapshot.val());
			});
		});
		console.log(secretnames);
	}

	getSecretNames();*/

	var color = colors[Math.floor(colors.length * Math.random())];
	var animal = animals[Math.floor(animals.length * Math.random())];
	var number = Math.floor((9999 - 1000) * Math.random()) + 1000;
	var secretname = color.charAt(0).toUpperCase() + color.substr(1) + animal.charAt(0).toUpperCase() + animal.substr(1) + number;

	var secretNameRef = new Firebase("https://tinderpreneurship.firebaseio.com/secretnames");
	console.log(secretname);
	secretNameRef.push(secretname);

	return secretname;

}

console.log("LOADED googleAuth.js");<commit_msg>Added arrays for matches<commit_after>var userID;
var authObject;

function checkUserInDatabase(authData){
	userID = authData.google.id;
	var path = "https://tinderpreneurship.firebaseio.com/users/" + userID;
	var userRef = new Firebase(path);
	userRef.once('value', function(snapshot){
		if(!snapshot.exists()){
			var userGoogleData = new Firebase(path + "/google");
			userGoogleData.set({
				uid: userID,
				name: authData.google.displayName,
				email: authData.google.email,
				img: authData.google.profileImageURL
			});
			var userProfileData = new Firebase(path + "/profile");
			userProfileData.set({
				description: "",
				desires: JSON.stringify([]),
				peeves: "",
				secretname: getNewSecretName(),
				strengths: JSON.stringify([]),
				pickedyou: JSON.stringify([]),
				youpicked: JSON.stringify([])
			});
			displayMessage("Welcome to Tinderpreneurship!
Since this is your first time, fill out this profile to help others learn more about you.")
			openSection('profile');
		}
		else{
			openSection('menu');
		}
	});
}

function googleLogin(){
	var ref = new Firebase("https://tinderpreneurship.firebaseio.com");
	ref.authWithOAuthPopup('google', function(error, authData){
		if(error){
			console.log(error);
		}
		else{
			console.log(authData);
			authObject = authData;
			checkUserInDatabase(authData);
		}
	},
	{
		scope: "email"
	});
}

/*--------------------------------------------*/
/*---> SECRET NAMES <-------------------------*/
/*--------------------------------------------*/

var colors = ["aeneous","albicant","albugineous","amaranthine","argent","atrous","aubergine","aurulent","azuline","azure","badious","beige","brunneous","burnet","caesious","cardinal","castaneous","castory","celadon","celeste","cerulean","cesious","chartreuse","chlorochrous","chrysochlorous","cinerious","cinnabar","citreous","citrine","claret","coccineous","columbine","coquelicot","corbeau","cramoisy","cretaceous","croceate","cyaneous","eburnean","erythraean","ferruginous","filemot","flammeous","flavescent","fuliginous","fulvous","fuscous","gamboge","glaucous","goldenrod","greige","gridelin","griseous","haematic","heliotrope","hoary","hyacinthine","ianthine","ibis","icterine","icteritious","incarnadine","indigo","infuscate","isabelline","jacinthe","jessamy","kermes","khaki","lateritious","leucochroic","liard","lovat","lurid","luteolous","luteous","lutescent","madder","magenta","maroon","mauve","mazarine","melanic","melichrous","meline","miniaceous","minium","modena","morel","nacarat","nankeen","nigricant","nigrine","niveous","ochre","ochroleucous","olivaceous","or","pavonated","periwinkle","perse","phoeniceous","piceous","plumbeous","ponceau","porphyrous","porraceous","prasinous","primrose","puccoon","puce","puniceous","purpure","purpureal","pyrrhous","rhodopsin","rubiginous","rubious","rufous","russet","sable","saffron","sage","sanguineous","sapphire","sarcoline","sepia","sinopia","slate","smalt","smaragdine","solferino","sorrel","spadiceous","stammel","stramineous","suede","sulphureous","tan","taupe","tawny","teal","terracotta","testaceous","tilleul","titian","topaz","turquoise","ultramarine","umber","vermeil","vermilion","vinaceous","vinous","violaceous","violet","virescent","virid","viridian","vitellary","wallflower","watchet","wheaten","whey","willowish","xanthic","zinnober"];

var animals = ["aardwolf","aasvogel","aberdevine","accentor","acipenser","addax","adjutant","adzebill","aepyornis","agouti","amberjack","amphiuma","anhinga","anoa","anole","antechinus","argali","aurochs","avocet","axolotl","aye-aye","babirusa","bandicoot","bangtail","banteng","barasingha","barbet","beira","bharal","binturong","biscacha","bittern","blauwbok","blenny","blesbok","bongo","bontbok","borzoi","brach","brachet","brandling","brocken","bulbul","bullock","cabrilla","caiman","caple","capybara","caracal","caracara","cassowary","chamois","chevrotain","chiru","chital","chuckwalla","civet","cleg","coelacanth","colobus","colocolo","colugo","conure","corella","coypu","culex","culver","curlew","cusk","dabchick","daw","degu","desman","dhole","dibatag","dik-dik","diprotodon","dobbin","dobsonfly","douc","douroucouli","dowitcher","duarf","dugong","duiker","dunnart","earwig","echidna","eland","emmet","eyas","falanouc","falconet","fossa","francolin","froghopper","galago","galah","gannet","gaur","gayal","gelada","gemsbok","genet","gerenuk","gharial","goa","goanna","goral","gowk","graphiure","grayling","grebe","grilse","grison","grivet","grysbok","guenon","guereza","guillemot","gundi","gymnure","hammerkop","harrier","havier","hellbender","hoatzin","hocco","hogget","huemul","hutia","hyrax","ibex","ibis","ichneumon","iguana","iiwi","ipiti","isatis","ithomiid","iulus","izard","jabiru","jacana","jade","jennet","jerboa","jiboya","junco","jurel","kagu","kaka","kea","keffel","kereru","kiang","kine","kinkajou","kleenebok","klipspringer","knobber","kob","kouprey","kudu","kyloe","lammergeier","langur","lechwe","leopon","leveret","limpkin","linsang","lorikeet","loris","lutung","malbrouck","mangabey","markhor","meerkat","morel","muntjac","murre","nightjar","numbat","nutria","nyala","octodont","okapi","olm","onager","onocrotal","oribi","oropendola","oryx","ouzel","oystercatcher","palfrey","pangolin","peccary","percheron","petrel","phalarope","phoenicopter","pichi","pichiciego","pika","porbeagle","potto","pratincole","prion","pudu","puku","quarrion","quaviver","quawk","quelea","querquedule","quetzal","queyock","quickhatch","quinnat","quokka","quoll","raad","rach","ratel","reebok","reedbuck","rooibok","rooirhebok","rorqual","rosella","saiga","saki","sambar","scanderoon","seriema","serow","serval","shearling","siamang","siskin","sitatunga","skink","skua","solenodon","sounder","spatangoid","springbok","springhare","steenbok","stellion","stirk","sumpter","sunbittern","suni","tabanid","tahr","takin","tamandua","tamaraw","tarpan","tayra","teg","tenrec","thamin","thylacine","tinamou","titi","topi","trogon","tsessebe","tuatara","tucutucu","turaco","tuza","uakari","uguisu","uintathere","uraster","urial","urochs","uromastix","urraca","urubu","vaquita","vedalia","vicuna","vireo","viscacha","wapiti","wether","whiffet","whitecoat","widgeon","wisent","woolbird","xanthareel","xeme","xenops","xenurine","xiphias","xiphosuran","yabby","yaffingale","yakow","yapok","yeanling","yelt","yelting","yowie","zander","zebrinny","zebrule","zebu","zemni","zeren","zho","zokor","zonure","zyzzyva"];

function getNewSecretName(){

	/* STILL NOT WORKING - TODO: Ensure that new secret names are unique
	var secretnames = [];

	function getSecretNames(){
		var secretNameRef = new Firebase("https://tinderpreneurship.firebaseio.com/users/secretnames");
		secretNameRef.once('value', function(snapshot){
			snapshot.forEach(function(childSnapshot){
				secretnames.push(childSnapshot.val());
			});
		});
		console.log(secretnames);
	}

	getSecretNames();*/

	var color = colors[Math.floor(colors.length * Math.random())];
	var animal = animals[Math.floor(animals.length * Math.random())];
	var number = Math.floor((9999 - 1000) * Math.random()) + 1000;
	var secretname = color.charAt(0).toUpperCase() + color.substr(1) + animal.charAt(0).toUpperCase() + animal.substr(1) + number;

	var secretNameRef = new Firebase("https://tinderpreneurship.firebaseio.com/secretnames");
	console.log(secretname);
	secretNameRef.push(secretname);

	return secretname;

}

console.log("LOADED googleAuth.js");<|endoftext|>


<commit_before>describe('Test date Picker Utils', function(){
  var utils, constants, tz = 'UTC';

  /**
   * Creates a moment object from an iso8601 string, using a pre-set timezone.
   */
  function dateBuilder(iso8601) {
    return moment.tz(iso8601, tz);
  }

  var model = dateBuilder('2014-06-29T19:00:00+00:00'); // sunday

  beforeEach(angular.mock.module('datePicker'));

  beforeEach(angular.mock.inject(function($injector){
    utils = $injector.get('datePickerUtils');
    constants = $injector.get('datePickerConfig');
    utils.setParams(tz);
  }));

  /*
   * At no point do we ever need to get minutes, weeks, years, months, or hours for an unknown date.
   *    * The only date building util function which is called without a specific date is getDaysOfWeek.
   *        * This is called via the update() function in datePicker.js if scope.weekdays is falsy.
   *    * These tests have therefore been removed.
   */

  it('get visible mins provided date', function(){
    var start = dateBuilder('2014-06-29T19:00:00+00:00'); // sunday
    var end = dateBuilder('2014-06-29T19:55:00+00:00'); // sunday
    var chosen = dateBuilder('2014-06-29T19:00:00+00:00'); // sunday
    var mins = utils.getVisibleMinutes(chosen, constants.step);

    expect(mins).toBeDefined();
    expect(start.isSame(mins[0])).toBe(true);
    expect(end.isSame(mins[mins.length-1])).toBe(true);
  });

  it('get visible weeks provided date', function(){
    var start = dateBuilder('2014-05-25T00:00:00+00:00'); // sunday
    var end = dateBuilder('2014-07-05T00:00:00+00:00');  // sunday
    var chosen = dateBuilder('2014-06-29T19:00:00+00:00'); // sunday
    var weeks = utils.getVisibleWeeks(chosen, constants.step);

    expect(weeks).toBeDefined();
    expect(start.isSame(weeks[0][0])).toBe(true);
    expect(end.isSame(weeks[5][weeks[5].length - 1])).toBe(true);
  });

  it('get visible years provided date', function(){
    var start = dateBuilder('2010-01-01T00:00:00+00:00'); // friday
    var end = dateBuilder('2021-01-01T00:00:00+00:00'); // friday
    var chosen = dateBuilder('2014-06-29T19:00:00+00:00'); // sunday
    var years = utils.getVisibleYears(chosen, constants.step);
    expect(years).toBeDefined();
    expect(start.isSame(years[0])).toBe(true);
    expect(end.isSame(years[years.length - 1])).toBe(true);
  });

  it('get default days of week', function(){
    var days = utils.getDaysOfWeek(null);

    expect(days).toBeDefined();
  });

  it('get days of week provided date', function(){
    var start = dateBuilder('2014-05-26T00:00:00+00:00'); // monday
    var end = dateBuilder('2014-06-01T00:00:00+00:00'); // sunday
    var days = utils.getDaysOfWeek(start);

    expect(days).toBeDefined();
    expect(start.isSame(days[0])).toBe(true);
    expect(end.isSame(days[days.length-1])).toBe(true);
  });

  it('get default months provided date', function(){
    var start = dateBuilder('2014-01-01T00:00:00+00:00'); // wednesday
    var end = dateBuilder('2014-12-01T00:00:00+00:00'); // monday
    var chosen = dateBuilder('2014-06-29T19:00:00+00:00'); // sunday
    var months = utils.getVisibleMonths(chosen);

    expect(months).toBeDefined();
    expect(start.isSame(months[0])).toBe(true);
    expect(end.isSame(months[months.length-1])).toBe(true);
  });

  it('get default hours provided date', function(){
    var start = dateBuilder('2014-06-29T00:00:00+00:00'); // sunday
    var end = dateBuilder('2014-06-29T23:00:00+00:00'); // sunday
    var chosen = dateBuilder('2014-06-29T19:00:00+00:00'); // sunday
    var hours = utils.getVisibleHours(chosen);

    expect(hours).toBeDefined();
    expect(start.isSame(hours[0])).toBe(true);
    expect(end.isSame(hours[hours.length-1])).toBe(true);
  });

  it('model is after date', function(){
    // model is 19h, dateAfter is 20h, so model should be before and not after
    var dateAfter =  dateBuilder('2014-06-29T20:00:00+00:00'); // sunday

    expect(utils.isAfter(model, dateAfter)).toBe(false);
    expect(utils.isBefore(model, dateAfter)).toBe(true);
  });

  it('model is before date', function(){
    // model is 19h, dateAfter is 18h, so model should be after and not before
    var dateAfter =  dateBuilder('2014-06-29T18:00:00+00:00'); // sunday

    expect(utils.isAfter(model, dateAfter)).toBe(true);
    expect(utils.isBefore(model, dateAfter)).toBe(false);
  });

  it('model is almost same', function(){
    var dateSimilar =  dateBuilder('2014-06-29T19:00:55.555'); // sunday

    expect(utils.isSameYear(model, dateSimilar)).toBe(true);
    expect(utils.isSameMonth(model, dateSimilar)).toBe(true);
    expect(utils.isSameDay(model, dateSimilar)).toBe(true);
    expect(utils.isSameHour(model, dateSimilar)).toBe(true);
    expect(utils.isSameMinutes(model, dateSimilar)).toBe(true);
  });

  //it('angular date format is a moment format', function () {
  //  //Angular formats: https://docs.angularjs.org/api/ng/filter/date
  //  //Moment formats: http://momentjs.com/docs/#/parsing/string-format/
  //  expect(utils.toMomentFormat('dd-MM-yyyy')).toBe('DD-MM-YYYY');
  //  expect(utils.toMomentFormat('EEEE MM/yy')).toBe('dddd MM/YY');
  //  expect(utils.toMomentFormat('dd MMMM yyyy HH:mm:ss.sss')).toBe('DD MMMM YYYY HH:mm:ss.SSS');
  //});
});
<commit_msg>Incorrect day of the week in test data comment<commit_after>describe('Test date Picker Utils', function(){
  var utils, constants, tz = 'UTC';

  /**
   * Creates a moment object from an iso8601 string, using a pre-set timezone.
   */
  function dateBuilder(iso8601) {
    return moment.tz(iso8601, tz);
  }

  var model = dateBuilder('2014-06-29T19:00:00+00:00'); // sunday

  beforeEach(angular.mock.module('datePicker'));

  beforeEach(angular.mock.inject(function($injector){
    utils = $injector.get('datePickerUtils');
    constants = $injector.get('datePickerConfig');
    utils.setParams(tz);
  }));

  /*
   * At no point do we ever need to get minutes, weeks, years, months, or hours for an unknown date.
   *    * The only date building util function which is called without a specific date is getDaysOfWeek.
   *        * This is called via the update() function in datePicker.js if scope.weekdays is falsy.
   *    * These tests have therefore been removed.
   */

  it('get visible mins provided date', function(){
    var start = dateBuilder('2014-06-29T19:00:00+00:00'); // sunday
    var end = dateBuilder('2014-06-29T19:55:00+00:00'); // sunday
    var chosen = dateBuilder('2014-06-29T19:00:00+00:00'); // sunday
    var mins = utils.getVisibleMinutes(chosen, constants.step);

    expect(mins).toBeDefined();
    expect(start.isSame(mins[0])).toBe(true);
    expect(end.isSame(mins[mins.length-1])).toBe(true);
  });

  it('get visible weeks provided date', function(){
    var start = dateBuilder('2014-05-25T00:00:00+00:00'); // sunday
    var end = dateBuilder('2014-07-05T00:00:00+00:00');  // saturday
    var chosen = dateBuilder('2014-06-29T19:00:00+00:00'); // sunday
    var weeks = utils.getVisibleWeeks(chosen, constants.step);

    expect(weeks).toBeDefined();
    expect(start.isSame(weeks[0][0])).toBe(true);
    expect(end.isSame(weeks[5][weeks[5].length - 1])).toBe(true);
  });

  it('get visible years provided date', function(){
    var start = dateBuilder('2010-01-01T00:00:00+00:00'); // friday
    var end = dateBuilder('2021-01-01T00:00:00+00:00'); // friday
    var chosen = dateBuilder('2014-06-29T19:00:00+00:00'); // sunday
    var years = utils.getVisibleYears(chosen, constants.step);
    expect(years).toBeDefined();
    expect(start.isSame(years[0])).toBe(true);
    expect(end.isSame(years[years.length - 1])).toBe(true);
  });

  it('get default days of week', function(){
    var days = utils.getDaysOfWeek(null);

    expect(days).toBeDefined();
  });

  it('get days of week provided date', function(){
    var start = dateBuilder('2014-05-26T00:00:00+00:00'); // monday
    var end = dateBuilder('2014-06-01T00:00:00+00:00'); // sunday
    var days = utils.getDaysOfWeek(start);

    expect(days).toBeDefined();
    expect(start.isSame(days[0])).toBe(true);
    expect(end.isSame(days[days.length-1])).toBe(true);
  });

  it('get default months provided date', function(){
    var start = dateBuilder('2014-01-01T00:00:00+00:00'); // wednesday
    var end = dateBuilder('2014-12-01T00:00:00+00:00'); // monday
    var chosen = dateBuilder('2014-06-29T19:00:00+00:00'); // sunday
    var months = utils.getVisibleMonths(chosen);

    expect(months).toBeDefined();
    expect(start.isSame(months[0])).toBe(true);
    expect(end.isSame(months[months.length-1])).toBe(true);
  });

  it('get default hours provided date', function(){
    var start = dateBuilder('2014-06-29T00:00:00+00:00'); // sunday
    var end = dateBuilder('2014-06-29T23:00:00+00:00'); // sunday
    var chosen = dateBuilder('2014-06-29T19:00:00+00:00'); // sunday
    var hours = utils.getVisibleHours(chosen);

    expect(hours).toBeDefined();
    expect(start.isSame(hours[0])).toBe(true);
    expect(end.isSame(hours[hours.length-1])).toBe(true);
  });

  it('model is after date', function(){
    // model is 19h, dateAfter is 20h, so model should be before and not after
    var dateAfter =  dateBuilder('2014-06-29T20:00:00+00:00'); // sunday

    expect(utils.isAfter(model, dateAfter)).toBe(false);
    expect(utils.isBefore(model, dateAfter)).toBe(true);
  });

  it('model is before date', function(){
    // model is 19h, dateAfter is 18h, so model should be after and not before
    var dateAfter =  dateBuilder('2014-06-29T18:00:00+00:00'); // sunday

    expect(utils.isAfter(model, dateAfter)).toBe(true);
    expect(utils.isBefore(model, dateAfter)).toBe(false);
  });

  it('model is almost same', function(){
    var dateSimilar =  dateBuilder('2014-06-29T19:00:55.555'); // sunday

    expect(utils.isSameYear(model, dateSimilar)).toBe(true);
    expect(utils.isSameMonth(model, dateSimilar)).toBe(true);
    expect(utils.isSameDay(model, dateSimilar)).toBe(true);
    expect(utils.isSameHour(model, dateSimilar)).toBe(true);
    expect(utils.isSameMinutes(model, dateSimilar)).toBe(true);
  });

  //it('angular date format is a moment format', function () {
  //  //Angular formats: https://docs.angularjs.org/api/ng/filter/date
  //  //Moment formats: http://momentjs.com/docs/#/parsing/string-format/
  //  expect(utils.toMomentFormat('dd-MM-yyyy')).toBe('DD-MM-YYYY');
  //  expect(utils.toMomentFormat('EEEE MM/yy')).toBe('dddd MM/YY');
  //  expect(utils.toMomentFormat('dd MMMM yyyy HH:mm:ss.sss')).toBe('DD MMMM YYYY HH:mm:ss.SSS');
  //});
});
<|endoftext|>