<commit_before>/**
 * This package provides SVG text functionality.
 *
 * @author Joschi <josua.krause@gmail.com>
 */

var jkjs;
if(typeof module !== "undefined") {
  jkjs = {};
  module.exports = jkjs;
} else {
  window.jkjs = window.jkjs || {}; // init namespace
  jkjs = window.jkjs;
}

jkjs.text = function() {

  /** Left alignment of text. */
  var ALIGN_LEFT = 0;
  /** Middle alignment of text. */
  var ALIGN_MIDDLE = 1;
  /** Right alignment of text. */
  var ALIGN_RIGHT = 2;

  this.align = {
    left: ALIGN_LEFT,
    middle: ALIGN_MIDDLE,
    right: ALIGN_RIGHT,
  };

  /** Top position of text. */
  var POS_TOP = 0;
  /** Center position of text. */
  var POS_CENTER = 1;
  /** Bottom position of text. */
  var POS_BOTTOM = 2;

  this.position = {
    top: POS_TOP,
    center: POS_CENTER,
    bottom: POS_BOTTOM,
  };

  var exact = true;
  this.exact = function(_) {
    if(!arguments.length) return exact;
    exact = _;
  };

  function getBBox(sel) {
    if(sel.node().getBBox) {
      return sel.node().getBBox();
    }
    var fs = sel.attr('font-size');
    var size = 16;
    if(fs) {
      size = +fs.replace(/[a-zA-Z]/g, '');
    }
    return {
      'width': size * 0.75 * sel.text().length,
      'height': size,
    };
  }

  function fit(line, selText, w, h) {
    var ow;
    var oh;
    if(exact || !selText.__textSizeCache) {
      selText.text(line);
      var own = getBBox(selText);
      ow = own.width;
      oh = own.height;
      if(!exact) {
        selText.__textSizeCache = {
          w: ow / line.length,
          h: oh,
        };
      }
    } else {
      ow = line.length * selText.__textSizeCache.w;
      oh = selText.__textSizeCache.h;
    }
    return {
      high: oh > h,
      wide: ow > w,
      height: oh,
    };
  }

  /** The ellipsis string. */
  var hellip = "\u2026";
  /** The short ellipsis string. */
  var shellip = "..";

  function shrink(line, wordwrap, before) {
    if(!wordwrap) {
      if(line.length < 4) {
        return [];
      }
      var sl = line.substring(0, line.length - (hellip.length + 1));
      if(sl[sl.length - 1] === ' ') {
        sl = sl.substring(0, sl.length - 1);
      }
      if(line.length < 7) {
        if(line[line.length - 1] === shellip[shellip.length - 1]) {
          return [ line.substring(0, line.length - (shellip.length + 1)) + shellip ];
        }
        return [ sl + shellip ];
      }
      return [ sl + hellip ];
    }
    var space = line.lastIndexOf(" ");
    if(space < 0) {
      return before.length ? [ line, before ] : [ line ];
    }
    var first = line.substring(0, space);
    if(line.length > space + 1) {
      return [ first, line.substring(space + 1) + " " + before ];
    }
    return before.length ? [ first, before ] : [ first ];
  }

  function computeSegments(box, text, wordwrap, textSel, all) {
    var segments = [];
    var w = box.width;
    var curY = box.y;
    var maxY = box.y + box.height;
    var height = Math.floor(all.height);
    if(!all.high) {
      if(!all.wide) {
        segments.push(text);
      } else {
        var ww = wordwrap;
        var cur = text;
        var rem = "";
        while(true) {
          var s = shrink(cur, ww, rem);
          if(!s.length) {
            break;
          }
          if(s[0] == cur) {
            ww = false;
          }
          var curFit = fit(s[0], textSel, w, maxY - curY);
          if(curFit.high) {
            if(!segments.length) {
              break;
            }
            curY -= height;
            cur = segments.pop() + " " + s[0];
            rem = "";
            ww = false;
            continue;
          }
          if(curFit.wide) {
            cur = s[0];
            rem = s.length > 1 ? s[1] : "";
            continue;
          }
          segments.push(s[0]);
          curY += height;
          if(s.length < 2) {
            break;
          }
          cur = s[1];
          rem = "";
        }
      }
    }
    return segments;
  }

  /**
   * Displays the given text in the given bounding box. If needed the text is wrapped or shortened using ellipses.
   *
   * @param selText
   *          A selection of one text element.
   * @param text
   *          The text to display.
   * @param box
   *          The bounding box. {x, y, width, height}.
   * @param wordwrap
   *          Whether to allow wrapping around word boundaries when the box is too small. If false only ellipses are used.
   * @param horAlign
   *          The horizontal alignment of the text. Defaults to left alignment. Valid values are jkjs.text.align.{left, middle, right}.
   * @param verPos
   *          The vertical positioning. Defaults to top. Valid values are jkjs.text.position.{top, center, bottom}.
   * @param addTitle
   *          Whether to add a title element for tool-tips. Defaults to false.
   *          If a string is passed this string will be used as title.
   * @param guaranteeText
   *          Whether text will be forced even if there is not enough room. Defaults to false.
   * @returns
   *          Whether the text element contains any text. This can be used to remove the text element if not needed.
   *
jkjs.text.display(sel, ...) || sel.remove();

   */
  this.display = function(selText, text, box, wordwrap, horAlign, verPos, addTitle, guaranteeText) {
    // clean previous state
    selText.selectAll("tspan").remove();
    selText.attr("x", null);
    selText.attr("y", null);
    selText.attr("text-anchor", null);
    selText.attr("alignment-baseline", null);
    // compute segments
    var ra = horAlign || ALIGN_LEFT;
    var boxW = box.width;
    var all = fit(text, selText, boxW, box.height);
    var height = Math.floor(all.height);
    var segments = computeSegments(box, text, wordwrap, selText, all);
    if(!segments.length && guaranteeText) {
      segments = [ shellip ];
    }
    // produce geometry
    if(ra !== ALIGN_LEFT) {
      selText.style("text-anchor", ra === ALIGN_MIDDLE ? "middle" : "end");
    }
    var backH = 0;
    var vp = verPos || POS_TOP;
    if(vp === POS_CENTER) {
      selText.style("alignment-baseline", "central");
      backH = height * 0.5;
    }
    var x = box.x;
    var y = box.y;
    var anchorX;
    if(ra === ALIGN_LEFT) {
      anchorX = x;
    } else if(ra === ALIGN_MIDDLE) {
      anchorX = x + boxW * 0.5;
    } else {
      anchorX = x + boxW;
    }
    var boxH = box.height;
    var offH;
    if(vp === POS_TOP) {
      offH = y;
    } else if(vp === POS_CENTER) {
      offH = y + (boxH - segments.length * height) * 0.5;
    } else if(vp === POS_BOTTOM) {
      offH = y + boxH - segments.length * height;
    }
    if(segments.length === 1) {
      selText.text(segments[0])
        .attr("x", anchorX)
        .attr("y", offH + height - backH);
    } else {
      selText.text("");
      if(segments.length) {
        var posY = offH;
        segments.forEach(function(seg) {
          posY += height;
          selText.append("tspan")
            .attr("x", anchorX)
            .attr("y", posY - backH)
            .text(seg);
        });
      }
    }
    if(addTitle) {
      selText.selectAll("title").remove();
      selText.append("title").text(!!addTitle !== addTitle ? addTitle : text);
    }
    return segments.length != 0;
  };

}; // jkjs.text

jkjs.text = new jkjs.text(); // create instance
<commit_msg>noShrink arg<commit_after>/**
 * This package provides SVG text functionality.
 *
 * @author Joschi <josua.krause@gmail.com>
 */

var jkjs;
if(typeof module !== "undefined") {
  jkjs = {};
  module.exports = jkjs;
} else {
  window.jkjs = window.jkjs || {}; // init namespace
  jkjs = window.jkjs;
}

