<commit_before>/**
 *  Copyright (c) 2010 Marat Nepomnyashy    maratbn@gmail
 *  All rights reserved.
 *
 *  Module:         h5ile.js
 *
 *  Description:    JavaScript utility / helper library for HTML 5 File API
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *      * Redistributions of source code must retain the above copyright
 *        notice, this list of conditions and the following disclaimer.
 *      * Redistributions in binary form must reproduce the above copyright
 *        notice, this list of conditions and the following disclaimer in the
 *        documentation and/or other materials provided with the distribution.
 *      * Neither the name of the <organization> nor the
 *        names of its contributors may be used to endorse or promote products
 *        derived from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 *  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 */

window.h5ile = {
    /**
     *  Creates a visible HTML form field file input tag, prepares it to load
     *  files, and appends it as a child to the DOM element with the DOM id
     *  specified.
     *
     *  @param  idParentElement         DOM id of the parent element
     *
     *  @param  params                  JSON structure with file processing
     *                                  parameters.
     *
     *          params.loadtext         Sub-field for text loading settings.
     *
     *          params.loadtext.onloadend
     *                                  Callback function for when a file has
     *                                  been loaded as regular text.
     *                                  1st parameter:  'File' object read.
     *                                  2nd parameter:  'FileReader' object.
     *
     *  @returns the created tag.
     */
    createVisibleFileInput: function(idParentElement, params) {
        var elParent = document.getElementById(idParentElement);
        if (!elParent) throw new Error("h5ile: Invalid parent element");

        // Based on:
        // https://developer.mozilla.org/en/using_files_from_web_applications

        var elInput = document.createElement('input');
        elInput.setAttribute('type', 'file');

        var _processChange = function() {
                if (!this.files) {
                    throw new Error("h5ile:  Expected 'FileList' object, but"
                                    + " did not get any");
                }

                for (var i = 0; i < this.files.length; i++) {
                    var file = this.files[i];
                    if (!file) continue;

                    if (params &&
                        params.loadtext &&
                        params.loadtext.onloadend) {

                        var reader = new FileReader();

                        reader.onabort = function() {
                                alert("h5ile:  Aborted text loading of file '" + file.name + "'.");
                            }
                        reader.onloadend = function() {
                                params.loadtext.onloadend(file, reader);
                            }
                        reader.readAsText(file);
                    }
                }
            }

        if (elInput.addEventListener) {
            elInput.addEventListener('change', _processChange, false);
        } else if (elInput.attachEvent) {
            elInput.attachEvent('change', _processChange);
        } else {
            throw new Error("h5ile:  Expected either 'addEventListener' or 'attachEvent'.");
        }

        elParent.appendChild(elInput);

        return elInput;
    },

    /**
     *  @returns  Boolean true if the platform supports HTML 5 File API.
     */
    isFileAPISupported: function() {
        return window.File && window.FileReader ? true : false;
    }
}<commit_msg>Split out method 'prepareFileInput(...)' out of 'createVisibleFileInput(...)'.<commit_after>/**
 *  Copyright (c) 2010 Marat Nepomnyashy    maratbn@gmail
 *  All rights reserved.
 *
 *  Module:         h5ile.js
 *
 *  Description:    JavaScript utility / helper library for HTML 5 File API
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *      * Redistributions of source code must retain the above copyright
 *        notice, this list of conditions and the following disclaimer.
 *      * Redistributions in binary form must reproduce the above copyright
 *        notice, this list of conditions and the following disclaimer in the
 *        documentation and/or other materials provided with the distribution.
 *      * Neither the name of the <organization> nor the
 *        names of its contributors may be used to endorse or promote products
 *        derived from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 *  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 */

window.h5ile = {
    /**
     *  Creates a visible HTML form field file input tag, prepares it to load
     *  files, and appends it as a child to the DOM element with the DOM id
     *  specified.
     *
     *  @param  idParentElement         DOM id of the parent element
     *
     *  @param  params                  JSON structure with file processing
     *                                  parameters.
     *
     *          params.loadtext         Sub-field for text loading settings.
     *
     *          params.loadtext.onloadend
     *                                  Callback function for when a file has
     *                                  been loaded as regular text.
     *                                  1st parameter:  'File' object read.
     *                                  2nd parameter:  'FileReader' object.
     *
     *  @returns the created tag.
     */
    createVisibleFileInput: function(idParentElement, params) {
        var elParent = document.getElementById(idParentElement);
        if (!elParent) throw new Error("h5ile: Invalid parent element");

        var elInput = document.createElement('input');
        elInput.setAttribute('type', 'file');

        this.prepareFileInput(elInput, params);

        elParent.appendChild(elInput);

        return elInput;
    },

    /**
     *  @returns  Boolean true if the platform supports HTML 5 File API.
     */
    isFileAPISupported: function() {
        return window.File && window.FileReader ? true : false;
    },

    /**
     *  Prepares the HTML form field file input tag element specified to load
     *  files.
     *
     *  @param  elInput                 Reference to the form field file input
     *                                  tag element to prepare.
     *
     *  @param  params                  JSON structure with file processing
     *                                  parameters.
     *
     *          params.loadtext         Sub-field for text loading settings.
     *
     *          params.loadtext.onloadend
     *                                  Callback function for when a file has
     *                                  been loaded as regular text.
     *                                  1st parameter:  'File' object read.
     *                                  2nd parameter:  'FileReader' object.
     *
     */
    prepareFileInput: function(elInput, params) {

        // Based on:
        // https://developer.mozilla.org/en/using_files_from_web_applications

        var _processChange = function() {
                if (!this.files) {
                    throw new Error("h5ile:  Expected 'FileList' object, but"
                                    + " did not get any");
                }

                for (var i = 0; i < this.files.length; i++) {
                    var file = this.files[i];
                    if (!file) continue;

                    if (params &&
                        params.loadtext &&
                        params.loadtext.onloadend) {

                        var reader = new FileReader();

                        reader.onabort = function() {
                                alert("h5ile:  Aborted text loading of file '" + file.name + "'.");
                            }
                        reader.onloadend = function() {
                                params.loadtext.onloadend(file, reader);
                            }
                        reader.readAsText(file);
                    }
                }
            }

        if (elInput.addEventListener) {
            elInput.addEventListener('change', _processChange, false);
        } else if (elInput.attachEvent) {
            elInput.attachEvent('change', _processChange);
        } else {
            throw new Error("h5ile:  Expected either 'addEventListener' or 'attachEvent'.");
        }
    }
}<|endoftext|>


<commit_before>var fs = require("fs"),
    path = require("path"),
    tape = require("tape"),
    queue = require("d3-queue"),
    d3 = require("../");

tape("formatLocale({decimal: decimal}) observes the specified decimal point", function(test) {
  test.equal(d3.formatLocale({decimal: "|"}).format("06.2f")(2), "002|00");
  test.equal(d3.formatLocale({decimal: "/"}).format("06.2f")(2), "002/00");
  test.end();
});

tape("formatLocale({currency: [prefix, suffix]}) observes the specified currency prefix and suffix", function(test) {
  test.equal(d3.formatLocale({decimal: ".", currency: ["฿", ""]}).format("$06.2f")(2), "฿02.00");
  test.equal(d3.formatLocale({decimal: ".", currency: ["", "฿"]}).format("$06.2f")(2), "02.00฿");
  test.end();
});

tape("formatLocale({grouping: null}) does not perform any grouping", function(test) {
  test.equal(d3.formatLocale({decimal: ".", grouping: null}).format("012,.2f")(2), "000000002.00");
  test.end();
});

tape("formatLocale({grouping: [sizes…]}) observes the specified group sizes", function(test) {
  test.equal(d3.formatLocale({decimal: ".", grouping: [3], thousands: ","}).format("012,.2f")(2), "0,000,002.00");
  test.equal(d3.formatLocale({decimal: ".", grouping: [2], thousands: ","}).format("012,.2f")(2), "0,00,00,02.00");
  test.equal(d3.formatLocale({decimal: ".", grouping: [2, 3], thousands: ","}).format("012,.2f")(2), "00,000,02.00");
  test.equal(d3.formatLocale({decimal: ".", grouping: [3, 2, 2, 2, 2, 2, 2], thousands: ","}).format(",d")(1e12), "10,00,00,00,00,000");
  test.end();
});

tape("formatLocale({thousands: separator}) observes the specified group separator", function(test) {
  test.equal(d3.formatLocale({decimal: ".", grouping: [3], thousands: " "}).format("012,.2f")(2), "0 000 002.00");
  test.equal(d3.formatLocale({decimal: ".", grouping: [3], thousands: "/"}).format("012,.2f")(2), "0/000/002.00");
  test.end();
});

tape("locale data is valid", function(test) {
  fs.readdir("locale", function(error, locales) {
    if (error) throw error;
    var q = queue.queue(1);
    locales.forEach(function(locale) {
      if (!/\.json$/i.test(locale)) return;
      q.defer(testLocale, path.join("locale", locale));
    });
    q.awaitAll(function(error) {
      if (error) throw error;
      test.end();
    });
  });

  function testLocale(locale, callback) {
    fs.readFile(locale, "utf8", function(error, locale) {
      if (error) return void callback(error);
      locale = JSON.parse(locale);
      test.deepEqual(Object.keys(locale).sort(), ["currency", "decimal", "grouping", "thousands"]);
      locale = d3.formatLocale(locale);
      callback(null);
    });
  }
});
<commit_msg>Add @curran’s tests.<commit_after>var fs = require("fs"),
    path = require("path"),
    tape = require("tape"),
    queue = require("d3-queue"),
    d3 = require("../");

