<commit_before>import { Trans } from "@lingui/macro";
import classNames from "classnames";
import { Link } from "react-router";
import { MountService } from "foundation-ui";
import React from "react";
import { Table, Tooltip } from "reactjs-components";

import DateUtil from "#SRC/js/utils/DateUtil";
import Icon from "#SRC/js/components/Icon";
import MesosStateStore from "#SRC/js/stores/MesosStateStore";
import TableUtil from "#SRC/js/utils/TableUtil";
import TimeAgo from "#SRC/js/components/TimeAgo";
import Units from "#SRC/js/utils/Units";

import DeclinedOffersReasons from "../constants/DeclinedOffersReasons";

class DeclinedOffersTable extends React.Component {
  areResourcesUnmatched(requestedResource, receivedResource) {
    if (Array.isArray(receivedResource)) {
      return receivedResource.includes(requestedResource);
    }

    return receivedResource >= requestedResource;
  }

  getColumnClassNameFn(classes) {
    return (prop, sortBy) => {
      return classNames(classes, {
        active: prop === sortBy.prop
      });
    };
  }

  getColumnHeadingFn(defaultHeading, abbreviation) {
    return (prop, order, sortBy) => {
      const caretClassNames = classNames("caret", {
        [`caret--${order}`]: order != null,
        "caret--visible": sortBy.prop === prop
      });

      let columnHeading = defaultHeading || prop;

      if (abbreviation != null) {
        columnHeading = [

            {columnHeading}
          ,

            {abbreviation}

        ];
      }

      return (

          {columnHeading}

      );
    };
  }

  getMatchedResourcesSortFn(resource) {
    return (item, prop) => {
      // It's possible that prop is one of the resources, or timestamp for a
      // tiebreaker. Return the timestamp in ms if it's the current prop.
      if (prop === "timestamp") {
        return DateUtil.strToMs(item[prop]);
      }

      const { unmatchedResource = [] } = item;

      if (unmatchedResource.includes(resource)) {
        return 1;
      }

      return 0;
    };
  }

  getMatchedOfferRenderFn(resource) {
    const { summary } = this.props;

    return (prop, row) => {
      const { unmatchedResource = [] } = row;
      const isResourceUnmatched = unmatchedResource.includes(resource);
      const receivedResourceClasses = classNames({
        "text-danger": isResourceUnmatched
      });

      let requestedResource = (summary[prop] || { requested: 0 }).requested;
      let receivedResource = row.offered[prop];

      let requestedResourceSuffix = "";
      let receivedResourceSuffix = "";
      let icon = null;

      if (isResourceUnmatched) {
        icon = <Icon color="red" id="close" size="mini" />;

        if (
          unmatchedResource.includes(DeclinedOffersReasons.UNFULFILLED_ROLE) &&
          this.areResourcesUnmatched(requestedResource, receivedResource)
        ) {
          requestedResourceSuffix = `(Role: ${summary.roles.requested})`;
          receivedResourceSuffix = `(Role: ${row.offered.roles})`;
        }
      } else {
        icon = <Icon color="green" id="check" size="mini" />;
      }

      if (Array.isArray(receivedResource)) {
        receivedResource = receivedResource.join(", ");
      }

      if (Array.isArray(requestedResource)) {
        requestedResource = requestedResource.join(", ");
      }

      if (["cpus", "mem", "disk"].includes(prop)) {
        requestedResource = Units.formatResource(prop, requestedResource);
        receivedResource = Units.formatResource(prop, receivedResource);
      } else {
        if (!requestedResource) {
          requestedResource = "N/A";
        }

        if (!receivedResource) {
          receivedResource = "N/A";
        }
      }

      const tooltipContent = (

            <Trans render="strong">Requested</Trans>
            {": "}
            {requestedResource}
            {` ${requestedResourceSuffix}`}

            <Trans render="strong">Received</Trans>
            {": "}
            {receivedResource}
            {` ${receivedResourceSuffix}`}

      );

      return (
        <Tooltip content={tooltipContent} maxWidth={400} wrapText={true}>
          {icon}
        </Tooltip>
      );
    };
  }

  getColGroup() {
    return (
      <colgroup>
        <col />
        <col style={{ width: "10%" }} />
        <col style={{ width: "10%" }} />
        <col className="hidden-large-up" style={{ width: "30%" }} />
        <col className="hidden-medium-down" style={{ width: "10%" }} />
        <col className="hidden-medium-down" style={{ width: "10%" }} />
        <col className="hidden-medium-down" style={{ width: "10%" }} />
        <col style={{ width: "10%" }} />
        <col className="hidden-small-down" />
      </colgroup>
    );
  }

  getColumns() {
    return [
      {
        heading: this.getColumnHeadingFn("Host"),
        prop: "hostname",
        className: this.getColumnClassNameFn(),
        render: (prop, row) => {
          const hostname = row[prop];
          const node = MesosStateStore.getNodeFromHostname(hostname);

          return (
            <Link className="table-cell-link-primary" to={`/nodes/${node.id}`}>
              {hostname}
            </Link>
          );
        },
        sortable: true
      },
      {
        heading: this.getColumnHeadingFn("Role", "RLE"),
        prop: "roles",
        className: this.getColumnClassNameFn("text-align-center"),
        render: this.getMatchedOfferRenderFn(
          DeclinedOffersReasons.UNFULFILLED_ROLE
        ),
        sortable: true,
        sortFunction: TableUtil.getSortFunction(
          "timestamp",
          this.getMatchedResourcesSortFn(DeclinedOffersReasons.UNFULFILLED_ROLE)
        )
      },
      {
        heading: this.getColumnHeadingFn("Constraint", "CSTR"),
        prop: "constraints",
        className: this.getColumnClassNameFn("text-align-center"),
        render: this.getMatchedOfferRenderFn(
          DeclinedOffersReasons.UNFULFILLED_CONSTRAINT
        ),
        sortable: true,
        sortFunction: TableUtil.getSortFunction(
          "timestamp",
          this.getMatchedResourcesSortFn(
            DeclinedOffersReasons.UNFULFILLED_CONSTRAINT
          )
        )
      },
      {
        heading: this.getColumnHeadingFn("CPU/MEM/DSK"),
        prop: "cpus",
        className: this.getColumnClassNameFn(
          "text-align-center hidden-large-up"
        ),
        render: (prop, row) => {
          return (

              {this.getMatchedOfferRenderFn(
                DeclinedOffersReasons.INSUFFICIENT_CPU
              )(prop, row)}
              {this.getMatchedOfferRenderFn(
                DeclinedOffersReasons.INSUFFICIENT_MEM
              )(prop, row)}
              {this.getMatchedOfferRenderFn(
                DeclinedOffersReasons.INSUFFICIENT_DISK
              )(prop, row)}

          );
        },
        sortable: true,
        sortFunction: TableUtil.getSortFunction(
          "timestamp",
          this.getMatchedResourcesSortFn(DeclinedOffersReasons.INSUFFICIENT_CPU)
        )
      },
      {
        heading: this.getColumnHeadingFn("CPU"),
        prop: "cpus",
        className: this.getColumnClassNameFn(
          "text-align-center hidden-medium-down"
        ),
        render: this.getMatchedOfferRenderFn(
          DeclinedOffersReasons.INSUFFICIENT_CPU
        ),
        sortable: true,
        sortFunction: TableUtil.getSortFunction(
          "timestamp",
          this.getMatchedResourcesSortFn(DeclinedOffersReasons.INSUFFICIENT_CPU)
        )
      },
      {
        heading: this.getColumnHeadingFn("Mem"),
        prop: "mem",
        className: this.getColumnClassNameFn(
          "text-align-center hidden-medium-down"
        ),
        render: this.getMatchedOfferRenderFn(
          DeclinedOffersReasons.INSUFFICIENT_MEM
        ),
        sortable: true,
        sortFunction: TableUtil.getSortFunction(
          "timestamp",
          this.getMatchedResourcesSortFn(DeclinedOffersReasons.INSUFFICIENT_MEM)
        )
      },
      {
        heading: this.getColumnHeadingFn("Disk", "DSK"),
        prop: "disk",
        className: this.getColumnClassNameFn(
          "text-align-center hidden-medium-down"
        ),
        render: this.getMatchedOfferRenderFn(
          DeclinedOffersReasons.INSUFFICIENT_DISK
        ),
        sortable: true,
        sortFunction: TableUtil.getSortFunction(
          "timestamp",
          this.getMatchedResourcesSortFn(
            DeclinedOffersReasons.INSUFFICIENT_DISK
          )
        )
      },
      {
        heading: this.getColumnHeadingFn("GPU"),
        prop: "gpus",
        className: this.getColumnClassNameFn("text-align-center"),
        render: this.getMatchedOfferRenderFn(
          DeclinedOffersReasons.INSUFFICIENT_GPU
        ),
        sortable: true,
        sortFunction: TableUtil.getSortFunction(
          "timestamp",
          this.getMatchedResourcesSortFn(DeclinedOffersReasons.INSUFFICIENT_GPU)
        )
      },
      {
        heading: this.getColumnHeadingFn("Port", "PRT"),
        prop: "ports",
        className: this.getColumnClassNameFn("text-align-center"),
        render: this.getMatchedOfferRenderFn(
          DeclinedOffersReasons.INSUFFICIENT_PORTS
        ),
        sortable: true,
        sortFunction: TableUtil.getSortFunction(
          "timestamp",
          this.getMatchedResourcesSortFn(
            DeclinedOffersReasons.INSUFFICIENT_PORTS
          )
        )
      },
      {
        heading: this.getColumnHeadingFn("Received"),
        prop: "timestamp",
        className: this.getColumnClassNameFn(
          "text-align-right hidden-small-down"
        ),
        render: (prop, row) => <TimeAgo time={DateUtil.strToMs(row[prop])} />,
        sortable: true
      }
    ];
  }

  render() {
    const { offers } = this.props;

    return (
      <MountService.Mount type="DeclinedOffersTable">

      </MountService.Mount>
    );
  }
}

module.exports = DeclinedOffersTable;
<commit_msg>feat(DeclinedOffersTable): mark strings for translation<commit_after>import { Trans } from "@lingui/macro";
import { i18nMark } from "@lingui/react";
import classNames from "classnames";
import { Link } from "react-router";
import { MountService } from "foundation-ui";
import React from "react";
import { Table, Tooltip } from "reactjs-components";