jkjs.text = function() {

  /** Left alignment of text. */
  var ALIGN_LEFT = 0;
  /** Middle alignment of text. */
  var ALIGN_MIDDLE = 1;
  /** Right alignment of text. */
  var ALIGN_RIGHT = 2;

  this.align = {
    left: ALIGN_LEFT,
    middle: ALIGN_MIDDLE,
    right: ALIGN_RIGHT,
  };

  /** Top position of text. */
  var POS_TOP = 0;
  /** Center position of text. */
  var POS_CENTER = 1;
  /** Bottom position of text. */
  var POS_BOTTOM = 2;

  this.position = {
    top: POS_TOP,
    center: POS_CENTER,
    bottom: POS_BOTTOM,
  };

  var exact = true;
  this.exact = function(_) {
    if(!arguments.length) return exact;
    exact = _;
  };

  function getBBox(sel) {
    if(sel.node().getBBox) {
      return sel.node().getBBox();
    }
    var fs = sel.attr('font-size');
    var size = 16;
    if(fs) {
      size = +fs.replace(/[a-zA-Z]/g, '');
    }
    return {
      'width': size * 0.75 * sel.text().length,
      'height': size,
    };
  }

  function fit(line, selText, w, h) {
    var ow;
    var oh;
    if(exact || !selText.__textSizeCache) {
      selText.text(line);
      var own = getBBox(selText);
      ow = own.width;
      oh = own.height;
      if(!exact) {
        selText.__textSizeCache = {
          w: ow / line.length,
          h: oh,
        };
      }
    } else {
      ow = line.length * selText.__textSizeCache.w;
      oh = selText.__textSizeCache.h;
    }
    return {
      high: oh > h,
      wide: ow > w,
      height: oh,
    };
  }

  /** The ellipsis string. */
  var hellip = "\u2026";
  /** The short ellipsis string. */
  var shellip = "..";

  function shrink(line, wordwrap, before, noShrink) {
    if(noShrink) {
      return [];
    }
    if(!wordwrap) {
      if(line.length < 4) {
        return [];
      }
      var sl = line.substring(0, line.length - (hellip.length + 1));
      if(sl[sl.length - 1] === ' ') {
        sl = sl.substring(0, sl.length - 1);
      }
      if(line.length < 7) {
        if(line[line.length - 1] === shellip[shellip.length - 1]) {
          return [ line.substring(0, line.length - (shellip.length + 1)) + shellip ];
        }
        return [ sl + shellip ];
      }
      return [ sl + hellip ];
    }
    var space = line.lastIndexOf(" ");
    if(space < 0) {
      return before.length ? [ line, before ] : [ line ];
    }
    var first = line.substring(0, space);
    if(line.length > space + 1) {
      return [ first, line.substring(space + 1) + " " + before ];
    }
    return before.length ? [ first, before ] : [ first ];
  }

  function computeSegments(box, text, wordwrap, textSel, all, noShrink) {
    var segments = [];
    var w = box.width;
    var curY = box.y;
    var maxY = box.y + box.height;
    var height = Math.floor(all.height);
    if(!all.high) {
      if(!all.wide) {
        segments.push(text);
      } else {
        var ww = wordwrap;
        var cur = text;
        var rem = "";
        while(true) {
          var s = shrink(cur, ww, rem, noShrink);
          if(!s.length) {
            break;
          }
          if(s[0] == cur) {
            ww = false;
          }
          var curFit = fit(s[0], textSel, w, maxY - curY);
          if(curFit.high) {
            if(!segments.length) {
              break;
            }
            curY -= height;
            cur = segments.pop() + " " + s[0];
            rem = "";
            ww = false;
            continue;
          }
          if(curFit.wide) {
            cur = s[0];
            rem = s.length > 1 ? s[1] : "";
            continue;
          }
          segments.push(s[0]);
          curY += height;
          if(s.length < 2) {
            break;
          }
          cur = s[1];
          rem = "";
        }
      }
    }
    return segments;
  }

  /**
   * Displays the given text in the given bounding box. If needed the text is wrapped or shortened using ellipses.
   *
   * @param selText
   *          A selection of one text element.
   * @param text
   *          The text to display.
   * @param box
   *          The bounding box. {x, y, width, height}.
   * @param wordwrap
   *          Whether to allow wrapping around word boundaries when the box is too small. If false only ellipses are used.
   * @param horAlign
   *          The horizontal alignment of the text. Defaults to left alignment. Valid values are jkjs.text.align.{left, middle, right}.
   * @param verPos
   *          The vertical positioning. Defaults to top. Valid values are jkjs.text.position.{top, center, bottom}.
   * @param addTitle
   *          Whether to add a title element for tool-tips. Defaults to false.
   *          If a string is passed this string will be used as title.
   * @param guaranteeText
   *          Whether text will be forced even if there is not enough room. Defaults to false.
   * @param noShrink
   *          Whether to shrink the text.
   * @returns
   *          Whether the text element contains any text. This can be used to remove the text element if not needed.
   *
jkjs.text.display(sel, ...) || sel.remove();

   */
  this.display = function(selText, text, box, wordwrap, horAlign, verPos, addTitle, guaranteeText, noShrink) {
    // clean previous state
    selText.selectAll("tspan").remove();
    selText.attr("x", null);
    selText.attr("y", null);
    selText.attr("text-anchor", null);
    selText.attr("alignment-baseline", null);
    // compute segments
    var ra = horAlign || ALIGN_LEFT;
    var boxW = box.width;
    var all = fit(text, selText, boxW, box.height);
    var height = Math.floor(all.height);
    var segments = computeSegments(box, text, wordwrap, selText, all, noShrink);
    if(!segments.length && guaranteeText) {
      segments = [ shellip ];
    }
    // produce geometry
    if(ra !== ALIGN_LEFT) {
      selText.style("text-anchor", ra === ALIGN_MIDDLE ? "middle" : "end");
    }
    var backH = 0;
    var vp = verPos || POS_TOP;
    if(vp === POS_CENTER) {
      selText.style("alignment-baseline", "central");
      backH = height * 0.5;
    }
    var x = box.x;
    var y = box.y;
    var anchorX;
    if(ra === ALIGN_LEFT) {
      anchorX = x;
    } else if(ra === ALIGN_MIDDLE) {
      anchorX = x + boxW * 0.5;
    } else {
      anchorX = x + boxW;
    }
    var boxH = box.height;
    var offH;
    if(vp === POS_TOP) {
      offH = y;
    } else if(vp === POS_CENTER) {
      offH = y + (boxH - segments.length * height) * 0.5;
    } else if(vp === POS_BOTTOM) {
      offH = y + boxH - segments.length * height;
    }
    if(segments.length === 1) {
      selText.text(segments[0])
        .attr("x", anchorX)
        .attr("y", offH + height - backH);
    } else {
      selText.text("");
      if(segments.length) {
        var posY = offH;
        segments.forEach(function(seg) {
          posY += height;
          selText.append("tspan")
            .attr("x", anchorX)
            .attr("y", posY - backH)
            .text(seg);
        });
      }
    }
    if(addTitle) {
      selText.selectAll("title").remove();
      selText.append("title").text(!!addTitle !== addTitle ? addTitle : text);
    }
    return segments.length != 0;
  };

}; // jkjs.text

jkjs.text = new jkjs.text(); // create instance
<|endoftext|>


<commit_before>// Copyright 2017, University of Colorado Boulder

/**
 * Deploys a production version after incrementing the test version number.
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 */

'use strict';

const SimVersion = require( '../common/SimVersion' );
const booleanPrompt = require( '../common/booleanPrompt' );
const build = require( '../common/build' );
const buildServerRequest = require( '../common/buildServerRequest' );
const checkoutMaster = require( '../common/checkoutMaster' );
const checkoutTarget = require( '../common/checkoutTarget' );
const execute = require( '../common/execute' );
const getDependencies = require( '../common/getDependencies' );
const getRepoVersion = require( '../common/getRepoVersion' );
const gitAdd = require( '../common/gitAdd' );
const gitCommit = require( '../common/gitCommit' );
const gitIsClean = require( '../common/gitIsClean' );
const gitPush = require( '../common/gitPush' );
const gruntCommand = require( '../common/gruntCommand' );
const hasRemoteBranch = require( '../common/hasRemoteBranch' );
const npmUpdate = require( '../common/npmUpdate' );
const setRepoVersion = require( '../common/setRepoVersion' );
const simMetadata = require( '../common/simMetadata' );
const updateDependenciesJSON = require( '../common/updateDependenciesJSON' );
const vpnCheck = require( '../common/vpnCheck' );
const grunt = require( 'grunt' );
const _ = require( 'lodash' ); // eslint-disable-line

/**
 * Deploys a production version after incrementing the test version number.
 * @public
 *
 * @param {string} repo
 * @param {string} branch
 * @param {Array.<string>} brands
 * @param {boolean} noninteractive
 * @param {string} [message] - Optional message to append to the version-increment commit.
 * @returns {Promise.<SimVersion>}
 */
module.exports = async function( repo, branch, brands, noninteractive, message ) {
  SimVersion.ensureReleaseBranch( branch );

  if ( !( await vpnCheck() ) ) {
    grunt.fail.fatal( 'VPN or being on campus is required for this build. Ensure VPN is enabled, or that you have access to phet-server.int.colorado.edu' );
  }

  const isClean = await gitIsClean( repo );
  if ( !isClean ) {
    throw new Error( `Unclean status in ${repo}, cannot create release branch` );
  }

  if ( !( await hasRemoteBranch( repo, branch ) ) ) {
    throw new Error( `Cannot find release branch ${branch} for ${repo}` );
  }

  if ( !grunt.file.exists( `../${repo}/assets/${repo}-screenshot.png` ) && brands.includes( 'phet' ) ) {
    throw new Error( `Missing screenshot file (${repo}/assets/${repo}-screenshot.png), aborting production deployment` );
  }

  if ( !await booleanPrompt( 'Are QA credits up-to-date?', noninteractive ) ) {
    throw new Error( 'Aborted production deployment' );
  }

  if ( !await booleanPrompt( 'Are there no untested maintenance patches that need spot checks? (An issue would be created in the sim repo)', noninteractive ) ) {
    throw new Error( 'Aborted production deployment' );
  }

  await checkoutTarget( repo, branch, true ); // include npm update

  try {
    const previousVersion = await getRepoVersion( repo );
    let version;
    let versionChanged;

    if ( previousVersion.testType === null ) {
      if ( noninteractive || !await booleanPrompt( `It appears that the last deployment was a production deployment (${previousVersion.toString()}).\nWould you like to redeploy (i.e. did the last production deploy fail for some reason?)`, false ) ) {
        throw new Error( 'Aborted production deployment: It appears that the last deployment was for production.' );
      }

      version = previousVersion;
      versionChanged = false;
    }
    else if ( previousVersion.testType === 'rc' ) {
      version = new SimVersion( previousVersion.major, previousVersion.minor, previousVersion.maintenance );
      versionChanged = true;
    }
    else {
      throw new Error( 'Aborted production deployment since the version number cannot be incremented safely' );
    }

    const isFirstVersion = !( await simMetadata( {
      summary: true,
      simulation: repo
    } ).projects );

    // Initial deployment nags
    if ( isFirstVersion ) {
      if ( !await booleanPrompt( 'Is the master checklist complete (e.g. are screenshots added to assets, etc.)', noninteractive ) ) {
        throw new Error( 'Aborted production deployment' );
      }
    }

    const versionString = version.toString();

    // caps-lock should hopefully shout this at people. do we have a text-to-speech synthesizer we can shout out of their speakers?
    // SECOND THOUGHT: this would be horrible during automated maintenance releases.
    if ( !await booleanPrompt( `DEPLOY ${repo} ${versionString} (brands: ${brands.join( ',' )}) to PRODUCTION`, noninteractive ) ) {
      throw new Error( 'Aborted production deployment' );
    }

    if ( versionChanged ) {
      await setRepoVersion( repo, version, message );
      await gitPush( repo, branch );
    }

    // Make sure our correct npm dependencies are set
    await npmUpdate( repo );
    await npmUpdate( 'chipper' );

    // Update the README on the branch
    grunt.log.writeln( 'Updating branch README' );
    try {
      await execute( gruntCommand, [ 'published-README' ], `../${repo}` );
    }
    catch( e ) {
      grunt.log.writeln( 'published-README error, may not exist, will try generate-published-README' );
      try {
        await execute( gruntCommand, [ 'generate-published-README' ], `../${repo}` );
      }
      catch( e ) {
        grunt.log.writeln( 'No published README generation found' );
      }
    }
    await gitAdd( repo, 'README.md' );
    try {
      await gitCommit( repo, `Generated published README.md as part of a production deploy for ${versionString}` );
      await gitPush( repo, branch );
    }
    catch( e ) {
      grunt.log.writeln( 'Production README is already up-to-date' );
    }

    // No special options required here, as we send the main request to the build server
    grunt.log.writeln( await build( repo, {
      brands: brands
    } ) );

    /**
     * The necessary clean up steps to do if aborting after the build
     * @param {string} message - message to error out with
     * @returns {Promise<void>}
     */
    const postBuildAbort = async message => {

      // Abort version update
      if ( versionChanged ) {
        await setRepoVersion( repo, previousVersion, message );
        await gitPush( repo, branch );
      }

      // Abort checkout, (will be caught and master will be checked out
      throw new Error( message );
    };

    if ( !await booleanPrompt( `Please test the built version of ${repo}.\nIs it ready to deploy?`, noninteractive ) ) {
      await postBuildAbort( 'Aborted production deployment (aborted version change too).' );
    }

    // Move over dependencies.json and commit/push
    await updateDependenciesJSON( repo, brands, versionString, branch );

    // Send the build request
    await buildServerRequest( repo, version, branch, await getDependencies( repo ), {
      locales: '*',
      brands: brands,
      servers: [ 'dev', 'production' ]
    } );

    // Move back to master
    await checkoutMaster( repo, true );

    if ( brands.includes( 'phet' ) ) {
      grunt.log.writeln( `Deployed: https://phet.colorado.edu/sims/html/${repo}/latest/${repo}_en.html` );
    }
    if ( brands.includes( 'phet-io' ) ) {
      grunt.log.writeln( `Deployed: https://phet-io.colorado.edu/sims/${repo}/${versionString}/` );
    }

    grunt.log.writeln( 'Please wait for the build-server to complete the deployment, and then test!' );

    if ( isFirstVersion && brands.includes( 'phet' ) ) {
      grunt.log.writeln( 'After testing, let the simulation lead know it has been deployed, so they can edit metadata on the website' );

      // Update the README on master
      grunt.log.writeln( 'Updating master README' );
      await execute( gruntCommand, [ 'published-README' ], `../${repo}` );
      await gitAdd( repo, 'README.md' );
      try {
        await gitCommit( repo, `Generated published README.md as part of a production deploy for ${versionString}` );
        await gitPush( repo, 'master' );
      }
      catch( e ) {
        grunt.log.writeln( 'Production README is already up-to-date' );
      }
    }

    // phet-io nags from the checklist
    if ( brands.includes( 'phet-io' ) ) {
      grunt.log.writeln( 'If this is a version that will be used with students, then make sure to remove the password protection.' );
      grunt.log.writeln( 'See https://github.com/phetsims/phet-io/blob/master/doc/phet-io-security.md for details.' );
      grunt.log.writeln( '' );
      grunt.log.writeln( 'Make sure that the current level of instrumentation is represented here in the Instrumentation Status Spreadsheet:' );
      grunt.log.writeln( 'https://docs.google.com/spreadsheets/d/18_QNGuVtYtxOEKG9xRBs_PSQpyvzySF1Gk5puR-5Fv4/edit#gid=1881767354' );
      grunt.log.writeln( '' );
      grunt.log.writeln( 'If you are delivering this to a partner, update partners.md (phet-io/doc/partners.md) to show this delivery.' );
      grunt.log.writeln( 'Read the intro of the document to make sure that you format the entry correctly.' );
    }

    return version;
  }
  catch( e ) {
    grunt.log.warn( 'Detected failure during deploy, reverting to master' );
    await checkoutMaster( repo, true );
    throw e;
  }
};
<commit_msg>Improving wording for no-RC-in-between-production or redeploy prompt<commit_after>// Copyright 2017, University of Colorado Boulder