tape("formatLocale({decimal: decimal}) observes the specified decimal point", function(test) {
  test.equal(d3.formatLocale({decimal: "|"}).format("06.2f")(2), "002|00");
  test.equal(d3.formatLocale({decimal: "/"}).format("06.2f")(2), "002/00");
  test.end();
});

tape("formatLocale({currency: [prefix, suffix]}) observes the specified currency prefix and suffix", function(test) {
  test.equal(d3.formatLocale({decimal: ".", currency: ["฿", ""]}).format("$06.2f")(2), "฿02.00");
  test.equal(d3.formatLocale({decimal: ".", currency: ["", "฿"]}).format("$06.2f")(2), "02.00฿");
  test.end();
});

tape("formatLocale({grouping: null}) does not perform any grouping", function(test) {
  test.equal(d3.formatLocale({decimal: ".", grouping: null}).format("012,.2f")(2), "000000002.00");
  test.end();
});

tape("formatLocale({grouping: [sizes…]}) observes the specified group sizes", function(test) {
  test.equal(d3.formatLocale({decimal: ".", grouping: [3], thousands: ","}).format("012,.2f")(2), "0,000,002.00");
  test.equal(d3.formatLocale({decimal: ".", grouping: [2], thousands: ","}).format("012,.2f")(2), "0,00,00,02.00");
  test.equal(d3.formatLocale({decimal: ".", grouping: [2, 3], thousands: ","}).format("012,.2f")(2), "00,000,02.00");
  test.equal(d3.formatLocale({decimal: ".", grouping: [3, 2, 2, 2, 2, 2, 2], thousands: ","}).format(",d")(1e12), "10,00,00,00,00,000");
  test.end();
});

tape("formatLocale(…) can format numbers using the Indian numbering system.", function(test) {
  var format = d3.formatLocale(require("../locale/en-IN")).format(",");
  test.equal(format(10), "10");
  test.equal(format(100), "100");
  test.equal(format(1000), "1,000");
  test.equal(format(10000), "10,000");
  test.equal(format(100000), "1,00,000");
  test.equal(format(1000000), "10,00,000");
  test.equal(format(10000000), "1,00,00,000");
  test.equal(format(10000000.4543), "1,00,00,000.4543");
  test.equal(format(1000.321), "1,000.321");
  test.equal(format(10.5), "10.5");
  test.equal(format(-10), "-10");
  test.equal(format(-100), "-100");
  test.equal(format(-1000), "-1,000");
  test.equal(format(-10000), "-10,000");
  test.equal(format(-100000), "-1,00,000");
  test.equal(format(-1000000), "-10,00,000");
  test.equal(format(-10000000), "-1,00,00,000");
  test.equal(format(-10000000.4543), "-1,00,00,000.4543");
  test.equal(format(-1000.321), "-1,000.321");
  test.equal(format(-10.5), "-10.5");
  test.end();
});

tape("formatLocale({thousands: separator}) observes the specified group separator", function(test) {
  test.equal(d3.formatLocale({decimal: ".", grouping: [3], thousands: " "}).format("012,.2f")(2), "0 000 002.00");
  test.equal(d3.formatLocale({decimal: ".", grouping: [3], thousands: "/"}).format("012,.2f")(2), "0/000/002.00");
  test.end();
});

tape("locale data is valid", function(test) {
  fs.readdir("locale", function(error, locales) {
    if (error) throw error;
    var q = queue.queue(1);
    locales.forEach(function(locale) {
      if (!/\.json$/i.test(locale)) return;
      q.defer(testLocale, path.join("locale", locale));
    });
    q.awaitAll(function(error) {
      if (error) throw error;
      test.end();
    });
  });

  function testLocale(locale, callback) {
    fs.readFile(locale, "utf8", function(error, locale) {
      if (error) return void callback(error);
      locale = JSON.parse(locale);
      test.deepEqual(Object.keys(locale).sort(), ["currency", "decimal", "grouping", "thousands"]);
      locale = d3.formatLocale(locale);
      callback(null);
    });
  }
});
<|endoftext|>


<commit_before>import cloneDeep from 'lodash/cloneDeep';
import React from 'react';
import { FormattedMessage } from 'react-intl';
import PropTypes from 'prop-types';
import {
  Paneset,
  Pane,
  PaneMenu,
  IconButton,
  Button,
  ExpandAllButton,
  expandAllFunction,
  Row,
  Col,
  Headline,
  AccordionSet
} from '@folio/stripes/components';
import stripesForm from '@folio/stripes/form';

import {
  EditUserInfo,
  EditExtendedInfo,
  EditContactInfo,
  EditProxy,
  EditUserPerms,
  EditServicePoints,
} from './components/EditSections';

import { HasCommand } from './components/Commander';

import { getFullName } from './util';

import css from './UserForm.css';

function validate(values, props) {
  const errors = {};
  errors.personal = {};

  if (!values.personal || !values.personal.lastName) {
    errors.personal.lastName = <FormattedMessage id="ui-users.errors.missingRequiredField" />;
  }

  if (!values.username && values.creds && values.creds.password) {
    errors.username = <FormattedMessage id="ui-users.errors.missingRequiredUsername" />;
  }

  if (!props.initialValues.id && (!values.creds || !values.creds.password) && values.username) {
    errors.creds = { password: <FormattedMessage id="ui-users.errors.missingRequiredPassword" /> };
  }

  if (!values.patronGroup) {
    errors.patronGroup = <FormattedMessage id="ui-users.errors.missingRequiredPatronGroup" />;
  }

  if (!values.personal || !values.personal.preferredContactTypeId) {
    if (errors.personal) errors.personal.preferredContactTypeId = <FormattedMessage id="ui-users.errors.missingRequiredContactType" />;
    else errors.personal = { preferredContactTypeId: <FormattedMessage id="ui-users.errors.missingRequiredContactType" /> };
  }

  if (values.personal && values.personal.addresses) {
    errors.personal.addresses = [];
    values.personal.addresses.forEach((addr) => {
      const err = (!addr.addressType) ? { addressType: <FormattedMessage id="ui-users.errors.missingRequiredAddressType" /> } : {};
      errors.personal.addresses.push(err);
    });
  }

  if (values.servicePoints && values.preferredServicePoint === undefined) {
    errors.preferredServicePoint = <FormattedMessage id="ui-users.errors.missingRequiredPreferredServicePoint" />;
  }

  return errors;
}

function asyncValidate(values, dispatch, props, blurredField) {
  if (blurredField === 'username' && values.username !== props.initialValues.username) {
    return new Promise((resolve, reject) => {
      const uv = props.parentMutator.uniquenessValidator;
      const query = `(username=="${values.username}")`;
      uv.reset();
      return uv.GET({ params: { query } }).then((users) => {
        if (users.length > 0) {
          const error = { username: <FormattedMessage id="ui-users.errors.usernameUnavailable" /> };
          reject(error);
        } else {
          resolve();
        }
      });
    });
  }
  return new Promise(resolve => resolve());
}

class UserForm extends React.Component {
  static propTypes = {
    stripes: PropTypes.shape({
      connect: PropTypes.func,
      intl: PropTypes.object.isRequired,
    }).isRequired,
    handleSubmit: PropTypes.func.isRequired,
    parentMutator: PropTypes.shape({ // eslint-disable-line react/no-unused-prop-types
      uniquenessValidator: PropTypes.shape({
        reset: PropTypes.func.isRequired,
        GET: PropTypes.func.isRequired,
      }).isRequired,
    }),
    parentResources: PropTypes.object,
    pristine: PropTypes.bool,
    submitting: PropTypes.bool,
    onCancel: PropTypes.func,
    initialValues: PropTypes.object,
  };

  constructor(props) {
    super();

    this.state = {
      sections: {
        editUserInfo: true,
        extendedInfo: true,
        contactInfo: true,
        proxy: false,
        permissions: false,
        servicePoints: false,
      },
    };

    this.handleExpandAll = this.handleExpandAll.bind(this);
    this.handleSectionToggle = this.handleSectionToggle.bind(this);
    this.toggleAllSections = this.toggleAllSections.bind(this);
    this.collapseAllSections = this.collapseAllSections.bind(this);
    this.expandAllSections = this.expandAllSections.bind(this);

    this.ignoreEnterKey = this.ignoreEnterKey.bind(this);
    this.executeSave = this.executeSave.bind(this);
    this.closeButton = React.createRef();

    this.keyboardCommands = [
      {
        name: 'save',
        handler: this.handleSaveKeyCommand
      },
      {
        name: 'ignoreEnter',
        handler: this.ignoreEnterKey,
        shortcut: 'enter'
      },
      {
        name: 'cancel',
        handler: props.onCancel,
        shortcut: 'esc'
      },
      {
        name: 'expandAllSections',
        handler: this.expandAllSections,
        shortcut: 'mod+['
      },
      {
        name: 'collapseAllSections',
        handler: this.collapseAllSections,
        shortcut: 'mod+]'
      }
    ];

    if (props.initialValues.id) {
      this.connectedEditUserPerms = props.stripes.connect(EditUserPerms);
    }
  }

  componentDidMount() {
    // focus first interactive thing so that shortcuts will work immediately.
    this.closeButton.current.focus();
  }

  getAddFirstMenu() {
    const { onCancel } = this.props;

    return (
      <PaneMenu>
        <IconButton
          id="clickable-closenewuserdialog"
          onClick={onCancel}
          ref={this.closeButton}
          title={this.props.stripes.intl.formatMessage({ id: 'ui-users.crud.closeNewUserDialog' })}
          ariaLabel={this.props.stripes.intl.formatMessage({ id: 'ui-users.crud.closeNewUserDialog' })}
          icon="closeX"
        />
      </PaneMenu>
    );
  }