import DateUtil from "#SRC/js/utils/DateUtil";
import Icon from "#SRC/js/components/Icon";
import MesosStateStore from "#SRC/js/stores/MesosStateStore";
import TableUtil from "#SRC/js/utils/TableUtil";
import TimeAgo from "#SRC/js/components/TimeAgo";
import Units from "#SRC/js/utils/Units";

import DeclinedOffersReasons from "../constants/DeclinedOffersReasons";

class DeclinedOffersTable extends React.Component {
  areResourcesUnmatched(requestedResource, receivedResource) {
    if (Array.isArray(receivedResource)) {
      return receivedResource.includes(requestedResource);
    }

    return receivedResource >= requestedResource;
  }

  getColumnClassNameFn(classes) {
    return (prop, sortBy) => {
      return classNames(classes, {
        active: prop === sortBy.prop
      });
    };
  }

  getColumnHeadingFn(defaultHeading, abbreviation) {
    return (prop, order, sortBy) => {
      const caretClassNames = classNames("caret", {
        [`caret--${order}`]: order != null,
        "caret--visible": sortBy.prop === prop
      });

      const columnHeading = defaultHeading || prop;

      if (abbreviation != null) {
        return (

            <Trans
              id={columnHeading}
              render="span"
              key="full-text"
              className="hidden-medium-down"
            />
            <Trans
              id={abbreviation}
              render="span"
              key="abbreviation"
              className="hidden-large-up"
            />

        );
      }

      return (

          <Trans render="span" id={columnHeading} />

      );
    };
  }

  getMatchedResourcesSortFn(resource) {
    return (item, prop) => {
      // It's possible that prop is one of the resources, or timestamp for a
      // tiebreaker. Return the timestamp in ms if it's the current prop.
      if (prop === "timestamp") {
        return DateUtil.strToMs(item[prop]);
      }

      const { unmatchedResource = [] } = item;

      if (unmatchedResource.includes(resource)) {
        return 1;
      }

      return 0;
    };
  }

  getMatchedOfferRenderFn(resource) {
    const { summary } = this.props;

    return (prop, row) => {
      const { unmatchedResource = [] } = row;
      const isResourceUnmatched = unmatchedResource.includes(resource);
      const receivedResourceClasses = classNames({
        "text-danger": isResourceUnmatched
      });

      let requestedResource = (summary[prop] || { requested: 0 }).requested;
      let receivedResource = row.offered[prop];

      let requestedResourceSuffix = "";
      let receivedResourceSuffix = "";
      let icon = null;

      if (isResourceUnmatched) {
        icon = <Icon color="red" id="close" size="mini" />;

        if (
          unmatchedResource.includes(DeclinedOffersReasons.UNFULFILLED_ROLE) &&
          this.areResourcesUnmatched(requestedResource, receivedResource)
        ) {
          requestedResourceSuffix = (
            <Trans render="span">(Role: {summary.roles.requested})</Trans>
          );
          receivedResourceSuffix = (
            <Trans className="text-nowrap" render="span">
              (Role: {row.offered.roles})
            </Trans>
          );
        }
      } else {
        icon = <Icon color="green" id="check" size="mini" />;
      }

      if (Array.isArray(receivedResource)) {
        receivedResource = receivedResource.join(", ");
      }

      if (Array.isArray(requestedResource)) {
        requestedResource = requestedResource.join(", ");
      }

      if (["cpus", "mem", "disk"].includes(prop)) {
        requestedResource = Units.formatResource(prop, requestedResource);
        receivedResource = Units.formatResource(prop, receivedResource);
      } else {
        if (!requestedResource) {
          requestedResource = "N/A";
        }

        if (!receivedResource) {
          receivedResource = "N/A";
        }
      }

      const tooltipContent = (

            <Trans render="strong">Requested</Trans>
            {": "}
            {requestedResource} {requestedResourceSuffix}

            <Trans render="strong">Received</Trans>
            {": "}

              {receivedResource}
            {" "}
            {receivedResourceSuffix}

      );

      return (
        <Tooltip content={tooltipContent} maxWidth={400} wrapText={true}>
          {icon}
        </Tooltip>
      );
    };
  }

  getColGroup() {
    return (
      <colgroup>
        <col />
        <col style={{ width: "10%" }} />
        <col style={{ width: "10%" }} />
        <col className="hidden-large-up" style={{ width: "30%" }} />
        <col className="hidden-medium-down" style={{ width: "10%" }} />
        <col className="hidden-medium-down" style={{ width: "10%" }} />
        <col className="hidden-medium-down" style={{ width: "10%" }} />
        <col style={{ width: "10%" }} />
        <col className="hidden-small-down" />
      </colgroup>
    );
  }

  getColumns() {
    return [
      {
        heading: this.getColumnHeadingFn(i18nMark("Host")),
        prop: "hostname",
        className: this.getColumnClassNameFn(),
        render: (prop, row) => {
          const hostname = row[prop];
          const node = MesosStateStore.getNodeFromHostname(hostname);

          return (
            <Link className="table-cell-link-primary" to={`/nodes/${node.id}`}>
              {hostname}
            </Link>
          );
        },
        sortable: true
      },
      {
        heading: this.getColumnHeadingFn(i18nMark("Role"), i18nMark("RLE")),
        prop: "roles",
        className: this.getColumnClassNameFn("text-align-center"),
        render: this.getMatchedOfferRenderFn(
          DeclinedOffersReasons.UNFULFILLED_ROLE
        ),
        sortable: true,
        sortFunction: TableUtil.getSortFunction(
          "timestamp",
          this.getMatchedResourcesSortFn(DeclinedOffersReasons.UNFULFILLED_ROLE)
        )
      },
      {
        heading: this.getColumnHeadingFn(
          i18nMark("Constraint"),
          i18nMark("CSTR")
        ),
        prop: "constraints",
        className: this.getColumnClassNameFn("text-align-center"),
        render: this.getMatchedOfferRenderFn(
          DeclinedOffersReasons.UNFULFILLED_CONSTRAINT
        ),
        sortable: true,
        sortFunction: TableUtil.getSortFunction(
          "timestamp",
          this.getMatchedResourcesSortFn(
            DeclinedOffersReasons.UNFULFILLED_CONSTRAINT
          )
        )
      },
      {
        heading: this.getColumnHeadingFn(i18nMark("CPU/MEM/DSK")),
        prop: "cpus",
        className: this.getColumnClassNameFn(
          "text-align-center hidden-large-up"
        ),
        render: (prop, row) => {
          return (

              {this.getMatchedOfferRenderFn(
                DeclinedOffersReasons.INSUFFICIENT_CPU
              )(prop, row)}
              {this.getMatchedOfferRenderFn(
                DeclinedOffersReasons.INSUFFICIENT_MEM
              )(prop, row)}
              {this.getMatchedOfferRenderFn(
                DeclinedOffersReasons.INSUFFICIENT_DISK
              )(prop, row)}

          );
        },
        sortable: true,
        sortFunction: TableUtil.getSortFunction(
          "timestamp",
          this.getMatchedResourcesSortFn(DeclinedOffersReasons.INSUFFICIENT_CPU)
        )
      },
      {
        heading: this.getColumnHeadingFn(i18nMark("CPU")),
        prop: "cpus",
        className: this.getColumnClassNameFn(
          "text-align-center hidden-medium-down"
        ),
        render: this.getMatchedOfferRenderFn(
          DeclinedOffersReasons.INSUFFICIENT_CPU
        ),
        sortable: true,
        sortFunction: TableUtil.getSortFunction(
          "timestamp",
          this.getMatchedResourcesSortFn(DeclinedOffersReasons.INSUFFICIENT_CPU)
        )
      },
      {
        heading: this.getColumnHeadingFn(i18nMark("Mem")),
        prop: "mem",
        className: this.getColumnClassNameFn(
          "text-align-center hidden-medium-down"
        ),
        render: this.getMatchedOfferRenderFn(
          DeclinedOffersReasons.INSUFFICIENT_MEM
        ),
        sortable: true,
        sortFunction: TableUtil.getSortFunction(
          "timestamp",
          this.getMatchedResourcesSortFn(DeclinedOffersReasons.INSUFFICIENT_MEM)
        )
      },
      {
        heading: this.getColumnHeadingFn(i18nMark("Disk"), i18nMark("DSK")),
        prop: "disk",
        className: this.getColumnClassNameFn(
          "text-align-center hidden-medium-down"
        ),
        render: this.getMatchedOfferRenderFn(
          DeclinedOffersReasons.INSUFFICIENT_DISK
        ),
        sortable: true,
        sortFunction: TableUtil.getSortFunction(
          "timestamp",
          this.getMatchedResourcesSortFn(
            DeclinedOffersReasons.INSUFFICIENT_DISK
          )
        )
      },
      {
        heading: this.getColumnHeadingFn(i18nMark("GPU")),
        prop: "gpus",
        className: this.getColumnClassNameFn("text-align-center"),
        render: this.getMatchedOfferRenderFn(
          DeclinedOffersReasons.INSUFFICIENT_GPU
        ),
        sortable: true,
        sortFunction: TableUtil.getSortFunction(
          "timestamp",
          this.getMatchedResourcesSortFn(DeclinedOffersReasons.INSUFFICIENT_GPU)
        )
      },
      {
        heading: this.getColumnHeadingFn(i18nMark("Port"), i18nMark("PRT")),
        prop: "ports",
        className: this.getColumnClassNameFn("text-align-center"),
        render: this.getMatchedOfferRenderFn(
          DeclinedOffersReasons.INSUFFICIENT_PORTS
        ),
        sortable: true,
        sortFunction: TableUtil.getSortFunction(
          "timestamp",
          this.getMatchedResourcesSortFn(
            DeclinedOffersReasons.INSUFFICIENT_PORTS
          )
        )
      },
      {
        heading: this.getColumnHeadingFn(i18nMark("Received")),
        prop: "timestamp",
        className: this.getColumnClassNameFn(
          "text-align-right hidden-small-down"
        ),
        render: (prop, row) => <TimeAgo time={DateUtil.strToMs(row[prop])} />,
        sortable: true
      }
    ];
  }

  render() {
    const { offers } = this.props;

    return (
      <MountService.Mount type="DeclinedOffersTable">

      </MountService.Mount>
    );
  }
}

module.exports = DeclinedOffersTable;
<|endoftext|>