/**
 * Deploys a production version after incrementing the test version number.
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 */

'use strict';

const SimVersion = require( '../common/SimVersion' );
const booleanPrompt = require( '../common/booleanPrompt' );
const build = require( '../common/build' );
const buildServerRequest = require( '../common/buildServerRequest' );
const checkoutMaster = require( '../common/checkoutMaster' );
const checkoutTarget = require( '../common/checkoutTarget' );
const execute = require( '../common/execute' );
const getDependencies = require( '../common/getDependencies' );
const getRepoVersion = require( '../common/getRepoVersion' );
const gitAdd = require( '../common/gitAdd' );
const gitCommit = require( '../common/gitCommit' );
const gitIsClean = require( '../common/gitIsClean' );
const gitPush = require( '../common/gitPush' );
const gruntCommand = require( '../common/gruntCommand' );
const hasRemoteBranch = require( '../common/hasRemoteBranch' );
const npmUpdate = require( '../common/npmUpdate' );
const setRepoVersion = require( '../common/setRepoVersion' );
const simMetadata = require( '../common/simMetadata' );
const updateDependenciesJSON = require( '../common/updateDependenciesJSON' );
const vpnCheck = require( '../common/vpnCheck' );
const grunt = require( 'grunt' );
const _ = require( 'lodash' ); // eslint-disable-line

/**
 * Deploys a production version after incrementing the test version number.
 * @public
 *
 * @param {string} repo
 * @param {string} branch
 * @param {Array.<string>} brands
 * @param {boolean} noninteractive
 * @param {string} [message] - Optional message to append to the version-increment commit.
 * @returns {Promise.<SimVersion>}
 */
module.exports = async function( repo, branch, brands, noninteractive, message ) {
  SimVersion.ensureReleaseBranch( branch );

  if ( !( await vpnCheck() ) ) {
    grunt.fail.fatal( 'VPN or being on campus is required for this build. Ensure VPN is enabled, or that you have access to phet-server.int.colorado.edu' );
  }

  const isClean = await gitIsClean( repo );
  if ( !isClean ) {
    throw new Error( `Unclean status in ${repo}, cannot create release branch` );
  }

  if ( !( await hasRemoteBranch( repo, branch ) ) ) {
    throw new Error( `Cannot find release branch ${branch} for ${repo}` );
  }

  if ( !grunt.file.exists( `../${repo}/assets/${repo}-screenshot.png` ) && brands.includes( 'phet' ) ) {
    throw new Error( `Missing screenshot file (${repo}/assets/${repo}-screenshot.png), aborting production deployment` );
  }

  if ( !await booleanPrompt( 'Are QA credits up-to-date?', noninteractive ) ) {
    throw new Error( 'Aborted production deployment' );
  }

  if ( !await booleanPrompt( 'Are there no untested maintenance patches that need spot checks? (An issue would be created in the sim repo)', noninteractive ) ) {
    throw new Error( 'Aborted production deployment' );
  }

  await checkoutTarget( repo, branch, true ); // include npm update

  try {
    const previousVersion = await getRepoVersion( repo );
    let version;
    let versionChanged;

    if ( previousVersion.testType === null ) {
      if ( noninteractive || !await booleanPrompt( `The last deployment was a production deployment (${previousVersion.toString()}) and an RC version is required between production versions. Would you like to redeploy ${previousVersion.toString()} (y) or cancel this process and revert to master (N)`, false ) ) {
        throw new Error( 'Aborted production deployment: It appears that the last deployment was for production.' );
      }

      version = previousVersion;
      versionChanged = false;
    }
    else if ( previousVersion.testType === 'rc' ) {
      version = new SimVersion( previousVersion.major, previousVersion.minor, previousVersion.maintenance );
      versionChanged = true;
    }
    else {
      throw new Error( 'Aborted production deployment since the version number cannot be incremented safely' );
    }

    const isFirstVersion = !( await simMetadata( {
      summary: true,
      simulation: repo
    } ).projects );

    // Initial deployment nags
    if ( isFirstVersion ) {
      if ( !await booleanPrompt( 'Is the master checklist complete (e.g. are screenshots added to assets, etc.)', noninteractive ) ) {
        throw new Error( 'Aborted production deployment' );
      }
    }

    const versionString = version.toString();

    // caps-lock should hopefully shout this at people. do we have a text-to-speech synthesizer we can shout out of their speakers?
    // SECOND THOUGHT: this would be horrible during automated maintenance releases.
    if ( !await booleanPrompt( `DEPLOY ${repo} ${versionString} (brands: ${brands.join( ',' )}) to PRODUCTION`, noninteractive ) ) {
      throw new Error( 'Aborted production deployment' );
    }

    if ( versionChanged ) {
      await setRepoVersion( repo, version, message );
      await gitPush( repo, branch );
    }

    // Make sure our correct npm dependencies are set
    await npmUpdate( repo );
    await npmUpdate( 'chipper' );

    // Update the README on the branch
    grunt.log.writeln( 'Updating branch README' );
    try {
      await execute( gruntCommand, [ 'published-README' ], `../${repo}` );
    }
    catch( e ) {
      grunt.log.writeln( 'published-README error, may not exist, will try generate-published-README' );
      try {
        await execute( gruntCommand, [ 'generate-published-README' ], `../${repo}` );
      }
      catch( e ) {
        grunt.log.writeln( 'No published README generation found' );
      }
    }
    await gitAdd( repo, 'README.md' );
    try {
      await gitCommit( repo, `Generated published README.md as part of a production deploy for ${versionString}` );
      await gitPush( repo, branch );
    }
    catch( e ) {
      grunt.log.writeln( 'Production README is already up-to-date' );
    }

    // No special options required here, as we send the main request to the build server
    grunt.log.writeln( await build( repo, {
      brands: brands
    } ) );

    /**
     * The necessary clean up steps to do if aborting after the build
     * @param {string} message - message to error out with
     * @returns {Promise<void>}
     */
    const postBuildAbort = async message => {

      // Abort version update
      if ( versionChanged ) {
        await setRepoVersion( repo, previousVersion, message );
        await gitPush( repo, branch );
      }

      // Abort checkout, (will be caught and master will be checked out
      throw new Error( message );
    };

    if ( !await booleanPrompt( `Please test the built version of ${repo}.\nIs it ready to deploy?`, noninteractive ) ) {
      await postBuildAbort( 'Aborted production deployment (aborted version change too).' );
    }

    // Move over dependencies.json and commit/push
    await updateDependenciesJSON( repo, brands, versionString, branch );

    // Send the build request
    await buildServerRequest( repo, version, branch, await getDependencies( repo ), {
      locales: '*',
      brands: brands,
      servers: [ 'dev', 'production' ]
    } );

    // Move back to master
    await checkoutMaster( repo, true );

    if ( brands.includes( 'phet' ) ) {
      grunt.log.writeln( `Deployed: https://phet.colorado.edu/sims/html/${repo}/latest/${repo}_en.html` );
    }
    if ( brands.includes( 'phet-io' ) ) {
      grunt.log.writeln( `Deployed: https://phet-io.colorado.edu/sims/${repo}/${versionString}/` );
    }

    grunt.log.writeln( 'Please wait for the build-server to complete the deployment, and then test!' );

    if ( isFirstVersion && brands.includes( 'phet' ) ) {
      grunt.log.writeln( 'After testing, let the simulation lead know it has been deployed, so they can edit metadata on the website' );

      // Update the README on master
      grunt.log.writeln( 'Updating master README' );
      await execute( gruntCommand, [ 'published-README' ], `../${repo}` );
      await gitAdd( repo, 'README.md' );
      try {
        await gitCommit( repo, `Generated published README.md as part of a production deploy for ${versionString}` );
        await gitPush( repo, 'master' );
      }
      catch( e ) {
        grunt.log.writeln( 'Production README is already up-to-date' );
      }
    }

    // phet-io nags from the checklist
    if ( brands.includes( 'phet-io' ) ) {
      grunt.log.writeln( 'If this is a version that will be used with students, then make sure to remove the password protection.' );
      grunt.log.writeln( 'See https://github.com/phetsims/phet-io/blob/master/doc/phet-io-security.md for details.' );
      grunt.log.writeln( '' );
      grunt.log.writeln( 'Make sure that the current level of instrumentation is represented here in the Instrumentation Status Spreadsheet:' );
      grunt.log.writeln( 'https://docs.google.com/spreadsheets/d/18_QNGuVtYtxOEKG9xRBs_PSQpyvzySF1Gk5puR-5Fv4/edit#gid=1881767354' );
      grunt.log.writeln( '' );
      grunt.log.writeln( 'If you are delivering this to a partner, update partners.md (phet-io/doc/partners.md) to show this delivery.' );
      grunt.log.writeln( 'Read the intro of the document to make sure that you format the entry correctly.' );
    }

    return version;
  }
  catch( e ) {
    grunt.log.warn( 'Detected failure during deploy, reverting to master' );
    await checkoutMaster( repo, true );
    throw e;
  }
};
<|endoftext|>


<commit_before>/* eslint-disable @typescript-eslint/no-var-requires */
const _ = require('lodash');
const path = require('path');
const tailwind = require('tailwindcss');
const glob = require('glob-all');