  getLastMenu(id, label) {
    const { pristine } = this.props;

    return (
      <PaneMenu>
        <Button
          id={id}
          type="submit"
          title={label}
          disabled={pristine || this.state.submitting}
          buttonStyle="primary paneHeaderNewButton"
          marginBottom0
        >
          {label}
        </Button>
      </PaneMenu>
    );
  }

  handleExpandAll(sections) {
    this.setState({ sections });
  }

  // eslint-disable-next-line class-methods-use-this
  ignoreEnterKey = (e) => {
    e.preventDefault();
  }

  handleSectionToggle({ id }) {
    this.setState((curState) => {
      const newState = cloneDeep(curState);
      newState.sections[id] = !newState.sections[id];
      return newState;
    });
  }

  toggleAllSections(expand) {
    this.setState((curState) => {
      const newSections = expandAllFunction(curState.sections, expand);
      return {
        sections: newSections
      };
    });
  }

  expandAllSections(e) {
    e.preventDefault();
    this.toggleAllSections(true);
  }

  collapseAllSections(e) {
    e.preventDefault();
    this.toggleAllSections(false);
  }

  handleSaveKeyCommand = (e) => {
    e.preventDefault();
    this.executeSave();
  }

  executeSave() {
    const { handleSubmit, onSubmit } = this.props;
    const submitter = handleSubmit(onSubmit);
    submitter();
  }

  render() {
    const { initialValues, stripes: { intl } } = this.props;
    const { sections } = this.state;
    const firstMenu = this.getAddFirstMenu();
    const paneTitle = initialValues.id ? getFullName(initialValues) : intl.formatMessage({ id: 'ui-users.crud.createUser' });
    const lastMenu = initialValues.id ?
      this.getLastMenu('clickable-updateuser', intl.formatMessage({ id: 'ui-users.crud.updateUser' })) :
      this.getLastMenu('clickable-createnewuser', intl.formatMessage({ id: 'ui-users.crud.createUser' }));

    return (
      <HasCommand commands={this.keyboardCommands}>
        <form className={css.UserFormRoot} id="form-user" onSubmit={this.executeSave}>
          <Paneset isRoot>
            <Pane defaultWidth="100%" firstMenu={firstMenu} lastMenu={lastMenu} paneTitle={paneTitle} appIcon={{ app: 'users' }}>

                <Headline size="xx-large" tag="h2">{getFullName(initialValues)}</Headline>
                <Row end="xs">
                  <Col xs>
                    <ExpandAllButton accordionStatus={sections} onToggle={this.handleExpandAll} />
                  </Col>
                </Row>
                <AccordionSet>
                  <EditUserInfo
                    accordionId="editUserInfo"
                    expanded={sections.editUserInfo}
                    onToggle={this.handleSectionToggle}
                    {...this.props}
                  />
                  <EditExtendedInfo
                    accordionId="extendedInfo"
                    expanded={sections.extendedInfo}
                    onToggle={this.handleSectionToggle}
                    userId={initialValues.id}
                    userFirstName={initialValues.personal.firstName}
                    userEmail={initialValues.personal.email}
                  />
                  <EditContactInfo
                    accordionId="contactInfo"
                    expanded={sections.contactInfo}
                    onToggle={this.handleSectionToggle}
                    {...this.props}
                  />
                  {initialValues.id &&

                      <EditProxy
                        accordionId="proxy"
                        expanded={sections.proxy}
                        onToggle={this.handleSectionToggle}
                        {...this.props}
                      />
                      <this.connectedEditUserPerms
                        accordionId="permissions"
                        expanded={sections.permissions}
                        onToggle={this.handleSectionToggle}
                        {...this.props}
                      />
                      <EditServicePoints
                        accordionId="servicePoints"
                        expanded={sections.servicePoints}
                        onToggle={this.handleSectionToggle}
                        {...this.props}
                      />

                  }
                </AccordionSet>

            </Pane>
          </Paneset>
        </form>
      </HasCommand>
    );
  }
}

export default stripesForm({
  form: 'userForm',
  validate,
  asyncValidate,
  asyncBlurFields: ['username'],
  navigationCheck: true,
  enableReinitialize: true,
})(UserForm);
<commit_msg>put back save button state<commit_after>import cloneDeep from 'lodash/cloneDeep';
import React from 'react';
import { FormattedMessage } from 'react-intl';
import PropTypes from 'prop-types';
import {
  Paneset,
  Pane,
  PaneMenu,
  IconButton,
  Button,
  ExpandAllButton,
  expandAllFunction,
  Row,
  Col,
  Headline,
  AccordionSet
} from '@folio/stripes/components';
import stripesForm from '@folio/stripes/form';

import {
  EditUserInfo,
  EditExtendedInfo,
  EditContactInfo,
  EditProxy,
  EditUserPerms,
  EditServicePoints,
} from './components/EditSections';

import { HasCommand } from './components/Commander';

import { getFullName } from './util';

import css from './UserForm.css';

function validate(values, props) {
  const errors = {};
  errors.personal = {};

  if (!values.personal || !values.personal.lastName) {
    errors.personal.lastName = <FormattedMessage id="ui-users.errors.missingRequiredField" />;
  }

  if (!values.username && values.creds && values.creds.password) {
    errors.username = <FormattedMessage id="ui-users.errors.missingRequiredUsername" />;
  }

  if (!props.initialValues.id && (!values.creds || !values.creds.password) && values.username) {
    errors.creds = { password: <FormattedMessage id="ui-users.errors.missingRequiredPassword" /> };
  }

  if (!values.patronGroup) {
    errors.patronGroup = <FormattedMessage id="ui-users.errors.missingRequiredPatronGroup" />;
  }

  if (!values.personal || !values.personal.preferredContactTypeId) {
    if (errors.personal) errors.personal.preferredContactTypeId = <FormattedMessage id="ui-users.errors.missingRequiredContactType" />;
    else errors.personal = { preferredContactTypeId: <FormattedMessage id="ui-users.errors.missingRequiredContactType" /> };
  }

  if (values.personal && values.personal.addresses) {
    errors.personal.addresses = [];
    values.personal.addresses.forEach((addr) => {
      const err = (!addr.addressType) ? { addressType: <FormattedMessage id="ui-users.errors.missingRequiredAddressType" /> } : {};
      errors.personal.addresses.push(err);
    });
  }

  if (values.servicePoints && values.preferredServicePoint === undefined) {
    errors.preferredServicePoint = <FormattedMessage id="ui-users.errors.missingRequiredPreferredServicePoint" />;
  }

  return errors;
}

function asyncValidate(values, dispatch, props, blurredField) {
  if (blurredField === 'username' && values.username !== props.initialValues.username) {
    return new Promise((resolve, reject) => {
      const uv = props.parentMutator.uniquenessValidator;
      const query = `(username=="${values.username}")`;
      uv.reset();
      return uv.GET({ params: { query } }).then((users) => {
        if (users.length > 0) {
          const error = { username: <FormattedMessage id="ui-users.errors.usernameUnavailable" /> };
          reject(error);
        } else {
          resolve();
        }
      });
    });
  }
  return new Promise(resolve => resolve());
}

class UserForm extends React.Component {
  static propTypes = {
    stripes: PropTypes.shape({
      connect: PropTypes.func,
      intl: PropTypes.object.isRequired,
    }).isRequired,
    handleSubmit: PropTypes.func.isRequired,
    parentMutator: PropTypes.shape({ // eslint-disable-line react/no-unused-prop-types
      uniquenessValidator: PropTypes.shape({
        reset: PropTypes.func.isRequired,
        GET: PropTypes.func.isRequired,
      }).isRequired,
    }),
    parentResources: PropTypes.object,
    pristine: PropTypes.bool,
    submitting: PropTypes.bool,
    onCancel: PropTypes.func,
    initialValues: PropTypes.object,
  };

  constructor(props) {
    super();

    this.state = {
      sections: {
        editUserInfo: true,
        extendedInfo: true,
        contactInfo: true,
        proxy: false,
        permissions: false,
        servicePoints: false,
      },
    };

    this.handleExpandAll = this.handleExpandAll.bind(this);
    this.handleSectionToggle = this.handleSectionToggle.bind(this);
    this.toggleAllSections = this.toggleAllSections.bind(this);
    this.collapseAllSections = this.collapseAllSections.bind(this);
    this.expandAllSections = this.expandAllSections.bind(this);

    this.ignoreEnterKey = this.ignoreEnterKey.bind(this);
    this.executeSave = this.executeSave.bind(this);
    this.closeButton = React.createRef();

    this.keyboardCommands = [
      {
        name: 'save',
        handler: this.handleSaveKeyCommand
      },
      {
        name: 'ignoreEnter',
        handler: this.ignoreEnterKey,
        shortcut: 'enter'
      },
      {
        name: 'cancel',
        handler: props.onCancel,
        shortcut: 'esc'
      },
      {
        name: 'expandAllSections',
        handler: this.expandAllSections,
        shortcut: 'mod+['
      },
      {
        name: 'collapseAllSections',
        handler: this.collapseAllSections,
        shortcut: 'mod+]'
      }
    ];

    if (props.initialValues.id) {
      this.connectedEditUserPerms = props.stripes.connect(EditUserPerms);
    }
  }

  componentDidMount() {
    // focus first interactive thing so that shortcuts will work immediately.
    this.closeButton.current.focus();
  }