<commit_before>/*
 *  asf -- Ada Server Faces
 *  Copyright (C) 2009, 2010, 2011, 2012, 2013 Stephane Carrez
 *  Written by Stephane Carrez (Stephane.Carrez@gmail.com)
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
var ASF = {};

(function () {
    /**
     * Execute the AJAX response action represented by the JSON object action.
     *
     * @param node the current node
     * @param action the JSON action object
     */
    ASF.ExecuteOne = function(node, action) {
        var id = action.id ? action.id : node;
        if (action.child) {
            id = $(id).children(action.child);
        }
        if (action.action === "update") {
	        $(id).html(action.data);

        } else if (action.action === "prepend") {
	        $(id).prepend(action.data);

        } else if (action.action === "append") {
	        $(id).append(action.data);

        } else if (action.action === "show") {
            $(id).show('slow');

        } else if (action.action === "hide") {
            $(id).hide('slow');

        } else if (action.action === "delete") {
	        $(id).remove();

        } else if (action.action === "removeClass") {
	        $(id).removeClass(action.data);

        } else if (action.action === "addClass") {
	        $(id).addClass(action.data);

        } else if (action.action === "fadeIn") {
            $(id).fadeIn('slow');

        } else if (action.action === "fadeOut") {
            $(id).fadeOut('slow');

        } else if (action.action === "slideUp") {
            $(id).slideUp('slow');

        } else if (action.action === "slideDown") {
            $(id).slideDown('slow');

        } else if (action.action === "closeDialog") {
            $(id).dialog('close');

        } else if (action.action === "redirect") {
            document.location = action.url;

        } else if (action.action === "message") {
	        ASF.Message(node, action.id, action.data);

        } else if (action.action === "script") {
            try {
                eval(action.script);
            } catch (e) {
                alert(e);
            }

	    } else if (action.action === "clear") {
	        $(id).each(function() {
                switch (this.type) {
                case 'password':
                case 'select-multiple':
                case 'select-one':
                case 'text':
                case 'textarea':
                    $(this).val('');
                    break;
                case 'checkbox':
                case 'radio':
                    this.checked = false;
                    break;
                }
            });
	    }
    };

    ASF.Execute = function(node, data) {
        if (data) {
            for (var i = 0; i < data.length; i++) {
                ASF.ExecuteOne(node, data[i]);
            }
        }
    };

    /**
     * Handle an AJAX operation that failed.
     */
    ASF.AjaxError = function(jqXHDR, node) {
        var contentType = jqXHDR.getResponseHeader('Content-type');
        if (contentType && contentType.match(/^application\/json(;.*)?$/i)) {
            var data = $.parseJSON(jqXHDR.responseText);
            ASF.Execute(node, data);
        }
    };

    /**
     * Update the target container with the content of the AJAX GET request
     * on the given URL.  The target parameter is optional.
     *
     * @param node the current element
     * @param url the URL to fetch using an HTTP GET
     * @param target the optional target element
     * @param complete an optional function called when the response is received
     */
    ASF.Update = function(node, url, target, complete) {
        /* Find the container to update */
        var d;
        if (target != null) {
            d = $(target);
        } else {
            d = $(node);
            if (!d.is('.asf-container')) {
                d = d.parent('.asf-container');
            }
        }
        if (d.length > 0) {
            /* Perform the HTTP GET */
            jQuery.ajax({
                url: url,
                context: document.body,
                success: function(data, status, jqXHDR) {
                    var contentType = jqXHDR.getResponseHeader('Content-type');
                    if (contentType == null) {
                        contentType = "text/html";
                    }
                    if (contentType.match(/^text\/(html|xml)(;.*)?$/i)) {
                        d.html(jqXHDR.responseText);

                    } else if (contentType.match(/^application\/json(;.*)?$/i)) {
                        ASF.Execute(d, data);
                    }
                    if (complete != null) {
                        complete(d, jqXHDR);
                    }
               },
               error: function(jqXHDR, status, error) {
                   ASF.AjaxError(jqXHDR, d);
               }
            });
        }
    };

    /**
     * Submit the current form.  The node element refers to the element being clicked.
     * From that element, we can identify the form to submit.  The element to refresh upon
     * the form submit is an outer element that should have the asf-container class.
     * If not such element as parent node, the parent node of the form is used.
     *
     * After the form is submitted, the response is executed if it is a JSON response.
     * If the response is an HTML content, the container element is refreshed with it.
     *
     * @param node the current element
     * @param url the URL to fetch using an HTTP GET
     * @param target the optional target element
     */
    ASF.Submit = function(node) {
        /* Find the form and container to update */
        var f = $(node).closest("form");
        var d = $(f);
        if (!d.is('.asf-container,ui-dialog-content')) {
            d = d.closest('.asf-container,.ui-dialog-content');
        }
        if (d.length == 0) {
            d = $(f).parent();
        }
        if (d.length > 0) {
            var params;
            var params = $(f).serialize();
            var url = $(f).attr('action');

            if (node.tagName == 'a' || node.tagName == 'A') {
                params = node.id + "=1&" + $(f).serialize();
            } else {
                params = node.name + "=1&" + $(f).serialize();
            }
            /**
             * Send notification on form to indicate a form submit is now in progress.
             */
            $(f).triggerHandler("notifySubmit", d);

            /* Perform the HTTP POST */
            jQuery.ajax({
                type: "POST",
                url: url,
                data: params,
                context: document.body,
                success: function(data, status, jqXHDR) {
                    var contentType = jqXHDR.getResponseHeader('Content-type');
                    if (contentType == null) {
                        contentType = "text/html";
                    }
                    $(f).triggerHandler("successSubmit", d);
                    if (contentType.match(/^text\/(html|xml)(;.*)?$/i)) {
                        d.fadeOut("fast", function() {
                            d.html(jqXHDR.responseText);
                            d.fadeIn("fast");
                        });

                    } else if (contentType.match(/^application\/json(;.*)?$/i)) {
                        ASF.Execute(d, data);
                    }
               },
               error: function(jqXHDR, status, error) {
                   ASF.AjaxError(jqXHDR, d);
               }
            });
        }
        return false;
    };

    /**
     * Open a dialog box and fetch the dialog content from the given URI.
     *
     * @param node the current element
     * @param id the dialog id
     * @param url the URL to fetch using an HTTP GET
     * @param params the optional dialog options
     */
    ASF.OpenDialog = function(node, id, url, params) {
        var div = $(id);
        if (div.length > 0) {
            return false;
        }

        div = document.createElement("div");
        div.id = id;
        div = $(div);

        var d = $(document);
        if (d.length == 0) {
            return false;
        }

        $(d).append($(div));

        /* Perform the HTTP GET */
        jQuery.ajax({
            url: url,
            context: document.body,
            success: function(data, status, jqXHDR) {
                var contentType = jqXHDR.getResponseHeader('Content-type');
                if (contentType == null) {
                    contentType = "text/html";
                }
                if (contentType.match(/^text\/(html|xml)(;.*)?$/i)) {
                    $(div).dialog({
                        autoOpen: false,
                        show: "blind",
                        hide: "explode",
                        minWidth: 600,
                        close: function() {
                            $(div).dialog('destroy');
                            $(div).remove();
                            if (params && params.close) {
                                params.close(node);
                            }
                        }
                     });

                     $(div).html(jqXHDR.responseText);

                     /**
                      * Extract a title from the inner form to setup the dialog box.
                      */
                     var dTitle, dBox = $(div).children('div');
                     if (dBox.length == 0) {
                        dTitle = $(div).children('h2');
                     } else {
                        dTitle = $(dBox).children('h2');
                     }
                     if (dTitle.length > 0) {
                        $(div).dialog("option", "title", dTitle.html());
                        dTitle.remove();
                     } else {
                        dTitle = $(div).children('div').attr('title');
                        if (dTitle != null) {
                            $(div).dialog("option", "title", dTitle );
                            /* $(div).attr('title', title); */
                        }
                     }
                     $(div).dialog('open');

                } else if (contentType.match(/^application\/json(;.*)?$/i)) {
                    ASF.Execute(node, data);
                }
            },
            error: function(jqXHDR, status, error) {
                ASF.AjaxError(jqXHDR, d);
            }
        });
        return false;
    };

    /**
     * Close the dialog box identified by the given identifier.
     *
     * @param id the dialog box identifier
     */
    ASF.CloseDialog = function(id) {
        $('#' + id).dialog('close');
        return false;
    };

    /**
     * Create and display a popup message near the node element.
     *
     * @param node the element giving the location of the message
     * @param id the message id or null
     * @param message the HTML message content
     */
    ASF.Message = function(node, id, message) {
        if (!id) {
            id = "#asf-message";
        }
        var div = $(id);
        if (div.length == 0) {
            div = document.createElement("div");
            div.id = id.substring(1);
            $(document.body).append($(div));
        }

        $(div).html(message).message({}).message("attachment", node);
    };
})();