const AssetsManifestPlugin = require('webpack-assets-manifest');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const PurgeCssPlugin = require('purgecss-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');

const isProduction = process.env.NODE_ENV === 'production';

let plugins = [
    new MiniCssExtractPlugin({ filename: isProduction ? 'bundle.[chunkhash:8].css' : 'bundle.[hash:8].css' }),
    new AssetsManifestPlugin({
        writeToDisk: true,
        publicPath: true,
        integrity: true,
        integrityHashes: ['sha384'],
    }),
    new ForkTsCheckerWebpackPlugin(),
];

if (isProduction) {
    plugins = plugins.concat([
        new PurgeCssPlugin({
            paths: glob.sync([
                path.join(__dirname, 'resources/scripts/**/*.ts'),
                path.join(__dirname, 'resources/themes/pterodactyl/**/*.blade.php'),
            ]),
            whitelistPatterns: [/^xterm/],
            extractors: [
                {
                    extractor: class {
                        static extract (content) {
                            return content.match(/[A-z0-9-:\/]+/g) || [];
                        }
                    },
                    extensions: ['html', 'ts', 'tsx', 'js', 'php'],
                },
            ],
        }),
    ]);
}

module.exports = {
    cache: true,
    target: 'web',
    mode: process.env.NODE_ENV,
    devtool: isProduction ? false : 'eval-source-map',
    performance: {
        hints: false,
    },
    entry: [
        'react-hot-loader/patch',
        './resources/styles/main.css',
        './resources/scripts/index.tsx',
    ],
    output: {
        path: path.resolve(__dirname, 'public/assets'),
        filename: isProduction ? 'bundle.[chunkhash:8].js' : 'bundle.[hash:8].js',
        chunkFilename: isProduction ? '[name].[chunkhash:8].js' : '[name].[hash:8].js',
        publicPath: _.get(process.env, 'PUBLIC_PATH', '') + '/assets/',
        crossOriginLoading: 'anonymous',
    },
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                exclude: /node_modules/,
                use: [
                    {
                        loader: 'babel-loader',
                        options: {
                            cacheDirectory: !isProduction,
                            presets: [
                                '@babel/typescript',
                                '@babel/env',
                                '@babel/react',
                            ],
                            plugins: [
                                'tailwind-components',
                                'react-hot-loader/babel',
                                '@babel/transform-runtime',
                                '@babel/proposal-class-properties',
                                '@babel/proposal-object-rest-spread',
                                '@babel/syntax-dynamic-import',
                            ],
                        },
                    },
                ],
            },
            {
                test: /\.css$/,
                include: [
                    path.resolve(__dirname, 'resources'),
                ],
                use: [
                    {
                        loader: MiniCssExtractPlugin.loader,
                        options: {
                            hmr: !isProduction,
                        },
                    },
                    {
                        loader: 'css-loader',
                        options: {
                            sourceMap: !isProduction,
                            importLoaders: 1,
                        },
                    },
                    { loader: 'resolve-url-loader' },
                    {
                        loader: 'postcss-loader',
                        options: {
                            ident: 'postcss',
                            sourceMap: true,
                            plugins: [
                                require('postcss-import'),
                                tailwind('./tailwind.js'),
                                require('postcss-preset-env')({
                                    stage: 2,
                                }),
                                require('precss'),
                            ].concat(isProduction ? require('cssnano') : []),
                        },
                    },
                ],
            },
            {
                test: /\.(png|jpg|gif|svg)$/,
                loader: 'file-loader',
                options: {
                    name: '[name].[ext]?[hash:8]',
                },
            },
        ],
    },
    resolve: {
        extensions: ['.ts', '.tsx', '.js', '.json'],
        alias: {
            '@': path.join(__dirname, 'resources/scripts'),
        },
        symlinks: false,
    },
    plugins: plugins,
    optimization: {
        minimize: isProduction,
        minimizer: [
            new TerserPlugin({
                cache: true,
                parallel: true,
                terserOptions: {
                    safari10: true,
                    mangle: true,
                    output: {
                        comments: false,
                    },
                },
            }),
        ],
    },
    watchOptions: {
        ignored: /node_modules/,
    },
    devServer: {
        contentBase: path.join(__dirname, 'public'),
        publicPath: _.get(process.env, 'PUBLIC_PATH', '') + '/assets/',
        allowedHosts: [
            '.pterodactyl.test',
        ],
        headers: {
            'Access-Control-Allow-Origin': '*',
        },
    },
};
<commit_msg>Helps to run purgecss against actual files<commit_after>/* eslint-disable @typescript-eslint/no-var-requires */
const _ = require('lodash');
const path = require('path');
const tailwind = require('tailwindcss');
const glob = require('glob-all');

const AssetsManifestPlugin = require('webpack-assets-manifest');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const PurgeCssPlugin = require('purgecss-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');

const isProduction = process.env.NODE_ENV === 'production';

let plugins = [
    new MiniCssExtractPlugin({ filename: isProduction ? 'bundle.[chunkhash:8].css' : 'bundle.[hash:8].css' }),
    new AssetsManifestPlugin({
        writeToDisk: true,
        publicPath: true,
        integrity: true,
        integrityHashes: ['sha384'],
    }),
    new ForkTsCheckerWebpackPlugin(),
];

if (isProduction) {
    plugins = plugins.concat([
        new PurgeCssPlugin({
            paths: glob.sync([
                path.join(__dirname, 'resources/scripts/**/*.tsx'),
                path.join(__dirname, 'resources/views/templates/**/*.blade.php'),
            ]),
            whitelistPatterns: [/^xterm/],
            extractors: [
                {
                    extractor: class {
                        static extract (content) {
                            return content.match(/[A-z0-9-:\/]+/g) || [];
                        }
                    },
                    extensions: ['html', 'ts', 'tsx', 'js', 'php'],
                },
            ],
        }),
    ]);
}

module.exports = {
    cache: true,
    target: 'web',
    mode: process.env.NODE_ENV,
    devtool: isProduction ? false : 'eval-source-map',
    performance: {
        hints: false,
    },
    entry: [
        'react-hot-loader/patch',
        './resources/styles/main.css',
        './resources/scripts/index.tsx',
    ],
    output: {
        path: path.resolve(__dirname, 'public/assets'),
        filename: isProduction ? 'bundle.[chunkhash:8].js' : 'bundle.[hash:8].js',
        chunkFilename: isProduction ? '[name].[chunkhash:8].js' : '[name].[hash:8].js',
        publicPath: _.get(process.env, 'PUBLIC_PATH', '') + '/assets/',
        crossOriginLoading: 'anonymous',
    },
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                exclude: /node_modules/,
                use: [
                    {
                        loader: 'babel-loader',
                        options: {
                            cacheDirectory: !isProduction,
                            presets: [
                                '@babel/typescript',
                                '@babel/env',
                                '@babel/react',
                            ],
                            plugins: [
                                'tailwind-components',
                                'react-hot-loader/babel',
                                '@babel/transform-runtime',
                                '@babel/proposal-class-properties',
                                '@babel/proposal-object-rest-spread',
                                '@babel/syntax-dynamic-import',
                            ],
                        },
                    },
                ],
            },
            {
                test: /\.css$/,
                include: [
                    path.resolve(__dirname, 'resources'),
                ],
                use: [
                    {
                        loader: MiniCssExtractPlugin.loader,
                        options: {
                            hmr: !isProduction,
                        },
                    },
                    {
                        loader: 'css-loader',
                        options: {
                            sourceMap: !isProduction,
                            importLoaders: 1,
                        },
                    },
                    { loader: 'resolve-url-loader' },
                    {
                        loader: 'postcss-loader',
                        options: {
                            ident: 'postcss',
                            sourceMap: true,
                            plugins: [
                                require('postcss-import'),
                                tailwind('./tailwind.js'),
                                require('postcss-preset-env')({
                                    stage: 2,
                                }),
                                require('precss'),
                            ].concat(isProduction ? require('cssnano') : []),
                        },
                    },
                ],
            },
            {
                test: /\.(png|jpg|gif|svg)$/,
                loader: 'file-loader',
                options: {
                    name: '[name].[ext]?[hash:8]',
                },
            },
        ],
    },
    resolve: {
        extensions: ['.ts', '.tsx', '.js', '.json'],
        alias: {
            '@': path.join(__dirname, 'resources/scripts'),
        },
        symlinks: false,
    },
    plugins: plugins,
    optimization: {
        minimize: isProduction,
        minimizer: [
            new TerserPlugin({
                cache: true,
                parallel: true,
                terserOptions: {
                    safari10: true,
                    mangle: true,
                    output: {
                        comments: false,
                    },
                },
            }),
        ],
    },
    watchOptions: {
        ignored: /node_modules/,
    },
    devServer: {
        contentBase: path.join(__dirname, 'public'),
        publicPath: _.get(process.env, 'PUBLIC_PATH', '') + '/assets/',
        allowedHosts: [
            '.pterodactyl.test',
        ],
        headers: {
            'Access-Control-Allow-Origin': '*',
        },
    },
};
<|endoftext|>


<commit_before>function loadProducts(baseRequest, requestStr) {
    alert(requestStr);
    $.ajax({
        url: requestStr,
        type: "GET",
        dataType: "JSON",
        success: function (jsonObjArray) {
            for (var i = 0; i < jsonObjArray.length; i++) {

                var jsonObj = jsonObjArray[i];

                jsonObj.ProductCode = '';

                alert(JSON.stringify(jsonObj));

                $.ajax({
                    url: baseRequest + '/api/' + 'updateProduct.php',
                    type: "POST",
                    dataType: "JSON",
                    data: jsonObj,
                    success: function(jsonObj) {
                        alert('Success');
                    },
                    error: function(jsonObj) {
                        alert('Error: ' + JSON.stringify(jsonObj));
                        return;
                    }
                });
            }
        },
        error: function(errorMsg) {
            alert('Error: ' + JSON.stringify(errorMsg));
        }
    });

}

function loadCustomers(baseRequest, requestStr) {
    $.ajax({
        url: requestStr,
        type: "GET",
        dataType: "JSON",
        success: function (jsonObjArray) {
            for (var i = 0; i < jsonObjArray.length; i++) {

                var jsonObj = jsonObjArray[i];

                jsonObj.CustomerID = '';

                $.ajax({
                    url: baseRequest + '/api/' + 'updateCustomer.php',
                    type: "POST",
                    dataType: "JSON",
                    data: jsonObj,
                    success: function(jsonObj) {

                    },
                    error: function(jsonObj) {
                        alert('Error: ' + JSON.stringify(jsonObj));
                        return;
                    }
                });
            }
        },
        error: function(errorMsg) {
            alert('Error: ' + JSON.stringify(errorMsg));
            return;
        }
    });
}