  getAddFirstMenu() {
    const { onCancel } = this.props;

    return (
      <PaneMenu>
        <IconButton
          id="clickable-closenewuserdialog"
          onClick={onCancel}
          ref={this.closeButton}
          title={this.props.stripes.intl.formatMessage({ id: 'ui-users.crud.closeNewUserDialog' })}
          ariaLabel={this.props.stripes.intl.formatMessage({ id: 'ui-users.crud.closeNewUserDialog' })}
          icon="closeX"
        />
      </PaneMenu>
    );
  }

  getLastMenu(id, label) {
    const { pristine, submitting } = this.props;

    return (
      <PaneMenu>
        <Button
          id={id}
          type="submit"
          title={label}
          disabled={pristine || submitting}
          buttonStyle="primary paneHeaderNewButton"
          marginBottom0
        >
          {label}
        </Button>
      </PaneMenu>
    );
  }

  handleExpandAll(sections) {
    this.setState({ sections });
  }

  // eslint-disable-next-line class-methods-use-this
  ignoreEnterKey = (e) => {
    e.preventDefault();
  }

  handleSectionToggle({ id }) {
    this.setState((curState) => {
      const newState = cloneDeep(curState);
      newState.sections[id] = !newState.sections[id];
      return newState;
    });
  }

  toggleAllSections(expand) {
    this.setState((curState) => {
      const newSections = expandAllFunction(curState.sections, expand);
      return {
        sections: newSections
      };
    });
  }

  expandAllSections(e) {
    e.preventDefault();
    this.toggleAllSections(true);
  }

  collapseAllSections(e) {
    e.preventDefault();
    this.toggleAllSections(false);
  }

  handleSaveKeyCommand = (e) => {
    e.preventDefault();
    this.executeSave();
  }

  executeSave() {
    const { handleSubmit, onSubmit } = this.props;
    const submitter = handleSubmit(onSubmit);
    submitter();
  }

  render() {
    const { initialValues, stripes: { intl } } = this.props;
    const { sections } = this.state;
    const firstMenu = this.getAddFirstMenu();
    const paneTitle = initialValues.id ? getFullName(initialValues) : intl.formatMessage({ id: 'ui-users.crud.createUser' });
    const lastMenu = initialValues.id ?
      this.getLastMenu('clickable-updateuser', intl.formatMessage({ id: 'ui-users.crud.updateUser' })) :
      this.getLastMenu('clickable-createnewuser', intl.formatMessage({ id: 'ui-users.crud.createUser' }));

    return (
      <HasCommand commands={this.keyboardCommands}>
        <form className={css.UserFormRoot} id="form-user" onSubmit={this.executeSave}>
          <Paneset isRoot>
            <Pane defaultWidth="100%" firstMenu={firstMenu} lastMenu={lastMenu} paneTitle={paneTitle} appIcon={{ app: 'users' }}>

                <Headline size="xx-large" tag="h2">{getFullName(initialValues)}</Headline>
                <Row end="xs">
                  <Col xs>
                    <ExpandAllButton accordionStatus={sections} onToggle={this.handleExpandAll} />
                  </Col>
                </Row>
                <AccordionSet>
                  <EditUserInfo
                    accordionId="editUserInfo"
                    expanded={sections.editUserInfo}
                    onToggle={this.handleSectionToggle}
                    {...this.props}
                  />
                  <EditExtendedInfo
                    accordionId="extendedInfo"
                    expanded={sections.extendedInfo}
                    onToggle={this.handleSectionToggle}
                    userId={initialValues.id}
                    userFirstName={initialValues.personal.firstName}
                    userEmail={initialValues.personal.email}
                  />
                  <EditContactInfo
                    accordionId="contactInfo"
                    expanded={sections.contactInfo}
                    onToggle={this.handleSectionToggle}
                    {...this.props}
                  />
                  {initialValues.id &&

                      <EditProxy
                        accordionId="proxy"
                        expanded={sections.proxy}
                        onToggle={this.handleSectionToggle}
                        {...this.props}
                      />
                      <this.connectedEditUserPerms
                        accordionId="permissions"
                        expanded={sections.permissions}
                        onToggle={this.handleSectionToggle}
                        {...this.props}
                      />
                      <EditServicePoints
                        accordionId="servicePoints"
                        expanded={sections.servicePoints}
                        onToggle={this.handleSectionToggle}
                        {...this.props}
                      />

                  }
                </AccordionSet>

            </Pane>
          </Paneset>
        </form>
      </HasCommand>
    );
  }
}

export default stripesForm({
  form: 'userForm',
  validate,
  asyncValidate,
  asyncBlurFields: ['username'],
  navigationCheck: true,
  enableReinitialize: true,
})(UserForm);
<|endoftext|>


<commit_before>'use strict';

var expect = require('chai').expect;
var uuid = require('node-uuid');
var chance = new require('chance')();

var LokiJSStore = require('../');
var TokenStore = require('passwordless-tokenstore');

var Loki = require('lokijs');

var standardTests = require('passwordless-tokenstore-test');

var testFile = 'tokenstore-test.json';
var testCollection = 'passwordless-token';

function TokenStoreFactory() {
	return new LokiJSStore(testFile);
}

var beforeEachTest = function(done) {
	var db = new Loki(testFile);
	db.loadDatabase({}, function() {
		db.deleteDatabase(null, function() {
			done();
		});
	})
}

var afterEachTest = function(done) {
	var db = new Loki(testFile);
	db.loadDatabase({}, function() {
		db.deleteDatabase(null, function() {
			done();
		});
	})
}

// Call all standard tests
standardTests(TokenStoreFactory, beforeEachTest, afterEachTest);

describe('Specific tests', function() {

	beforeEach(function(done) {
		beforeEachTest(done);
	})

	afterEach(function(done) {
		afterEachTest(done);
	})

	it('should not allow the instantiation with an empty constructor', function () {
		expect(function() { new LokiJSStore() }).to.throw(Error);
	})

	it('should not allow the instantiation with a wrongly instantiated constructor', function () {
		expect(function() { new LokiJSStore(123) }).to.throw(Error);
	})

	it('should allow proper instantiation', function () {
		expect(function() { TokenStoreFactory() }).to.not.throw();
	})

	it('should allow proper instantiation with options', function () {
		expect(function() { new LokiJSStore(testFile, { lokijsstore: {collection:'user'}}) }).to.not.throw();
	})

	// it('should default to "passwordless-token" as collection name', function (done) {
	// 	var store = TokenStoreFactory();

	// 	MongoClient.connect(testUri, function(err, db) {
	// 		db.collection('passwordless-token', {strict:true}, function(err, collection) {
	// 			expect(err).to.exist;

	// 			store.storeOrUpdate(uuid.v4(), chance.email(),
	// 				1000*60, 'http://' + chance.domain() + '/page.html',
	// 				function() {
	// 					db.collection('passwordless-token', {strict:true}, function(err, collection) {
	// 						expect(collection).to.exist;
	// 						expect(err).to.not.exist;
	// 						done();
	// 					});
	// 				});
	// 		});
	// 	})
	// })

	// it('should change name of collection based on "mongostore.collection"', function (done) {
	// 	var store = new LokiJSStore(testUri, { mongostore : { collection: 'whatsup' }});

	// 	MongoClient.connect(testUri, function(err, db) {
	// 		db.collection('whatsup', {strict:true}, function(err, collection) {
	// 			expect(err).to.exist;

	// 			store.storeOrUpdate(uuid.v4(), chance.email(),
	// 				1000*60, 'http://' + chance.domain() + '/page.html',
	// 				function() {
	// 					db.collection('whatsup', {strict:true}, function(err, collection) {
	// 						expect(collection).to.exist;
	// 						expect(err).to.not.exist;
	// 						done();
	// 					});
	// 				});
	// 		});
	// 	})
	// })

	// it('should store tokens only in their hashed form', function (done) {
	// 	var store = TokenStoreFactory();
	// 	var token = uuid.v4();
	// 	var uid = chance.email();
	// 	store.storeOrUpdate(token, uid,
	// 		1000*60, 'http://' + chance.domain() + '/page.html',
	// 		function() {
	// 			MongoClient.connect(testUri, function(err, db) {
	// 				db.collection('passwordless-token', function(err, collection) {
	// 					collection.findOne({uid: uid}, function(err, item) {
	// 						expect(item.uid).to.equal(uid);
	// 						expect(item.hashedToken).to.not.equal(token);
	// 						done();
	// 					});
	// 				});
	// 			})
	// 		});
	// })

	// it('should store tokens not only hashed but also salted', function (done) {
	// 	var store = TokenStoreFactory();
	// 	var token = uuid.v4();
	// 	var uid = chance.email();
	// 	store.storeOrUpdate(token, uid,
	// 		1000*60, 'http://' + chance.domain() + '/page.html',
	// 		function() {
	// 			MongoClient.connect(testUri, function(err, db) {
	// 				db.collection('passwordless-token', function(err, collection) {
	// 					collection.findOne({uid: uid}, function(err, item) {
	// 						var hashedToken1 = item.hashedToken;
	// 						store.clear(function() {
	// 							store.storeOrUpdate(token, uid,
	// 								1000*60, 'http://' + chance.domain() + '/page.html',
	// 								function() {
	// 									collection.findOne({uid: uid}, function(err, item) {
	// 										var hashedToken2 = item.hashedToken;
	// 										expect(hashedToken2).to.not.equal(hashedToken1);
	// 										done();
	// 									});
	// 								});
	// 						})
	// 					});
	// 				});
	// 			})
	// 		});
	// })
})<commit_msg>ADD collection option to rename collection<commit_after>'use strict';

var expect = require('chai').expect;
var uuid = require('node-uuid');
var chance = new require('chance')();

var LokiJSStore = require('../');
var TokenStore = require('passwordless-tokenstore');