<commit_msg>New operation ASF.Post<commit_after>/*
 *  asf -- Ada Server Faces
 *  Copyright (C) 2009, 2010, 2011, 2012, 2013 Stephane Carrez
 *  Written by Stephane Carrez (Stephane.Carrez@gmail.com)
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
var ASF = {};

(function () {
    /**
     * Execute the AJAX response action represented by the JSON object action.
     *
     * @param node the current node
     * @param action the JSON action object
     */
    ASF.ExecuteOne = function(node, action) {
        var id = action.id ? action.id : node;
        if (action.child) {
            id = $(id).children(action.child);
        }
        if (action.action === "update") {
	        $(id).html(action.data);

        } else if (action.action === "prepend") {
	        $(id).prepend(action.data);

        } else if (action.action === "append") {
	        $(id).append(action.data);

        } else if (action.action === "show") {
            $(id).show('slow');

        } else if (action.action === "hide") {
            $(id).hide('slow');

        } else if (action.action === "delete") {
	        $(id).remove();

        } else if (action.action === "removeClass") {
	        $(id).removeClass(action.data);

        } else if (action.action === "addClass") {
	        $(id).addClass(action.data);

        } else if (action.action === "fadeIn") {
            $(id).fadeIn('slow');

        } else if (action.action === "fadeOut") {
            $(id).fadeOut('slow');

        } else if (action.action === "slideUp") {
            $(id).slideUp('slow');

        } else if (action.action === "slideDown") {
            $(id).slideDown('slow');

        } else if (action.action === "closeDialog") {
            $(id).dialog('close');

        } else if (action.action === "redirect") {
            document.location = action.url;

        } else if (action.action === "message") {
	        ASF.Message(node, action.id, action.data);

        } else if (action.action === "script") {
            try {
                eval(action.script);
            } catch (e) {
                alert(e);
            }

	    } else if (action.action === "clear") {
	        $(id).each(function() {
                switch (this.type) {
                case 'password':
                case 'select-multiple':
                case 'select-one':
                case 'text':
                case 'textarea':
                    $(this).val('');
                    break;
                case 'checkbox':
                case 'radio':
                    this.checked = false;
                    break;
                }
            });
	    }
    };

    ASF.Execute = function(node, data) {
        if (data) {
            for (var i = 0; i < data.length; i++) {
                ASF.ExecuteOne(node, data[i]);
            }
        }
    };

    /**
     * Handle an AJAX operation that failed.
     */
    ASF.AjaxError = function(jqXHDR, node) {
        var contentType = jqXHDR.getResponseHeader('Content-type');
        if (contentType && contentType.match(/^application\/json(;.*)?$/i)) {
            var data = $.parseJSON(jqXHDR.responseText);
            ASF.Execute(node, data);
        }
    };

    /**
     * Update the target container with the content of the AJAX GET request
     * on the given URL.  The target parameter is optional.
     *
     * @param node the current element
     * @param url the URL to fetch using an HTTP GET
     * @param target the optional target element
     * @param complete an optional function called when the response is received
     */
    ASF.Update = function(node, url, target, complete) {
        /* Find the container to update */
        var d;
        if (target != null) {
            d = $(target);
        } else {
            d = $(node);
            if (!d.is('.asf-container')) {
                d = d.parent('.asf-container');
            }
        }
        if (d.length > 0) {
            /* Perform the HTTP GET */
            jQuery.ajax({
                url: url,
                context: document.body,
                success: function(data, status, jqXHDR) {
                    var contentType = jqXHDR.getResponseHeader('Content-type');
                    if (contentType == null) {
                        contentType = "text/html";
                    }
                    if (contentType.match(/^text\/(html|xml)(;.*)?$/i)) {
                        d.html(jqXHDR.responseText);

                    } else if (contentType.match(/^application\/json(;.*)?$/i)) {
                        ASF.Execute(d, data);
                    }
                    if (complete != null) {
                        complete(d, jqXHDR);
                    }
               },
               error: function(jqXHDR, status, error) {
                   ASF.AjaxError(jqXHDR, d);
               }
            });
        }
    };

    /**
     * Submit the current form.  The node element refers to the element being clicked.
     * From that element, we can identify the form to submit.  The element to refresh upon
     * the form submit is an outer element that should have the asf-container class.
     * If not such element as parent node, the parent node of the form is used.
     *
     * After the form is submitted, the response is executed if it is a JSON response.
     * If the response is an HTML content, the container element is refreshed with it.
     *
     * @param node the current element
     * @param url the URL to fetch using an HTTP GET
     * @param target the optional target element
     */
    ASF.Submit = function(node) {
        /* Find the form and container to update */
        var f = $(node).closest("form");
        var d = $(f);
        if (!d.is('.asf-container,ui-dialog-content')) {
            d = d.closest('.asf-container,.ui-dialog-content');
        }
        if (d.length == 0) {
            d = $(f).parent();
        }
        if (d.length > 0) {
            var params;
            var params = $(f).serialize();
            var url = $(f).attr('action');

            if (node.tagName == 'a' || node.tagName == 'A') {
                params = node.id + "=1&" + $(f).serialize();
            } else {
                params = node.name + "=1&" + $(f).serialize();
            }
            /**
             * Send notification on form to indicate a form submit is now in progress.
             */
            $(f).triggerHandler("notifySubmit", d);

            /* Perform the HTTP POST */
            jQuery.ajax({
                type: "POST",
                url: url,
                data: params,
                context: document.body,
                success: function(data, status, jqXHDR) {
                    var contentType = jqXHDR.getResponseHeader('Content-type');
                    if (contentType == null) {
                        contentType = "text/html";
                    }
                    $(f).triggerHandler("successSubmit", d);
                    if (contentType.match(/^text\/(html|xml)(;.*)?$/i)) {
                        d.fadeOut("fast", function() {
                            d.html(jqXHDR.responseText);
                            d.fadeIn("fast");
                        });

                    } else if (contentType.match(/^application\/json(;.*)?$/i)) {
                        ASF.Execute(d, data);
                    }
               },
               error: function(jqXHDR, status, error) {
                   ASF.AjaxError(jqXHDR, d);
               }
            });
        }
        return false;
    };

    /**
     * Perform an HTTP POST on the given URL.
     *
     * @param node the node element that will be updated by default on the AJAX response.
     * @param url the HTTP URL.
     * @param params the HTTP POST parameters.
     */
    ASF.Post = function(node, url, params) {
        /* Perform the HTTP POST */
        jQuery.ajax({
            type: "POST",
            url: url,
            data: params,
            context: document.body,
            success: function(data, status, jqXHDR) {
                var contentType = jqXHDR.getResponseHeader('Content-type');
                if (contentType == null) {
                    contentType = "text/html";
                }
                if (contentType.match(/^text\/(html|xml)(;.*)?$/i)) {
                    $(node).html(jqXHDR.responseText);

                } else if (contentType.match(/^application\/json(;.*)?$/i)) {
                    ASF.Execute(node, data);
                }
            },
            error: function(jqXHDR, status, error) {
                ASF.AjaxError(jqXHDR, d);
            }
        });
        return false;
    };

    /**
     * Open a dialog box and fetch the dialog content from the given URI.
     *
     * @param node the current element
     * @param id the dialog id
     * @param url the URL to fetch using an HTTP GET
     * @param params the optional dialog options
     */
    ASF.OpenDialog = function(node, id, url, params) {
        var div = $(id);
        if (div.length > 0) {
            return false;
        }

        div = document.createElement("div");
        div.id = id;
        div = $(div);

        var d = $(document);
        if (d.length == 0) {
            return false;
        }

        $(d).append($(div));

        /* Perform the HTTP GET */
        jQuery.ajax({
            url: url,
            context: document.body,
            success: function(data, status, jqXHDR) {
                var contentType = jqXHDR.getResponseHeader('Content-type');
                if (contentType == null) {
                    contentType = "text/html";
                }
                if (contentType.match(/^text\/(html|xml)(;.*)?$/i)) {
                    $(div).dialog({
                        autoOpen: false,
                        show: "blind",
                        hide: "explode",
                        minWidth: 600,
                        close: function() {
                            $(div).dialog('destroy');
                            $(div).remove();
                            if (params && params.close) {
                                params.close(node);
                            }
                        }
                     });

                     $(div).html(jqXHDR.responseText);

                     /**
                      * Extract a title from the inner form to setup the dialog box.
                      */
                     var dTitle, dBox = $(div).children('div');
                     if (dBox.length == 0) {
                        dTitle = $(div).children('h2');
                     } else {
                        dTitle = $(dBox).children('h2');
                     }
                     if (dTitle.length > 0) {
                        $(div).dialog("option", "title", dTitle.html());
                        dTitle.remove();
                     } else {
                        dTitle = $(div).children('div').attr('title');
                        if (dTitle != null) {
                            $(div).dialog("option", "title", dTitle );
                            /* $(div).attr('title', title); */
                        }
                     }
                     $(div).dialog('open');

                } else if (contentType.match(/^application\/json(;.*)?$/i)) {
                    ASF.Execute(node, data);
                }
            },
            error: function(jqXHDR, status, error) {
                ASF.AjaxError(jqXHDR, d);
            }
        });
        return false;
    };

    /**
     * Close the dialog box identified by the given identifier.
     *
     * @param id the dialog box identifier
     */
    ASF.CloseDialog = function(id) {
        $('#' + id).dialog('close');
        return false;
    };

    /**
     * Create and display a popup message near the node element.
     *
     * @param node the element giving the location of the message
     * @param id the message id or null
     * @param message the HTML message content
     */
    ASF.Message = function(node, id, message) {
        if (!id) {
            id = "#asf-message";
        }
        var div = $(id);
        if (div.length == 0) {
            div = document.createElement("div");
            div.id = id.substring(1);
            $(document.body).append($(div));
        }

        $(div).html(message).message({}).message("attachment", node);
    };
})();

<|endoftext|>


<commit_before>      case "barchart":

        vars.params = {
          x_scale: [{
              name: "linear",
              func: d3.scale.ordinal()
                      .rangeRoundBands([0, vars.width], .1)
                      .domain(vars.data.map(function(d) { return d[vars.var_x]; })),
            }
          ],

          x_ticks: 10,

          y_scale: [{
              name: "linear",
              func: d3.scale.linear()
                      .range([vars.height, 0])
                      .domain([0, d3.max(vars.data, function(d) { return d[vars.var_y]; })]),
            }
          ],

          connect: {
            type: null
          },
        };

        vars = vistk.utils.merge(vars, vars.params);

        // Params break down is required as there are some dependencies
        vars.items = [{
          attr: "country",
          marks: [{
              type: "rect",
              rotate: "0"
            }, {
              type: "text",
              rotate: "90",
              translate: null
            }]
        }, {
          attr: "continent",
          marks: [{
            // Stacked bar chart
          }]
        }];

        // REGISTER EVENTS
        vars.evt.register("highlightOn", function(d) { });
        vars.evt.register("highlightOut", function(d) { });
        vars.evt.register("selection", function(d) { });
        vars.evt.register("resize", function(d) { });
