<commit_before>const { inspect } = require('util');

const { RPError, OPError } = require('./errors');
const now = require('./helpers/unix_timestamp');
const { authenticatedPost } = require('./helpers/client');
const processResponse = require('./helpers/process_response');
const TokenSet = require('./token_set');

class DeviceFlowHandle {
  #aborted;
  #client;
  #clientAssertionPayload;
  #DPoP;
  #exchangeBody;
  #expires_at;
  #interval;
  #maxAge;
  #response;
  constructor({ client, exchangeBody, clientAssertionPayload, response, maxAge, DPoP }) {
    ['verification_uri', 'user_code', 'device_code'].forEach((prop) => {
      if (typeof response[prop] !== 'string' || !response[prop]) {
        throw new RPError(
          `expected ${prop} string to be returned by Device Authorization Response, got %j`,
          response[prop],
        );
      }
    });

    if (!Number.isSafeInteger(response.expires_in)) {
      throw new RPError(
        'expected expires_in number to be returned by Device Authorization Response, got %j',
        response.expires_in,
      );
    }

    this.#expires_at = now() + response.expires_in;
    this.#client = client;
    this.#DPoP = DPoP;
    this.#maxAge = maxAge;
    this.#exchangeBody = exchangeBody;
    this.#clientAssertionPayload = clientAssertionPayload;
    this.#response = response;
    this.#interval = response.interval * 1000 || 5000;
  }

  abort() {
    this.#aborted = true;
  }