function loadInvoices(baseRequest, requestStr) {
    $.ajax({
        url: requestStr,
        type: "GET",
        dataType: "JSON",
        success: function (jsonObjArray) {
            for (var i = 0; i < jsonObjArray.length; i++) {

                var jsonObj = jsonObjArray[i];

                jsonObj.InvoiceNo = '';

                $.ajax({
                    url: baseRequest + '/api/' + 'updateInvoice.php',
                    type: "POST",
                    dataType: "JSON",
                    data: jsonObj,
                    success: function(jsonObj) {

                    },
                    error: function(jsonObj) {
                        alert('Error: ' + JSON.stringify(jsonObj));
                        return;
                    }
                });
            }
        },
        error: function(errorMsg) {
            alert('Error: ' + JSON.stringify(errorMsg));
            return;
        }
    });
}

function submissionCallback() {
    /* (event.preventDefault)
        event.preventDefault();
    else
        event.returnValue = false;*/

    console.log('Here');

    var paramStr = $('#url_field').val();

    var customerRequestStr = paramStr + '/api/searchCustomersByField.php?doc=customer&op=min&field=CustomerID&value[]=1';
    var invoiceRequestStr = paramStr + '/api/searchInvoicesByField.php?doc=invoice&op=min&field=InvoiceNo&value[]=1';
    var productRequestStr = paramStr + '/api/searchProductsByField.php?doc=product&op=min&field=ProductCode&value[]=1';

    var baseRequest = paramStr;

    alert('All the external database entries will be added');

    $('#url_field').css('color', 'red').val('Importing,please wait...').prop('disabled', true);

    $.ajax({
        url: productRequestStr,
        type: "GET",
        dataType: "JSON",
        success: function (productArray) {

            if (productArray.error != undefined)
                return;

            $.ajax({
                url: customerRequestStr,
                type: "GET",
                dataType: "JSON",
                success: function (costumerArray) {

                    if (costumerArray.error != undefined)
                        return;

                    $.ajax({
                        url: invoiceRequestStr,
                        type: "GET",
                        dataType: "JSON",
                        success: function (invoiceArray) {

                            if (invoiceArray.error != undefined)
                                return;

                            for (var i = 0; i < productArray.length; i++) {

                                var jsonObj = productArray[i];

                                jsonObj.ProductCode = '';

                                $.ajax({
                                    url: baseRequest + '/api/' + 'updateProduct.php',
                                    type: "POST",
                                    dataType: "JSON",
                                    data: {
                                        product: JSON.stringify(jsonObj)
                                    },
                                    async : false,
                                    success: function(retVal) {
                                        console.error(JSON.stringify(retVal));
                                    },
                                    error: function(retVal) {
                                        console.error('Error: ' + JSON.stringify(retVal));
                                        return;
                                    }
                                });
                            }

                            for (var i = 0; i < costumerArray.length; i++) {

                                var jsonObj = costumerArray[i];

                                jsonObj.CustomerID = '';

                                $.ajax({
                                    url: baseRequest + '/api/' + 'updateCustomer.php',
                                    type: "POST",
                                    dataType: "JSON",
                                    data: {
                                        customer: JSON.stringify(jsonObj)
                                    },
                                    async : false,
                                    success: function(retVal) {
                                        console.error(JSON.stringify(retVal));
                                    },
                                    error: function(retVal) {
                                        console.error('Error: ' + JSON.stringify(retVal));
                                        return;
                                    }
                                });
                            }

                            for (var i = 0; i < invoiceArray.length; i++) {

                                var jsonObj = invoiceArray[i];

                                jsonObj.InvoiceNo = '';

                                $.ajax({
                                    url: baseRequest + '/api/' + 'updateInvoice.php',
                                    type: "POST",
                                    dataType: "JSON",
                                    data: {
                                        invoice: JSON.stringify(jsonObj)
                                    },
                                    success: function(retVal) {
                                        console.error(JSON.stringify(retVal));
                                    },
                                    error: function(retVal) {
                                        console.error('Error: ' + JSON.stringify(retVal));
                                        return;
                                    }
                                });
                            }

                            $('#url_field').css('color', 'black').val('Done!').prop('disabled', false);

                        }
                    });
                }
            });
        }
        });

    // loadProducts(paramStr, productRequestStr);
    // loadCustomers(paramStr, customerRequestStr);
    // loadInvoices(paramStr, invoiceRequestStr);
}

function loadExt() {
    $('#import_url_form #input_button').click(function () {
        //$('#url_field').css('color', 'red').val('Importing,please wait...').prop('disabled', true);
        submissionCallback();
    });
}
<commit_msg>Remove commented lines in importExternalDb.js<commit_after>function loadProducts(baseRequest, requestStr) {
    alert(requestStr);
    $.ajax({
        url: requestStr,
        type: "GET",
        dataType: "JSON",
        success: function (jsonObjArray) {
            for (var i = 0; i < jsonObjArray.length; i++) {

                var jsonObj = jsonObjArray[i];

                jsonObj.ProductCode = '';

                alert(JSON.stringify(jsonObj));

                $.ajax({
                    url: baseRequest + '/api/' + 'updateProduct.php',
                    type: "POST",
                    dataType: "JSON",
                    data: jsonObj,
                    success: function(jsonObj) {
                        alert('Success');
                    },
                    error: function(jsonObj) {
                        alert('Error: ' + JSON.stringify(jsonObj));
                        return;
                    }
                });
            }
        },
        error: function(errorMsg) {
            alert('Error: ' + JSON.stringify(errorMsg));
        }
    });

}

function loadCustomers(baseRequest, requestStr) {
    $.ajax({
        url: requestStr,
        type: "GET",
        dataType: "JSON",
        success: function (jsonObjArray) {
            for (var i = 0; i < jsonObjArray.length; i++) {

                var jsonObj = jsonObjArray[i];

                jsonObj.CustomerID = '';

                $.ajax({
                    url: baseRequest + '/api/' + 'updateCustomer.php',
                    type: "POST",
                    dataType: "JSON",
                    data: jsonObj,
                    success: function(jsonObj) {

                    },
                    error: function(jsonObj) {
                        alert('Error: ' + JSON.stringify(jsonObj));
                        return;
                    }
                });
            }
        },
        error: function(errorMsg) {
            alert('Error: ' + JSON.stringify(errorMsg));
            return;
        }
    });
}

function loadInvoices(baseRequest, requestStr) {
    $.ajax({
        url: requestStr,
        type: "GET",
        dataType: "JSON",
        success: function (jsonObjArray) {
            for (var i = 0; i < jsonObjArray.length; i++) {

                var jsonObj = jsonObjArray[i];

                jsonObj.InvoiceNo = '';

                $.ajax({
                    url: baseRequest + '/api/' + 'updateInvoice.php',
                    type: "POST",
                    dataType: "JSON",
                    data: jsonObj,
                    success: function(jsonObj) {

                    },
                    error: function(jsonObj) {
                        alert('Error: ' + JSON.stringify(jsonObj));
                        return;
                    }
                });
            }
        },
        error: function(errorMsg) {
            alert('Error: ' + JSON.stringify(errorMsg));
            return;
        }
    });
}

function submissionCallback() {
    console.log('Here');

    var paramStr = $('#url_field').val();

    var customerRequestStr = paramStr + '/api/searchCustomersByField.php?doc=customer&op=min&field=CustomerID&value[]=1';
    var invoiceRequestStr = paramStr + '/api/searchInvoicesByField.php?doc=invoice&op=min&field=InvoiceNo&value[]=1';
    var productRequestStr = paramStr + '/api/searchProductsByField.php?doc=product&op=min&field=ProductCode&value[]=1';

    var baseRequest = paramStr;

    alert('All the external database entries will be added');

    $('#url_field').css('color', 'red').val('Importing,please wait...').prop('disabled', true);

    $.ajax({
        url: productRequestStr,
        type: "GET",
        dataType: "JSON",
        success: function (productArray) {

            if (productArray.error != undefined)
                return;

            $.ajax({
                url: customerRequestStr,
                type: "GET",
                dataType: "JSON",
                success: function (costumerArray) {

                    if (costumerArray.error != undefined)
                        return;

                    $.ajax({
                        url: invoiceRequestStr,
                        type: "GET",
                        dataType: "JSON",
                        success: function (invoiceArray) {

                            if (invoiceArray.error != undefined)
                                return;

                            for (var i = 0; i < productArray.length; i++) {

                                var jsonObj = productArray[i];

                                jsonObj.ProductCode = '';

                                $.ajax({
                                    url: baseRequest + '/api/' + 'updateProduct.php',
                                    type: "POST",
                                    dataType: "JSON",
                                    data: {
                                        product: JSON.stringify(jsonObj)
                                    },
                                    async : false,
                                    success: function(retVal) {
                                        console.error(JSON.stringify(retVal));
                                    },
                                    error: function(retVal) {
                                        console.error('Error: ' + JSON.stringify(retVal));
                                        return;
                                    }
                                });
                            }

                            for (var i = 0; i < costumerArray.length; i++) {

                                var jsonObj = costumerArray[i];

                                jsonObj.CustomerID = '';

                                $.ajax({
                                    url: baseRequest + '/api/' + 'updateCustomer.php',
                                    type: "POST",
                                    dataType: "JSON",
                                    data: {
                                        customer: JSON.stringify(jsonObj)
                                    },
                                    async : false,
                                    success: function(retVal) {
                                        console.error(JSON.stringify(retVal));
                                    },
                                    error: function(retVal) {
                                        console.error('Error: ' + JSON.stringify(retVal));
                                        return;
                                    }
                                });
                            }

                            for (var i = 0; i < invoiceArray.length; i++) {

                                var jsonObj = invoiceArray[i];

                                jsonObj.InvoiceNo = '';

                                $.ajax({
                                    url: baseRequest + '/api/' + 'updateInvoice.php',
                                    type: "POST",
                                    dataType: "JSON",
                                    data: {
                                        invoice: JSON.stringify(jsonObj)
                                    },
                                    success: function(retVal) {
                                        console.error(JSON.stringify(retVal));
                                    },
                                    error: function(retVal) {
                                        console.error('Error: ' + JSON.stringify(retVal));
                                        return;
                                    }
                                });
                            }

                            $('#url_field').css('color', 'black').val('Done!').prop('disabled', false);

                        }
                    });
                }
            });
        }
        });
}

function loadExt() {
    $('#import_url_form #input_button').click(function () {
        submissionCallback();
    });
}
<|endoftext|>


<commit_before>const path = require('path');
const slsw = require('serverless-webpack');
var nodeExternals = require('webpack-node-externals');

module.exports = {
entry: './handler.js',
   target: 'node',
   externals: [nodeExternals()],
   output: {
    libraryTarget: 'commonjs',
    path: path.join(__dirname, '.webpack'),
    filename: '[name].js'
  }
  module: {
    loaders: [{
      test: /\.js$/,
      loaders: ['babel-loader'],
      include: __dirname
    }]
  },
};
<commit_msg>webpack config part 2.<commit_after>const path = require('path');
const slsw = require('serverless-webpack');
var nodeExternals = require('webpack-node-externals');

module.exports = {
entry: './handler.js',
   target: 'node',
   externals: [nodeExternals()],
   output: {
      libraryTarget: 'commonjs',
      path: '.webpack',
      filename: 'handler.js', // this should match the first part of function handler in serverless.yml
   },
  module: {
      loaders: [
         {
            test: /\.jsx?$/,
            exclude: /node_modules/,
            loaders: ["babel-loader"]
         }
      ]
   }
};
<|endoftext|>