/*
        // AXIS
        vars.svg.call(vistk.utils.axis)
                .select(".x.axis")
                .attr("transform", "translate(0," + (vars.height - vars.margin.bottom - vars.margin.top) + ")")
              .append("text") // TODO: fix axis labels
                .attr("class", "label")
                .attr("x", vars.width-vars.margin.left-vars.margin.right)
                .attr("y", -6)
                .style("text-anchor", "end")
                .text(function(d) { return vars.var_x; });

        vars.svg.call(vistk.utils.y_axis);

        vars.svg.selectAll(".bar")
            .data(vars.data)
          .enter()
            .append("rect")
            .attr("class", "bar")
            .attr("x", function(d) { return vars.x_scale[0]["func"](d.letter); })
            .attr("width", vars.x_scale[0]["func"].rangeBand())
            .attr("y", function(d) { return vars.y_scale[0]["func"](d.frequency); })
            .attr("height", function(d) { return vars.height - vars.y_scale[0]["func"](d.frequency); });

*/
        // PRE-UPDATE
        var gItems = vars.svg.selectAll(".mark__group")
                         .data(vars.new_data, function(d, i) { return i; });

        // ENTER
        var gItems_enter = gItems.enter()
                        .append("g")
                        .each(vistk.utils.items_group)
                        .attr("transform", function(d, i) {
                          return "translate(" + vars.margin.left + ", " + vars.height/2 + ")";
                        });

        // Add graphical marks
        vars.items[0].marks.forEach(function(d) {

          vars.mark.type = d.type;
          vars.mark.rotate = d.rotate;

          gItems_enter.each(vistk.utils.items_mark)
            .select("rect")
            .attr("class", "bar")
       //     .attr("x", function(d) { return vars.x_scale[0]["func"](d[vars.var_x]); })
            .attr("width", vars.x_scale[0]["func"].rangeBand())
            .attr("y", function(d) { return 100- vars.y_scale[0]["func"](d[vars.var_y]); })
            .attr("height", function(d) { return vars.y_scale[0]["func"](d[vars.var_y]); });

        });

        // EXIT
        var gItems_exit = gItems.exit().style("opacity", 0.1);

        // POST-UPDATE
        vars.svg.selectAll(".mark__group")
                        .transition()
                        .delay(function(d, i) { return i / vars.data.length * 100; })
                        .duration(vars.duration)
                        .attr("transform", function(d, i) {
                          if(vars.x_type === "index") {
                            return "translate(" + d[vars.var_x] + ", " + vars.height/2 + ")";
                          } else {
                            return "translate(" + vars.x_scale[0]["func"](d[vars.var_x]) + ", " + vars.height/2 + ")";
                          }
                        });

/*
        var xAxis = d3.svg.axis()
            .scale(vars.x_scale[0]["func"])
            .orient("bottom");

        var yAxis = d3.svg.axis()
            .scale(vars.y_scale[0]["func"])
            .orient("left")
            .ticks(10, "%");

        vars.svg.append("g")
            .attr("transform", "translate(" + vars.margin.left + "," + vars.margin.top + ")");

        vars.svg.append("g")
            .attr("class", "x axis")
            .attr("transform", "translate(0," + vars.height + ")")
            .call(xAxis);

        vars.svg.append("g")
            .attr("class", "y axis")
            .call(yAxis)
          .append("text")
            .attr("transform", "rotate(-90)")
            .attr("y", 6)
            .attr("dy", ".71em")
            .style("text-anchor", "end")
            .text("Frequency");
*/

      break;
<commit_msg>Params for bar chart<commit_after>      case "barchart":

        vars.params = {
          x_scale: [{
              name: "linear",
              func: d3.scale.ordinal()
                      .rangeRoundBands([0, vars.width], .1)
                      .domain(vars.data.map(function(d) { return d[vars.var_x]; })),
            }
          ],

          x_ticks: 10,

          y_scale: [{
              name: "linear",
              func: d3.scale.linear()
                      .range([vars.height, 0])
                      .domain([0, d3.max(vars.data, function(d) { return d[vars.var_y]; })]),
            }
          ],

          items: [{
            attr: "country",
            marks: [{
                type: "rect",
                rotate: "0"
              }, {
                type: "text",
                rotate: "90",
                translate: null,
                anchor: "end"
              }]
          }, {
            attr: "continent",
            marks: [{
              // Stacked bar chart
            }]
          }],

          connect: {
            type: null
          },
        };

        vars = vistk.utils.merge(vars, vars.params);

        // REGISTER EVENTS
        vars.evt.register("highlightOn", function(d) { });
        vars.evt.register("highlightOut", function(d) { });
        vars.evt.register("selection", function(d) { });
        vars.evt.register("resize", function(d) { });
/*
        // AXIS
        vars.svg.call(vistk.utils.axis)
                .select(".x.axis")
                .attr("transform", "translate(0," + (vars.height - vars.margin.bottom - vars.margin.top) + ")")
              .append("text") // TODO: fix axis labels
                .attr("class", "label")
                .attr("x", vars.width-vars.margin.left-vars.margin.right)
                .attr("y", -6)
                .style("text-anchor", "end")
                .text(function(d) { return vars.var_x; });

*/

        vars.svg.call(vistk.utils.y_axis);
        vars.svg.call(vistk.utils.axis);

        // PRE-UPDATE
        var gItems = vars.svg.selectAll(".mark__group")
                         .data(vars.new_data, function(d, i) { return i; });

        // ENTER
        var gItems_enter = gItems.enter()
                        .append("g")
                        .each(vistk.utils.items_group)
                        .attr("transform", function(d, i) {
                          return "translate(" + vars.margin.left + ", " + vars.height/2 + ")";
                        });

        // Add graphical marks
        vars.items[0].marks.forEach(function(d) {

          vars.mark.type = d.type;
          vars.mark.rotate = d.rotate;

          gItems_enter.each(vistk.utils.items_mark)
            .select("rect")
            .attr("class", "bar")
       //     .attr("x", function(d) { return vars.x_scale[0]["func"](d[vars.var_x]); })
            .attr("width", vars.x_scale[0]["func"].rangeBand())
            .attr("y", function(d) { return 100- vars.y_scale[0]["func"](d[vars.var_y]); })
            .attr("height", function(d) { return vars.y_scale[0]["func"](d[vars.var_y]); });

        });

        // EXIT
        var gItems_exit = gItems.exit().style("opacity", 0.1);

        // POST-UPDATE
        vars.svg.selectAll(".mark__group")
                        .transition()
                        .delay(function(d, i) { return i / vars.data.length * 100; })
                        .duration(vars.duration)
                        .attr("transform", function(d, i) {
                          if(vars.x_type === "index") {
                            return "translate(" + d[vars.var_x] + ", " + vars.height/2 + ")";
                          } else {
                            return "translate(" + vars.x_scale[0]["func"](d[vars.var_x]) + ", " + vars.height/2 + ")";
                          }
                        });

      break;
<|endoftext|>