var Loki = require('lokijs');

var standardTests = require('passwordless-tokenstore-test');

var testFile = 'tokenstore-test.json';
var testCollection = 'passwordless-token';

function TokenStoreFactory() {
	return new LokiJSStore(testFile);
}

var beforeEachTest = function(done) {
	var db = new Loki(testFile);
	db.loadDatabase({}, function() {
		db.deleteDatabase(null, function() {
			done();
		});
	})
}

var afterEachTest = function(done) {
	var db = new Loki(testFile);
	db.loadDatabase({}, function() {
		db.deleteDatabase(null, function() {
			done();
		});
	})
}

// Call all standard tests
standardTests(TokenStoreFactory, beforeEachTest, afterEachTest);

describe('Specific tests', function() {

	beforeEach(function(done) {
		beforeEachTest(done);
	})

	afterEach(function(done) {
		afterEachTest(done);
	})

	it('should not allow the instantiation with an empty constructor', function () {
		expect(function() { new LokiJSStore() }).to.throw(Error);
	})

	it('should not allow the instantiation with a wrongly instantiated constructor', function () {
		expect(function() { new LokiJSStore(123) }).to.throw(Error);
	})

	it('should allow proper instantiation', function () {
		expect(function() { TokenStoreFactory() }).to.not.throw();
	})

	it('should allow proper instantiation with options', function () {
		expect(function() { new LokiJSStore(testFile, { lokijsstore: {collection:'user'}}) }).to.not.throw();
	})

	it('should default to "passwordless-token" as collection name', function (done) {
		var store = TokenStoreFactory();

		store.storeOrUpdate(uuid.v4(), chance.email(),
			1000*60, 'http://' + chance.domain() + '/page.html',
			function() {
				var db = new Loki(testFile);
				db.loadDatabase({}, function() {
					var collection = db.getCollection('passwordless-token');
					var collection2 = db.getCollection('other');
					expect(collection).to.exist;
					expect(collection2).to.not.exist;
					done();
				})
		})
	})

	it('should change name of collection based on "lokijsstore.collection"', function (done) {
		var store = new LokiJSStore(testFile, { lokijsstore : { collection: 'othername' }});

		store.storeOrUpdate(uuid.v4(), chance.email(),
			1000*60, 'http://' + chance.domain() + '/page.html',
			function() {
				var db = new Loki(testFile);
				db.loadDatabase({}, function() {
					var collection = db.getCollection('passwordless-token');
					var collection2 = db.getCollection('othername');
					expect(collection).to.not.exist;
					expect(collection2).to.exist;
					done();
				})
		})
	})

	// it('should store tokens only in their hashed form', function (done) {
	// 	var store = TokenStoreFactory();
	// 	var token = uuid.v4();
	// 	var uid = chance.email();
	// 	store.storeOrUpdate(token, uid,
	// 		1000*60, 'http://' + chance.domain() + '/page.html',
	// 		function() {
	// 			MongoClient.connect(testUri, function(err, db) {
	// 				db.collection('passwordless-token', function(err, collection) {
	// 					collection.findOne({uid: uid}, function(err, item) {
	// 						expect(item.uid).to.equal(uid);
	// 						expect(item.hashedToken).to.not.equal(token);
	// 						done();
	// 					});
	// 				});
	// 			})
	// 		});
	// })

	// it('should store tokens not only hashed but also salted', function (done) {
	// 	var store = TokenStoreFactory();
	// 	var token = uuid.v4();
	// 	var uid = chance.email();
	// 	store.storeOrUpdate(token, uid,
	// 		1000*60, 'http://' + chance.domain() + '/page.html',
	// 		function() {
	// 			MongoClient.connect(testUri, function(err, db) {
	// 				db.collection('passwordless-token', function(err, collection) {
	// 					collection.findOne({uid: uid}, function(err, item) {
	// 						var hashedToken1 = item.hashedToken;
	// 						store.clear(function() {
	// 							store.storeOrUpdate(token, uid,
	// 								1000*60, 'http://' + chance.domain() + '/page.html',
	// 								function() {
	// 									collection.findOne({uid: uid}, function(err, item) {
	// 										var hashedToken2 = item.hashedToken;
	// 										expect(hashedToken2).to.not.equal(hashedToken1);
	// 										done();
	// 									});
	// 								});
	// 						})
	// 					});
	// 				});
	// 			})
	// 		});
	// })
})<|endoftext|>


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

// Module dependencies.
var url = require('url');
var util = require('util');

var ServiceClient = require('../../node_modules/azure/node_modules/azure-common/lib/services/serviceclient');
var WebResource = require('../../node_modules/azure/node_modules/azure-common/lib/http/webresource');
var Constants = require('../../node_modules/azure/node_modules/azure-common/lib/util/constants');
var HeaderConstants = Constants.HeaderConstants;

// Expose 'CommunityUtil'.
exports = module.exports = CommunityUtil;

/**
* Creates a new CommunityUtil object.
*
* @constructor
*/
function CommunityUtil(managementEndPoint) {
  CommunityUtil['super_'].call(this);
  var serviceHost = 'vmdepot.msopentech.com';
  var managementEndPointAsUrl = url.parse(managementEndPoint);
  if (managementEndPointAsUrl.host == 'management.core.chinacloudapi.cn') {
    serviceHost = 'vmdepot.msopentech.cn';
  }

  this.Constants = {
    SERVICEHOST : serviceHost,
    SERVICE: '/OData.svc'
  };

  this._initDefaultFilter();

  var self = this;
  self.authenticationProvider = {
    signRequest: function (request, cb) {
      request.key = self.keyvalue;
      request.cert = self.certvalue;

      cb(null);
    }
  };
}

util.inherits(CommunityUtil, ServiceClient);

/**
* Resolve uid
*
* @param {function} callback  The callback function called on completion. Required.
*/
CommunityUtil.prototype.resolveUid = function (uid, callback) {
  var path = this.Constants.SERVICE + '/ResolveUid';
  var webResource = WebResource.get(path)
    .withQueryOption('uid', '\''+ uid + '\'');

  this.performRequest(webResource, null, null, function (responseObject, next) {
    var finalCallback = function (returnObject) {
      callback(returnObject.error, returnObject.response);
    };

    next(responseObject, finalCallback);
  });
};

/**
* Builds the request options to be passed to the http.request method.
*
* @param {WebResource} webResource The webresource where to build the options from.
* @param {object}      options     The body of the request.
* @param {object}      options     The request options.
* @param {function(error, requestOptions)}  callback  The callback function.
* @return {undefined}
*/
CommunityUtil.prototype._buildRequestOptions = function(webResource, body, options, callback) {
  var self = this;

  self.host = self._getHostname();

  webResource.withHeader(HeaderConstants.CONTENT_TYPE, self._getContentType());
  webResource.withHeader(HeaderConstants.ACCEPT_HEADER, self._getAcceptType());
  webResource.withHeader(HeaderConstants.ACCEPT_CHARSET_HEADER, 'UTF-8');
  webResource.withHeader(HeaderConstants.HOST_HEADER, self.host);

  CommunityUtil['super_'].prototype._buildRequestOptions.call(this, webResource, body, options, callback);
};

/**
* Get the content-type string based on serializeType
*
* @return {string}
*/
CommunityUtil.prototype._getContentType = function() {
  return 'application/xml';
};

/**
* Get the accept header string based on serializeType
*
* @return {string}
*/
CommunityUtil.prototype._getAcceptType = function() {
  return 'application/json';
};

/**
* Get service host name
*/
CommunityUtil.prototype._getHostname = function () {
  return this.Constants.SERVICEHOST;
};
<commit_msg>Fixed broken requires in communityutil<commit_after>//
// Copyright (c) Microsoft and contributors.  All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//

// Module dependencies.
var url = require('url');
var util = require('util');

var azureCommon = require('azure-common');
var ServiceClient = azureCommon.ServiceClient;
var WebResource = azureCommon.webResource;
var Constants = azureCommon.Constants;
var HeaderConstants = Constants.HeaderConstants;

// Expose 'CommunityUtil'.
exports = module.exports = CommunityUtil;

/**
* Creates a new CommunityUtil object.
*
* @constructor
*/
function CommunityUtil(managementEndPoint) {
  CommunityUtil['super_'].call(this);
  var serviceHost = 'vmdepot.msopentech.com';
  var managementEndPointAsUrl = url.parse(managementEndPoint);
  if (managementEndPointAsUrl.host == 'management.core.chinacloudapi.cn') {
    serviceHost = 'vmdepot.msopentech.cn';
  }

  this.Constants = {
    SERVICEHOST : serviceHost,
    SERVICE: '/OData.svc'
  };

  this._initDefaultFilter();

  var self = this;
  self.authenticationProvider = {
    signRequest: function (request, cb) {
      request.key = self.keyvalue;
      request.cert = self.certvalue;

      cb(null);
    }
  };
}

util.inherits(CommunityUtil, ServiceClient);

/**
* Resolve uid
*
* @param {function} callback  The callback function called on completion. Required.
*/
CommunityUtil.prototype.resolveUid = function (uid, callback) {
  var path = this.Constants.SERVICE + '/ResolveUid';
  var webResource = WebResource.get(path)
    .withQueryOption('uid', '\''+ uid + '\'');

  this.performRequest(webResource, null, null, function (responseObject, next) {
    var finalCallback = function (returnObject) {
      callback(returnObject.error, returnObject.response);
    };

    next(responseObject, finalCallback);
  });
};