<commit_before>/**
 * @fileOverview OverviewCtrl angular controller
 */
'use strict';

define(['./module', 'darkwallet', 'frontend/port'], function (controllers, DarkWallet, Port) {
  controllers.controller('OverviewCtrl', ['$scope', '$history', function($scope, $history) {

  $scope.allPockets = [];

  /**
   * Select a pocket from the grid
   */
  $scope.selectGridPocket = function(pocket) {
      if (pocket.type == 'pocket') {
          $scope.selectPocket(pocket.name, pocket.index);
      } else if (pocket.type == 'fund') {
          $scope.selectFund(pocket.fund, pocket.index);
      }
  };

  /**
   * Update a pocket's information in place
   */
  var updatePocket = function(newData, position) {
      var found = $scope.allPockets.filter(function(pocket) {return (newData.type == pocket.type && newData.name == pocket.name)});
      if (found.length) {
          Object.keys(newData).forEach(function(key) {
              found[key] = newData[key];
          });
      } else if (position) {
          $scope.allPockets.splice(position, 0, newData);
      } else {
          $scope.allPockets.push(newData);
      }
  };

  /**
   * Calculate all balances
   */
  var calculateBalances = function() {
      var identity = DarkWallet.getIdentity();

      var total = {confirmed: 0, unconfirmed: 0, current: 0};

      identity.wallet.pockets.hdPockets.forEach(function(pocket, i) {
          if (!pocket) {
              return;
          }
          var balance = identity.wallet.getBalance(i, 'hd');

          // Update total
          total.confirmed += balance.confirmed;
          total.current += balance.current;
          total.unconfirmed += balance.unconfirmed;

          // Save the pocket information
          updatePocket({name: pocket.name, mixing: pocket.mixing, balance: balance, type: 'pocket', index: i});
      });
      identity.wallet.multisig.funds.forEach(function(fund, i) {
          if (!fund) {
              return;
          }
          var balance = identity.wallet.getBalance(fund.address, 'multisig');

          // Update total
          total.current += balance.current;
          total.confirmed += balance.confirmed;
          total.unconfirmed += balance.unconfirmed;

          // Save the pocket information
          updatePocket({name: fund.name, mixing: fund.mixing, balance: balance, type: 'fund', fund: fund, index: i});
      });
      $scope.setOverview(total);
      // updatePocket({name: 'Total', balance: total, type: 'total'}, identity.wallet.pockets.hdPockets.length-1);

  };

  /**
   * Calculate everything if we have an identity loaded.
   */
  var loaded = DarkWallet.getIdentity();
  if (loaded) {
      loaded = loaded.name;
      calculateBalances();
  };

  /**
   * Listen to events
   */
  Port.connectNg('wallet', $scope, function(data) {
      if (data.type === 'ready' && data.identity !== loaded) {
          // Ready event, recalculate balances and cleanup pockets
          loaded = data.identity;
          $scope.allPockets.splice(0, $scope.allPockets.length);
          calculateBalances();
      }
      else if (data.type === 'height') {
          // We may want to recalculate something on height
          $scope.currentHeight = data.value;
          calculateBalances();
      }
      else if (data.type === 'rename') {
          loaded = data.newName;
      }
  });

  Port.connectNg('gui', $scope, function(data) {
      if (data.type === 'balance') {
          // Balance event
          calculateBalances();
      }
  });

  }]);
});
<commit_msg>Don't crash if a pocket doesn't exist for a fund.<commit_after>/**
 * @fileOverview OverviewCtrl angular controller
 */
'use strict';

define(['./module', 'darkwallet', 'frontend/port'], function (controllers, DarkWallet, Port) {
  controllers.controller('OverviewCtrl', ['$scope', '$history', function($scope, $history) {

  $scope.allPockets = [];

  /**
   * Select a pocket from the grid
   */
  $scope.selectGridPocket = function(pocket) {
      if (pocket.type == 'pocket') {
          $scope.selectPocket(pocket.name, pocket.index);
      } else if (pocket.type == 'fund') {
          $scope.selectFund(pocket.fund, pocket.index);
      }
  };

  /**
   * Update a pocket's information in place
   */
  var updatePocket = function(newData, position) {
      var found = $scope.allPockets.filter(function(pocket) {return (newData.type == pocket.type && newData.name == pocket.name)});
      if (found.length) {
          Object.keys(newData).forEach(function(key) {
              found[key] = newData[key];
          });
      } else if (position) {
          $scope.allPockets.splice(position, 0, newData);
      } else {
          $scope.allPockets.push(newData);
      }
  };

  /**
   * Calculate all balances
   */
  var calculateBalances = function() {
      var identity = DarkWallet.getIdentity();

      var total = {confirmed: 0, unconfirmed: 0, current: 0};

      identity.wallet.pockets.hdPockets.forEach(function(pocket, i) {
          if (!pocket) {
              return;
          }
          var balance = identity.wallet.getBalance(i, 'hd');

          // Update total
          total.confirmed += balance.confirmed;
          total.current += balance.current;
          total.unconfirmed += balance.unconfirmed;

          // Save the pocket information
          updatePocket({name: pocket.name, mixing: pocket.mixing, balance: balance, type: 'pocket', index: i});
      });
      identity.wallet.multisig.funds.forEach(function(fund, i) {
          if (!fund || !identity.wallet.pockets.getPocket(fund.address, 'multisig')) {
              return;
          }
          var balance = identity.wallet.getBalance(fund.address, 'multisig');

          // Update total
          total.current += balance.current;
          total.confirmed += balance.confirmed;
          total.unconfirmed += balance.unconfirmed;

          // Save the pocket information
          updatePocket({name: fund.name, mixing: fund.mixing, balance: balance, type: 'fund', fund: fund, index: i});
      });
      $scope.setOverview(total);
      // updatePocket({name: 'Total', balance: total, type: 'total'}, identity.wallet.pockets.hdPockets.length-1);

  };

  /**
   * Calculate everything if we have an identity loaded.
   */
  var loaded = DarkWallet.getIdentity();
  if (loaded) {
      loaded = loaded.name;
      calculateBalances();
  };

  /**
   * Listen to events
   */
  Port.connectNg('wallet', $scope, function(data) {
      if (data.type === 'ready' && data.identity !== loaded) {
          // Ready event, recalculate balances and cleanup pockets
          loaded = data.identity;
          $scope.allPockets.splice(0, $scope.allPockets.length);
          calculateBalances();
      }
      else if (data.type === 'height') {
          // We may want to recalculate something on height
          $scope.currentHeight = data.value;
          calculateBalances();
      }
      else if (data.type === 'rename') {
          loaded = data.newName;
      }
  });

  Port.connectNg('gui', $scope, function(data) {
      if (data.type === 'balance') {
          // Balance event
          calculateBalances();
      }
  });

  }]);
});
<|endoftext|>


<commit_before>import mongoose from 'mongoose';
import moment from 'moment-timezone';
import { getSession, requireAdministrator, authorizedForDomain } from './auth';
import { catcher } from './utils';

mongoose.Promise = global.Promise;

const ID_REGEXP = /^[0-9a-fA-F]{24}$/;

// Generic

export function addPopulate(query, populate) {
  if (Array.isArray(populate)) {
    populate.forEach(pop => query.populate(pop));
  } else {
    query.populate(populate);
  }
}

export default (router, options) => {
  const { category, modelName } = options;
  const Doc = mongoose.model(modelName);
  let methods = options.methods || ['get', 'put', 'delete', 'index', 'post'];
  if (options.omit) {
    methods = methods.filter(m => !options.omit.some(o => o === m));
  }

  if (methods.indexOf('get') >= 0) {
    const getOpts = options.get || {};
    router.get(`/${category}/:id`, (req, res) => {
      getSession(req)
      .then(getOpts.authorization || options.authorization || requireAdministrator)
      .then((session) => {
        const id = req.params.id;
        let criteria;
        if (ID_REGEXP.test(id)) {
          criteria = { _id: id };
        } else if (getOpts.pathAlias) {
          criteria = { $or: [{ path: id }, { pathAlias: id }] };
        } else {
          criteria = { path: id };
        }
        const query = Doc.findOne(criteria);
        if (req.query.select) {
          query.select(req.query.select);
        }
        if (req.query.populate) {
          const populate = JSON.parse(req.query.populate);
          if (populate === true) {
            // populate from options
            if (getOpts.populate) {
              addPopulate(query, getOpts.populate);
            }
          } else {
            addPopulate(query, populate);
          }
        } else if (getOpts.populate) {
          addPopulate(query, getOpts.populate);
        }
        return query.exec()
        .then((doc) => {
          if (!doc) {
            res.status(404);
            return Promise.reject({ status: 404 });
          }
          return doc;
        })
        .then(doc => (getOpts.transformOut ?
          getOpts.transformOut(doc, req, session) : doc));
      })
      .then((doc) => {
        if (doc.modified) {
          res.setHeader('Last-Modified',
            moment.utc(doc.modified).format('ddd, DD MMM YYYY HH:mm:ss [GMT]'));
          res.setHeader('Cache-Control', 'max-age=0');
        }
        res.json(doc);
      })
      .catch(error => catcher(error, res));
    });
  }

  if (methods.indexOf('put') >= 0) {
    const putOpts = options.put || {};
    router.put(`/${category}/:id`, (req, res) => {
      const id = req.params.id;
      getSession(req)
      .then(putOpts.authorization || options.authorization || requireAdministrator)
      .then((session) => {
        const data = req.body;
        data.modified = moment.utc();
        data.userId = session.userId;
        return data;
      })
      .then(data => (putOpts.transformIn ?
        putOpts.transformIn(data, req) : data))
      .then(data => (putOpts.validate ?
        putOpts.validate(data, req) : data))
      .then(data => Doc.findOneAndUpdate({ _id: id }, data,
        { new: true, runValidators: true }).exec())
      .then(doc => (putOpts.transformOut ?
        putOpts.transformOut(doc, req) : doc))
      .then(doc => res.status(200).json(doc))
      .catch(error => catcher(error, res));
    });
  }

  if (methods.indexOf('delete') >= 0) {
    const deleteOpts = options.delete || {};
    router.delete(`/${category}/:id`, (req, res) => {
      const id = req.params.id;
      getSession(req)
      .then(deleteOpts.authorization || options.authorization || requireAdministrator)
      .then(() => Doc.findById(id).exec())
      .then(doc => doc.remove())
      .then(doc => (deleteOpts.deleteRelated ?
        deleteOpts.deleteRelated(doc, req) : doc))
      .then(() => res.status(200).send())
      .catch(error => catcher(error, res));
    });
  }

  if (methods.indexOf('index') >= 0) {
    const indexOpts = options.index || {};
    router.get(`/${category}`, (req, res) => {
      getSession(req)
      .then(indexOpts.authorization || options.authorization || requireAdministrator)
      .then((session) => {
        const searchProperties = indexOpts.searchProperties || 'name';
        const query = Doc.find();
        if (indexOpts.filterAuthorized) {
          query.find(indexOpts.filterAuthorized(session));
        }
        if (req.query.search) {
          if (indexOpts.textSearch) {
            // This isn't working :(
            query.find(
              { $text: { $search: req.query.search } },
              { score: { $meta: 'textScore' } },
            );
            query.sort({ score: { $meta: 'textScore' }, modified: -1 });
          } else {
            const exp = new RegExp(req.query.search, 'i');
            if (Array.isArray(searchProperties)) {
              query.or(searchProperties.map((property) => {
                const obj = {};
                obj[property] = exp;
                return obj;
              }));
            } else {
              const obj = {};
              obj[searchProperties] = exp;
              query.find(obj);
            }
          }
        }
        if (req.query.adminable) {
          query.find(authorizedForDomain(session));
        }
        if (req.query.filter) {
          let filter = JSON.parse(req.query.filter);
          if (typeof filter === 'string') {
            // need double de-escape,
            // first to de-string and then to de-stringify
            filter = JSON.parse(filter);
          }
          query.find(filter);
        }
        if (req.query.sort && (!indexOpts.textSearch || !req.query.search)) {
          query.sort(req.query.sort);
        }
        if (req.query.select) {
          query.select(req.query.select);
        }
        if (req.query.populate) {
          const populate = JSON.parse(req.query.populate);
          if (populate === true) {
            // populate from options
            if (indexOpts.populate) {
              addPopulate(query, indexOpts.populate);
            }
          } else {
            addPopulate(query, populate);
          }
        }
        if (req.query.distinct) {
          query.distinct(req.query.distinct);
        } else if (req.query.limit) {
          query.limit(parseInt(req.query.limit, 10));
        } else {
          query.limit(20);
        }
        if (req.query.skip) {
          query.skip(parseInt(req.query.skip, 10));
        }
        return query.exec();
      })
      .then(docs => (indexOpts.transformOut ?
        indexOpts.transformOut(docs, req) : docs))
      .then((docs) => {
        res.setHeader('Cache-Control', 'max-age=0');
        res.json(docs);
      })
      .catch(error => catcher(error, res));
    });
  }

  if (methods.indexOf('post') >= 0) {
    const postOpts = options.post || {};
    router.post(`/${category}`, (req, res) => {
      getSession(req)
      .then(postOpts.authorization || options.authorization || requireAdministrator)
      .then((session) => {
        const data = req.body;
        data.created = moment.utc();
        data.modified = data.created;
        data.userId = session.userId;
        return data;
      })
      .then(data => (postOpts.transformIn ?
        postOpts.transformIn(data, req) : data))
      .then(data => (postOpts.validate ?
        postOpts.validate(data, req) : data))
      .then(data => (new Doc(data)).save())
      .then(doc => (postOpts.transformOut ?
        postOpts.transformOut(doc, req) : doc))
      .then(doc => res.status(200).json(doc))
      .catch(error => catcher(error, res));
    });
  }
};
<commit_msg>Changed index api calls to not mix filterAuthorized and adminable.<commit_after>import mongoose from 'mongoose';
import moment from 'moment-timezone';
import { getSession, requireAdministrator, authorizedForDomain } from './auth';
import { catcher } from './utils';