<commit_before>/*jslint indent: 4, nomen: true, plusplus: true */
/*globals process, require, console */
(function () {

    'use strict';

    var // variables
        description_file, // fichier de description des scenarios
        defaults = {
            files: [], // nombre de documents a traiter
            indent: '    ',
            extension: '.js',
            input_folder: '',
            cwd: process.cwd(),
            spec_extension: '.spec.js'
        },
        // lodash
        _ = require('lodash.template'),
        isarray = require('lodash.isarray'),
        // requires
        path = require('path'),
        chalk = require('chalk'),
        fse = require('fs-extra'),
        yaml = require('js-yaml'),
        inquirer = require('inquirer'),
        commander = require('commander'),
        esformatter = require('esformatter'),
        isvalidpath = require('is-valid-path');

    //
    // traitement des params args du cli
    commander
        .version('0.1.1')
        .usage('[options] <spec_folder ...>')
        .option('-Y, --yes', 'Force files overwrite')
        .option('-g, --generate', 'Generate spec files')
        .parse(process.argv);

    /**
     *
     * Par defaut
     * Au lance du cli sans options
     * Affichage dans la console
     * du fichier YAML
     *
     */
    function outputInConsole(file) {
        try {
            process.stdout.write(chalk.bold.green('describing: ') + chalk.bold(file + '\n'));
            var rstream = fse.createReadStream(file, {
                encoding: 'utf8'
            });
            rstream
                .on('error', function (err) {
                    throw err;
                })
                .on('data', function (data) {
                    process.stdout.write(data);
                }).on('end', function () {
                    process.exit(0);
                });
        } catch (e) {
            throw e;
        }
    }

    /**
     *
     * Verifciation si le fichier
     * de spec existe dans le repertoire
     * de sortie
     *
     */
    function fileExists(file) {
        try {
            fse.statSync(file);
            return true;
        } catch (e) {
            return false;
        }
    }

    /**
     *
     * Creation d'un fichier de test
     *
     */
    function writeSpecFile(file, content, overwrite) {
        try {
            process.stderr.write(chalk.gray('writing: ' + file + '\n'));
            if (overwrite) {
                fse.removeSync(file);
            }
            fse.outputFileSync(file, content, {
                encoding: 'utf8'
            });
            process.stderr.write(chalk.bold.gray('info: ') + chalk.bold.gray('file has been written\n'));
        } catch (e) {
            throw e;
        }
    }

    /**
     *
     *
     *
     */
    function createQuestion(file, index) {
        file = path.relative(defaults.cwd, file);
        return {
            default: false,
            type: 'confirm',
            name: 'overwrite_' + index,
            message: file + ' will be overwritten, continue ?'
        };
    }

    /**
     *
     *
     *
     */
    function parseItCases(cases) {
        var result = '',
            compiled = _('it(\'<%- description %>\', function(){});\n');
        cases.forEach(function (value) {
            result += compiled({
                description: value
            });
        });
        return result;
    }

    function parseStories(values) {
        var cases,
            result = '',
            compiled = _('describe(\'<%- label %>\', function(){<%= value %>});\n\n');
        Object.keys(values).forEach(function(label){
            cases = values[label];
            if(isarray(cases)){
                result += compiled({
                    label: label,
                    value: parseItCases(cases)
                });
            } else {
                result += compiled({
                    label: label,
                    value: parseStories(cases)
                });
            }
        });
        return result;
    }

    /**
     *
     * Parse le document yml
     * Pour créer les fichiers de tests
     *
     */
    function parseSpecs(spec) {
        var values, output_file, will_prompt, question, data,
            prompts = [],
            prompts_data = [],
            file_content = '',
            body_content = '',
            spec_files = Object.keys(spec),
            format_options = {
                indent: {
                    value: defaults.indent
                }
            },
            compiled = _('/*jshint unused: false */\n/*jslint indent: 4, nomen: true */\n/*global __dirname, jasmine, process, require, define, describe, xdescribe, it, xit, expect, beforeEach, afterEach, afterLast, console */\n(function(){\n\t\'use strict\';\n\tvar cwd = process.cwd(),\path = require(\'path\'),\nexpect = require(\'chai\'),\nnsinon = require(\'sinon\'),\n<%= name %> = require(path.join(cwd, \'<%= file %>\'));\n\ndescribe(\'<%- name %>\', function(){\n\n<%= body %>});\n\n}());\n');

        spec_files.forEach(function (spec_file) {

            // check si le chemin de fichier est valide
            if (!isvalidpath(spec_file)) {
                return false;
            }
            //
            // nom du fichier de sortie
            output_file = path.join(defaults.cwd, defaults.folder, path.normalize(spec_file));
            output_file = output_file.replace(defaults.extension, defaults.spec_extension);
            //
            // check si le fichier existe
            will_prompt = fileExists(output_file);
            //
            // recuperation des valeurs
            // des scenarios de test
            file_content = '';
            values = spec[spec_file];
            if (!values.length) {
                // is some DESCRIBE cases
                file_content += parseStories(values);
            } else {
                // is an IT case
                file_content += parseItCases(values);
            }
            //
            // templating du body
            body_content = esformatter.format(compiled({
                file: spec_file,
                body: file_content,
                name: path.basename(spec_file, path.extname(spec_file))
            }), format_options);
            //
            // si le fichier existe
            if (will_prompt && commander.yes) {
                writeSpecFile(output_file, body_content);
                //
            } else if (will_prompt && !commander.yes) {
                question = createQuestion(output_file, prompts.length);
                prompts_data.push({
                    file: output_file,
                    content: body_content
                });
                prompts.push(question);
            } else {
                writeSpecFile(output_file, body_content);
            }
        });
        // si il y a des question
        // on envoi le prompt pour l'user
        if (prompts.length) {
            inquirer.prompt(prompts, function (answers) {
                Object.keys(answers)
                    .forEach(function (key, index) {
                        if (answers[key]) {
                            data = prompts_data[index];
                            writeSpecFile(data.file, data.content);
                        }
                    });
            });
        } else {
            // sinon on arrete le process
            process.exit(0);
        }
    }

    /* -----------------------------------------------------------------------------
     *
     * parse les arguments du cli
     *
     ----------------------------------------------------------------------------- */
    if (!commander.args.length) {
        process.stderr.write(chalk.bold.red('Error: ') + chalk.bold('missing arguments\n'));
        process.exit(1);
        // error
    }

    // construction du chemin
    // vers le fichier de description
    defaults.folder = commander.args[0];
    description_file = path.join(defaults.cwd, defaults.folder, 'stories.yml');

    // si l'argment generate
    // n'a pas ete sette par l'user
    // on redirige la sortie vers la console
    if (!commander.generate) {
        return outputInConsole(description_file);
    }
    //
    // charge le fichier de description
    // depuis le folder en argument du cli
    try {
        yaml.safeLoadAll(fse.readFileSync(description_file, 'utf8'), parseSpecs);
    } catch (e) {
        // erreur lors du process
        process.stderr.write(chalk.bold.red('Error: ') + chalk.bold(e.message) + '\n');
        console.log(e.stack);
        process.exit(1);
    }

}());
<commit_msg>add before and after each<commit_after>/*jslint indent: 4, nomen: true, plusplus: true */
/*globals process, require, console */
(function () {

    'use strict';

    var // variables
        description_file, // fichier de description des scenarios
        defaults = {
            files: [], // nombre de documents a traiter
            indent: '    ',
            extension: '.js',
            input_folder: '',
            cwd: process.cwd(),
            spec_extension: '.spec.js'
        },
        // lodash
        _ = require('lodash.template'),
        isarray = require('lodash.isarray'),
        // requires
        path = require('path'),
        chalk = require('chalk'),
        fse = require('fs-extra'),
        yaml = require('js-yaml'),
        inquirer = require('inquirer'),
        commander = require('commander'),
        esformatter = require('esformatter'),
        isvalidpath = require('is-valid-path');

    //
    // traitement des params args du cli
    commander
        .version('0.1.1')
        .usage('[options] <spec_folder ...>')
        .option('-Y, --yes', 'Force files overwrite')
        .option('-g, --generate', 'Generate spec files')
        .parse(process.argv);

    /**
     *
     * Par defaut
     * Au lance du cli sans options
     * Affichage dans la console
     * du fichier YAML
     *
     */
    function outputInConsole(file) {
        try {
            process.stdout.write(chalk.bold.green('describing: ') + chalk.bold(file + '\n'));
            var rstream = fse.createReadStream(file, {
                encoding: 'utf8'
            });
            rstream
                .on('error', function (err) {
                    throw err;
                })
                .on('data', function (data) {
                    process.stdout.write(data);
                }).on('end', function () {
                    process.exit(0);
                });
        } catch (e) {
            throw e;
        }
    }

    /**
     *
     * Verifciation si le fichier
     * de spec existe dans le repertoire
     * de sortie
     *
     */
    function fileExists(file) {
        try {
            fse.statSync(file);
            return true;
        } catch (e) {
            return false;
        }
    }

    /**
     *
     * Creation d'un fichier de test
     *
     */
    function writeSpecFile(file, content, overwrite) {
        try {
            process.stderr.write(chalk.gray('writing: ' + file + '\n'));
            if (overwrite) {
                fse.removeSync(file);
            }
            fse.outputFileSync(file, content, {
                encoding: 'utf8'
            });
            process.stderr.write(chalk.bold.gray('info: ') + chalk.bold.gray('file has been written\n'));
        } catch (e) {
            throw e;
        }
    }

    /**
     *
     *
     *
     */
    function createQuestion(file, index) {
        file = path.relative(defaults.cwd, file);
        return {
            default: false,
            type: 'confirm',
            name: 'overwrite_' + index,
            message: file + ' will be overwritten, continue ?'
        };
    }

    /**
     *
     *
     *
     */
    function parseItCases(cases) {
        var result = '',
            compiled = _('it(\'<%- description %>\', function(){});\n');
        cases.forEach(function (value) {
            result += compiled({
                description: value
            });
        });
        return result;
    }

    function parseStories(values) {
        var cases,
            result = '',
            compiled = _('describe(\'<%- label %>\', function(){<%= value %>});\n\n');
        Object.keys(values).forEach(function(label){
            cases = values[label];
            if(isarray(cases)){
                result += compiled({
                    label: label,
                    value: parseItCases(cases)
                });
            } else {
                result += compiled({
                    label: label,
                    value: parseStories(cases)
                });
            }
        });
        return result;
    }

    /**
     *
     * Parse le document yml
     * Pour créer les fichiers de tests
     *
     */
    function parseSpecs(spec) {
        var values, output_file, will_prompt, question, data,
            prompts = [],
            prompts_data = [],
            file_content = '',
            body_content = '',
            spec_files = Object.keys(spec),
            format_options = {
                indent: {
                    value: defaults.indent
                }
            },
            compiled = _('/*jshint unused: false */\n/*jslint indent: 4, nomen: true */\n/*global __dirname, jasmine, process, require, define, describe, xdescribe, it, xit, expect, beforeEach, afterEach, afterLast, console */\n(function(){\n\t\'use strict\';\n\tvar cwd = process.cwd(),\path = require(\'path\'),\nexpect = require(\'chai\'),\nnsinon = require(\'sinon\'),\n<%= name %> = require(path.join(cwd, \'<%= file %>\'));\n\ndescribe(\'<%- name %>\', function(){\n\nbeforeEach(function(){});afterEach(function(){});<%= body %>});\n\n}());\n');

        spec_files.forEach(function (spec_file) {

            // check si le chemin de fichier est valide
            if (!isvalidpath(spec_file)) {
                return false;
            }
            //
            // nom du fichier de sortie
            output_file = path.join(defaults.cwd, defaults.folder, path.normalize(spec_file));
            output_file = output_file.replace(defaults.extension, defaults.spec_extension);
            //
            // check si le fichier existe
            will_prompt = fileExists(output_file);
            //
            // recuperation des valeurs
            // des scenarios de test
            file_content = '';
            values = spec[spec_file];
            if (!values.length) {
                // is some DESCRIBE cases
                file_content += parseStories(values);
            } else {
                // is an IT case
                file_content += parseItCases(values);
            }
            //
            // templating du body
            body_content = esformatter.format(compiled({
                file: spec_file,
                body: file_content,
                name: path.basename(spec_file, path.extname(spec_file))
            }), format_options);
            //
            // si le fichier existe
            if (will_prompt && commander.yes) {
                writeSpecFile(output_file, body_content);
                //
            } else if (will_prompt && !commander.yes) {
                question = createQuestion(output_file, prompts.length);
                prompts_data.push({
                    file: output_file,
                    content: body_content
                });
                prompts.push(question);
            } else {
                writeSpecFile(output_file, body_content);
            }
        });
        // si il y a des question
        // on envoi le prompt pour l'user
        if (prompts.length) {
            inquirer.prompt(prompts, function (answers) {
                Object.keys(answers)
                    .forEach(function (key, index) {
                        if (answers[key]) {
                            data = prompts_data[index];
                            writeSpecFile(data.file, data.content);
                        }
                    });
            });
        } else {
            // sinon on arrete le process
            process.exit(0);
        }
    }

    /* -----------------------------------------------------------------------------
     *
     * parse les arguments du cli
     *
     ----------------------------------------------------------------------------- */
    if (!commander.args.length) {
        process.stderr.write(chalk.bold.red('Error: ') + chalk.bold('missing arguments\n'));
        process.exit(1);
        // error
    }

    // construction du chemin
    // vers le fichier de description
    defaults.folder = commander.args[0];
    description_file = path.join(defaults.cwd, defaults.folder, 'stories.yml');

    // si l'argment generate
    // n'a pas ete sette par l'user
    // on redirige la sortie vers la console
    if (!commander.generate) {
        return outputInConsole(description_file);
    }
    //
    // charge le fichier de description
    // depuis le folder en argument du cli
    try {
        yaml.safeLoadAll(fse.readFileSync(description_file, 'utf8'), parseSpecs);
    } catch (e) {
        // erreur lors du process
        process.stderr.write(chalk.bold.red('Error: ') + chalk.bold(e.message) + '\n');
        console.log(e.stack);
        process.exit(1);
    }

}());
<|endoftext|>


<commit_before>#!/usr/bin/env node

import process from 'process';
import path from 'path';
import yargs from 'yargs';

import { downloadSchema, generate } from '.';
import { ToolError, logError } from './errors'

import 'source-map-support/register'

// Make sure unhandled errors in async code are propagated correctly
process.on('unhandledRejection', (error) => { throw error });

process.on('uncaughtException', handleError);

function handleError(error) {
  logError(error);
  process.exit(1);
}