  async poll({ signal } = {}) {
    if ((signal && signal.aborted) || this.#aborted) {
      throw new RPError('polling aborted');
    }

    if (this.expired()) {
      throw new RPError(
        'the device code %j has expired and the device authorization session has concluded',
        this.device_code,
      );
    }

    await new Promise((resolve) => setTimeout(resolve, this.#interval));

    const response = await authenticatedPost.call(
      this.#client,
      'token',
      {
        form: {
          ...this.#exchangeBody,
          grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
          device_code: this.device_code,
        },
        responseType: 'json',
      },
      { clientAssertionPayload: this.#clientAssertionPayload, DPoP: this.#DPoP },
    );

    let responseBody;
    try {
      responseBody = processResponse(response);
    } catch (err) {
      switch (err instanceof OPError && err.error) {
        case 'slow_down':
          this.#interval += 5000;
        case 'authorization_pending':
          return this.poll({ signal });
        default:
          throw err;
      }
    }

    const tokenset = new TokenSet(responseBody);

    if ('id_token' in tokenset) {
      await this.#client.decryptIdToken(tokenset);
      await this.#client.validateIdToken(tokenset, undefined, 'token', this.#maxAge);
    }

    return tokenset;
  }

  get device_code() {
    return this.#response.device_code;
  }

  get user_code() {
    return this.#response.user_code;
  }

  get verification_uri() {
    return this.#response.verification_uri;
  }

  get verification_uri_complete() {
    return this.#response.verification_uri_complete;
  }

  get expires_in() {
    return Math.max.apply(null, [this.#expires_at - now(), 0]);
  }

  expired() {
    return this.expires_in === 0;
  }

  /* istanbul ignore next */
  [inspect.custom]() {
    return `${this.constructor.name} ${inspect(this.#response, {
      depth: Infinity,
      colors: process.stdout.isTTY,
      compact: false,
      sorted: true,
    })}`;
  }
}

module.exports = DeviceFlowHandle;
<commit_msg>refactor: device flow poll to use client.grant<commit_after>const { inspect } = require('util');

const { RPError, OPError } = require('./errors');
const now = require('./helpers/unix_timestamp');
const { authenticatedPost } = require('./helpers/client');
const processResponse = require('./helpers/process_response');
const TokenSet = require('./token_set');

class DeviceFlowHandle {
  #aborted;
  #client;
  #clientAssertionPayload;
  #DPoP;
  #exchangeBody;
  #expires_at;
  #interval;
  #maxAge;
  #response;
  constructor({ client, exchangeBody, clientAssertionPayload, response, maxAge, DPoP }) {
    ['verification_uri', 'user_code', 'device_code'].forEach((prop) => {
      if (typeof response[prop] !== 'string' || !response[prop]) {
        throw new RPError(
          `expected ${prop} string to be returned by Device Authorization Response, got %j`,
          response[prop],
        );
      }
    });

    if (!Number.isSafeInteger(response.expires_in)) {
      throw new RPError(
        'expected expires_in number to be returned by Device Authorization Response, got %j',
        response.expires_in,
      );
    }

    this.#expires_at = now() + response.expires_in;
    this.#client = client;
    this.#DPoP = DPoP;
    this.#maxAge = maxAge;
    this.#exchangeBody = exchangeBody;
    this.#clientAssertionPayload = clientAssertionPayload;
    this.#response = response;
    this.#interval = response.interval * 1000 || 5000;
  }

  abort() {
    this.#aborted = true;
  }

  async poll({ signal } = {}) {
    if ((signal && signal.aborted) || this.#aborted) {
      throw new RPError('polling aborted');
    }

    if (this.expired()) {
      throw new RPError(
        'the device code %j has expired and the device authorization session has concluded',
        this.device_code,
      );
    }

    await new Promise((resolve) => setTimeout(resolve, this.#interval));

    let tokenset;
    try {
      tokenset = await this.#client.grant(
        {
          ...this.#exchangeBody,
          grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
          device_code: this.device_code,
        },
        { clientAssertionPayload: this.#clientAssertionPayload, DPoP: this.#DPoP },
      );
    } catch (err) {
      switch (err instanceof OPError && err.error) {
        case 'slow_down':
          this.#interval += 5000;
        case 'authorization_pending':
          return this.poll({ signal });
        default:
          throw err;
      }
    }

    if ('id_token' in tokenset) {
      await this.#client.decryptIdToken(tokenset);
      await this.#client.validateIdToken(tokenset, undefined, 'token', this.#maxAge);
    }

    return tokenset;
  }

  get device_code() {
    return this.#response.device_code;
  }

  get user_code() {
    return this.#response.user_code;
  }

  get verification_uri() {
    return this.#response.verification_uri;
  }

  get verification_uri_complete() {
    return this.#response.verification_uri_complete;
  }

  get expires_in() {
    return Math.max.apply(null, [this.#expires_at - now(), 0]);
  }

  expired() {
    return this.expires_in === 0;
  }

  /* istanbul ignore next */
  [inspect.custom]() {
    return `${this.constructor.name} ${inspect(this.#response, {
      depth: Infinity,
      colors: process.stdout.isTTY,
      compact: false,
      sorted: true,
    })}`;
  }
}

module.exports = DeviceFlowHandle;
<|endoftext|>


<commit_before>/*jshint -W117 */
/* global
 Velocity:true
 */

Velocity = Velocity || {};

(function () {
  'use strict';

//////////////////////////////////////////////////////////////////////
// Public Methods
//

    /**
     * Mirrors can share the same codebase as the main process. This method will run provided code
     * inside a mirror only.
     *
     * where: client / server
     *
     * @method onTest
     * @param {Function} code
     *
     */
    Velocity.onTest = function (code) {
      Meteor.call('velocity/isMirror', function (err, res) {
        if (res) {
          code();
        }
      });
    };

    if (Meteor.isServer) {
      /**
       * @method
       * @see velocity/setOption
       */
      Velocity.setOption = function (name, value) {
        Meteor.call('velocity/setOption', name, value);
      };

      /**
       * @see velocity/setOptions
       */
      Velocity.setOptions = function (options) {
        Meteor.call('velocity/setOptions', options);
      };

      /**
       * @see velocity/getOption
       */
      Velocity.getOption = function (name) {
        Meteor.call('velocity/getOption', name);
      };
    }

    Meteor.methods({
      /**
       * Set a option.
       * @method velocity/setOption
       * @param name The name of the option.
       * @param value The value of the option.
       */
      'velocity/setOption': function (name, value) {
        check(name, String);
        check(value, Match.Any);

        VelocityOptions.upsert(
          {name: name},
          {$set: {name: name, value: value}}
        );
      },

      /**
       * Set multiple options.
       * @method velocity/setOptions
       * @param options Hash with options (name: value).
       */
      'velocity/setOptions': function (options) {
        check(options, Object);

        for (var name in options) {
          if (options.hasOwnProperty(name)) {
            Meteor.call('velocity/setOption', name, options[name]);
          }
        }
      },

      /**
       * Get a option
       * @method velocity/getOption
       * @param name The name of the option.
       * @returns {*} The value of the option or null.
       */
      'velocity/getOption': function (name) {
        check(name, String);

        var option = VelocityOptions.findOne({name: name});
        return option ? option.value : null;
      }
    });
})();
<commit_msg>expose VELOCITY environment variable as method<commit_after>/*jshint -W117 */
/* global
 Velocity:true
 */

Velocity = Velocity || {};

(function () {
  'use strict';

//////////////////////////////////////////////////////////////////////
// Public Methods
//

    /**
     * Mirrors can share the same codebase as the main process. This method will run provided code
     * inside a mirror only.
     *
     * where: client / server
     *
     * @method onTest
     * @param {Function} code
     *
     */
    Velocity.onTest = function (code) {
      Meteor.call('velocity/isMirror', function (err, res) {
        if (res) {
          code();
        }
      });
    };

    if (Meteor.isServer) {
      /**
       * @method
       * @see velocity/setOption
       */
      Velocity.setOption = function (name, value) {
        Meteor.call('velocity/setOption', name, value);
      };

      /**
       * @see velocity/setOptions
       */
      Velocity.setOptions = function (options) {
        Meteor.call('velocity/setOptions', options);
      };

      /**
       * @see velocity/getOption
       */
      Velocity.getOption = function (name) {
        Meteor.call('velocity/getOption', name);
      };
    }

    Meteor.methods({
      /**
       * Set a option.
       * @method velocity/setOption
       * @param name The name of the option.
       * @param value The value of the option.
       */
      'velocity/setOption': function (name, value) {
        check(name, String);
        check(value, Match.Any);

        VelocityOptions.upsert(
          {name: name},
          {$set: {name: name, value: value}}
        );
      },

      /**
       * Set multiple options.
       * @method velocity/setOptions
       * @param options Hash with options (name: value).
       */
      'velocity/setOptions': function (options) {
        check(options, Object);

        for (var name in options) {
          if (options.hasOwnProperty(name)) {
            Meteor.call('velocity/setOption', name, options[name]);
          }
        }
      },

      /**
       * Get a option
       * @method velocity/getOption
       * @param name The name of the option.
       * @returns {*} The value of the option or null.
       */
      'velocity/getOption': function (name) {
        check(name, String);

        var option = VelocityOptions.findOne({name: name});
        return option ? option.value : null;
      },

      /**
       * Exposes the VELOCITY flag
       *
       * @method velocity/isEnabled
       */
      'velocity/isEnabled': function () {
        if (process.env.VELOCITY === undefined) {
          return true;
        } else {
          return !!parseInt(process.env.VELOCITY);
        }
      }
    });
})();
<|endoftext|>


<commit_before>// Styles
import '../../stylus/components/_autocompletes.styl'

// Extensions
import VSelect, { defaultMenuProps as VSelectMenuProps } from '../VSelect/VSelect'
import VTextField from '../VTextField/VTextField'

// Utils
import { keyCodes } from '../../util/helpers'

const defaultMenuProps = {
  ...VSelectMenuProps,
  offsetY: true,
  offsetOverflow: true,
  transition: false
}

/* @vue/component */
export default VSelect.extend({
  name: 'v-autocomplete',

  props: {
    allowOverflow: {
      type: Boolean,
      default: true
    },
    browserAutocomplete: {
      type: String,
      default: 'off'
    },
    filter: {
      type: Function,
      default: (item, queryText, itemText) => {
        return itemText.toLocaleLowerCase().indexOf(queryText.toLocaleLowerCase()) > -1
      }
    },
    hideNoData: Boolean,
    noFilter: Boolean,
    searchInput: {
      default: undefined
    },
    menuProps: {
      type: VSelect.options.props.menuProps.type,
      default: () => defaultMenuProps
    },
    autoSelectFirst: {
      type: Boolean,
      default: false
    }
  },

  data: vm => ({
    attrsInput: null,
    lazySearch: vm.searchInput
  }),

  computed: {
    classes () {
      return Object.assign({}, VSelect.options.computed.classes.call(this), {
        'v-autocomplete': true,
        'v-autocomplete--is-selecting-index': this.selectedIndex > -1
      })
    },
    computedItems () {
      return this.filteredItems
    },
    selectedValues () {
      return this.selectedItems.map(item => this.getValue(item))
    },
    hasDisplayedItems () {
      return this.hideSelected
        ? this.filteredItems.some(item => !this.hasItem(item))
        : this.filteredItems.length > 0
    },
    /**
     * The range of the current input text
     *
     * @return {Number}
     */
    currentRange () {
      if (this.selectedItem == null) return 0

      return this.getText(this.selectedItem).toString().length
    },
    filteredItems () {
      if (!this.isSearching || this.noFilter || this.internalSearch == null) return this.allItems

      return this.allItems.filter(item => this.filter(item, this.internalSearch.toString(), this.getText(item).toString()))
    },
    internalSearch: {
      get () {
        return this.lazySearch
      },
      set (val) {
        this.lazySearch = val

        this.$emit('update:searchInput', val)
      }
    },
    isAnyValueAllowed () {
      return false
    },
    isDirty () {
      return this.searchIsDirty || this.selectedItems.length > 0
    },
    isSearching () {
      if (this.multiple) return this.searchIsDirty

      return (
        this.searchIsDirty &&
        this.internalSearch !== this.getText(this.selectedItem)
      )
    },
    menuCanShow () {
      if (!this.isFocused) return false

      return this.hasDisplayedItems || !this.hideNoData
    },
    $_menuProps () {
      const props = VSelect.options.computed.$_menuProps.call(this)
      props.contentClass = `v-autocomplete__content ${props.contentClass || ''}`.trim()
      return {
        ...defaultMenuProps,
        ...props
      }
    },
    searchIsDirty () {
      return this.internalSearch != null &&
        this.internalSearch !== ''
    },
    selectedItem () {
      if (this.multiple) return null

      return this.selectedItems.find(i => {
        return this.valueComparator(this.getValue(i), this.getValue(this.internalValue))
      })
    },
    listData () {
      const data = VSelect.options.computed.listData.call(this)

      Object.assign(data.props, {
        items: this.virtualizedItems,
        noFilter: (
          this.noFilter ||
          !this.isSearching ||
          !this.filteredItems.length
        ),
        searchInput: this.internalSearch
      })

      return data
    }
  },

  watch: {
    filteredItems (val) {
      this.onFilteredItemsChanged(val)
    },
    internalValue () {
      this.setSearch()
    },
    isFocused (val) {
      if (val) {
        this.$refs.input &&
          this.$refs.input.select()
      } else {
        this.updateSelf()
      }
    },
    isMenuActive (val) {
      if (val || !this.hasSlot) return

      this.lazySearch = null
    },
    items (val, oldVal) {
      // If we are focused, the menu
      // is not active, hide no data is enabled,
      // and items change
      // User is probably async loading
      // items, try to activate the menu
      if (
        !(oldVal && oldVal.length) &&
        this.hideNoData &&
        this.isFocused &&
        !this.isMenuActive &&
        val.length
      ) this.activateMenu()
    },
    searchInput (val) {
      this.lazySearch = val
    },
    internalSearch (val) {
      this.onInternalSearchChanged(val)
    }
  },

  created () {
    this.setSearch()
  },

  methods: {
    onFilteredItemsChanged (val) {
      this.setMenuIndex(-1)

      this.$nextTick(() => {
        this.setMenuIndex(val.length > 0 && (val.length === 1 || this.autoSelectFirst) ? 0 : -1)
      })
    },
    onInternalSearchChanged (val) {
      this.updateMenuDimensions()
    },
    updateMenuDimensions () {
      if (this.isMenuActive &&
        this.$refs.menu
      ) {
        this.$refs.menu.updateDimensions()
      }
    },
    changeSelectedIndex (keyCode) {
      // Do not allow changing of selectedIndex
      // when search is dirty
      if (this.searchIsDirty) return

      if (![
        keyCodes.backspace,
        keyCodes.left,
        keyCodes.right,
        keyCodes.delete
      ].includes(keyCode)) return

      const indexes = this.selectedItems.length - 1

      if (keyCode === keyCodes.left) {
        this.selectedIndex = this.selectedIndex === -1
          ? indexes
          : this.selectedIndex - 1
      } else if (keyCode === keyCodes.right) {
        this.selectedIndex = this.selectedIndex >= indexes
          ? -1
          : this.selectedIndex + 1
      } else if (this.selectedIndex === -1) {
        this.selectedIndex = indexes
        return
      }

      const currentItem = this.selectedItems[this.selectedIndex]

      if ([
        keyCodes.backspace,
        keyCodes.delete
      ].includes(keyCode) &&
        !this.getDisabled(currentItem)
      ) {
        const newIndex = this.selectedIndex === indexes
          ? this.selectedIndex - 1
          : this.selectedItems[this.selectedIndex + 1]
            ? this.selectedIndex
            : -1

        if (newIndex === -1) {
          this.setValue(this.multiple ? [] : undefined)
        } else {
          this.selectItem(currentItem)
        }

        this.selectedIndex = newIndex
      }
    },
    clearableCallback () {
      this.internalSearch = undefined

      VSelect.options.methods.clearableCallback.call(this)
    },
    genInput () {
      const input = VTextField.options.methods.genInput.call(this)

      input.data.attrs.role = 'combobox'
      input.data.domProps.value = this.internalSearch

      return input
    },
    genSelections () {
      return this.hasSlot || this.multiple
        ? VSelect.options.methods.genSelections.call(this)
        : []
    },
    onClick () {
      if (this.isDisabled) return

      this.selectedIndex > -1
        ? (this.selectedIndex = -1)
        : this.onFocus()

      this.activateMenu()
    },
    onEnterDown () {
      // Avoid invoking this method
      // will cause updateSelf to
      // be called emptying search
    },
    onInput (e) {
      if (this.selectedIndex > -1) return

      // If typing and menu is not currently active
      if (e.target.value) {
        this.activateMenu()
        if (!this.isAnyValueAllowed) this.setMenuIndex(0)
      }

      this.mask && this.resetSelections(e.target)
      this.internalSearch = e.target.value
      this.badInput = e.target.validity && e.target.validity.badInput
    },
    onKeyDown (e) {
      const keyCode = e.keyCode

      VSelect.options.methods.onKeyDown.call(this, e)

      // The ordering is important here
      // allows new value to be updated
      // and then moves the index to the
      // proper location
      this.changeSelectedIndex(keyCode)
    },
    onTabDown (e) {
      VSelect.options.methods.onTabDown.call(this, e)
      this.updateSelf()
    },
    setSelectedItems () {
      VSelect.options.methods.setSelectedItems.call(this)

      // #4273 Don't replace if searching
      // #4403 Don't replace if focused
      if (!this.isFocused) this.setSearch()
    },
    setSearch () {
      // Wait for nextTick so selectedItem
      // has had time to update
      this.$nextTick(() => {
        this.internalSearch = (
          this.multiple &&
          this.internalSearch
        )
          ? this.internalSearch
          : (
            !this.selectedItems.length ||
            this.multiple ||
            this.hasSlot
          )
            ? null
            : this.getText(this.selectedItem)
      })
    },
    updateSelf () {
      this.updateAutocomplete()
    },
    updateAutocomplete () {
      if (!this.searchIsDirty &&
        !this.internalValue
      ) return

      if (!this.valueComparator(
        this.internalSearch,
        this.getValue(this.internalValue)
      )) {
        this.setSearch()
      }
    },
    hasItem (item) {
      return this.selectedValues.indexOf(this.getValue(item)) > -1
    }
  }
})
<commit_msg>fix(VAutocomplete): remove search when tabbing out of input<commit_after>// Styles
import '../../stylus/components/_autocompletes.styl'

// Extensions
import VSelect, { defaultMenuProps as VSelectMenuProps } from '../VSelect/VSelect'
import VTextField from '../VTextField/VTextField'

// Utils
import { keyCodes } from '../../util/helpers'

const defaultMenuProps = {
  ...VSelectMenuProps,
  offsetY: true,
  offsetOverflow: true,
  transition: false
}

/* @vue/component */
export default VSelect.extend({
  name: 'v-autocomplete',

  props: {
    allowOverflow: {
      type: Boolean,
      default: true
    },
    browserAutocomplete: {
      type: String,
      default: 'off'
    },
    filter: {
      type: Function,
      default: (item, queryText, itemText) => {
        return itemText.toLocaleLowerCase().indexOf(queryText.toLocaleLowerCase()) > -1
      }
    },
    hideNoData: Boolean,
    noFilter: Boolean,
    searchInput: {
      default: undefined
    },
    menuProps: {
      type: VSelect.options.props.menuProps.type,
      default: () => defaultMenuProps
    },
    autoSelectFirst: {
      type: Boolean,
      default: false
    }
  },

  data: vm => ({
    attrsInput: null,
    lazySearch: vm.searchInput
  }),

  computed: {
    classes () {
      return Object.assign({}, VSelect.options.computed.classes.call(this), {
        'v-autocomplete': true,
        'v-autocomplete--is-selecting-index': this.selectedIndex > -1
      })
    },
    computedItems () {
      return this.filteredItems
    },
    selectedValues () {
      return this.selectedItems.map(item => this.getValue(item))
    },
    hasDisplayedItems () {
      return this.hideSelected
        ? this.filteredItems.some(item => !this.hasItem(item))
        : this.filteredItems.length > 0
    },
    /**
     * The range of the current input text
     *
     * @return {Number}
     */
    currentRange () {
      if (this.selectedItem == null) return 0

      return this.getText(this.selectedItem).toString().length
    },
    filteredItems () {
      if (!this.isSearching || this.noFilter || this.internalSearch == null) return this.allItems

      return this.allItems.filter(item => this.filter(item, this.internalSearch.toString(), this.getText(item).toString()))
    },
    internalSearch: {
      get () {
        return this.lazySearch
      },
      set (val) {
        this.lazySearch = val

        this.$emit('update:searchInput', val)
      }
    },
    isAnyValueAllowed () {
      return false
    },
    isDirty () {
      return this.searchIsDirty || this.selectedItems.length > 0
    },
    isSearching () {
      if (this.multiple) return this.searchIsDirty

      return (
        this.searchIsDirty &&
        this.internalSearch !== this.getText(this.selectedItem)
      )
    },
    menuCanShow () {
      if (!this.isFocused) return false

      return this.hasDisplayedItems || !this.hideNoData
    },
    $_menuProps () {
      const props = VSelect.options.computed.$_menuProps.call(this)
      props.contentClass = `v-autocomplete__content ${props.contentClass || ''}`.trim()
      return {
        ...defaultMenuProps,
        ...props
      }
    },
    searchIsDirty () {
      return this.internalSearch != null &&
        this.internalSearch !== ''
    },
    selectedItem () {
      if (this.multiple) return null

      return this.selectedItems.find(i => {
        return this.valueComparator(this.getValue(i), this.getValue(this.internalValue))
      })
    },
    listData () {
      const data = VSelect.options.computed.listData.call(this)

      Object.assign(data.props, {
        items: this.virtualizedItems,
        noFilter: (
          this.noFilter ||
          !this.isSearching ||
          !this.filteredItems.length
        ),
        searchInput: this.internalSearch
      })

      return data
    }
  },

  watch: {
    filteredItems (val) {
      this.onFilteredItemsChanged(val)
    },
    internalValue () {
      this.setSearch()
    },
    isFocused (val) {
      if (val) {
        this.$refs.input &&
          this.$refs.input.select()
      } else {
        this.updateSelf()
      }
    },
    isMenuActive (val) {
      if (val || !this.hasSlot) return

      this.lazySearch = null
    },
    items (val, oldVal) {
      // If we are focused, the menu
      // is not active, hide no data is enabled,
      // and items change
      // User is probably async loading
      // items, try to activate the menu
      if (
        !(oldVal && oldVal.length) &&
        this.hideNoData &&
        this.isFocused &&
        !this.isMenuActive &&
        val.length
      ) this.activateMenu()
    },
    searchInput (val) {
      this.lazySearch = val
    },
    internalSearch (val) {
      this.onInternalSearchChanged(val)
    }
  },

  created () {
    this.setSearch()
  },

  methods: {
    onFilteredItemsChanged (val) {
      this.setMenuIndex(-1)

      this.$nextTick(() => {
        this.setMenuIndex(val.length > 0 && (val.length === 1 || this.autoSelectFirst) ? 0 : -1)
      })
    },
    onInternalSearchChanged (val) {
      this.updateMenuDimensions()
    },
    updateMenuDimensions () {
      if (this.isMenuActive &&
        this.$refs.menu
      ) {
        this.$refs.menu.updateDimensions()
      }
    },
    changeSelectedIndex (keyCode) {
      // Do not allow changing of selectedIndex
      // when search is dirty
      if (this.searchIsDirty) return

      if (![
        keyCodes.backspace,
        keyCodes.left,
        keyCodes.right,
        keyCodes.delete
      ].includes(keyCode)) return

      const indexes = this.selectedItems.length - 1

      if (keyCode === keyCodes.left) {
        this.selectedIndex = this.selectedIndex === -1
          ? indexes
          : this.selectedIndex - 1
      } else if (keyCode === keyCodes.right) {
        this.selectedIndex = this.selectedIndex >= indexes
          ? -1
          : this.selectedIndex + 1
      } else if (this.selectedIndex === -1) {
        this.selectedIndex = indexes
        return
      }

      const currentItem = this.selectedItems[this.selectedIndex]

      if ([
        keyCodes.backspace,
        keyCodes.delete
      ].includes(keyCode) &&
        !this.getDisabled(currentItem)
      ) {
        const newIndex = this.selectedIndex === indexes
          ? this.selectedIndex - 1
          : this.selectedItems[this.selectedIndex + 1]
            ? this.selectedIndex
            : -1

        if (newIndex === -1) {
          this.setValue(this.multiple ? [] : undefined)
        } else {
          this.selectItem(currentItem)
        }

        this.selectedIndex = newIndex
      }
    },
    clearableCallback () {
      this.internalSearch = undefined

      VSelect.options.methods.clearableCallback.call(this)
    },
    genInput () {
      const input = VTextField.options.methods.genInput.call(this)

      input.data.attrs.role = 'combobox'
      input.data.domProps.value = this.internalSearch

      return input
    },
    genSelections () {
      return this.hasSlot || this.multiple
        ? VSelect.options.methods.genSelections.call(this)
        : []
    },
    onClick () {
      if (this.isDisabled) return

      this.selectedIndex > -1
        ? (this.selectedIndex = -1)
        : this.onFocus()

      this.activateMenu()
    },
    onEnterDown () {
      // Avoid invoking this method
      // will cause updateSelf to
      // be called emptying search
    },
    onInput (e) {
      if (this.selectedIndex > -1) return

      // If typing and menu is not currently active
      if (e.target.value) {
        this.activateMenu()
        if (!this.isAnyValueAllowed) this.setMenuIndex(0)
      }

      this.mask && this.resetSelections(e.target)
      this.internalSearch = e.target.value
      this.badInput = e.target.validity && e.target.validity.badInput
    },
    onKeyDown (e) {
      const keyCode = e.keyCode

      VSelect.options.methods.onKeyDown.call(this, e)

      // The ordering is important here
      // allows new value to be updated
      // and then moves the index to the
      // proper location
      this.changeSelectedIndex(keyCode)
    },
    onTabDown (e) {
      VSelect.options.methods.onTabDown.call(this, e)
      this.updateSelf()
    },
    setSelectedItems () {
      VSelect.options.methods.setSelectedItems.call(this)

      // #4273 Don't replace if searching
      // #4403 Don't replace if focused
      if (!this.isFocused) this.setSearch()
    },
    setSearch () {
      // Wait for nextTick so selectedItem
      // has had time to update
      this.$nextTick(() => {
        this.internalSearch = (
          this.multiple &&
          this.internalSearch &&
          this.isMenuActive
        )
          ? this.internalSearch
          : (
            !this.selectedItems.length ||
            this.multiple ||
            this.hasSlot
          )
            ? null
            : this.getText(this.selectedItem)
      })
    },
    updateSelf () {
      this.updateAutocomplete()
    },
    updateAutocomplete () {
      if (!this.searchIsDirty &&
        !this.internalValue
      ) return

      if (!this.valueComparator(
        this.internalSearch,
        this.getValue(this.internalValue)
      )) {
        this.setSearch()
      }
    },
    hasItem (item) {
      return this.selectedValues.indexOf(this.getValue(item)) > -1
    }
  }
})
<|endoftext|>


<commit_before>var meshColors =  {
  selected: '#DDA0DD', //Purple
  unclaimed: '#E6FF00', //Green
  claimed: '#F0054C', //Pink
};

var makeMap = function(style) {
  var australia_coord = [-29.8650, 131.2094];
  var map = L.map('map').setView(australia_coord, 4);

  var tileLayer = L.tileLayer('http://{s}.tiles.wmflabs.org/bw-mapnik/{z}/{x}/{y}.png', {
      attribution: '© OpenStreetMap contributors'
  }).addTo(map);

  var styleFor = function(feature) {
    var color = style.unclaimed
    if (feature.properties.selected) {
      color = style.selected
    }
    return {
      weight: 2,
      opacity: 1,
      color: 'white',
      dashArray: '3',
      fillColor: color,
      fillOpacity: 0.5,
    }
  }

  var meshInteractions = function() {
    var reStyle = function(mesh, style) {
      mesh.setStyle(style);
      if (!L.Browser.ie && !L.Browser.opera) {
        mesh.bringToFront();
      }
    };

    var selections = {};
    var highlightStyle = {
        weight: 3,
        color: '#666',
        dashArray: '',
        fillOpacity: 0.9,
    };

    return {
      selections: selections,
      mouseover: function(e) {
        reStyle(e.target, highlightStyle);
      },
      mouseout: function(e) {
        reStyle(e.target, styleFor(e.target.feature));
      },
      click: function(e) {
        var mesh = e.target;
        if (e.target.feature.properties.selected) {
          e.target.feature.properties.selected = false;
          selections[e.target.feature.properties.slug] = false;
        } else {
          e.target.feature.properties.selected = true;
          selections[e.target.feature.properties.slug] = true;
        }
        reStyle(mesh, styleFor(mesh.feature));
      },
    };
  }();

  return {
    render: function(features) {
      var onEachFeatureCB = function(feature, layer) {
        layer.on(meshInteractions)
      }

      var mesh_boxes = L.geoJson(
                      {"type": 'FeatureCollection', "features": features},
                      { style: styleFor, onEachFeature: onEachFeatureCB }
                    ).addTo(map);

      map.fitBounds(mesh_boxes.getBounds());
    },
    clear: function() {
        map.eachLayer(function(layer) {
          if (layer != tileLayer) {
            map.removeLayer(layer)
          }
        });
    },
    blocks: {
      newlySelected: function() {
        var newlySelected = []
        for(var meshId in meshInteractions.selections) {
          if(meshInteractions.selections[meshId]) {
            newlySelected.push(meshId);
          }
        }

        return newlySelected;
      },
      cleared: function() {
        var cleared = []
        for(var meshId in meshInteractions.selections) {
          if(meshInteractions.selections[meshId] === false) {
            cleared.push(meshId);
          }
        }

        return cleared;
      }
    }
  };
}

var getUrlParameter = function getUrlParameter(sParam) {
    var sPageURL = decodeURIComponent(window.location.search.substring(1)),
        sURLVariables = sPageURL.split('&'),
        sParameterName,
        i;

    for (i = 0; i < sURLVariables.length; i++) {
        sParameterName = sURLVariables[i].split('=');

        if (sParameterName[0] === sParam) {
            return sParameterName[1] === undefined ? true : sParameterName[1];
        }
    }
}

$('#map').height($(window).height() - $('.header').height() - 190);
$('#map').width($(window).width());
var map = makeMap(meshColors);
var electorateId = getUrlParameter('electorate');
if (electorateId) {
  $.getJSON('/electorate/' + getUrlParameter('electorate') + '/meshblocks', map.render);
}
<commit_msg>fix mouse over error on meshblocks<commit_after>var meshColors =  {
  selected: '#DDA0DD', //Purple
  unclaimed: '#E6FF00', //Green
  claimed: '#F0054C', //Pink
};

var makeMap = function(style) {
  var australia_coord = [-29.8650, 131.2094];
  var map = L.map('map').setView(australia_coord, 4);

  var tileLayer = L.tileLayer('http://{s}.tiles.wmflabs.org/bw-mapnik/{z}/{x}/{y}.png', {
      attribution: '© OpenStreetMap contributors'
  }).addTo(map);

  var styleFor = function(feature) {
    var color = style.unclaimed
    if (feature.properties.selected) {
      color = style.selected
    }
    return {
      weight: 2,
      opacity: 1,
      color: 'white',
      dashArray: '3',
      fillColor: color,
      fillOpacity: 0.5,
    }
  }

  var meshInteractions = function() {
    var selections = {};
    var highlightStyle = {
        weight: 3,
        color: '#666',
        dashArray: '',
        fillOpacity: 0.9,
    };

    return {
      mouseover: function(e) {
      	e.target.setStyle(highlightStyle);
      },
      mouseout: function(e) {
        e.target.setStyle(styleFor(e.target.feature));
      },
      click: function(e) {
        var mesh = e.target;
        if (e.target.feature.properties.selected) {
          e.target.feature.properties.selected = false;
          selections[e.target.feature.properties.slug] = false;
        } else {
          e.target.feature.properties.selected = true;
          selections[e.target.feature.properties.slug] = true;
        }
        e.target.setStyle(styleFor(mesh.feature));
      },
      blocks: {
	      newlySelected: function() {
	        var newlySelected = []
	        for(var meshId in selections) {
	          if(selections[meshId]) {
	            newlySelected.push(meshId);
	          }
	        }

	        return newlySelected;
	      },
	      cleared: function() {
	        var cleared = []
	        for(var meshId in selections) {
	          if(selections[meshId] === false) {
	            cleared.push(meshId);
	          }
	        }

	        return cleared;
	      }
	    }
      };
  }();

  return {
    render: function(features) {
      var onEachFeatureCB = function(feature, layer) {
        layer.on(meshInteractions)
      }

      var mesh_boxes = L.geoJson(
                      {"type": 'FeatureCollection', "features": features},
                      { style: styleFor, onEachFeature: onEachFeatureCB }
                    ).addTo(map);

      map.fitBounds(mesh_boxes.getBounds());
    },
    clear: function() {
        map.eachLayer(function(layer) {
          if (layer != tileLayer) {
            map.removeLayer(layer)
          }
        });
    },
    blocks: meshInteractions.blocks
  };
}

var getUrlParameter = function getUrlParameter(sParam) {
    var sPageURL = decodeURIComponent(window.location.search.substring(1)),
        sURLVariables = sPageURL.split('&'),
        sParameterName,
        i;

    for (i = 0; i < sURLVariables.length; i++) {
        sParameterName = sURLVariables[i].split('=');

        if (sParameterName[0] === sParam) {
            return sParameterName[1] === undefined ? true : sParameterName[1];
        }
    }
}

$('#map').height($(window).height() - $('.header').height() - 190);
$('#map').width($(window).width());
var map = makeMap(meshColors);
var electorateId = getUrlParameter('electorate');
if (electorateId) {
  $.getJSON('/electorate/' + getUrlParameter('electorate') + '/meshblocks', map.render);
}
<|endoftext|>


<commit_before>/**
* @license Apache-2.0
*
* Copyright (c) 2019 The Stdlib Authors.
*
* 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.
*/

'use strict';

/*
* When adding modules to the namespace, ensure that they are added in alphabetical order according to module name.
*/

// MODULES //

var setReadOnly = require( '@stdlib/utils/define-read-only-property' );

// MAIN //

/**
* Top-level namespace.
*
* @namespace ns
*/
var ns = {};

/**
* @name iterAbs
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/iter/special/abs}
*/
setReadOnly( ns, 'iterAbs', require( '@stdlib/math/iter/special/abs' ) );

/**
* @name iterAbs2
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/iter/special/abs2}
*/
setReadOnly( ns, 'iterAbs2', require( '@stdlib/math/iter/special/abs2' ) );

/**
* @name iterAcos
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/iter/special/acos}
*/
setReadOnly( ns, 'iterAcos', require( '@stdlib/math/iter/special/acos' ) );

/**
* @name iterAcosh
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/iter/special/acosh}
*/
setReadOnly( ns, 'iterAcosh', require( '@stdlib/math/iter/special/acosh' ) );

/**
* @name iterAdd
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/iter/special/add}
*/
setReadOnly( ns, 'iterAdd', require( '@stdlib/math/iter/special/add' ) );

/**
* @name iterAsin
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/iter/special/asin}
*/
setReadOnly( ns, 'iterAsin', require( '@stdlib/math/iter/special/asin' ) );

/**
* @name iterCos
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/iter/special/cos}
*/
setReadOnly( ns, 'iterCos', require( '@stdlib/math/iter/special/cos' ) );

/**
* @name iterDivide
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/iter/special/divide}
*/
setReadOnly( ns, 'iterDivide', require( '@stdlib/math/iter/special/divide' ) );

/**
* @name iterMod
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/iter/special/mod}
*/
setReadOnly( ns, 'iterMod', require( '@stdlib/math/iter/special/mod' ) );

/**
* @name iterMultiply
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/iter/special/multiply}
*/
setReadOnly( ns, 'iterMultiply', require( '@stdlib/math/iter/special/multiply' ) );

/**
* @name iterSin
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/iter/special/sin}
*/
setReadOnly( ns, 'iterSin', require( '@stdlib/math/iter/special/sin' ) );

/**
* @name iterSubtract
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/iter/special/subtract}
*/
setReadOnly( ns, 'iterSubtract', require( '@stdlib/math/iter/special/subtract' ) );

// EXPORTS //

module.exports = ns;
<commit_msg>Update namespace<commit_after>/**
* @license Apache-2.0
*
* Copyright (c) 2019 The Stdlib Authors.
*
* 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.
*/

'use strict';

/*
* When adding modules to the namespace, ensure that they are added in alphabetical order according to module name.
*/

// MODULES //

var setReadOnly = require( '@stdlib/utils/define-read-only-property' );

// MAIN //

/**
* Top-level namespace.
*
* @namespace ns
*/
var ns = {};

/**
* @name iterAbs
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/iter/special/abs}
*/
setReadOnly( ns, 'iterAbs', require( '@stdlib/math/iter/special/abs' ) );

/**
* @name iterAbs2
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/iter/special/abs2}
*/
setReadOnly( ns, 'iterAbs2', require( '@stdlib/math/iter/special/abs2' ) );

/**
* @name iterAcos
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/iter/special/acos}
*/
setReadOnly( ns, 'iterAcos', require( '@stdlib/math/iter/special/acos' ) );

/**
* @name iterAcosh
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/iter/special/acosh}
*/
setReadOnly( ns, 'iterAcosh', require( '@stdlib/math/iter/special/acosh' ) );

/**
* @name iterAdd
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/iter/special/add}
*/
setReadOnly( ns, 'iterAdd', require( '@stdlib/math/iter/special/add' ) );

/**
* @name iterAsin
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/iter/special/asin}
*/
setReadOnly( ns, 'iterAsin', require( '@stdlib/math/iter/special/asin' ) );

/**
* @name iterAsinh
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/iter/special/asinh}
*/
setReadOnly( ns, 'iterAsinh', require( '@stdlib/math/iter/special/asinh' ) );

/**
* @name iterCos
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/iter/special/cos}
*/
setReadOnly( ns, 'iterCos', require( '@stdlib/math/iter/special/cos' ) );

/**
* @name iterDivide
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/iter/special/divide}
*/
setReadOnly( ns, 'iterDivide', require( '@stdlib/math/iter/special/divide' ) );

/**
* @name iterMod
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/iter/special/mod}
*/
setReadOnly( ns, 'iterMod', require( '@stdlib/math/iter/special/mod' ) );

/**
* @name iterMultiply
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/iter/special/multiply}
*/
setReadOnly( ns, 'iterMultiply', require( '@stdlib/math/iter/special/multiply' ) );

/**
* @name iterSin
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/iter/special/sin}
*/
setReadOnly( ns, 'iterSin', require( '@stdlib/math/iter/special/sin' ) );

/**
* @name iterSubtract
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/iter/special/subtract}
*/
setReadOnly( ns, 'iterSubtract', require( '@stdlib/math/iter/special/subtract' ) );

// EXPORTS //

module.exports = ns;
<|endoftext|>


<commit_before>app.notification = {
  /**
   * The amount of time to allow to pass before the notification is
   * automatically hidden
   */
  timeout: 5000,

  /**
   * Requests permission to show desktop notifications
   */
  requestPermission: function(onSuccess, onError) {
    if (!this.hasDesktopPermission()) {
      var callback = $.proxy(function() {
        if (this.hasDesktopPermission()) {
          onSuccess();
        } else {
          onError();
        }
      }, this);

      if (window.webkitNotifications) {
        webkitNotifications.requestPermission(callback);
      } else if (window.Notification) {
        Notification.requestPermission(callback);
      }

      // Make sure the user notices the authorization
      app.notification.show("Please select Allow above to start using desktop notifications");
    }
  },

  /**
   * Determines whether the app currently has permission to generate desktop
   * notifications
   */
  hasDesktopPermission: function() {
    var hasPermission = false;
    if (window.webkitNotifications) {
      hasPermission = webkitNotifications.checkPermission() == 0;
    } else if (window.Notification) {
      hasPermission = Notification.permission == 'granted';
    }

    return hasPermission;
  },

  /**
   * Determines whether the app show be display messages as desktop notifications
   */
  useDesktopNotifications: function() {
    return this.hasDesktopPermission() && app.settings.get('useDesktopNotifications') == 'true';
  },

  /**
   * Shows a notification with the given message
   */
  show: function(message, options) {
    if (!options) { options = {desktop: false}; }

    if (options.desktop && this.useDesktopNotifications()) {
      var title = 'Google Hangouts';
      var icon = 'http://' + app.host + '/assets/images/google-hangouts-icon.png';
      var notification;

      if (window.webkitNotifications) {
        notification = webkitNotifications.createNotification(icon, title, message);
        notification.show();
        setTimeout($.proxy(notification.cancel, notification), this.timeout);
      } else {
        notification = new Notification(title, {icon: icon, body: message});
        setTimeout($.proxy(notification.close, notification), this.timeout);
      }
    } else {
      gapi.hangout.layout.displayNotice(message);
    }
  }
};<commit_msg>Fix desktop notification setting not always being tracked properly<commit_after>app.notification = {
  /**
   * The amount of time to allow to pass before the notification is
   * automatically hidden
   */
  timeout: 5000,

  /**
   * Requests permission to show desktop notifications
   */
  requestPermission: function(onSuccess, onError) {
    if (this.hasDesktopPermission()) {
      onSuccess();
    } else {
      var callback = $.proxy(function() {
        if (this.hasDesktopPermission()) {
          onSuccess();
        } else {
          onError();
        }
      }, this);

      if (window.webkitNotifications) {
        webkitNotifications.requestPermission(callback);
      } else if (window.Notification) {
        Notification.requestPermission(callback);
      }

      // Make sure the user notices the authorization
      app.notification.show("Please select Allow above to start using desktop notifications");
    }
  },

  /**
   * Determines whether the app currently has permission to generate desktop
   * notifications
   */
  hasDesktopPermission: function() {
    var hasPermission = false;
    if (window.webkitNotifications) {
      hasPermission = webkitNotifications.checkPermission() == 0;
    } else if (window.Notification) {
      hasPermission = Notification.permission == 'granted';
    }

    return hasPermission;
  },

  /**
   * Determines whether the app show be display messages as desktop notifications
   */
  useDesktopNotifications: function() {
    return this.hasDesktopPermission() && app.settings.get('useDesktopNotifications') == 'true';
  },

  /**
   * Shows a notification with the given message
   */
  show: function(message, options) {
    if (!options) { options = {desktop: false}; }

    if (options.desktop && this.useDesktopNotifications()) {
      var title = 'Google Hangouts';
      var icon = 'http://' + app.host + '/assets/images/google-hangouts-icon.png';
      var notification;

      if (window.webkitNotifications) {
        notification = webkitNotifications.createNotification(icon, title, message);
        notification.show();
        setTimeout($.proxy(notification.cancel, notification), this.timeout);
      } else {
        notification = new Notification(title, {icon: icon, body: message});
        setTimeout($.proxy(notification.close, notification), this.timeout);
      }
    } else {
      gapi.hangout.layout.displayNotice(message);
    }
  }
};<|endoftext|>


<commit_before>define([], function () {

    var undefined;

    // easing functions http://goo.gl/5HLl8
    Math.easeInOutQuad = function (t, b, c, d) {
        t /= d / 2;
        if (t < 1) {
            return c / 2 * t * t + b
        }
        t--;
        return -c / 2 * (t * (t - 2) - 1) + b;
    };

    // requestAnimationFrame for Smart Animating http://goo.gl/sx5sts
    var requestAnimationFrame = (function () {
        return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function (callback) {
            window.setTimeout(callback, 1000 / 60);
        };
    })();

    /***
     *
     * @param {String|HTMLElement} idOrElement
     * @param {Number} [offset=0]
     * @param {Number} [duration=500]
     * @param {Function} callback
     */
    return function (idOrElement, offset, duration, callback) {

        if (offset instanceof Function) {
            callback = offset;
            offset = 0;
        }

        if (duration instanceof Function) {
            callback = duration;
            duration = null;
        }

        duration = (duration == null) ? 500 : duration;
        offset = offset || 0;

        if (!idOrElement) {
            callback && callback();
            return;
        }

        var to = undefined,
            element;

        if (idOrElement instanceof Number) {
            to = idOrElement;
        } else if (typeof(idOrElement) === "string") {
            element = document.querySelector(idOrElement);
        } else if (idOrElement instanceof (window.HTMLElement || window.Element)) {
            element = idOrElement;
        }

        if (!element) {
            callback && callback();
            return;
        }

        // find the parent that has an overflow

        var parent = element.parentNode,
            computedStyle;

        while (parent) {
            if (parent.nodeType == 9) {
                return;
            }

            try {
                computedStyle = window.getComputedStyle(parent, null);
            } catch (e) {
            }

            if (computedStyle.overflowY == "auto" || computedStyle.overflowY == "scroll" || computedStyle.overflowX == "auto" || computedStyle.overflowX == "scroll") {
                break;
            }

            parent = parent.parentNode;
        }

        if (!parent) {
            callback && callback();
        }

        // check if the element is in the view
        var parentRect = parent.getBoundingClientRect(),
            rect = element.getBoundingClientRect(),
            scrollToX = null,
            scrollToY = null;

        if ((computedStyle.overflowX == "auto" || computedStyle.overflowX == "scroll") &&
            rect.left < parentRect.left || rect.left >= parentRect.left + parentRect.width
        ) {
            scrollToX = parent.scrollLeft + (rect.left - (parentRect.left + parentRect.width) / 2);
        }

        if ((computedStyle.overflowY == "auto" || computedStyle.overflowY == "scroll") &&
            rect.top < parentRect.top || rect.top >= parentRect.top + parentRect.height
        ) {

        }

        scrollTo(scrollToX, scrollToY);

        function scrollTo(toX) {

            // figure out if this is moz || IE because they use documentElement
            var startX = parent.scrollLeft,
                change = toX - startX,
                currentTime = 0,
                increment = 20;

            var animateScroll = function () {
                // increment the time
                currentTime += increment;
                // find the value with the quadratic in-out easing function

                if (toX != null) {
                    parent.scrollLeft = Math.easeInOutQuad(currentTime, startX, change, duration);
                }

                // do the animation unless its over
                if (currentTime < duration) {
                    requestAnimationFrame(animateScroll);
                } else {
                    callback && callback();
                }
            };

            animateScroll();
        }

    };

});<commit_msg>scroll current font family into view<commit_after>define([], function () {

    var undefined;

    // easing functions http://goo.gl/5HLl8
    Math.easeInOutQuad = function (t, b, c, d) {
        t /= d / 2;
        if (t < 1) {
            return c / 2 * t * t + b
        }
        t--;
        return -c / 2 * (t * (t - 2) - 1) + b;
    };

    // requestAnimationFrame for Smart Animating http://goo.gl/sx5sts
    var requestAnimationFrame = (function () {
        return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function (callback) {
            window.setTimeout(callback, 1000 / 60);
        };
    })();

    /***
     *
     * @param {String|HTMLElement} idOrElement
     * @param {Number} [offset=0]
     * @param {Number} [duration=500]
     * @param {Function} callback
     */
    return function (idOrElement, offset, duration, callback) {

        if (offset instanceof Function) {
            callback = offset;
            offset = 0;
        }

        if (duration instanceof Function) {
            callback = duration;
            duration = null;
        }

        duration = (duration == null) ? 500 : duration;
        offset = offset || 0;

        if (!idOrElement) {
            callback && callback();
            return;
        }

        var to = undefined,
            element;

        if (idOrElement instanceof Number) {
            to = idOrElement;
        } else if (typeof(idOrElement) === "string") {
            element = document.querySelector(idOrElement);
        } else if (idOrElement instanceof (window.HTMLElement || window.Element)) {
            element = idOrElement;
        }

        if (!element) {
            callback && callback();
            return;
        }

        // find the parent that has an overflow

        var parent = element.parentNode,
            computedStyle;

        while (parent) {
            if (parent.nodeType == 9) {
                return;
            }

            try {
                computedStyle = window.getComputedStyle(parent, null);
            } catch (e) {
            }

            if (computedStyle.overflowY == "auto" || computedStyle.overflowY == "scroll" || computedStyle.overflowX == "auto" || computedStyle.overflowX == "scroll") {
                break;
            }

            parent = parent.parentNode;
        }

        if (!parent) {
            callback && callback();
        }

        // check if the element is in the view
        var parentRect = parent.getBoundingClientRect(),
            rect = element.getBoundingClientRect(),
            scrollToX = null,
            scrollToY = null;

        if ((computedStyle.overflowX == "auto" || computedStyle.overflowX == "scroll") &&
            rect.left < parentRect.left || rect.left >= parentRect.left + parentRect.width
        ) {
            scrollToX = parent.scrollLeft + (rect.left - (parentRect.left + parentRect.width) / 2);
        }

        if ((computedStyle.overflowY == "auto" || computedStyle.overflowY == "scroll") &&
            rect.top < parentRect.top || rect.top >= parentRect.top + parentRect.height
        ) {
            scrollToY = parent.scrollTop + (rect.top - parentRect.top - parentRect.height / 2 + rect.height / 2);
        }

        scrollTo(scrollToX, scrollToY);

        function scrollTo(toX, toY) {

            // figure out if this is moz || IE because they use documentElement
            var startX = parent.scrollLeft,
                startY = parent.scrollTop,
                changeX = toX - startX,
                changeY = toY - startY,
                currentTime = 0,
                increment = 20;

            var animateScroll = function () {
                // increment the time
                currentTime += increment;
                // find the value with the quadratic in-out easing function

                if (toX != null) {
                    parent.scrollLeft = Math.easeInOutQuad(currentTime, startX, changeX, duration);
                }

                if (toY != null) {
                    parent.scrollTop = Math.easeInOutQuad(currentTime, startY, changeY, duration);
                }

                // do the animation unless its over
                if (currentTime < duration) {
                    requestAnimationFrame(animateScroll);
                } else {
                    callback && callback();
                }
            };

            animateScroll();
        }

    };

});<|endoftext|>


<commit_before>/*jslint node: true*/

//First we call the packages we need.
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var bugsnag = require("bugsnag");
bugsnag.register("9d5907a30dcfaf8806e542fbf61cf623");

pull = require('pull').set('http://github.com/deliverymanager/printServer', __dirname, function () {
	pull.sync()
})

/*
var forever = require('forever-monitor');

var child = new(forever.Monitor)('index.js', {
    max: 3,
    silent: false,
    args: []
});

child.on('exit', function() {
    console.log('index.js has exited after 3 restarts');
});

child.start();
*/
/*

var gitPullCron = require('git-pull-cron');
- Clone given repo into /dev/my-repo, replacing what's already there
- Schedule cron to run every weekday (Mon-Fri) at 11:30am
- When cron task runs, a `git pull origin master` will be performed
- Once cron task has run the callback will get invoked with latest commit info
 */
/*
gitPullCron.init('https://github.com/deliverymanager/printServer', './Applications', '00 00 * * * *', function(err, commit) {
    if (err) {
        return console.error(err.stack);
    }

    console.log('Updated to commit: ' + commit.id);
});
*/

//Here I am creating the singleton connection to the MongoDb server.
//This connection will be used in all the controllers and middleware in the app.
//mongoDbConnection(function(db) {});

var os = require('os');
console.log(os.platform());
console.log(os.type());
if (os.type() == "Windows_NT") {

    //First we need to check if the service is already installed

    //If no then we check if the user has administrative priviledges
    //On windows XP nothing with happen as most of the times the user is admin
    //On Windows 7 etc, the pop prompt will appear asking for administrative priviledges
    /*
    var wincmd = require('node-windows');

    wincmd.isAdminUser(function(isAdmin) {
        if (isAdmin) {
            console.log('The user has administrative privileges.');
            //Then we need to install and start the service!
            var Service = require('node-windows').Service;

            // Create a new service object
            var svc = new Service({
                name: 'Delivery Manager Print Server',
                description: 'deliverymanager.gr',
                script: 'C:\\printServer\\index.js'
            });

            // Listen for the "install" event, which indicates the
            // process is available as a service.
            svc.on('install', function() {
                svc.start();
            });

            svc.install();

        } else {
            console.log('NOT AN ADMIN');
        }
    });
    */
}

console.log(os.hostname());
console.log(os.arch());
console.log(os.release());
console.log(os.cpus());
var interfaces = os.networkInterfaces();
var addresses = [];
for (var k in interfaces) {
    for (var k2 in interfaces[k]) {
        var address = interfaces[k][k2];
        if (address.family === 'IPv4' && !address.internal) {
            addresses.push(address.address);
        }
    }
}

console.log(addresses[0]);

//Here I am placing the cron jobs
//var cron = require("./cronjobs");
app.use(function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    next();
});
//In order to disable to flags for chromium
//open /Users/anestis/Downloads Chromium.app --args –allow-file-access-from-files -disable-web-security

// configure app to use bodyParser()
// this will let us get the data from a POST
//This is an express middleware
//It handles the data sent before sending them to the routes.
app.use(bodyParser.json());
app.get('/printServer', function(req, res) {
    console.log("/printServer was just called");
    //res.json is used usually when I want to return data from an API
    res.json({
        message: 'Live  git pull works'
    });
});

app.get('/getPrinters', function(req, res) {
    console.log("/printServer was just called");
    //res.json is used usually when I want to return data from an API
    var printer = require("printer");
    var util = require('util');
    console.log("installed printers:\n" + util.inspect(printer.getPrinters(), {
        colors: true,
        depth: 10
    }));

    res.json({
        message: printer.getPrinters()
    });
});

app.get('/testError', function(req, res) {
    console.log("/testError was just called");
    //res.json is used usually when I want to return data from an API
    //throw new Error('something bad happened');
    var fs = require('fs');

    fs.readFile('somefile.txt', function(err, data) {
        if (err) throw err;
        console.log(data);
    });
});

var port;
var portfinder = require('portfinder');
portfinder.basePort = 4950;
portfinder.getPort(function(err, cleanPort) {
    //
    // `port` is guarenteed to be a free port
    // in this scope.
    //
    port = cleanPort;
    app.listen(port, function() {
        console.log("Node app is running at localhost:" + port);
    });

});
<commit_msg>chnages<commit_after>/*jslint node: true*/

//First we call the packages we need.
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var bugsnag = require("bugsnag");
bugsnag.register("9d5907a30dcfaf8806e542fbf61cf623");

pull = require('pull').set('http://github.com/deliverymanager/printServer', file.path.join(__dirname));
pull.sync();

/*
var forever = require('forever-monitor');

var child = new(forever.Monitor)('index.js', {
    max: 3,
    silent: false,
    args: []
});

child.on('exit', function() {
    console.log('index.js has exited after 3 restarts');
});

child.start();
*/
/*

var gitPullCron = require('git-pull-cron');
- Clone given repo into /dev/my-repo, replacing what's already there
- Schedule cron to run every weekday (Mon-Fri) at 11:30am
- When cron task runs, a `git pull origin master` will be performed
- Once cron task has run the callback will get invoked with latest commit info
 */
/*
gitPullCron.init('https://github.com/deliverymanager/printServer', './Applications', '00 00 * * * *', function(err, commit) {
    if (err) {
        return console.error(err.stack);
    }

    console.log('Updated to commit: ' + commit.id);
});
*/

//Here I am creating the singleton connection to the MongoDb server.
//This connection will be used in all the controllers and middleware in the app.
//mongoDbConnection(function(db) {});

var os = require('os');
console.log(os.platform());
console.log(os.type());
if (os.type() == "Windows_NT") {

    //First we need to check if the service is already installed

    //If no then we check if the user has administrative priviledges
    //On windows XP nothing with happen as most of the times the user is admin
    //On Windows 7 etc, the pop prompt will appear asking for administrative priviledges
    /*
    var wincmd = require('node-windows');

    wincmd.isAdminUser(function(isAdmin) {
        if (isAdmin) {
            console.log('The user has administrative privileges.');
            //Then we need to install and start the service!
            var Service = require('node-windows').Service;

            // Create a new service object
            var svc = new Service({
                name: 'Delivery Manager Print Server',
                description: 'deliverymanager.gr',
                script: 'C:\\printServer\\index.js'
            });

            // Listen for the "install" event, which indicates the
            // process is available as a service.
            svc.on('install', function() {
                svc.start();
            });

            svc.install();

        } else {
            console.log('NOT AN ADMIN');
        }
    });
    */
}

console.log(os.hostname());
console.log(os.arch());
console.log(os.release());
console.log(os.cpus());
var interfaces = os.networkInterfaces();
var addresses = [];
for (var k in interfaces) {
    for (var k2 in interfaces[k]) {
        var address = interfaces[k][k2];
        if (address.family === 'IPv4' && !address.internal) {
            addresses.push(address.address);
        }
    }
}

console.log(addresses[0]);

//Here I am placing the cron jobs
//var cron = require("./cronjobs");
app.use(function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    next();
});
//In order to disable to flags for chromium
//open /Users/anestis/Downloads Chromium.app --args –allow-file-access-from-files -disable-web-security

// configure app to use bodyParser()
// this will let us get the data from a POST
//This is an express middleware
//It handles the data sent before sending them to the routes.
app.use(bodyParser.json());
app.get('/printServer', function(req, res) {
    console.log("/printServer was just called");
    //res.json is used usually when I want to return data from an API
    res.json({
        message: 'Live  git pull works'
    });
});

app.get('/getPrinters', function(req, res) {
    console.log("/printServer was just called");
    //res.json is used usually when I want to return data from an API
    var printer = require("printer");
    var util = require('util');
    console.log("installed printers:\n" + util.inspect(printer.getPrinters(), {
        colors: true,
        depth: 10
    }));

    res.json({
        message: printer.getPrinters()
    });
});

app.get('/testError', function(req, res) {
    console.log("/testError was just called");
    //res.json is used usually when I want to return data from an API
    //throw new Error('something bad happened');
    var fs = require('fs');

    fs.readFile('somefile.txt', function(err, data) {
        if (err) throw err;
        console.log(data);
    });
});

var port;
var portfinder = require('portfinder');
portfinder.basePort = 4950;
portfinder.getPort(function(err, cleanPort) {
    //
    // `port` is guarenteed to be a free port
    // in this scope.
    //
    port = cleanPort;
    app.listen(port, function() {
        console.log("Node app is running at localhost:" + port);
    });

});
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Dialog, {
  DialogContent,
  DialogContentText,
  DialogTitle,
} from 'material-ui/Dialog';
import Slide from 'material-ui/transitions/Slide';
import StripeCheckout from '../checkout/stripe-checkout';

function Transition(props) {
  return <Slide direction="up" {...props} />;
}

class PaymentDialog extends Component {
  constructor(props) {
    super(props);
    this.state = {
      price: null,
      open: false
    }
    this.onClose = this.onClose.bind(this);

  }

  componentWillMount() {
    this.setState({price: this.props.price, open: this.props.open});
  }

  componentWillReceiveProps(prop){
    this.setState({price: prop.price, open: prop.open});
  }

  onClose() {
    this.setState({
      open: false
    })
  }

  render() {
    return (
      <Dialog
        open={this.state.open}
        onClose={this.handleClose}
        aria-labelledby="alert-dialog-slide-title"
        aria-describedby="alert-dialog-slide-description"
        fullWidth={true}
      >
        <DialogTitle id="alert-dialog-slide-title">
          Realizar pagamento
        </DialogTitle>
        <DialogContent>
          <DialogContentText id="alert-dialog-slide-description">
            Preecha os dados do cartão para efetuar o pagamento
          </DialogContentText>
          <StripeCheckout { ...this.props } />
        </DialogContent>
      </Dialog>
    )
  }

}

export default PaymentDialog;
<commit_msg>taking out stripe from form to see if causing the bug<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Dialog, {
  DialogContent,
  DialogContentText,
  DialogTitle,
} from 'material-ui/Dialog';
import Slide from 'material-ui/transitions/Slide';
import StripeCheckout from '../checkout/stripe-checkout';

function Transition(props) {
  return <Slide direction="up" {...props} />;
}

class PaymentDialog extends Component {
  constructor(props) {
    super(props);
    this.state = {
      price: null,
      open: false
    }
    this.onClose = this.onClose.bind(this);

  }

  componentWillMount() {
    this.setState({price: this.props.price, open: this.props.open});
  }

  componentWillReceiveProps(prop){
    this.setState({price: prop.price, open: prop.open});
  }

  onClose() {
    this.setState({
      open: false
    })
  }

  render() {
    return (
      <Dialog
        open={this.state.open}
        transition={Transition}
        onClose={this.handleClose}
        aria-labelledby="alert-dialog-slide-title"
        aria-describedby="alert-dialog-slide-description"
        fullWidth={true}
      >
        <DialogTitle id="alert-dialog-slide-title">
          Realizar pagamento
        </DialogTitle>
        <DialogContent>
          <DialogContentText id="alert-dialog-slide-description">
            Preecha os dados do cartão para efetuar o pagamento
          </DialogContentText>
        </DialogContent>
      </Dialog>
    )
  }

}

export default PaymentDialog;
<|endoftext|>


<commit_before>// xss-blacklist-test.js
//
// Test the XSS blacklist middleware
//
// Copyright 2016, 2017 AJ Jordan <alex@strugee.net>
//
// 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.

"use strict";

var assert = require("assert"),
    vows = require("vows"),
    _ = require("lodash"),
    Step = require("step"),
    Browser = require("zombie"),
    oauthutil = require("./lib/oauth"),
    apputil = require("./lib/app"),
    http = require("http"),
    withAppSetup = apputil.withAppSetup,
    br;

vows.describe("XSS blacklist middleware").addBatch({
    "When we require the XSS blacklist middleware": {
        topic: function() {
            return require("../lib/xssblacklist.js");
        },
        "it works": function(middleware) {
            assert.isObject(middleware);
        },
        "and we get its xssCheck export": {
            topic: function(middleware) {
                return middleware.xssCheck;
            },
            "it exists": function(xssCheck) {
                assert.isFunction(xssCheck);
            }
        }
    }
})["export"](module);
<commit_msg>Give a different suite name to the second XSS test<commit_after>// xss-blacklist-test.js
//
// Test the XSS blacklist middleware module
//
// Copyright 2016, 2017 AJ Jordan <alex@strugee.net>
//
// 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.

"use strict";

var assert = require("assert"),
    vows = require("vows"),
    _ = require("lodash"),
    Step = require("step"),
    Browser = require("zombie"),
    oauthutil = require("./lib/oauth"),
    apputil = require("./lib/app"),
    http = require("http"),
    withAppSetup = apputil.withAppSetup,
    br;

vows.describe("XSS blacklist middleware module").addBatch({
    "When we require the XSS blacklist middleware": {
        topic: function() {
            return require("../lib/xssblacklist.js");
        },
        "it works": function(middleware) {
            assert.isObject(middleware);
        },
        "and we get its xssCheck export": {
            topic: function(middleware) {
                return middleware.xssCheck;
            },
            "it exists": function(xssCheck) {
                assert.isFunction(xssCheck);
            }
        }
    }
})["export"](module);
<|endoftext|>


<commit_before><commit_msg>Added skip authorisation on getting configuration<commit_after><|endoftext|>


<commit_before>module.exports = function(environment) {
    var Dimension = require("../tree/dimension"),
        Color = require("../tree/color"),
        Quoted = require("../tree/quoted"),
        URL = require("../tree/url"),
        functionRegistry = require("./function-registry");

    functionRegistry.add("svg-gradient", function(direction) {

        function throwArgumentDescriptor() {
            throw { type: "Argument", message: "svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position]" };
        }

        if (arguments.length < 3) {
            throwArgumentDescriptor();
        }
        var stops = Array.prototype.slice.call(arguments, 1),
            gradientDirectionSvg,
            gradientType = "linear",
            rectangleDimension = 'x="0" y="0" width="1" height="1"',
            renderEnv = {compress: false},
            returner,
            directionValue = direction.toCSS(renderEnv),
            i, color, position, positionValue, alpha;

        switch (directionValue) {
            case "to bottom":
                gradientDirectionSvg = 'x1="0%" y1="0%" x2="0%" y2="100%"';
                break;
            case "to right":
                gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="0%"';
                break;
            case "to bottom right":
                gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="100%"';
                break;
            case "to top right":
                gradientDirectionSvg = 'x1="0%" y1="100%" x2="100%" y2="0%"';
                break;
            case "ellipse":
            case "ellipse at center":
                gradientType = "radial";
                gradientDirectionSvg = 'cx="50%" cy="50%" r="75%"';
                rectangleDimension = 'x="-50" y="-50" width="101" height="101"';
                break;
            default:
                throw { type: "Argument", message: "svg-gradient direction must be 'to bottom', 'to right', 'to bottom right', 'to top right' or 'ellipse at center'" };
        }
        returner = '<?xml version="1.0" ?>' +
            '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none">' +
            '<' + gradientType + 'Gradient id="gradient" gradientUnits="userSpaceOnUse" ' + gradientDirectionSvg + '>';

        for (i = 0; i < stops.length; i+= 1) {
            if (stops[i].value) {
                color = stops[i].value[0];
                position = stops[i].value[1];
            } else {
                color = stops[i];
                position = undefined;
            }

            if (!(color instanceof Color) || (!((i === 0 || i+1 === stops.length) && position === undefined) && !(position instanceof Dimension))) {
                throwArgumentDescriptor();
            }
            positionValue = position ? position.toCSS(renderEnv) : i === 0 ? "0%" : "100%";
            alpha = color.alpha;
            returner += '<stop offset="' + positionValue + '" stop-color="' + color.toRGB() + '"' + (alpha < 1 ? ' stop-opacity="' + alpha + '"' : '') + '/>';
        }
        returner += '</' + gradientType + 'Gradient>' +
            '<rect ' + rectangleDimension + ' fill="url(#gradient)" /></svg>';

        returner = encodeURIComponent(returner);

        returner = "data:image/svg+xml," + returner;
        return new URL(new Quoted("'" + returner + "'", returner, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo);
    });
};
<commit_msg>fixes svg-gradient function broken by prev. color object changes<commit_after>module.exports = function(environment) {
    var Dimension = require("../tree/dimension"),
        Color = require("../tree/color"),
        Expression = require("../tree/expression"),
        Quoted = require("../tree/quoted"),
        URL = require("../tree/url"),
        functionRegistry = require("./function-registry");

    functionRegistry.add("svg-gradient", function(direction) {

        function throwArgumentDescriptor() {
            throw { type: "Argument", message: "svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position]" };
        }

        if (arguments.length < 3) {
            throwArgumentDescriptor();
        }
        var stops = Array.prototype.slice.call(arguments, 1),
            gradientDirectionSvg,
            gradientType = "linear",
            rectangleDimension = 'x="0" y="0" width="1" height="1"',
            renderEnv = {compress: false},
            returner,
            directionValue = direction.toCSS(renderEnv),
            i, color, position, positionValue, alpha;

        switch (directionValue) {
            case "to bottom":
                gradientDirectionSvg = 'x1="0%" y1="0%" x2="0%" y2="100%"';
                break;
            case "to right":
                gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="0%"';
                break;
            case "to bottom right":
                gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="100%"';
                break;
            case "to top right":
                gradientDirectionSvg = 'x1="0%" y1="100%" x2="100%" y2="0%"';
                break;
            case "ellipse":
            case "ellipse at center":
                gradientType = "radial";
                gradientDirectionSvg = 'cx="50%" cy="50%" r="75%"';
                rectangleDimension = 'x="-50" y="-50" width="101" height="101"';
                break;
            default:
                throw { type: "Argument", message: "svg-gradient direction must be 'to bottom', 'to right', 'to bottom right', 'to top right' or 'ellipse at center'" };
        }
        returner = '<?xml version="1.0" ?>' +
            '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none">' +
            '<' + gradientType + 'Gradient id="gradient" gradientUnits="userSpaceOnUse" ' + gradientDirectionSvg + '>';

        for (i = 0; i < stops.length; i+= 1) {
            if (stops[i] instanceof Expression) {
                color = stops[i].value[0];
                position = stops[i].value[1];
            } else {
                color = stops[i];
                position = undefined;
            }

            if (!(color instanceof Color) || (!((i === 0 || i+1 === stops.length) && position === undefined) && !(position instanceof Dimension))) {
                throwArgumentDescriptor();
            }
            positionValue = position ? position.toCSS(renderEnv) : i === 0 ? "0%" : "100%";
            alpha = color.alpha;
            returner += '<stop offset="' + positionValue + '" stop-color="' + color.toRGB() + '"' + (alpha < 1 ? ' stop-opacity="' + alpha + '"' : '') + '/>';
        }
        returner += '</' + gradientType + 'Gradient>' +
            '<rect ' + rectangleDimension + ' fill="url(#gradient)" /></svg>';

        returner = encodeURIComponent(returner);

        returner = "data:image/svg+xml," + returner;
        return new URL(new Quoted("'" + returner + "'", returner, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo);
    });
};
<|endoftext|>


<commit_before>function PieInfographic(stats) {
	this.stats = stats;
	this.render = render;
	this.currentPie = 0;
	this._angles = {};
	this._pathNodes = [];

	function render(parentEl) {

		var self = this;

		var svgEl = document.createElementNS('http://www.w3.org/2000/svg', 'svg'),
			parentGroupEl = document.createElementNS('http://www.w3.org/2000/svg', 'g'),
			svgDimensions, center, radius,
			baseAngle, expandedAngle, shrunkAngle;

		svgEl.setAttribute('style', 'width:100%;height:100%');

		if (typeof(parentEl) !== undefined) {
			parentGroupEl.classList.add('outer-group');
			svgEl.appendChild(parentGroupEl);
			parentEl.appendChild(svgEl);
		}

		svgDimensions = {
			width: svgEl.clientWidth,
			height: svgEl.clientHeight
		};

		center = {
			x: svgEl.clientWidth / 2,
			y: svgEl.clientHeight / 2
		};

		radius = svgDimensions.width * 0.4; //Occupying 80% of the SVG size

		baseAngle = 2 * Math.PI / this.stats.length;
		expandedAngle = Math.min(2 * Math.PI - (0.15 * Math.PI * this.stats.length), baseAngle * 4, Math.PI); //Pie, on expansion to 3 times, should leave atleast 36 degrees for each other pie, and cannot be more than 180 degrees.
		shrunkAngle = (2 * Math.PI - expandedAngle) / (stats.length - 1); //Angle when a pie is shrunk

		self._angles.baseAngle = baseAngle;
		self._angles.expandedAngle = expandedAngle;
		self._angles.shrunkAngle = shrunkAngle;

		for(var i=0; i<stats.length;i++){
			var pathEl = document.createElementNS('http://www.w3.org/2000/svg', 'path');
			pathEl.setAttribute('fill', stats[i].color);

			pathEl.addEventListener('click',function(event){
				_performAction('expand', self._pathNodes.indexOf(event.target));
			});

			this._pathNodes.push(parentGroupEl.appendChild(pathEl));
		}

		_performAction('normal');

		function _performAction(state,index){

			var arcPositions = [];

			if(state === 'normal'){
				arcPositions = _getArcPositionsForState(state);
			} else if(state === 'expand'){
				arcPositions = _getArcPositionsForState(state,index);
			}

			if(state === 'normal'){

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

					//TODO: Animate with some durations/easing here.
					_animateTo(self._pathNodes[i],arcPositions[i], (state === 'normal')? 0:1);

					//Set the data attribute for state
					if(state === 'normal')
						self._pathNodes[i].setAttribute('data-state',state);
					else if(state === 'expand' && i === index)
						self._pathNodes[i].setAttribute('data-state',state);
					else
						self._pathNodes[i].setAttribute('data-state','shrink');
				}

			} else{

				var targetAngles = [],
				increments = [];

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

					targetAngles.push([
						_cartesianToPolar(center,arcPositions[i][0]).theta,
						_cartesianToPolar(center,arcPositions[i][1]).theta
					]);

					//Calculating first set of increments
					increments.push(_getNextIncrement(self._pathNodes[i],targetAngles[i]));
				}

				function drawIncrement(){

					for (var i = 0; i < increments.length; i++) {
						if(increments[i] !== null)
							self._pathNodes[i].setAttribute('d', increments[i]);
					};

					console.log('Drew one increment');

					increments = [];
					var nextFrameRequestNeeded = false;

					//Get the next set of increments
					for(i=0; i < self._pathNodes.length; i++){

						increments.push(_getNextIncrement(self._pathNodes[i],targetAngles[i]));

						if(increments[i] !== null){
							nextFrameRequestNeeded = true;
						}
					}

					//if increments has one non-null entry
					if(nextFrameRequestNeeded)
						window.requestAnimationFrame(drawIncrement);
				}

				window.requestAnimationFrame(drawIncrement);
			}
		}

		//Calculate arc start-end positions for each pie based on the state.
		function _getArcPositionsForState(state,index){

			var arcPositions = [],angleOffset;

			if(state === 'normal'){

					angleOffset = self._angles.baseAngle/2;

					for(var i=0;i<stats.length;i++){
						arcPositions.push([
							_polarToCartesian(center,radius,angleOffset),
							_polarToCartesian(center,radius,angleOffset - baseAngle)
						]);
						angleOffset-=baseAngle;
					}

			}else if(state === 'expand'){
					index = index || 0;

					if(index === 0){
						angleOffset = self._angles.expandedAngle/2;
					}else{
						angleOffset = self._angles.shrunkAngle/2;
					}

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

						var arcPoints = [ _polarToCartesian(center,radius,angleOffset) ]; //Pushing the start point

						if(i === index){
							arcPoints.push(_polarToCartesian(center,radius,angleOffset - expandedAngle));
							angleOffset -= expandedAngle;
						}else{
							arcPoints.push(_polarToCartesian(center,radius,angleOffset - shrunkAngle));
							angleOffset -= shrunkAngle;
						}
						arcPositions.push(arcPoints);
					}
			}

			return arcPositions;
		}

		function _animateTo(el,arcPoints,duration){
			if(duration <=0){
				el.setAttribute('d',_getPathDescForArcPositions(center,radius,arcPoints[0],arcPoints[1]));
				return;
			}
		}

		function _getNextIncrement(el,targetAngles){

			var currentArcPoints = _getArcCoordinates(el);
			var sourceAngles = [ _cartesianToPolar(center,currentArcPoints[0]).theta,
				_cartesianToPolar(center,currentArcPoints[1]).theta
			];

			if(Math.abs(targetAngles[0] - sourceAngles[0]) <= Math.pow(10,-10)  &&
				Math.abs(targetAngles[1] - sourceAngles[1]) <= Math.pow(10,-10)){
				//If source and target angles are equal to precision of 10 decimals, stop the increments.
				return null;
			}

			if(sourceAngles[0] < targetAngles[0])
				sourceAngles[0] = Math.min(sourceAngles[0]+0.1,targetAngles[0]);
			else if(sourceAngles[0] > targetAngles[0])
				sourceAngles[0] = Math.max(sourceAngles[0]-0.1,targetAngles[0]);

			if(sourceAngles[1] < targetAngles[1])
				sourceAngles[1] = Math.min(sourceAngles[1]+0.1,targetAngles[1]);
			else if(sourceAngles[1] > targetAngles[1])
				sourceAngles[1] = Math.max(sourceAngles[1]-0.1,targetAngles[1]);

			return _getPathDescForArcPositions(center,radius,
					_polarToCartesian(center,radius,sourceAngles[0]),
					_polarToCartesian(center,radius,sourceAngles[1]));

		}

		function _getPathDescForArcPositions(center, radius, startPoint, endPoint) {
			var points = 'M' + center.x + ',' + center.y;

			points += ' L ' + startPoint.x + ' ' + startPoint.y;

			points += ' A ' + radius + ' ' + radius +
				' 1 0 1 ' + endPoint.x + ' ' + endPoint.y;

			//points += ' M ' + endPoint.x + ' ' + endPoint.y;
			points += ' L ' + center.x + ' ' + center.y;
			points += ' Z';

			return points;
		}

		function _createAnimElement(tag, attrs) {
			var animEl = document.createElementNS('http://www.w3.org/2000/svg', tag);
			for (key in attrs)
				animEl.setAttribute(key, attrs[key]);
			return animEl;
		}

		function _polarToCartesian(center,radius,angle){
			return {
				x: center.x + (Math.cos(angle) * radius),
				y: center.y - (Math.sin(angle) * radius)
			};
		}

		function _cartesianToPolar(center,point){

			var theta = Math.atan2(point.y - center.y,point.x - center.x);

			if(theta > 0)
				theta *= -1;
			else if(theta < 0)
				theta = -1 * (2*Math.PI + theta);

			return {
				r: radius,
				theta: theta
			};
		}

		function _getArcCoordinates(pathEl){
			var desc = pathEl.getAttribute('d'),
			startPoints = desc.split('L ')[1].split(' A')[0].split(' '),
			endPoints = desc.split('1 0 1 ')[1].split(' L')[0].split(' ');

			return [{
				x: parseFloat(startPoints[0]),
				y: parseFloat(startPoints[1])
			},{
				x: parseFloat(endPoints[0]),
				y: parseFloat(endPoints[1])
			}];
		}

		function _getArcAngleForState(state){
			if(state === 'normal')
				return self._angles.baseAngle;
			else if(state === 'expand')
				return self._angles.expandedAngle;
			else if(state === 'shrink')
				return self._angles.shrunkAngle;

			return null;
		}

	}
}

window.onload = function() {
	var graphicWrapper = document.getElementsByTagName('div')[0],
		graphic = new PieInfographic([{
			color: '#5793F3'
		}, {
			color: '#DD4D79'
		}, {
			color: '#BD3B47'
		}, {
			color: '#DD4444'
		}, {
			color: '#FD9C35'
		}, {
			color: '#FEC42C'
		}, {
			color: '#D4Df5A'
		}, {
			color: '#5578C2'
		}]);

	graphic.render(graphicWrapper);
};<commit_msg>Fixing internal function with references to module properties.<commit_after>function PieInfographic(stats) {

	this.stats = stats;
	this.render = render;

	this._angles = {};
	this._pathNodes = [];
	this._center = 0;
	this._radius = 0;
	this._performAction = _performAction;
	this._getArcPositionsForState = _getArcPositionsForState;
	this._setDataAttributes = _setDataAttributes;
	this._getNextIncrement = _getNextIncrement;

	function render(parentEl) {

		var self = this;

		var svgEl = document.createElementNS('http://www.w3.org/2000/svg', 'svg'),
			parentGroupEl = document.createElementNS('http://www.w3.org/2000/svg', 'g'),
			svgDimensions, center, radius,
			baseAngle, expandedAngle, shrunkAngle;

		svgEl.setAttribute('style', 'width:100%;height:100%');

		if (typeof(parentEl) !== undefined) {
			parentGroupEl.classList.add('outer-group');
			svgEl.appendChild(parentGroupEl);
			parentEl.appendChild(svgEl);
		}

		svgDimensions = {
			width: svgEl.clientWidth,
			height: svgEl.clientHeight
		};

		center = {
			x: svgEl.clientWidth / 2,
			y: svgEl.clientHeight / 2
		};

		radius = svgDimensions.width * 0.4; //Occupying 80% of the SVG size

		self._center = center;
		self._radius = radius;

		baseAngle = 2 * Math.PI / this.stats.length;
		expandedAngle = Math.min(2 * Math.PI - (0.15 * Math.PI * this.stats.length), baseAngle * 4, Math.PI); //Pie, on expansion to 3 times, should leave atleast 36 degrees for each other pie, and cannot be more than 180 degrees.
		shrunkAngle = (2 * Math.PI - expandedAngle) / (stats.length - 1); //Angle when a pie is shrunk

		self._angles.baseAngle = baseAngle;
		self._angles.expandedAngle = expandedAngle;
		self._angles.shrunkAngle = shrunkAngle;

		for(var i=0; i<stats.length;i++){
			var pathEl = document.createElementNS('http://www.w3.org/2000/svg', 'path');
			pathEl.setAttribute('fill', stats[i].color);

			pathEl.addEventListener('click',function(event){
					self._performAction('normal');

					//Rotate the graphic here.

					self._performAction('expand', self._pathNodes.indexOf(event.target));
			});

			this._pathNodes.push(parentGroupEl.appendChild(pathEl));
		}

		this._performAction('normal');
	}

	function _performAction(state,index){

			var self = this,
			center = self._center,
			radius = self._radius,
			arcPositions = [];

			if(state === 'normal'){

				arcPositions = self._getArcPositionsForState(state);

				for(var i=0; i< self._pathNodes.length;i++){
					self._pathNodes[i].setAttribute('d',
						_getPathDescForArcPositions(center,radius,arcPositions[i][0],arcPositions[i][1]));
				}

				self._setDataAttributes(state,index);

			} else{

				var targetAngles = [],
				increments = [],
				arcPositions = self._getArcPositionsForState(state,index);

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

					targetAngles.push([
						_cartesianToPolar(center,arcPositions[i][0]).theta,
						_cartesianToPolar(center,arcPositions[i][1]).theta
					]);

					//Calculating first set of increments
					increments.push(self._getNextIncrement(self._pathNodes[i],targetAngles[i]));
				}

				function drawIncrement(){

					for (var i = 0; i < increments.length; i++) {
						if(increments[i] !== null)
							self._pathNodes[i].setAttribute('d', increments[i]);
					};

					console.log('Drew one increment');

					increments = [];
					var nextFrameRequestNeeded = false;

					//Get the next set of increments
					for(i=0; i < self._pathNodes.length; i++){

						increments.push(self._getNextIncrement(self._pathNodes[i],targetAngles[i]));

						if(increments[i] !== null){
							nextFrameRequestNeeded = true;
						}
					}

					//if increments has one non-null entry
					if(nextFrameRequestNeeded)
						window.requestAnimationFrame(drawIncrement);
					else
						self._setDataAttributes(state,index);
				}

				window.requestAnimationFrame(drawIncrement);
			}
		}

		//Calculate arc start-end positions for each pie based on the state.
		function _getArcPositionsForState(state,index){

			var self = this,
			center = self._center,
			radius = self._radius,
			baseAngle = self._angles.baseAngle,
			expandedAngle = self._angles.expandedAngle,
			shrunkAngle = self._angles.shrunkAngle,
			arcPositions = [],angleOffset;

			if(state === 'normal'){

					angleOffset = self._angles.baseAngle/2;

					for(var i=0;i<stats.length;i++){
						arcPositions.push([
							_polarToCartesian(center,radius,angleOffset),
							_polarToCartesian(center,radius,angleOffset - baseAngle)
						]);
						angleOffset-=baseAngle;
					}

			}else if(state === 'expand'){
					index = index || 0;

					if(index === 0){
						angleOffset = self._angles.expandedAngle/2;
					}else{
						angleOffset = self._angles.shrunkAngle/2;
					}

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

						var arcPoints = [ _polarToCartesian(center,radius,angleOffset) ]; //Pushing the start point

						if(i === index){
							arcPoints.push(_polarToCartesian(center,radius,angleOffset - expandedAngle));
							angleOffset -= expandedAngle;
						}else{
							arcPoints.push(_polarToCartesian(center,radius,angleOffset - shrunkAngle));
							angleOffset -= shrunkAngle;
						}
						arcPositions.push(arcPoints);
					}
			}

			return arcPositions;
		}

		function _getNextIncrement(el,targetAngles){

			var self = this,
			center = self._center,
			radius = self._radius,
			currentArcPoints = _getArcCoordinates(el);

			var sourceAngles = [ _cartesianToPolar(center,currentArcPoints[0]).theta,
				_cartesianToPolar(center,currentArcPoints[1]).theta
			];

			if(Math.abs(targetAngles[0] - sourceAngles[0]) <= Math.pow(10,-10)  &&
				Math.abs(targetAngles[1] - sourceAngles[1]) <= Math.pow(10,-10)){
				//If source and target angles are equal to precision of 10 decimals, stop the increments.
				return null;
			}

			if(sourceAngles[0] < targetAngles[0])
				sourceAngles[0] = Math.min(sourceAngles[0]+0.1,targetAngles[0]);
			else if(sourceAngles[0] > targetAngles[0])
				sourceAngles[0] = Math.max(sourceAngles[0]-0.1,targetAngles[0]);

			if(sourceAngles[1] < targetAngles[1])
				sourceAngles[1] = Math.min(sourceAngles[1]+0.1,targetAngles[1]);
			else if(sourceAngles[1] > targetAngles[1])
				sourceAngles[1] = Math.max(sourceAngles[1]-0.1,targetAngles[1]);

			return _getPathDescForArcPositions(center,radius,
					_polarToCartesian(center,radius,sourceAngles[0]),
					_polarToCartesian(center,radius,sourceAngles[1]));

		}

		function _getPathDescForArcPositions(center, radius, startPoint, endPoint) {
			var points = 'M' + center.x + ',' + center.y;

			points += ' L ' + startPoint.x + ' ' + startPoint.y;

			points += ' A ' + radius + ' ' + radius +
				' 1 0 1 ' + endPoint.x + ' ' + endPoint.y;

			points += ' L ' + center.x + ' ' + center.y;
			points += ' Z';

			return points;
		}

		function _createAnimElement(tag, attrs) {
			var animEl = document.createElementNS('http://www.w3.org/2000/svg', tag);
			for (key in attrs)
				animEl.setAttribute(key, attrs[key]);
			return animEl;
		}

		function _polarToCartesian(center,radius,angle){
			return {
				x: center.x + (Math.cos(angle) * radius),
				y: center.y - (Math.sin(angle) * radius)
			};
		}

		function _cartesianToPolar(center,point){

			var theta = Math.atan2(point.y - center.y,point.x - center.x);

			if(theta > 0)
				theta *= -1;
			else if(theta < 0)
				theta = -1 * (2*Math.PI + theta);

			return {
				r: Math.sqrt(Math.pow(point.y - center.y,2) + Math.pow(point.x - center.x,2)),
				theta: theta
			};
		}

		function _getArcCoordinates(pathEl){
			var desc = pathEl.getAttribute('d'),
			startPoints = desc.split('L ')[1].split(' A')[0].split(' '),
			endPoints = desc.split('1 0 1 ')[1].split(' L')[0].split(' ');

			return [{
				x: parseFloat(startPoints[0]),
				y: parseFloat(startPoints[1])
			},{
				x: parseFloat(endPoints[0]),
				y: parseFloat(endPoints[1])
			}];
		}

		function _setDataAttributes(state,index){

			var self  = this;

			for(var i=0;i<self._pathNodes.length;++i){
					if(state === 'normal')
						self._pathNodes[i].setAttribute('data-state',state);
					else if(state === 'expand' && i === index)
						self._pathNodes[i].setAttribute('data-state',state);
					else
						self._pathNodes[i].setAttribute('data-state','shrink');
			}
		}
}

window.onload = function() {
	var graphicWrapper = document.getElementsByTagName('div')[0],
		graphic = new PieInfographic([{
			color: '#5793F3'
		}, {
			color: '#DD4D79'
		}, {
			color: '#BD3B47'
		}, {
			color: '#DD4444'
		}, {
			color: '#FD9C35'
		}, {
			color: '#FEC42C'
		}, {
			color: '#D4Df5A'
		}, {
			color: '#5578C2'
		}]);

	graphic.render(graphicWrapper);
};<|endoftext|>