/**
* Builds the request options to be passed to the http.request method.
*
* @param {WebResource} webResource The webresource where to build the options from.
* @param {object}      options     The body of the request.
* @param {object}      options     The request options.
* @param {function(error, requestOptions)}  callback  The callback function.
* @return {undefined}
*/
CommunityUtil.prototype._buildRequestOptions = function(webResource, body, options, callback) {
  var self = this;

  self.host = self._getHostname();

  webResource.withHeader(HeaderConstants.CONTENT_TYPE, self._getContentType());
  webResource.withHeader(HeaderConstants.ACCEPT_HEADER, self._getAcceptType());
  webResource.withHeader(HeaderConstants.ACCEPT_CHARSET_HEADER, 'UTF-8');
  webResource.withHeader(HeaderConstants.HOST_HEADER, self.host);

  CommunityUtil['super_'].prototype._buildRequestOptions.call(this, webResource, body, options, callback);
};

/**
* Get the content-type string based on serializeType
*
* @return {string}
*/
CommunityUtil.prototype._getContentType = function() {
  return 'application/xml';
};

/**
* Get the accept header string based on serializeType
*
* @return {string}
*/
CommunityUtil.prototype._getAcceptType = function() {
  return 'application/json';
};

/**
* Get service host name
*/
CommunityUtil.prototype._getHostname = function () {
  return this.Constants.SERVICEHOST;
};
<|endoftext|>


<commit_before>import React, { Component } from "react"
import { prettyHours, dayNames } from "./utils/Strings"

const columnStyle = {
  width: "14%",
  height: "100%",
  textAlign: "center"
}

const hourColStyle = {
  display: "flex",
  flexDirection: "column",
  width: "5%"
}

const hourCol = () => {
  let column = [
]
  for (let i = 0, size = prettyHours.length; i < size; i++) {
    column.push(

        {prettyHours[i]}

    )
  }
  return column
}