yargs
  .command(
    'download-schema <server>',
    'Download a GraphQL schema from a server',
    {
      output: {
        demand: true,
        describe: 'Output path for GraphQL schema file',
        normalize: true
      },
      header: {
        alias: 'H',
        describe: 'Additional header to send to the server as part of the introspection query request',
        type: 'array',
        coerce: (arg) => {
          let additionalHeaders = {};
          for (const header of arg) {
            const [name, value] = header.split(/\s*:\s*/);
            if (!(name && value)) {
              throw new ToolError('Headers should be specified as "Name: Value"');
            }
            additionalHeaders[name] = value;
          }
          return additionalHeaders;
        }
      },
    },
    async argv => {
      const outputPath = path.resolve(argv.output);
      const additionalHeaders = argv.header;
      await downloadSchema(argv.server, outputPath, additionalHeaders);
    }
  )
  .command(
    'generate <input...>',
    'Generate code from a GraphQL schema and query documents',
    {
      schema: {
        demand: true,
        describe: 'Path to GraphQL schema file',
        normalize: true
      },
      output: {
        demand: true,
        describe: 'Output directory for the generated files',
        normalize: true
      },
      target: {
        demand: false,
        describe: 'Code generation target language',
      }
    },
    argv => {
      const inputPaths = argv.input.map(input => path.resolve(input));
      const schemaPath = path.resolve(argv.schema);
      const outputPath = path.resolve(argv.output);
      generate(inputPaths, schemaPath, outputPath, argv.target);
    },
  )
  .fail(function(message, error) {
    handleError(error ? error : new Error(message));
  })
  .help()
  .strict()
  .argv
<commit_msg>Don't print stack trace for CLI tool errors<commit_after>#!/usr/bin/env node

import process from 'process';
import path from 'path';
import yargs from 'yargs';

import { downloadSchema, generate } from '.';
import { ToolError, logError } from './errors'

import 'source-map-support/register'

// Make sure unhandled errors in async code are propagated correctly
process.on('unhandledRejection', (error) => { throw error });

process.on('uncaughtException', handleError);

function handleError(error) {
  logError(error);
  process.exit(1);
}

yargs
  .command(
    'download-schema <server>',
    'Download a GraphQL schema from a server',
    {
      output: {
        demand: true,
        describe: 'Output path for GraphQL schema file',
        normalize: true
      },
      header: {
        alias: 'H',
        describe: 'Additional header to send to the server as part of the introspection query request',
        type: 'array',
        coerce: (arg) => {
          let additionalHeaders = {};
          for (const header of arg) {
            const [name, value] = header.split(/\s*:\s*/);
            if (!(name && value)) {
              throw new ToolError('Headers should be specified as "Name: Value"');
            }
            additionalHeaders[name] = value;
          }
          return additionalHeaders;
        }
      },
    },
    async argv => {
      const outputPath = path.resolve(argv.output);
      const additionalHeaders = argv.header;
      await downloadSchema(argv.server, outputPath, additionalHeaders);
    }
  )
  .command(
    'generate <input...>',
    'Generate code from a GraphQL schema and query documents',
    {
      schema: {
        demand: true,
        describe: 'Path to GraphQL schema file',
        normalize: true
      },
      output: {
        demand: true,
        describe: 'Output directory for the generated files',
        normalize: true
      },
      target: {
        demand: false,
        describe: 'Code generation target language',
      }
    },
    argv => {
      const inputPaths = argv.input.map(input => path.resolve(input));
      const schemaPath = path.resolve(argv.schema);
      const outputPath = path.resolve(argv.output);
      generate(inputPaths, schemaPath, outputPath, argv.target);
    },
  )
  .fail(function(message, error) {
    handleError(error ? error : new ToolError(message));
  })
  .help()
  .strict()
  .argv
<|endoftext|>


<commit_before>#!/usr/bin/env node

const argv = require('yargs').argv
const colors = require('colors')
const fs = require('fs')
const glob = require('glob')
const jo = require('./main.js')
const manifest = require('../package.json')
const promisify = require('util').promisify

if (argv.version) {
  console.log(manifest.name + ' ' + manifest.version)
  process.exit(0)
}

if (argv.help || typeof argv._ === 'undefined' || argv._.length === 0) {
  const help = [
    '',
    'Rotate JPEG images based on EXIF orientation',
    '',
    colors.underline('Usage'),
    'jpeg-autorotate <path>',
    '',
    colors.underline('Options'),
    '--quality=<0-100>   JPEG output quality',
    '--version           Output current version',
    '--help              Output help',
    '',
  ]
  console.log(help.join('\n'))
  process.exit(0)
}

listFiles()
  .then(processFiles)
  .then(() => {
    process.exit(0)
  })
  .catch((error) => {
    console.log(error.message)
    process.exit(1)
  })

function listFiles() {
  return Promise.all(argv._.map((arg) => promisify(glob)(arg, {}))).then((files) => {
    return [].concat.apply([], files)
  })
}

function processFiles(files, index = 0) {
  if (index + 1 > files.length) {
    return Promise.resolve()
  }
  const filePath = files[index]
  return jo
    .rotate(filePath, {quality: argv.quality})
    .then(({buffer, orientation, quality, dimensions}) => {
      return promisify(fs.writeFile)(files[index], buffer).then(() => {
        return {orientation, quality, dimensions}
      })
    })
    .then(({orientation, quality, dimensions}) => {
      const message =
        'Processed (Orientation: ' +
        orientation +
        ') (Quality: ' +
        quality +
        '%) (Dimensions: ' +
        dimensions.width +
        'x' +
        dimensions.height +
        ')'
      console.log(filePath + ': ' + colors.green(message))
    })
    .catch((error) => {
      const isFatal = error.code !== jo.errors.correct_orientation
      console.log(filePath + ': ' + (isFatal ? colors.red(error.message) : colors.yellow(error.message)))
    })
}
<commit_msg>Fix #19<commit_after>#!/usr/bin/env node

const argv = require('yargs').argv
const colors = require('colors')
const fs = require('fs')
const glob = require('glob')
const jo = require('./main.js')
const manifest = require('../package.json')
const promisify = require('util').promisify

if (argv.version) {
  console.log(manifest.name + ' ' + manifest.version)
  process.exit(0)
}

if (argv.help || typeof argv._ === 'undefined' || argv._.length === 0) {
  const help = [
    '',
    'Rotate JPEG images based on EXIF orientation',
    '',
    colors.underline('Usage'),
    'jpeg-autorotate <path>',
    '',
    colors.underline('Options'),
    '--quality=<0-100>   JPEG output quality',
    '--version           Output current version',
    '--help              Output help',
    '',
  ]
  console.log(help.join('\n'))
  process.exit(0)
}

listFiles()
  .then(processFiles)
  .then(() => {
    process.exit(0)
  })
  .catch((error) => {
    console.log(error.message)
    process.exit(1)
  })

function listFiles() {
  return Promise.all(argv._.map((arg) => promisify(glob)(arg, {}))).then((files) => {
    return [].concat.apply([], files)
  })
}

function processFiles(files, index = 0) {
  if (index + 1 > files.length) {
    return Promise.resolve()
  }
  const filePath = files[index]
  return jo
    .rotate(filePath, {quality: argv.quality})
    .then(({buffer, orientation, quality, dimensions}) => {
      return promisify(fs.writeFile)(files[index], buffer).then(() => {
        return {orientation, quality, dimensions}
      })
    })
    .then(({orientation, quality, dimensions}) => {
      const message =
        'Processed (Orientation: ' +
        orientation +
        ') (Quality: ' +
        quality +
        '%) (Dimensions: ' +
        dimensions.width +
        'x' +
        dimensions.height +
        ')'
      console.log(filePath + ': ' + colors.green(message))
    })
    .catch((error) => {
      const isFatal = error.code !== jo.errors.correct_orientation
      console.log(filePath + ': ' + (isFatal ? colors.red(error.message) : colors.yellow(error.message)))
    })
    .then(() => processFiles(files, index + 1))
}
<|endoftext|>


<commit_before>var _ = require('./util');

var client = require('./client');

var args = process.argv;
var node = args.shift();
var script = args.shift();
var command = args.shift();

function cliErrorHandler(err) {
  console.log('ERROR');
  console.log(err);
}

function cliResponse(promise) {
  promise.then(function(a) {
    if(_.isUndefined(a)) return console.log('Done!');
    console.log.apply(this, arguments);
  }, cliErrorHandler, function(status) {
    console.log('STATUS: ', status);
  });
}

client.start().then(function() {

  switch (command) {
    case 'add':
      command = args.shift();
      if(!command) throw new Error('Must specify what to add');
      switch (command) {
        case 'app':
          var name = args.shift();
          var repoUrl = args.shift();
          var deployKey = args.shift();
          if (deployKey && _.fs.existsSync(deployKey))
            deployKey = _.fs.readFileSync(deployKey, {encoding: 'utf8'});
          return cliResponse(client.apps.add(name, repoUrl, deployKey));
        case 'server':
          var name = args.shift();
          var host = args.shift();
          var key = args.shift();
          var cert = args.shift();
          if(!key) key = './'+name+'.key';
          if(!cert) cert = './'+name+'.crt';
          key = _.fs.readFileSync(key, {encoding: 'utf8'});
          cert = _.fs.readFileSync(cert, {encoding: 'utf8'});
          return cliResponse(client.servers.add(name, host, key, cert));
        default:
          throw new Error('Cannot add "'+command+'" here');
      }
    case 'server':
    case 'servers':
      serverName = args.shift();
      if(!serverName) return cliResponse(client.servers.list());
      return client.servers.get(serverName).then(function(server) {
        // in the case of a "404", send them a list
        if(!server) return cliResponse(client.servers.list());
        else {
          command = args.shift();
          if(!command) console.log(server);
          switch (command) {
            case 'rename':
              var newName = args.shift();
              return cliResponse(client.servers.rename(serverName, newName));
            case 'remove':
              return cliResponse(client.servers.remove(serverName));
            case 'create':
              var type = args.shift();
              if(!type) throw new Error('Must specify what to add to this server');
              switch (type) {
                case 'build':
                  var appName = args.shift();
                  var refspec = args.shift();
                  return cliResponse(client.builds.create(serverName, appName, refspec));
                default:
                  throw new Error('Cannot add "'+type+'" to this server');
              }
            case 'builds':
            case 'build':
              var id = args.shift();
              if(!id) return cliResponse(client.builds.list(serverName));
              else return client.builds.get(serverName, id).then(function(build) {
                command = args.shift();
                if(!command) console.log(build);
                switch (command) {
                  case 'remove':
                    return cliResponse(client.builds.remove(serverName, id));
                  default:
                    throw new Error('Cannot run "'+command+'" command on a build');
                }
              }, cliErrorHandler);
            case 'instances':
            case 'instance':
              var instanceName = args.shift();
              if(!instanceName) return cliResponse(client.instances.list(serverName));
              command = args.shift();
              if (command == 'set') {
                var buildId = args.shift();
                var configFile = args.shift()
                if (!configFile) configFile = './' + instanceName + '.json';
                var config = _.fs.readFileSync(configFile, {encoding: 'utf8'});
                config = JSON.parse(config);
                return cliResponse(client.instances.set(serverName, instanceName, buildId, config));
              }
              client.instances.get(serverName, instanceName).then(function(instance) {
                if(!command) return console.log(instance);
                switch (command) {
                  case 'remove':
                    return cliResponse(client.instances.remove(serverName, instanceName));
                  case 'setConfig':
                    var configFile = args.shift()
                    if (!configFile) configFile = './' + instanceName + '.json';
                    var config = _.fs.readFileSync(configFile, {encoding: 'utf8'});
                    config = JSON.parse(config);
                    return cliResponse(client.instances.setConfig(serverName, instanceName, config));
                  case 'setBuild':
                    var buildId = args.shift()
                    return cliResponse(client.instances.setBuild(serverName, instanceName, buildId));
                  default:
                    throw new Error('Cannot run "'+command+'" command on an instance');
                }
              }, cliErrorHandler);
            default:
              throw new Error('Cannot run "'+command+'" on a server');
          }
        }
      }, cliErrorHandler);
    case 'app':
    case 'apps':
      appName = args.shift();
      if(!appName) return cliResponse(client.apps.list());
      return client.apps.get(appName).then(function(app) {
        // in the case of a "404", send them a list
        if(!app) return cliResponse(client.apps.list());
        else {
          command = args.shift();
          if(!command) console.log(app);
          switch (command) {
            case 'rename':
              var newName = args.shift();
              return cliResponse(client.apps.rename(appName, newName));
            case 'remove':
              return cliResponse(client.apps.remove(appName));
            default:
              throw new Error('Cannot run "'+command+'" on an app');
          }
        }
      }, cliErrorHandler);
  }

});<commit_msg>start formatting in CLI<commit_after>var _ = require('./util');