mongoose.Promise = global.Promise;

const ID_REGEXP = /^[0-9a-fA-F]{24}$/;

// Generic

export function addPopulate(query, populate) {
  if (Array.isArray(populate)) {
    populate.forEach(pop => query.populate(pop));
  } else {
    query.populate(populate);
  }
}

export default (router, options) => {
  const { category, modelName } = options;
  const Doc = mongoose.model(modelName);
  let methods = options.methods || ['get', 'put', 'delete', 'index', 'post'];
  if (options.omit) {
    methods = methods.filter(m => !options.omit.some(o => o === m));
  }

  if (methods.indexOf('get') >= 0) {
    const getOpts = options.get || {};
    router.get(`/${category}/:id`, (req, res) => {
      getSession(req)
      .then(getOpts.authorization || options.authorization || requireAdministrator)
      .then((session) => {
        const id = req.params.id;
        let criteria;
        if (ID_REGEXP.test(id)) {
          criteria = { _id: id };
        } else if (getOpts.pathAlias) {
          criteria = { $or: [{ path: id }, { pathAlias: id }] };
        } else {
          criteria = { path: id };
        }
        const query = Doc.findOne(criteria);
        if (req.query.select) {
          query.select(req.query.select);
        }
        if (req.query.populate) {
          const populate = JSON.parse(req.query.populate);
          if (populate === true) {
            // populate from options
            if (getOpts.populate) {
              addPopulate(query, getOpts.populate);
            }
          } else {
            addPopulate(query, populate);
          }
        } else if (getOpts.populate) {
          addPopulate(query, getOpts.populate);
        }
        return query.exec()
        .then((doc) => {
          if (!doc) {
            res.status(404);
            return Promise.reject({ status: 404 });
          }
          return doc;
        })
        .then(doc => (getOpts.transformOut ?
          getOpts.transformOut(doc, req, session) : doc));
      })
      .then((doc) => {
        if (doc.modified) {
          res.setHeader('Last-Modified',
            moment.utc(doc.modified).format('ddd, DD MMM YYYY HH:mm:ss [GMT]'));
          res.setHeader('Cache-Control', 'max-age=0');
        }
        res.json(doc);
      })
      .catch(error => catcher(error, res));
    });
  }

  if (methods.indexOf('put') >= 0) {
    const putOpts = options.put || {};
    router.put(`/${category}/:id`, (req, res) => {
      const id = req.params.id;
      getSession(req)
      .then(putOpts.authorization || options.authorization || requireAdministrator)
      .then((session) => {
        const data = req.body;
        data.modified = moment.utc();
        data.userId = session.userId;
        return data;
      })
      .then(data => (putOpts.transformIn ?
        putOpts.transformIn(data, req) : data))
      .then(data => (putOpts.validate ?
        putOpts.validate(data, req) : data))
      .then(data => Doc.findOneAndUpdate({ _id: id }, data,
        { new: true, runValidators: true }).exec())
      .then(doc => (putOpts.transformOut ?
        putOpts.transformOut(doc, req) : doc))
      .then(doc => res.status(200).json(doc))
      .catch(error => catcher(error, res));
    });
  }

  if (methods.indexOf('delete') >= 0) {
    const deleteOpts = options.delete || {};
    router.delete(`/${category}/:id`, (req, res) => {
      const id = req.params.id;
      getSession(req)
      .then(deleteOpts.authorization || options.authorization || requireAdministrator)
      .then(() => Doc.findById(id).exec())
      .then(doc => doc.remove())
      .then(doc => (deleteOpts.deleteRelated ?
        deleteOpts.deleteRelated(doc, req) : doc))
      .then(() => res.status(200).send())
      .catch(error => catcher(error, res));
    });
  }

  if (methods.indexOf('index') >= 0) {
    const indexOpts = options.index || {};
    router.get(`/${category}`, (req, res) => {
      getSession(req)
      .then(indexOpts.authorization || options.authorization || requireAdministrator)
      .then((session) => {
        const searchProperties = indexOpts.searchProperties || 'name';
        const query = Doc.find();
        if (req.query.adminable) {
          query.find(authorizedForDomain(session));
        } else if (indexOpts.filterAuthorized) {
          query.find(indexOpts.filterAuthorized(session));
        }
        if (req.query.search) {
          if (indexOpts.textSearch) {
            // This isn't working :(
            query.find(
              { $text: { $search: req.query.search } },
              { score: { $meta: 'textScore' } },
            );
            query.sort({ score: { $meta: 'textScore' }, modified: -1 });
          } else {
            const exp = new RegExp(req.query.search, 'i');
            if (Array.isArray(searchProperties)) {
              query.or(searchProperties.map((property) => {
                const obj = {};
                obj[property] = exp;
                return obj;
              }));
            } else {
              const obj = {};
              obj[searchProperties] = exp;
              query.find(obj);
            }
          }
        }
        if (req.query.filter) {
          let filter = JSON.parse(req.query.filter);
          if (typeof filter === 'string') {
            // need double de-escape,
            // first to de-string and then to de-stringify
            filter = JSON.parse(filter);
          }
          query.find(filter);
        }
        if (req.query.sort && (!indexOpts.textSearch || !req.query.search)) {
          query.sort(req.query.sort);
        }
        if (req.query.select) {
          query.select(req.query.select);
        }
        if (req.query.populate) {
          const populate = JSON.parse(req.query.populate);
          if (populate === true) {
            // populate from options
            if (indexOpts.populate) {
              addPopulate(query, indexOpts.populate);
            }
          } else {
            addPopulate(query, populate);
          }
        }
        if (req.query.distinct) {
          query.distinct(req.query.distinct);
        } else if (req.query.limit) {
          query.limit(parseInt(req.query.limit, 10));
        } else {
          query.limit(20);
        }
        if (req.query.skip) {
          query.skip(parseInt(req.query.skip, 10));
        }
        return query.exec();
      })
      .then(docs => (indexOpts.transformOut ?
        indexOpts.transformOut(docs, req) : docs))
      .then((docs) => {
        res.setHeader('Cache-Control', 'max-age=0');
        res.json(docs);
      })
      .catch(error => catcher(error, res));
    });
  }

  if (methods.indexOf('post') >= 0) {
    const postOpts = options.post || {};
    router.post(`/${category}`, (req, res) => {
      getSession(req)
      .then(postOpts.authorization || options.authorization || requireAdministrator)
      .then((session) => {
        const data = req.body;
        data.created = moment.utc();
        data.modified = data.created;
        data.userId = session.userId;
        return data;
      })
      .then(data => (postOpts.transformIn ?
        postOpts.transformIn(data, req) : data))
      .then(data => (postOpts.validate ?
        postOpts.validate(data, req) : data))
      .then(data => (new Doc(data)).save())
      .then(doc => (postOpts.transformOut ?
        postOpts.transformOut(doc, req) : doc))
      .then(doc => res.status(200).json(doc))
      .catch(error => catcher(error, res));
    });
  }
};
<|endoftext|>