const weekCol = () => {
  let column = []
  for (let i = 0; i < 34; i++) {
    column.push(

        {this.props.meetings[

    )
  }
  return column
}

class Weekview extends Component {
  render() {
    console.log(this.props.meetings)
    return (

          {hourCol()}

            {dayNames[0]}

          {weekCol()}

            {dayNames[1]}

          {weekCol()}

            {dayNames[2]}

          {weekCol()}

            {dayNames[3]}

          {weekCol()}

            {dayNames[4]}

          {weekCol()}

            {dayNames[5]}

          {weekCol()}

            {dayNames[6]}

          {weekCol()}

    )
  }
}

export default Weekview
<commit_msg>Hardcoded course object for demo purposes<commit_after>import React, { Component } from "react"
import { prettyHours, dayNames } from "./utils/Strings"

const columnStyle = {
  width: "14%",
  height: "100%",
  textAlign: "center"
}

const hourColStyle = {
  display: "flex",
  flexDirection: "column",
  width: "5%"
}

const hourCol = () => {
  let column = [
]
  for (let i = 0, size = prettyHours.length; i < size; i++) {
    column.push(

        {prettyHours[i]}

    )
  }
  return column
}

const weekCol = (meetings) => {
  let column = []
  for (let i = 0; i < 34; i++) {
    if (meetings !== null && meetings !== undefined && (meetings[0].starttime.substring(0, 2) * 2 -14) === i){

      column.push(

          <button style={{backgroundColor: 'lightblue', border: 'none', width: '100%', height: '250%'}}>
            {meetings[0].coursetitle}
          </button>

      )
    }else {
      column.push(

      )
    }
  }
  return column
}

class Weekview extends Component {
  render() {
    console.log(this.props.meetings)
    return (

          {hourCol()}

            {dayNames[0]}

          {weekCol(this.props.meetings[5][13])}

            {dayNames[1]}

          {weekCol()}

            {dayNames[2]}

          {weekCol()}

            {dayNames[3]}

          {weekCol()}

            {dayNames[4]}

          {weekCol()}

            {dayNames[5]}

          {weekCol()}

            {dayNames[6]}

          {weekCol()}

    )
  }
}

export default Weekview
<|endoftext|>


<commit_before>'use strict';

const chalk = require('chalk');
const yosay = require('../index.js');

/*
 * Yo. Fire this file locally with `node test/manual-test.js` at least after you
 * have newly generated the text fixtures to double check that all available
 * option have a correct looking output.
 * Thanks (ᵔᴥᵔ)
 */

console.log(yosay('Hello, and welcome to my fantastic generator full of whimsy and bubble gum!'));

console.log(yosay('Hi'));

console.log(yosay('Welcome to Yeoman, ladies and gentlemen!'));

console.log(yosay('Hi', {maxLength: 8}));

console.log(yosay('Hello, buddy!', {maxLength: 4}));

console.log(yosay(chalk.red.bgWhite('Hi')));

console.log(yosay(chalk.red.bgWhite('Hi') + ' there, sir!'));

console.log(yosay(chalk.red.bgWhite('Hi') + ' there, sir! ' + chalk.bgBlue.white('you are looking') + ' swell today!'));

console.log(yosay('first line\nsecond line\n\nfourth line'));

console.log(yosay('项目可以更新了'));

console.log(yosay('iloveunicornsiloveunicornsiloveunicornsiloveunicornsiloveunicornsiloveunicorns'));

console.log(yosay('Lie on your belly and purr when you are asleep shove bum in owner’s face like camera lens. Cough furball.', {maxLength: 11}));
console.log(yosay('Lie on your belly and purr when you are asleep shove bum in owner’s face like camera lens. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball.'));
console.log(yosay('Lie on your belly and purr when you are asleep shove bum in owner’s face like camera lens. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball.', {maxLength: 11}));
console.log(yosay('Lie on your belly and purr when you are asleep shove bum in owner’s face like camera lens. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball.', {maxLength: 26}));

console.log(yosay(
  'That’s it. Feel free to fire up the server with ' +
  chalk.green('`npm run start:dev`') +
  'or use our subgenerator to create endpoints.'
));

console.log(yosay('That’s it. Feel free to fire up the server with `npm run start:dev` or use our subgenerator to create endpoints.'));

console.log(yosay(
  'That’s it. Feel free to fire up the server with ' +
  chalk.green('`npm run start:dev`') + '.'
));

console.log(yosay(
  'That’s it. Feel free to fire up the server with ' +
  '`npm run start:dev`.'
));
<commit_msg>fix travis<commit_after>'use strict';
var chalk = require('chalk');
var yosay = require('../');

/*
 * Yo. Fire this file locally with `node test/manual-test.js` at least after you
 * have newly generated the text fixtures to double check that all available
 * option have a correct looking output.
 * Thanks (ᵔᴥᵔ)
 */

console.log(yosay('Hello, and welcome to my fantastic generator full of whimsy and bubble gum!'));

console.log(yosay('Hi'));

console.log(yosay('Welcome to Yeoman, ladies and gentlemen!'));

console.log(yosay('Hi', {maxLength: 8}));

console.log(yosay('Hello, buddy!', {maxLength: 4}));

console.log(yosay(chalk.red.bgWhite('Hi')));

console.log(yosay(chalk.red.bgWhite('Hi') + ' there, sir!'));

console.log(yosay(chalk.red.bgWhite('Hi') + ' there, sir! ' + chalk.bgBlue.white('you are looking') + ' swell today!'));

console.log(yosay('first line\nsecond line\n\nfourth line'));

console.log(yosay('项目可以更新了'));

console.log(yosay('iloveunicornsiloveunicornsiloveunicornsiloveunicornsiloveunicornsiloveunicorns'));

console.log(yosay('Lie on your belly and purr when you are asleep shove bum in owner’s face like camera lens. Cough furball.', {maxLength: 11}));
console.log(yosay('Lie on your belly and purr when you are asleep shove bum in owner’s face like camera lens. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball.'));
console.log(yosay('Lie on your belly and purr when you are asleep shove bum in owner’s face like camera lens. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball.', {maxLength: 11}));
console.log(yosay('Lie on your belly and purr when you are asleep shove bum in owner’s face like camera lens. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball. Cough furball.', {maxLength: 26}));

console.log(yosay(
  'That’s it. Feel free to fire up the server with ' +
  chalk.green('`npm run start:dev`') +
  'or use our subgenerator to create endpoints.'
));

console.log(yosay('That’s it. Feel free to fire up the server with `npm run start:dev` or use our subgenerator to create endpoints.'));

console.log(yosay(
  'That’s it. Feel free to fire up the server with ' +
  chalk.green('`npm run start:dev`') + '.'
));

console.log(yosay(
  'That’s it. Feel free to fire up the server with ' +
  '`npm run start:dev`.'
));
<|endoftext|>


<commit_before>'use babel'

import { Emitter } from 'atom'
import { View } from 'atom-space-pen-views'
import { logo } from '../../assets/svgs'
import getKeybinding from '../utils/get-keybinding'

/* when this file is run the keybindings aren't ready yet
 that's why giving atom some time to prepare before we ask
 for the keybinding */
setTimeout(() => {
  let keybinding = getKeybinding('command-palette:toggle')
  descriptions.ALL_GOOD.description = descriptions.ALL_GOOD.description.replace('!!!!', keybinding)
}, 3000)

const descriptions = {
  NOT_INSTALLED: {
    title: 'kd is missing',
    description: 'Please open a terminal window and install it with the following commands and come back once done.'
  },
  NOT_LOGGEDIN: {
    title: 'Login/Register',
    description: 'You are not logged in, please log in with the following commands and come back.'
  },
  DAEMON_NOT_INSTALLED: {
    title: 'Daemon is missing',
    description: 'It seems like the kd binary is installed but its daemon is missing, please install it with the following command.'
  },
  DAEMON_STOPPED: {
    title: 'Daemon is not running',
    description: 'kd daemon is not running please run it with the following command:'
  },
  ALL_GOOD: {
    title: 'kd is up & running',
    description: `The daemon is running. You're logged in! <br><br>Now you can open the command palette(!!!!) and type 'kd:' to see the available kd commands`
  }
}

const success = {
  NOT_INSTALLED: 'kd is installed',
  NOT_LOGGEDIN: 'you are logged in',
  DAEMON_NOT_INSTALLED: 'kd daemon is installed',
  DAEMON_STOPPED: 'kd daemon is running'
}

const helpers = {
  NOT_INSTALLED: [
    'brew tap rjeczalik/kd',
    'brew install kd --devel',
    'sudo kd daemon install --team <yourteam> --baseurl https://koding.com'
  ],
  NOT_LOGGEDIN: [
    'kd auth login --team <yourteam>'
  ],
  DAEMON_NOT_INSTALLED: [
    'sudo kd daemon install --team <yourteam>'
  ],
  DAEMON_STOPPED: [
    'sudo kd daemon restart'
  ]
}

export default class KDHelpView extends View {

  static content (data = {}) {
    this.div(() => {
      if (!data.mini) {
        this.div({ class: 'kd-help-view--logo' }, () => { this.raw(logo) })
      }
      this.div({ outlet: 'content' }, () => {
        this.raw("
checking kd…
")
      })
    })
  }

  setData (data = {}) {
    this.__data = data
    return data
  }

  getData () {
    return this.__data
  }

  initialize (data) {
    let { prompt, succeeded } = data
    this.setData(data)
    this.emitter = new Emitter()
    if (prompt) {
      this.setContent(prompt)
    }
    if (!prompt && succeeded.length) {
      succeeded.forEach(step => {
        this.appendContent(step)
      })
    }
  }

  setContent (prompt) {
    this.content.html('')
    let commandsHTML = ''
    if (helpers[prompt]) {
      for (let command of Array.from(helpers[prompt])) {
        commandsHTML += `<code>${command}</code><br>`
      }
    }
    this.content.append(`<h2>${descriptions[prompt].title}</h2>`)
    this.content.append(`<p>${descriptions[prompt].description}</p>`)
    if (commandsHTML) {
      this.content.append(`<pre>${commandsHTML}</pre>`)
    }
  }

  appendContent (step) {
    if (success[step]) {
      this.content.append(`<div class='icon icon-check'>${success[step]}</div>`)
    }
  }

}
<commit_msg>minor mac/linux only copy change<commit_after>'use babel'

import { Emitter } from 'atom'
import { View } from 'atom-space-pen-views'
import { logo } from '../../assets/svgs'
import getKeybinding from '../utils/get-keybinding'

/* when this file is run the keybindings aren't ready yet
 that's why giving atom some time to prepare before we ask
 for the keybinding */
setTimeout(() => {
  let keybinding = getKeybinding('command-palette:toggle')
  descriptions.ALL_GOOD.description = descriptions.ALL_GOOD.description.replace('!!!!', keybinding)
}, 3000)

const descriptions = {
  NOT_INSTALLED: {
    title: 'kd is missing',
    description: 'Please open a terminal window and install it with the following commands and come back once done. (mac/linux only)'
  },
  NOT_LOGGEDIN: {
    title: 'Login/Register',
    description: 'You are not logged in, please log in with the following commands and come back.'
  },
  DAEMON_NOT_INSTALLED: {
    title: 'Daemon is missing',
    description: 'It seems like the kd binary is installed but its daemon is missing, please install it with the following command.'
  },
  DAEMON_STOPPED: {
    title: 'Daemon is not running',
    description: 'kd daemon is not running please run it with the following command:'
  },
  ALL_GOOD: {
    title: 'kd is up & running',
    description: `The daemon is running. You're logged in! <br><br>Now you can open the command palette(!!!!) and type 'kd:' to see the available kd commands`
  }
}

const success = {
  NOT_INSTALLED: 'kd is installed',
  NOT_LOGGEDIN: 'you are logged in',
  DAEMON_NOT_INSTALLED: 'kd daemon is installed',
  DAEMON_STOPPED: 'kd daemon is running'
}

const helpers = {
  NOT_INSTALLED: [
    'brew tap rjeczalik/kd',
    'brew install kd --devel',
    'sudo kd daemon install --team <yourteam> --baseurl https://koding.com'
  ],
  NOT_LOGGEDIN: [
    'kd auth login --team <yourteam>'
  ],
  DAEMON_NOT_INSTALLED: [
    'sudo kd daemon install --team <yourteam>'
  ],
  DAEMON_STOPPED: [
    'sudo kd daemon restart'
  ]
}

export default class KDHelpView extends View {

  static content (data = {}) {
    this.div(() => {
      if (!data.mini) {
        this.div({ class: 'kd-help-view--logo' }, () => { this.raw(logo) })
      }
      this.div({ outlet: 'content' }, () => {
        this.raw("
checking kd…
")
      })
    })
  }

  setData (data = {}) {
    this.__data = data
    return data
  }

  getData () {
    return this.__data
  }

  initialize (data) {
    let { prompt, succeeded } = data
    this.setData(data)
    this.emitter = new Emitter()
    if (prompt) {
      this.setContent(prompt)
    }
    if (!prompt && succeeded.length) {
      succeeded.forEach(step => {
        this.appendContent(step)
      })
    }
  }

  setContent (prompt) {
    this.content.html('')
    let commandsHTML = ''
    if (helpers[prompt]) {
      for (let command of Array.from(helpers[prompt])) {
        commandsHTML += `<code>${command}</code><br>`
      }
    }
    this.content.append(`<h2>${descriptions[prompt].title}</h2>`)
    this.content.append(`<p>${descriptions[prompt].description}</p>`)
    if (commandsHTML) {
      this.content.append(`<pre>${commandsHTML}</pre>`)
    }
  }

  appendContent (step) {
    if (success[step]) {
      this.content.append(`<div class='icon icon-check'>${success[step]}</div>`)
    }
  }

}
<|endoftext|>


<commit_before>var Landing = {
    render: function() {
        showLoading();
        Landing.make_html();
    },

    make_html: function () {
        $('html,body').animate({scrollTop: 0}, 'fast');
        var landing_source = $("#landing").html();
        var template = Handlebars.compile(landing_source);
         $("#main-content").html(template());

        WSData.fetch_notice_data(Landing.render_notice_banner);

        var cards = [RegStatusCard,
                     VisualScheduleCard,
                     CourseCard,
                     FutureQuarterCard,
                     TuitionCard,
                     PCETuitionCard,
                     TextbookCard,
                     HfsCard,
                     LibraryCard];

        Cards.load_cards_in_order(cards, $("#landing_content"));

    },

    render_notice_banner: function () {
        var notice_banner = '',
            notice_data = WSData.notice_data();
        if (Notices.get_total_unread() > 0) {
            notice_banner = NoticeBanner.render(notice_data);
        }
        $("#notice_banner_location").html(notice_banner);
    }

};
<commit_msg>reordering cards on landing<commit_after>var Landing = {
    render: function() {
        showLoading();
        Landing.make_html();
    },

    make_html: function () {
        $('html,body').animate({scrollTop: 0}, 'fast');
        var landing_source = $("#landing").html();
        var template = Handlebars.compile(landing_source);
         $("#main-content").html(template());

        WSData.fetch_notice_data(Landing.render_notice_banner);

        var cards = [RegStatusCard,
                     FutureQuarterCard,
                     VisualScheduleCard,
                     CourseCard,
                     HfsCard,
                     TuitionCard,
                     LibraryCard];

        Cards.load_cards_in_order(cards, $("#landing_content"));

    },

    render_notice_banner: function () {
        var notice_banner = '',
            notice_data = WSData.notice_data();
        if (Notices.get_total_unread() > 0) {
            notice_banner = NoticeBanner.render(notice_data);
        }
        $("#notice_banner_location").html(notice_banner);
    }

};
<|endoftext|>


<commit_before>var _ = require('underscore');

require('es6-promise').polyfill();
require('isomorphic-fetch');
var callsync = require('./callsync')

function value(x) {
  var v = null
  if (_.isString(x)) {
    v = {'s': x}
  } else if (_.isNumber(x)) {
    if (x === Math.floor(x)) {
      v = {'n': x}
    } else {
      v = {'r': x}
    }
  }

  return v ? v : x
}

function OphionQuery(parent) {
  var parent = parent
  var query = []

  function labels(l) {
    if (!l) {
      l = []
    } else if (_.isString(l)) {
      l = [l]
    } else if (!_.isArray(l)) {
      console.log("not something we know how to make labels out of:")
      console.log(l)
    }

    return {'labels': l}
  }

  function by(b) {
    if (_.isString(b)) {
      return {'key': b}
    } else {
      return {'query': b.query}
    }
  }

  var operations = {
    query: query,

    V: function(l) {
      query.push({'V': labels(l)})
      return this
    },

    E: function(l) {
      query.push({'E': labels(l)})
      return this
    },

    incoming: function(l) {
      query.push({'in': labels(l)})
      return this
    },

    outgoing: function(l) {
      query.push({'out': labels(l)})
      return this
    },

    inEdge: function(l) {
      query.push({'inEdge': labels(l)})
      return this
    },

    outEdge: function(l) {
      query.push({'outEdge': labels(l)})
      return this
    },

    inVertex: function(l) {
      query.push({'inVertex': labels(l)})
      return this
    },

    outVertex: function(l) {
      query.push({'outVertex': labels(l)})
      return this
    },

    identity: function() {
      query.push({'identity': true})
      return this
    },

    mark: function(l) {
      query.push({'as': labels(l)})
      return this
    },

    select: function(l) {
      query.push({'select': labels(l)})
      return this
    },

    by: function(key) {
      // a key is either a string or an inner query that has already been
      // built and passed in.
      query.push({'by': _.isString(key) ? {'key': key} : {'query': key.query}})
      return this
    },

    id: function() {
      query.push({'id': true})
      return this
    },

    label: function() {
      query.push({'label': true})
      return this
    },

    values: function(l) {
      query.push({'values': labels(l)})
      return this
    },

    properties: function(l) {
      query.push({'properties': labels(l)})
      return this
    },

    propertyMap: function(l) {
      query.push({'propertyMap': labels(l)})
      return this
    },

    dedup: function(l) {
      query.push({'dedup': labels(l)})
      return this
    },

    limit: function(l) {
      query.push({'limit': l})
      return this
    },

    range: function(lower, upper) {
      query.push({'lower': lower, 'upper': upper})
      return this
    },

    count: function() {
      query.push({'count': true})
      return this
    },

    path: function() {
      query.push({'path': true})
      return this
    },

    aggregate: function(label) {
      query.push({'aggregate': label})
      return this
    },

    // group: function(by) {
    //   if (!)
    //   query.push({'groupCount': label})
    //   return this
    // },

    groupCount: function(b) {
      query.push({'groupCount': by(b)})
      return this
    },

    is: function(condition) {
      query.push({'is': condition})
      return this
    },

    has: function(key, h) {
      var out = {'key': key}
      if (_.isString(h) || _.isNumber(h)) {
        out['value'] = value(h)
      } else if (_.isArray(h)) {
        out['query'] = h.query
      } else {
        out['condition'] = h
      }

      query.push({'has': out})
      return this
    },

    hasLabel: function(l) {
      query.push({'hasLabel': labels(l)})
      return this
    },

    hasNot: function(key) {
      query.push({'hasNot': key})
      return this
    },

    match: function(queries) {
      query.push({'match': {'queries': _.map(queries, function(query) {return query.query})}})
      return this
    },

    execute: function(callback) {
      parent.execute(query, callback)
    }
  }

  return operations
}

function parseJson(s) {
  try {
    return JSON.parse(s)
  } catch(err) {
    return s
  }
}

function Ophion(site='') {
  var queryBase = '/vertex/query'

  return {
    execute: function(query, callback) {
      fetch(site + queryBase, {
        method: 'POST',
        headers: {'Content-Type': 'application/json', 'Accept': 'application/json'},
        body: JSON.stringify(query),
      }).then(function(response) {
        return response.text()
      }).then(function(text) {
        var lines = text.replace(/^\s+|\s+$/g, '').split("\n")
        var parsed = lines.map(parseJson)
        callback(parsed)
      })
    },

    query: function() {
      return OphionQuery(this)
    },

    q: function() {
      return OphionQuery(this)
    },

    as: function(l) {
      return OphionQuery(this).as(l)
    },

    eq: function(x) {
      return {'eq': value(x)}
    },

    neq: function(x) {
      return {'neq': value(x)}
    },

    gt: function(x) {
      return {'gt': value(x)}
    },

    gte: function(x) {
      return {'gte': value(x)}
    },

    lt: function(x) {
      return {'lt': value(x)}
    },

    lte: function(x) {
      return {'lte': value(x)}
    },

    between: function(lower, upper) {
      return {'between': {'lower': value(lower), 'upper': value(upper)}}
    },

    inside: function(lower, upper) {
      return {'inside': {'lower': value(lower), 'upper': value(upper)}}
    },

    outside: function(lower, upper) {
      return {'outside': {'lower': value(lower), 'upper': value(upper)}}
    },

    within: function(v) {
      return {'within': _.map(v, value)}
    },

    without: function(v) {
      return {'without': _.map(v, value)}
    }
  }
}

module.exports.Ophion = Ophion ;
module.exports.Callsync = callsync.callsync ;
<commit_msg>add mark<commit_after>var _ = require('underscore');

require('es6-promise').polyfill();
require('isomorphic-fetch');
var callsync = require('./callsync')

function value(x) {
  var v = null
  if (_.isString(x)) {
    v = {'s': x}
  } else if (_.isNumber(x)) {
    if (x === Math.floor(x)) {
      v = {'n': x}
    } else {
      v = {'r': x}
    }
  }

  return v ? v : x
}

function OphionQuery(parent) {
  var parent = parent
  var query = []

  function labels(l) {
    if (!l) {
      l = []
    } else if (_.isString(l)) {
      l = [l]
    } else if (!_.isArray(l)) {
      console.log("not something we know how to make labels out of:")
      console.log(l)
    }

    return {'labels': l}
  }

  function by(b) {
    if (_.isString(b)) {
      return {'key': b}
    } else {
      return {'query': b.query}
    }
  }

  var operations = {
    query: query,

    V: function(l) {
      query.push({'V': labels(l)})
      return this
    },

    E: function(l) {
      query.push({'E': labels(l)})
      return this
    },

    incoming: function(l) {
      query.push({'in': labels(l)})
      return this
    },

    outgoing: function(l) {
      query.push({'out': labels(l)})
      return this
    },

    inEdge: function(l) {
      query.push({'inEdge': labels(l)})
      return this
    },

    outEdge: function(l) {
      query.push({'outEdge': labels(l)})
      return this
    },

    inVertex: function(l) {
      query.push({'inVertex': labels(l)})
      return this
    },

    outVertex: function(l) {
      query.push({'outVertex': labels(l)})
      return this
    },

    identity: function() {
      query.push({'identity': true})
      return this
    },

    mark: function(l) {
      query.push({'as': labels(l)})
      return this
    },

    select: function(l) {
      query.push({'select': labels(l)})
      return this
    },

    by: function(key) {
      // a key is either a string or an inner query that has already been
      // built and passed in.
      query.push({'by': _.isString(key) ? {'key': key} : {'query': key.query}})
      return this
    },

    id: function() {
      query.push({'id': true})
      return this
    },

    label: function() {
      query.push({'label': true})
      return this
    },

    values: function(l) {
      query.push({'values': labels(l)})
      return this
    },

    properties: function(l) {
      query.push({'properties': labels(l)})
      return this
    },

    propertyMap: function(l) {
      query.push({'propertyMap': labels(l)})
      return this
    },

    dedup: function(l) {
      query.push({'dedup': labels(l)})
      return this
    },

    limit: function(l) {
      query.push({'limit': l})
      return this
    },

    range: function(lower, upper) {
      query.push({'lower': lower, 'upper': upper})
      return this
    },

    count: function() {
      query.push({'count': true})
      return this
    },

    path: function() {
      query.push({'path': true})
      return this
    },

    aggregate: function(label) {
      query.push({'aggregate': label})
      return this
    },

    // group: function(by) {
    //   if (!)
    //   query.push({'groupCount': label})
    //   return this
    // },

    groupCount: function(b) {
      query.push({'groupCount': by(b)})
      return this
    },

    is: function(condition) {
      query.push({'is': condition})
      return this
    },

    has: function(key, h) {
      var out = {'key': key}
      if (_.isString(h) || _.isNumber(h)) {
        out['value'] = value(h)
      } else if (_.isArray(h)) {
        out['query'] = h.query
      } else {
        out['condition'] = h
      }

      query.push({'has': out})
      return this
    },

    hasLabel: function(l) {
      query.push({'hasLabel': labels(l)})
      return this
    },

    hasNot: function(key) {
      query.push({'hasNot': key})
      return this
    },

    match: function(queries) {
      query.push({'match': {'queries': _.map(queries, function(query) {return query.query})}})
      return this
    },

    execute: function(callback) {
      parent.execute(query, callback)
    }
  }

  return operations
}

function parseJson(s) {
  try {
    return JSON.parse(s)
  } catch(err) {
    return s
  }
}

function Ophion(site='') {
  var queryBase = '/vertex/query'

  return {
    execute: function(query, callback) {
      fetch(site + queryBase, {
        method: 'POST',
        headers: {'Content-Type': 'application/json', 'Accept': 'application/json'},
        body: JSON.stringify(query),
      }).then(function(response) {
        return response.text()
      }).then(function(text) {
        var lines = text.replace(/^\s+|\s+$/g, '').split("\n")
        var parsed = lines.map(parseJson)
        callback(parsed)
      })
    },

    query: function() {
      return OphionQuery(this)
    },

    q: function() {
      return OphionQuery(this)
    },

    as: function(l) {
      return OphionQuery(this).as(l)
    },

    eq: function(x) {
      return {'eq': value(x)}
    },

    neq: function(x) {
      return {'neq': value(x)}
    },

    gt: function(x) {
      return {'gt': value(x)}
    },

    gte: function(x) {
      return {'gte': value(x)}
    },

    lt: function(x) {
      return {'lt': value(x)}
    },

    lte: function(x) {
      return {'lte': value(x)}
    },

    between: function(lower, upper) {
      return {'between': {'lower': value(lower), 'upper': value(upper)}}
    },

    inside: function(lower, upper) {
      return {'inside': {'lower': value(lower), 'upper': value(upper)}}
    },

    outside: function(lower, upper) {
      return {'outside': {'lower': value(lower), 'upper': value(upper)}}
    },

    within: function(v) {
      return {'within': _.map(v, value)}
    },

    without: function(v) {
      return {'without': _.map(v, value)}
    },

    mark: function(l) {
      return OphionQuery(this).mark(l)
    }
  }
}

module.exports.Ophion = Ophion ;
module.exports.Callsync = callsync.callsync ;
<|endoftext|>