var client = require('./client');

var args = process.argv;
var node = args.shift();
var script = args.shift();
var command = args.shift();

function cliErrorHandler(err) {
  console.log('ERROR');
  console.log(err);
}

function cliResponse(promise) {
  promise.then(function(a) {
    if(_.isUndefined(a)) return console.log('Done!');
    console.log.apply(this, arguments);
  }, cliErrorHandler, function(status) {
    console.log('STATUS: ', status);
  });
}

function listServers() {
  client.servers.list().then(function(servers) {
    console.log('NAME \tHOST');
    console.log('=======\t=======');
    _.each(servers, function(server) {
      console.log(server.name+' \t'+server.host);
    });
  }, cliErrorHandler);
}

function printServer(server) {
  console.log('NAME \tHOST');
  console.log('=======\t=======');
  console.log(server.name+' \t'+server.host);
}

function listInstances(serverName) {
  client.instances.list(serverName).then(function(_instances) {
    console.log('NAME \tBUILD\tSTATUS');
    console.log('=======\t=======\t=======');
    _.each(_instances, function(i, b) {
      console.log(i.name+'\t'+i.build);
    });
  }, cliErrorHandler);
}

function printInstance(instance) {
  console.log('NAME \tBUILD ID\tSTATUS');
  console.log('=======\t=======\t=======');
  console.log(instance.name+' \t'+instance.build);
}

function listBuilds(serverName) {
   client.builds.list(serverName).then(function(builds) {
    console.log('ID\tSTATUS');
    console.log('=======\t=======\t=======');
    _.each(builds, function(b) {
      console.log(b.id+'\t'+b.status);
    });
  }, cliErrorHandler);
}

function printBuild(build) {
  console.log('ID\tSTATUS\tSTATUS');
  console.log('=======\t=======\t=======');
  console.log(build.id);
}
client.start().then(function() {

  switch (command) {
    case 'add':
      command = args.shift();
      if(!command) throw new Error('Must specify what to add');
      switch (command) {
        case 'app':
          var name = args.shift();
          var repoUrl = args.shift();
          var deployKey = args.shift();
          if (deployKey && _.fs.existsSync(deployKey))
            deployKey = _.fs.readFileSync(deployKey, {encoding: 'utf8'});
          return cliResponse(client.apps.add(name, repoUrl, deployKey));
        case 'server':
          var name = args.shift();
          var host = args.shift();
          var key = args.shift();
          var cert = args.shift();
          if(!key) key = './'+name+'.key';
          if(!cert) cert = './'+name+'.crt';
          key = _.fs.readFileSync(key, {encoding: 'utf8'});
          cert = _.fs.readFileSync(cert, {encoding: 'utf8'});
          return cliResponse(client.servers.add(name, host, key, cert));
        default:
          throw new Error('Cannot add "'+command+'" here');
      }
    case 'server':
    case 'servers':
      serverName = args.shift();
      if(!serverName) return listServers();
      return client.servers.get(serverName).then(function(server) {
        // in the case of a "404", send them a list
        if(!server) return listServers();
        else {
          command = args.shift();
          if(!command) return printServer(server);
          switch (command) {
            case 'rename':
              var newName = args.shift();
              return cliResponse(client.servers.rename(serverName, newName));
            case 'remove':
              return cliResponse(client.servers.remove(serverName));
            case 'create':
              var type = args.shift();
              if(!type) throw new Error('Must specify what to add to this server');
              switch (type) {
                case 'build':
                  var appName = args.shift();
                  var refspec = args.shift();
                  return cliResponse(client.builds.create(serverName, appName, refspec));
                default:
                  throw new Error('Cannot add "'+type+'" to this server');
              }
            case 'builds':
            case 'build':
              var id = args.shift();
              if(!id) return listBuilds(serverName);
              else return client.builds.get(serverName, id).then(function(build) {
                command = args.shift();
                if(!command) return printBuild(build);
                switch (command) {
                  case 'remove':
                    return cliResponse(client.builds.remove(serverName, id));
                  default:
                    throw new Error('Cannot run "'+command+'" command on a build');
                }
              }, cliErrorHandler);
            case 'instances':
            case 'instance':
              var instanceName = args.shift();
              if(!instanceName) return listInstances(serverName);
              command = args.shift();
              if (command == 'set') {
                var buildId = args.shift();
                var configFile = args.shift()
                if (!configFile) configFile = './' + instanceName + '.json';
                var config = _.fs.readFileSync(configFile, {encoding: 'utf8'});
                config = JSON.parse(config);
                return cliResponse(client.instances.set(serverName, instanceName, buildId, config));
              }
              client.instances.get(serverName, instanceName).then(function(instance) {
                if(!command) return printInstance(instance);
                switch (command) {
                  case 'remove':
                    return cliResponse(client.instances.remove(serverName, instanceName));
                  case 'setConfig':
                    var configFile = args.shift()
                    if (!configFile) configFile = './' + instanceName + '.json';
                    var config = _.fs.readFileSync(configFile, {encoding: 'utf8'});
                    config = JSON.parse(config);
                    return cliResponse(client.instances.setConfig(serverName, instanceName, config));
                  case 'setBuild':
                    var buildId = args.shift()
                    return cliResponse(client.instances.setBuild(serverName, instanceName, buildId));
                  default:
                    throw new Error('Cannot run "'+command+'" command on an instance');
                }
              }, cliErrorHandler);
            default:
              throw new Error('Cannot run "'+command+'" on a server');
          }
        }
      }, cliErrorHandler);
    case 'app':
    case 'apps':
      appName = args.shift();
      if(!appName) return cliResponse(client.apps.list());
      return client.apps.get(appName).then(function(app) {
        // in the case of a "404", send them a list
        if(!app) return cliResponse(client.apps.list());
        else {
          command = args.shift();
          if(!command) console.log(app);
          switch (command) {
            case 'rename':
              var newName = args.shift();
              return cliResponse(client.apps.rename(appName, newName));
            case 'remove':
              return cliResponse(client.apps.remove(appName));
            default:
              throw new Error('Cannot run "'+command+'" on an app');
          }
        }
      }, cliErrorHandler);
  }

});<|endoftext|>


<commit_before>#!/usr/bin/env node

(function(process)
{

    'use strict';

    var url = require('url');
    var exec = require('child_process').exec;
    var colors = require('colors');
    var argv = require('yargs').argv;
    var os = require('os');

    var Crawler = require('./crawler.js');
    var PSI = require('./psi.js');
    var Report = require('./report.js');

    if (typeof argv._[0] === 'undefined')
    {
        console.log(colors.red('Please provide a valid base URL'));
        process.exit();
    }

    var baseurl = url.parse(argv._[0].search(/https?:\/\//) !== -1 ? argv._[0] : 'http://' + argv._[0]);

    var crawler = new Crawler(baseurl);
    crawler.crawl(_onCrawled);

    function _onCrawled(urls)
    {
        var psi = new PSI(baseurl, urls);
        psi.crawl(_onGetPSIResults);
    }

    function _onGetPSIResults(results)
    {
        var report = new Report(results);
        report.build(_onBuiltReport);
    }

    function _onBuiltReport(path)
    {
        console.log(colors.green('Report built.') + ' (' + path + ')');
        if (os.platform() === 'darwin')
        {
            exec('open ' + path);
        }
    }

})(process);
<commit_msg>Adds version output<commit_after>#!/usr/bin/env node

(function(process)
{

    'use strict';

    var url = require('url');
    var exec = require('child_process').exec;
    var colors = require('colors');
    var argv = require('yargs').argv;
    var os = require('os');

    var Crawler = require('./crawler.js');
    var PSI = require('./psi.js');
    var Report = require('./report.js');

    var manifest = require('../package.json');

    if (argv.version)
    {
        console.log('psi-report ' + manifest.version);
        process.exit();
    }

    if (typeof argv._[0] === 'undefined')
    {
        console.log(colors.red('Please provide a valid base URL'));
        process.exit();
    }

    var baseurl = url.parse(argv._[0].search(/https?:\/\//) !== -1 ? argv._[0] : 'http://' + argv._[0]);

    var crawler = new Crawler(baseurl);
    crawler.crawl(_onCrawled);

    function _onCrawled(urls)
    {
        var psi = new PSI(baseurl, urls);
        psi.crawl(_onGetPSIResults);
    }

    function _onGetPSIResults(results)
    {
        var report = new Report(results);
        report.build(_onBuiltReport);
    }

    function _onBuiltReport(path)
    {
        console.log(colors.green('Report built.') + ' (' + path + ')');
        if (os.platform() === 'darwin')
        {
            exec('open ' + path);
        }
    }

})(process);
<|endoftext|>