<commit_before>(function(window, document, location, ion) {

  var
  x,
  el;

  // Add listeners to each link in the document
  function click(e) {
    // an element has been clicked. If its a link its good to go
    // if its not a link then jump up its parents until you find
    // its wrapping link. If you never find a link do nothing.
    if(e.target) {
      el = e.target;
      if(el.tagName === "A") {
        return linkClick(e, el);
      }
      while(el.parentElement) {
        el = el.parentElement;
        if(el.tagName === "A") {
          return linkClick(e, el);
        }
      }
    }
  }

  // A link has been clicked
  function linkClick(e, el) {

    // if they clicked a link while scrolling don't nav to it
    if(ion.isScrolling) {
      e.preventDefault();
      return false;
    }

    // data-history-go="-1"
    // shortcut if they just want to use window.history.go()
    if(el.dataset.historyGo) {
      window.history.go( parseInt(el.dataset.historyGo, 10) );
      e.preventDefault();
      return false;
    }

    // only intercept the nav click if they're going to the same domain or page
    if (location.protocol === el.protocol && location.host === el.host) {

      // trigger the event that a new page should be shown
      ion.trigger("pageinit", el.href);

      // decide how to handle this click depending on the href
      if(el.getAttribute("href").indexOf("#") === 0) {
        // this click is going to another element within this same page

      } else {
        // this click is going to another page in the same domain
        requestData({
          url: el.href,
          success: successPageLoad,
          fail: failedPageLoad
        });
      }

      // stop the browser itself from continuing on with this click
      // the above code will take care of the navigation
      e.preventDefault();
      return false;
    }
  }

  function locationChange(e) {
    if(!this._initPopstate) {
      this._initPopstate = true;
      return;
    }

    requestData({
      url: location.href,
      success: successPageLoad,
      fail: failedPageLoad
    });
  }

  function requestData(options) {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', options.url, true);
    xhr.onreadystatechange = function() {
      if (xhr.readyState === 4) {
        if(xhr.status === 200) {
          options.success(xhr, options);
        } else {
          options.fail(xhr, options);
        }
      }
    };
    xhr.send();
  }

  function successPageLoad(xhr, options) {
    var data = parseXHR(xhr, options);
    ion.trigger("pageloaded", {
      data: data
    });
    history.pushState({}, data.title, data.url);
    document.title = data.title;
  }

  function failedPageLoad(xhr, options) {
    ion.trigger("pageinitfailed", {
      responseText: xhr.responseText,
      responseStatus: xhr.status
    });
  }

  function parseXHR(xhr, options) {
    var
    container,
    tmp,
    data = {};

    data.url = options.url;

    if (!xhr.responseText) return data;

    container = document.createElement('div');
    container.innerHTML = xhr.responseText;

    // get the title of the page
    tmp = container.querySelector("title");
    if(tmp) {
      data.title = tmp.innerText;
    } else {
      data.title = data.url;
    }

    // get the main content of the page
    tmp = container.querySelector("main");
    if(tmp) {
      data.main = tmp.innerHTML;
    } else {
      // something is wrong with the data, trigger that the page init failed
      ion.trigger("pageinitfailed");
    }

    return data;
  }

  // listen to every click
  document.addEventListener("click", click, false);

  // listen to when the location changes
  ion.on("popstate", locationChange);

})(this, document, location, ion = this.ion || {});
<commit_msg>More cleaning<commit_after><|endoftext|>


<commit_before>/* eslint-env node */
/* eslint-disable no-var, func-names, prefer-arrow-callback, prefer-template */
var path = require('path');
var webpack = require('webpack');
var BundleTracker = require('webpack-bundle-tracker');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var argv = require('yargs').argv;
var childProcess = require('child_process');

const BOLD = '\u001b[1m';
const END_BOLD = '\u001b[39m\u001b[22m';
const production = process.env.NODE_ENV === 'production';

var plugins = [
  new BundleTracker({ filename: './webpack-stats.json' }),
  new webpack.optimize.OccurrenceOrderPlugin(true),
  new ExtractTextPlugin(production ? '[name]-[hash].css' : '[name].css'),
  new webpack.DefinePlugin({
    PRODUCTION: production,
    DEVELOPMENT: !production,
    process: {
      env: {
        NODE_ENV: production ? '"production"' : '"development"',
      },
    },
  }),
];

if (production) {
  plugins = plugins.concat([
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false,
      },
    }),
  ]);
} else {
  plugins = plugins.concat([
    new webpack.NoErrorsPlugin(),
  ]);
}

module.exports = [
  {
    context: __dirname,
    devtool: production ? undefined : 'eval-source-map',

    entry: {
      selfrepair: [
        'babel-polyfill',
        './client/selfrepair/self_repair.js',
      ],
      control: [
        'babel-polyfill',
        './client/control/index.js',
        './client/control/sass/control.scss',
        './node_modules/font-awesome/scss/font-awesome.scss',
      ],
    },

    output: {
      path: path.resolve('./assets/bundles/'),
      filename: production ? '[name]-[hash].js' : '[name].js',
      chunkFilename: '[id].bundle.js',
    },
    externals: {
      'react/lib/ExecutionEnvironment': true,
      'react/lib/ReactContext': true,
      'react/addons': true,
    },

    plugins,

    module: {
      loaders: [
        {
          test: /\.js$/,
          exclude: /node_modules/,
          loader: 'babel',
        },
        {
          test: /\.json$/,
          loader: 'json-loader',
        },
        {
          test: /\.scss$/,
          loader: ExtractTextPlugin.extract('style', 'css?sourceMap!postcss!sass?sourceMap'),
        },
        {
          test: /\.(ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/,
          loader: 'file-loader',
        },
      ],
    },
  },
  {
    devtool: production ? undefined : 'eval-source-map',

    entry: {
      'console-log': './client/actions/console-log/index',
      'show-heartbeat': './client/actions/show-heartbeat/index',
    },

    plugins: [
      new BundleTracker({ filename: './webpack-stats-actions.json' }),
      new webpack.optimize.DedupePlugin(),
      new webpack.optimize.OccurrenceOrderPlugin(),
      new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }),

        // Small plugin to update the actions in the database if
        // --update-actions was passed.
      function updateActions() {
        this.plugin('done', function () {
          var cmd;
          if (argv['update-actions']) {
            // Don't disable actions since this is mostly for development.
            cmd = 'python manage.py update_actions';

            childProcess.exec(cmd, function (err, stdout, stderr) {
              console.log('\n' + BOLD + 'Updating Actions' + END_BOLD);
              console.log(stdout);
              if (stderr) {
                console.error(stderr);
              }
            });
          }
        });
      },
    ],

    output: {
      path: path.resolve('./assets/bundles/'),
      filename: production ? '[name]-[hash].js' : '[name].js',
    },

    module: {
      loaders: [
        {
          test: /\.js$/,
          exclude: /node_modules/,
          loader: 'babel-loader',
          query: {
            plugins: [
                ['transform-runtime', {
                  polyfill: false,
                  regenerator: true,
                }],
            ],
          },
        },
      ],
    },
  },
];
<commit_msg>Fix slow/crash on load<commit_after>/* eslint-env node */
/* eslint-disable no-var, func-names, prefer-arrow-callback, prefer-template */
var path = require('path');
var webpack = require('webpack');
var BundleTracker = require('webpack-bundle-tracker');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var argv = require('yargs').argv;
var childProcess = require('child_process');

const BOLD = '\u001b[1m';
const END_BOLD = '\u001b[39m\u001b[22m';
const production = process.env.NODE_ENV === 'production';

var plugins = [
  new BundleTracker({ filename: './webpack-stats.json' }),
  new webpack.optimize.OccurrenceOrderPlugin(true),
  new ExtractTextPlugin(production ? '[name]-[hash].css' : '[name].css'),
  new webpack.DefinePlugin({
    PRODUCTION: production,
    DEVELOPMENT: !production,
    process: {
      env: {
        NODE_ENV: production ? '"production"' : '"development"',
      },
    },
  }),
];

if (production) {
  plugins = plugins.concat([
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false,
      },
    }),
  ]);
} else {
  plugins = plugins.concat([
    new webpack.NoErrorsPlugin(),
  ]);
}

module.exports = [
  {
    context: __dirname,
    devtool: production ? undefined : 'eval',

    entry: {
      selfrepair: [
        'babel-polyfill',
        './client/selfrepair/self_repair.js',
      ],
      control: [
        'babel-polyfill',
        './client/control/index.js',
        './client/control/sass/control.scss',
        './node_modules/font-awesome/scss/font-awesome.scss',
      ],
    },

    output: {
      path: path.resolve('./assets/bundles/'),
      filename: production ? '[name]-[hash].js' : '[name].js',
      chunkFilename: '[id].bundle.js',
    },
    externals: {
      'react/lib/ExecutionEnvironment': true,
      'react/lib/ReactContext': true,
      'react/addons': true,
    },

    plugins,

    module: {
      loaders: [
        {
          test: /\.js$/,
          exclude: /node_modules/,
          loader: 'babel',
        },
        {
          test: /\.json$/,
          loader: 'json-loader',
        },
        {
          test: /\.scss$/,
          loader: ExtractTextPlugin.extract('style', 'css?sourceMap!postcss!sass?sourceMap'),
        },
        {
          test: /\.(ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/,
          loader: 'file-loader',
        },
      ],
    },
  },
  {
    devtool: production ? undefined : 'eval',

    entry: {
      'console-log': './client/actions/console-log/index',
      'show-heartbeat': './client/actions/show-heartbeat/index',
    },

    plugins: [
      new BundleTracker({ filename: './webpack-stats-actions.json' }),
      new webpack.optimize.DedupePlugin(),
      new webpack.optimize.OccurrenceOrderPlugin(),
      new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }),

        // Small plugin to update the actions in the database if
        // --update-actions was passed.
      function updateActions() {
        this.plugin('done', function () {
          var cmd;
          if (argv['update-actions']) {
            // Don't disable actions since this is mostly for development.
            cmd = 'python manage.py update_actions';

            childProcess.exec(cmd, function (err, stdout, stderr) {
              console.log('\n' + BOLD + 'Updating Actions' + END_BOLD);
              console.log(stdout);
              if (stderr) {
                console.error(stderr);
              }
            });
          }
        });
      },
    ],

    output: {
      path: path.resolve('./assets/bundles/'),
      filename: production ? '[name]-[hash].js' : '[name].js',
    },

    module: {
      loaders: [
        {
          test: /\.js$/,
          exclude: /node_modules/,
          loader: 'babel-loader',
          query: {
            plugins: [
                ['transform-runtime', {
                  polyfill: false,
                  regenerator: true,
                }],
            ],
          },
        },
      ],
    },
  },
];
<|endoftext|>


<commit_before>const mustBeLoggedIn = (req, res, next) => {
  if (!req.user) {
    return res.status(401).send('You must be logged in')
  }
  next()
}

const selfOnly = action => (req, res, next) => {
  if (req.params.id !== req.user.id) {
    return res.status(403).send(`You can only ${action} yourself.`)
  }
  next()
}

const forbidden = message => (req, res) => {
  res.status(403).send(message)
}

// Feel free to add more filters here (suggested: something that keeps out non-admins)

module.exports = {mustBeLoggedIn, selfOnly, forbidden}
<commit_msg>add admin middleware<commit_after>const mustBeLoggedIn = (req, res, next) => {
  if (!req.user) {
    return res.status(401).send('You must be logged in')
  }
  next()
}

const selfOnly = action => (req, res, next) => {
  if (req.params.id !== req.user.id) {
    return res.status(403).send(`You can only ${action} yourself.`)
  }
  next()
}

const forbidden = message => (req, res) => {
  res.status(403).send(message)
}

// Feel free to add more filters here (suggested: something that keeps out non-admins)

// We assume that req.user is an instance of a sequelize user,
// meaning they will have access to isAdmin bool column.
const mustBeAdmin = (req, res, next) => {
  if(!req.user.is_admin) {
    return res.status(403).send(`You can only do this if you're an admin`)
  }
  next()
}

module.exports = {mustBeLoggedIn, selfOnly, forbidden, mustBeAdmin}
<|endoftext|>