<commit_before>import React from 'react';
import classNames from 'classnames';

import UserAvatar from './../../shared/UserAvatar';
import Dropdown from './../../shared/Dropdown';
import Badge from './../../shared/Badge';
import Icon from './../../shared/Icon';
import AgentsCount from './../../organization/AgentsCount';
import BuildsCountBadge from './../../user/BuildsCountBadge';
import NewChangelogsBadge from './../../user/NewChangelogsBadge';
import permissions from './../../../lib/permissions';

import NavigationButton from './navigation-button';
import DropdownButton from './dropdown-button';

class Navigation extends React.Component {
  static propTypes = {
    organization: React.PropTypes.object,
    viewer: React.PropTypes.shape({
      user: React.PropTypes.shape({
        name: React.PropTypes.string.isRequired,
        avatar: React.PropTypes.shape({
          url: React.PropTypes.string.isRequired
        })
      }),
      organizations: React.PropTypes.shape({
        edges: React.PropTypes.array
      }),
      unreadChangelogs: React.PropTypes.shape({
        count: React.PropTypes.integer
      })
    })
  };

  state = {
    showingOrgDropdown: false,
    showingUserDropdown: false
  };

  render() {
    return (

              <NavigationButton href="/" className="px3 hover-faded-children" style={{paddingLeft: 0, paddingTop: 0, paddingBottom: 0}}>

              </NavigationButton>
              {this._newChangelogsBadge()}

            <Dropdown align="left" width={250} className="flex" style={{ minWidth: "5em"}} onToggle={this.handleOrgDropdownToggle}>
              <DropdownButton className={classNames({ "lime": this.state.showingOrgDropdown })}
                              style={{
                                backgroundImage: 'url(' + require('./nav-button-right-arrow.svg') + ')',
                                backgroundRepeat: 'no-repeat',
                                backgroundPosition: 'center right',
                                paddingRight: 20}}>

                  {this._organizationSelectorLabel()}

                  ▾

              </DropdownButton>
              {this._organizationsList()}
              <NavigationButton href="/organizations/new" className="block"><Icon icon="plus-circle" className="icon-mr" style={{width: 12, height: 12}} />Create New Organization</NavigationButton>
            </Dropdown>

            {this._topOrganizationMenu()}

            <NavigationButton className="xs-hide sm-hide" href={`/builds`}>My Builds <BuildsCountBadge className="hover-lime-child" viewer={this.props.viewer} /></NavigationButton>
            <NavigationButton className="xs-hide sm-hide" href={`/docs`}>Documentation</NavigationButton>
            <NavigationButton className="xs-hide sm-hide" href="mailto:support@buildkite.com">Support</NavigationButton>

            <Dropdown align="right" width={170} className="flex" onToggle={this.handleUserDropdownToggle}>
              <DropdownButton className={classNames({ "lime": this.state.showingUserDropdown })}
                              style={{paddingRight: 0}}>
                <UserAvatar user={this.props.viewer.user} className="flex-none flex items-center mr1" style={{width: 26, height: 26}} />
                {this.props.viewer.user.name}

                  ▾

              </DropdownButton>

              <NavigationButton className="md-hide lg-hide" href={`/builds`}>My Builds <BuildsCountBadge className="hover-lime-child" viewer={this.props.viewer} /></NavigationButton>
              <NavigationButton href="/user/settings">Personal Settings</NavigationButton>

                <NavigationButton className="md-hide lg-hide" href={`/docs`}>Documentation</NavigationButton>
                <NavigationButton className="md-hide lg-hide" href="mailto:support@buildkite.com">Support</NavigationButton>

              <form action="/logout" method="post" ref={c => this.logoutFormNode = c}>
                <input type="hidden" name="_method" value={"delete"} />
                <input type="hidden" name={window._csrf.param} value={window._csrf.token} />
                <NavigationButton onClick={this.handleLogoutClick}>Logout</NavigationButton>
              </form>
            </Dropdown>

        {this._bottomOrganizationMenu()}

    );
  }

  _newChangelogsBadge() {
    return (
      <NewChangelogsBadge className="mr2 relative" style={{ top: -5, marginLeft: -8 }} viewer={this.props.viewer} />
    )
  }

  _topOrganizationMenu() {
    if (this.props.organization) {
      return (

          {this._organizationMenu()}

      )
    }
  }

  _bottomOrganizationMenu() {
    if (this.props.organization) {
      return (

            {this._organizationMenu({ paddingLeft: 0 })}

      )
    }
  }

  handleOrgDropdownToggle = (visible) => {
    this.setState({ showingOrgDropdown: visible });
  };

  handleUserDropdownToggle = (visible) => {
    this.setState({ showingUserDropdown: visible });
  };

  handleLogoutClick = (e) => {
    e.preventDefault();
    this.logoutFormNode.submit();
  };

  _organizationSelectorLabel() {
    if(this.props.organization) {
      return this.props.organization.name;
    } else {
      return "Organizations"
    }
  }

  _organizationsList() {
    let nodes = [];
    this.props.viewer.organizations.edges.forEach((org) => {
      // Don't show the active organization in the selector
      if(!this.props.organization || (org.node.slug != this.props.organization.slug)) {
        nodes.push(<NavigationButton key={org.node.slug} href={`/${org.node.slug}`} className="block">{org.node.name}</NavigationButton>);
      }
    });

    if(nodes.length > 0) {
      return nodes;
    }
  }

  _organizationMenu(options = {}) {
    let organization = this.props.organization;
    let paddingLeft = options.paddingLeft != undefined ? options.paddingLeft : 15;

    if(organization) {
      return (

          <NavigationButton style={{ paddingLeft: paddingLeft }} href={`/${organization.slug}`}>Pipelines</NavigationButton>
          <NavigationButton href={`/organizations/${organization.slug}/agents`}>
            {'Agents'}
            <Badge className="hover-lime-child"><AgentsCount organization={organization} /></Badge>
          </NavigationButton>

          {this.renderOrganizationSettingsButton()}

      )
    }
  }

  renderOrganizationSettingsButton() {
    let organization = this.props.organization;

    return permissions(organization.permissions).first(
      {
        any: true,
        render: () => <NavigationButton href={`/organizations/${organization.slug}/settings`}>Settings</NavigationButton>
      }
    )
  }
}

export default Navigation;
<commit_msg>Revert "Added hidded tag to test cache busting on deploys"<commit_after>import React from 'react';
import classNames from 'classnames';

import UserAvatar from './../../shared/UserAvatar';
import Dropdown from './../../shared/Dropdown';
import Badge from './../../shared/Badge';
import Icon from './../../shared/Icon';
import AgentsCount from './../../organization/AgentsCount';
import BuildsCountBadge from './../../user/BuildsCountBadge';
import NewChangelogsBadge from './../../user/NewChangelogsBadge';
import permissions from './../../../lib/permissions';

import NavigationButton from './navigation-button';
import DropdownButton from './dropdown-button';

class Navigation extends React.Component {
  static propTypes = {
    organization: React.PropTypes.object,
    viewer: React.PropTypes.shape({
      user: React.PropTypes.shape({
        name: React.PropTypes.string.isRequired,
        avatar: React.PropTypes.shape({
          url: React.PropTypes.string.isRequired
        })
      }),
      organizations: React.PropTypes.shape({
        edges: React.PropTypes.array
      }),
      unreadChangelogs: React.PropTypes.shape({
        count: React.PropTypes.integer
      })
    })
  };

  state = {
    showingOrgDropdown: false,
    showingUserDropdown: false
  };

  render() {
    return (

              <NavigationButton href="/" className="px3 hover-faded-children" style={{paddingLeft: 0, paddingTop: 0, paddingBottom: 0}}>

              </NavigationButton>
              {this._newChangelogsBadge()}

            <Dropdown align="left" width={250} className="flex" style={{ minWidth: "5em"}} onToggle={this.handleOrgDropdownToggle}>
              <DropdownButton className={classNames({ "lime": this.state.showingOrgDropdown })}
                              style={{
                                backgroundImage: 'url(' + require('./nav-button-right-arrow.svg') + ')',
                                backgroundRepeat: 'no-repeat',
                                backgroundPosition: 'center right',
                                paddingRight: 20}}>

                  {this._organizationSelectorLabel()}

                  ▾

              </DropdownButton>
              {this._organizationsList()}
              <NavigationButton href="/organizations/new" className="block"><Icon icon="plus-circle" className="icon-mr" style={{width: 12, height: 12}} />Create New Organization</NavigationButton>
            </Dropdown>

            {this._topOrganizationMenu()}

            <NavigationButton className="xs-hide sm-hide" href={`/builds`}>My Builds <BuildsCountBadge className="hover-lime-child" viewer={this.props.viewer} /></NavigationButton>
            <NavigationButton className="xs-hide sm-hide" href={`/docs`}>Documentation</NavigationButton>
            <NavigationButton className="xs-hide sm-hide" href="mailto:support@buildkite.com">Support</NavigationButton>

            <Dropdown align="right" width={170} className="flex" onToggle={this.handleUserDropdownToggle}>
              <DropdownButton className={classNames({ "lime": this.state.showingUserDropdown })}
                              style={{paddingRight: 0}}>
                <UserAvatar user={this.props.viewer.user} className="flex-none flex items-center mr1" style={{width: 26, height: 26}} />
                {this.props.viewer.user.name}

                  ▾

              </DropdownButton>

              <NavigationButton className="md-hide lg-hide" href={`/builds`}>My Builds <BuildsCountBadge className="hover-lime-child" viewer={this.props.viewer} /></NavigationButton>
              <NavigationButton href="/user/settings">Personal Settings</NavigationButton>

                <NavigationButton className="md-hide lg-hide" href={`/docs`}>Documentation</NavigationButton>
                <NavigationButton className="md-hide lg-hide" href="mailto:support@buildkite.com">Support</NavigationButton>

              <form action="/logout" method="post" ref={c => this.logoutFormNode = c}>
                <input type="hidden" name="_method" value={"delete"} />
                <input type="hidden" name={window._csrf.param} value={window._csrf.token} />
                <NavigationButton onClick={this.handleLogoutClick}>Logout</NavigationButton>
              </form>
            </Dropdown>

        {this._bottomOrganizationMenu()}

    );
  }

  _newChangelogsBadge() {
    return (
      <NewChangelogsBadge className="mr2 relative" style={{ top: -5, marginLeft: -8 }} viewer={this.props.viewer} />
    )
  }

  _topOrganizationMenu() {
    if (this.props.organization) {
      return (

          {this._organizationMenu()}

      )
    }
  }

  _bottomOrganizationMenu() {
    if (this.props.organization) {
      return (

            {this._organizationMenu({ paddingLeft: 0 })}

      )
    }
  }

  handleOrgDropdownToggle = (visible) => {
    this.setState({ showingOrgDropdown: visible });
  };

  handleUserDropdownToggle = (visible) => {
    this.setState({ showingUserDropdown: visible });
  };

  handleLogoutClick = (e) => {
    e.preventDefault();
    this.logoutFormNode.submit();
  };

  _organizationSelectorLabel() {
    if(this.props.organization) {
      return this.props.organization.name;
    } else {
      return "Organizations"
    }
  }

  _organizationsList() {
    let nodes = [];
    this.props.viewer.organizations.edges.forEach((org) => {
      // Don't show the active organization in the selector
      if(!this.props.organization || (org.node.slug != this.props.organization.slug)) {
        nodes.push(<NavigationButton key={org.node.slug} href={`/${org.node.slug}`} className="block">{org.node.name}</NavigationButton>);
      }
    });

    if(nodes.length > 0) {
      return nodes;
    }
  }

  _organizationMenu(options = {}) {
    let organization = this.props.organization;
    let paddingLeft = options.paddingLeft != undefined ? options.paddingLeft : 15;

    if(organization) {
      return (

          <NavigationButton style={{ paddingLeft: paddingLeft }} href={`/${organization.slug}`}>Pipelines</NavigationButton>
          <NavigationButton href={`/organizations/${organization.slug}/agents`}>
            {'Agents'}
            <Badge className="hover-lime-child"><AgentsCount organization={organization} /></Badge>
          </NavigationButton>

          {this.renderOrganizationSettingsButton()}

      )
    }
  }

  renderOrganizationSettingsButton() {
    let organization = this.props.organization;

    return permissions(organization.permissions).first(
      {
        any: true,
        render: () => <NavigationButton href={`/organizations/${organization.slug}/settings`}>Settings</NavigationButton>
      }
    )
  }
}

export default Navigation;
<|endoftext|>


<commit_before>import Component from '@ember/component';
import { bindKeyboardShortcuts, unbindKeyboardShortcuts } from 'ember-keyboard-shortcuts';
import { isPresent } from '@ember/utils';
import { scheduleOnce } from '@ember/runloop';

export default Component.extend({

  tagName: 'section',
  elementId: 'new-message',

  message: '',
  usernames: null,

  keyboardShortcuts: Object.freeze({
    'tab': 'completeUsername'
  }),

  didInsertElement () {
    this._super(...arguments);
    bindKeyboardShortcuts(this);
  },

  willDestroyElement () {
    this._super(...arguments);
    unbindKeyboardShortcuts(this);
  },

  actions: {

    completeUsername () {
      let input = this.element.querySelector('#message-field');
      let cursorPosition = input.selectionStart;
      let textBeforeCursor = this.message.slice(0, cursorPosition);
      let textAfterCursor = this.message.slice(cursorPosition);
      let words = textBeforeCursor.split(' ');
      let searchWord = words.pop();

      if (isPresent(searchWord)) {
        let username = this.usernames.find(username => {
          return username.toLowerCase().startsWith(searchWord.toLowerCase());
        });

        if (isPresent(username)) {
          // add a colon when inserting the username in the beginning
          if (words.length === 0) {
            username = `${username}: `;
          }

          let lengthDiff = username.length - searchWord.length;
          let newCursorPosition = cursorPosition + lengthDiff;

          words.push(username);
          let newMessage = `${words.join(' ')}${textAfterCursor}`;
          this.set('message', newMessage);

          // set the cursor right behind the inserted username,
          // but we have to wait for the update of the input first
          scheduleOnce('afterRender', this, function () {
            input.focus();
            input.setSelectionRange(newCursorPosition, newCursorPosition);
          });
        }
      }
    }

  }

});
<commit_msg>Simplify completeUsername function and use consts<commit_after>import Component from '@ember/component';
import { bindKeyboardShortcuts, unbindKeyboardShortcuts } from 'ember-keyboard-shortcuts';
import { isPresent } from '@ember/utils';
import { scheduleOnce } from '@ember/runloop';

export default Component.extend({

  tagName: 'section',
  elementId: 'new-message',

  message: '',
  usernames: null,

  keyboardShortcuts: Object.freeze({
    'tab': 'completeUsername'
  }),

  didInsertElement () {
    this._super(...arguments);
    bindKeyboardShortcuts(this);
  },

  willDestroyElement () {
    this._super(...arguments);
    unbindKeyboardShortcuts(this);
  },

  actions: {

    completeUsername () {
      const input = this.element.querySelector('#message-field');
      const cursorPosition = input.selectionStart;
      const textBeforeCursor = this.message.slice(0, cursorPosition);
      const textAfterCursor = this.message.slice(cursorPosition);
      const words = textBeforeCursor.split(' ');
      const searchWord = words.pop();

      if (isEmpty(searchWord)) return;

      let username = this.usernames.find(username => {
        return username.toLowerCase().startsWith(searchWord.toLowerCase());
      });

      if (isEmpty(username)) return;

      // add a colon when inserting the username in the beginning
      if (words.length === 0) {
        username = `${username}: `;
      }

      const lengthDiff = username.length - searchWord.length;
      const newCursorPosition = cursorPosition + lengthDiff;

      words.push(username);
      const newMessage = `${words.join(' ')}${textAfterCursor}`;
      this.set('message', newMessage);

      // set the cursor right behind the inserted username,
      // but we have to wait for the update of the input first
      scheduleOnce('afterRender', this, function () {
        input.focus();
        input.setSelectionRange(newCursorPosition, newCursorPosition);
      });
    }

  }

});
<|endoftext|>


<commit_before>// Copyright (c) 2015, Evan Summers (twitter.com/evanxsummers)
// ISC license, see http://github.com/evanx/redexutil/LICENSE

// warning this automatically loads a number of modules in global

import assert from 'assert';
import lodash from 'lodash';

const startTime = new Date().getTime();

['assert', 'lodash', 'path'].forEach(moduleName => {
   module.exports[moduleName] = require(moduleName);
});

module.exports._ = module.exports.lodash;

['Arrays', 'Asserts', 'Collections', 'Dates', 'Errors',
   'Loggers', 'Maps', 'Millis', 'Maybe', 'Numbers', 'Objects',
   'Paths', 'Promises', 'Requests', 'Seconds', 'Strings',
   'Zlib'
   ].forEach(moduleName => {
      module.exports[moduleName] = require('./' + moduleName);
});
<commit_msg>update<commit_after>// Copyright (c) 2015, Evan Summers (twitter.com/evanxsummers)
// ISC license, see http://github.com/evanx/redexutil/LICENSE

// warning this automatically loads a number of modules in global

import assert from 'assert';
import lodash from 'lodash';

const startTime = new Date().getTime();

['assert', 'lodash', 'path'].forEach(moduleName => {
   module.exports[moduleName] = require(moduleName);
});

module.exports._ = module.exports.lodash;

['Arrays', 'Asserts', 'Collections', 'Dates', 'Errors',
   'Loggers', 'Maps', 'Millis', 'Maybe', 'Numbers', 'Objects',
   'Paths', 'Promises', 'Requests', 'Seconds', 'Strings',
   'Zlib'
   ].forEach(moduleName => {
      module.exports[moduleName] = require('./' + moduleName);
});
<|endoftext|>


<commit_before>/*global JustGage */
'use strict';

angular.module("ngJustGage", [])
    .directive('justGage', ['$timeout', function ($timeout) {
        return {
            restrict: 'EA',
            scope: {
                id: '@',
                class: '@',
                min: '=',
                max: '=',
                title: '@',
                value: '=',
                options: '='
            },
            template: '

',
            link: function (scope) {
                $timeout(function () {
                    var options, key, graph;

                    options = {
                        id: scope.id + '-justgage',
                        min: scope.min,
                        max: scope.max,
                        title: scope.title,
                        value: scope.value
                    };

                    if (scope.options) {
                        for (key in scope.options) {
                            if (scope.options.hasOwnProperty(key)) {
                                options[key] = scope.options[key];
                            }
                        }
                    }

                    graph = new JustGage(options);

                    scope.$watch('max', function (updatedMax) {
                        if (updatedMax !== undefined) {
                            graph.refresh(scope.value, updatedMax);
                        }
                    }, true);

                    scope.$watch('value', function (updatedValue) {
                        if (updatedValue !== undefined) {
                            graph.refresh(updatedValue);
                        }
                    }, true);

                });
            }
        };
    }]);
<commit_msg>justgage: Donut mode<commit_after>/*global JustGage */
'use strict';

angular.module("ngJustGage", [])
    .directive('justGage', ['$timeout', function ($timeout) {
        return {
            restrict: 'EA',
            scope: {
                id: '@',
                class: '@',
                min: '=',
                max: '=',
                title: '@',
                value: '=',
                options: '='
            },
            template: '

',
            link: function (scope) {
                $timeout(function () {
                    var options, key, graph;

                    options = {
                        id: scope.id + '-justgage',
                        min: scope.min,
                        max: scope.max,
                        title: scope.title,
                        value: scope.value,
                        donut: true,
                        symbol: '%'
                    };

                    if (scope.options) {
                        for (key in scope.options) {
                            if (scope.options.hasOwnProperty(key)) {
                                options[key] = scope.options[key];
                            }
                        }
                    }

                    graph = new JustGage(options);

                    scope.$watch('max', function (updatedMax) {
                        if (updatedMax !== undefined) {
                            graph.refresh(scope.value, updatedMax);
                        }
                    }, true);

                    scope.$watch('value', function (updatedValue) {
                        if (updatedValue !== undefined) {
                            graph.refresh(updatedValue);
                        }
                    }, true);

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


<commit_before>(function (exports) {

	/**
	 * Expose constructor
	 *
	 */
	exports.Utils = Utils;

	function Utils(){};

	Utils.getDate = function() {
		var d = new Date();
		var date = d.getUTCDate() + '-' + (d.getUTCMonth()+1) + '-' + d.getUTCFullYear() + ' '
				+ d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds() + ' '
				+ d.getMilliseconds();

		return date;
	};

	Utils.getTime = function() {
		var d = new Date();
		var time = d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds();

		return time;
	};

	Utils.getListSize = function (list) {
		var n = 0;
		for (var key in list) {
		    if (list.hasOwnProperty(key)) {
		    	n++;
		    }
		}

		//console.log('Calculated list length ' + n);

		return n;
	};

	//TODO: Improve
	Utils.print_r = function (array) {
		for (var i=0,len=array.length;i<len;i++){
			var el = array[i];
			if (typeof(el) === 'Array'){
				Utils.print_r(el);
			}
			else {
				if (typeof(el) === 'Object'){
					for (var key in el) {
						if (el.hasOwnProperty(key)){
							console.log(key + ' ->\n');
							Utils.print_r(el[key]);
						}
					}
				}
				else {
					console.log(el);
				}
			}
		}
	};

	Utils.objToArray = function (obj) {
	    var result = [];
	    for (var key in obj) {
	       if (obj.hasOwnProperty(key)) {
	           result.push(obj[key]);
	       }
	    }
	    return result;
	}

	/**
	 * Returns an array days, minutes, seconds, mi
	 * @param ms time in milliseconds
	 * @return array
	 */
	Utils.parseMilliseconds = function (ms) {

		var result = [];
		var x = ms / 1000;
		result[4] = x;
		var seconds = x % 60;
		result[3] = Math.floor(seconds);
		var x = x /60;
		var minutes = x % 60;
		result[2] = Math.floor(minutes);
		var x = x / 60;
		var hours = x % 24;
		result[1] = Math.floor(hours);
		var x = x / 24;
		var days = x;
		result[1] = Math.floor(days);

	    return result;
	};

	/**
	 * Returns an array of N array containing the same number of elements
	 * The last group could have less elements.
	 *
	 */
	Utils.getNGroups = function (array, N) {
		return Utils.getGroupsSizeN(array, Math.floor(array.length / N));
	};

	/**
	 * Returns an array of array containing N elements each
	 * The last group could have less elements.
	 *
	 */
	Utils.getGroupsSizeN = function (array, N) {

		var copy = array.slice(0);
		var len = copy.length;
		var originalLen = copy.length;
		var result = [];

		// Init values for the loop algorithm
		var i;
		var idx;
		var group = [];
		var count = 0;
		for (i=0; i < originalLen; i++) {

			// Get a random idx between 0 and array length
			idx = Math.floor(Math.random()*len);

			// Prepare the array container for the elements of a new group
			if (count >= N) {
				result.push(group);
				count = 0;
				group = [];
			}

			// Insert element in the group
			group.push(copy[idx]);

			// Update
			copy.splice(idx,1);
			len = copy.length;
			count++;
		}

		// Add any remaining element
		if (group.length > 0) {
			result.push(group);
		}

		return result;
	};

	/**
	 * Match each element of the array with N random others
	 *
	 */
	Utils.matchN = function (array, N) {
		var result = []
		var len = array.length;
		for (var i = 0 ; i < len ; i++) {
			var copy = array.slice(0);
			copy.splice(i,1);
			var group = Utils.getNRandom(copy,N);
			group.splice(0,1,array[i]);
			console.log('G');
			console.log(group);
			//Update
			result.push(group);
			group = [];
		}
		return result;
	};

	/**
	 * http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
	 *
	 */
	Utils.shuffle = function (array, N, callback) {
		var copy = array.slice(0);
		var len = array.length-1; // ! -1
		for (var i = len; i > 0; i--) {
			var j = Math.floor(Math.random(0,1)*i);
			var tmp = copy[j];
			copy[j] = copy[i];
			copy[i] = tmp;
			console.log(copy);
		}
		return copy;
	};

	Utils.getNRandom = function (array, N, callback) {
		return Utils.shuffle(array).slice(0,N);
	};

	Utils.generateCombinations = function (array, r, callback) {
	    function equal(a, b) {
	        for (var i = 0; i < a.length; i++) {
	            if (a[i] != b[i]) return false;
	        }
	        return true;
	    }
	    function values(i, a) {
	        var ret = [];
	        for (var j = 0; j < i.length; j++) ret.push(a[i[j]]);
	        return ret;
	    }
	    var n = array.length;
	    var indices = [];
	    for (var i = 0; i < r; i++) indices.push(i);
	    var final = [];
	    for (var i = n - r; i < n; i++) final.push(i);
	    while (!equal(indices, final)) {
	        callback(values(indices, array));
	        var i = r - 1;
	        while (indices[i] == n - r + i) i -= 1;
	        indices[i] += 1;
	        for (var j = i + 1; j < r; j++) indices[j] = indices[i] + j - i;
	    }
	    callback(values(indices, array));
	}

})('undefined' != typeof node ? node : module.exports);<commit_msg>Fixed bug in matchN<commit_after>(function (exports) {

	/**
	 * Expose constructor
	 *
	 */
	exports.Utils = Utils;

	function Utils(){};

	Utils.getDate = function() {
		var d = new Date();
		var date = d.getUTCDate() + '-' + (d.getUTCMonth()+1) + '-' + d.getUTCFullYear() + ' '
				+ d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds() + ' '
				+ d.getMilliseconds();

		return date;
	};

	Utils.getTime = function() {
		var d = new Date();
		var time = d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds();

		return time;
	};

	Utils.getListSize = function (list) {
		var n = 0;
		for (var key in list) {
		    if (list.hasOwnProperty(key)) {
		    	n++;
		    }
		}

		//console.log('Calculated list length ' + n);

		return n;
	};

	//TODO: Improve
	Utils.print_r = function (array) {
		for (var i=0,len=array.length;i<len;i++){
			var el = array[i];
			if (typeof(el) === 'Array'){
				Utils.print_r(el);
			}
			else {
				if (typeof(el) === 'Object'){
					for (var key in el) {
						if (el.hasOwnProperty(key)){
							console.log(key + ' ->\n');
							Utils.print_r(el[key]);
						}
					}
				}
				else {
					console.log(el);
				}
			}
		}
	};

	Utils.objToArray = function (obj) {
	    var result = [];
	    for (var key in obj) {
	       if (obj.hasOwnProperty(key)) {
	           result.push(obj[key]);
	       }
	    }
	    return result;
	}

	/**
	 * Returns an array days, minutes, seconds, mi
	 * @param ms time in milliseconds
	 * @return array
	 */
	Utils.parseMilliseconds = function (ms) {

		var result = [];
		var x = ms / 1000;
		result[4] = x;
		var seconds = x % 60;
		result[3] = Math.floor(seconds);
		var x = x /60;
		var minutes = x % 60;
		result[2] = Math.floor(minutes);
		var x = x / 60;
		var hours = x % 24;
		result[1] = Math.floor(hours);
		var x = x / 24;
		var days = x;
		result[1] = Math.floor(days);

	    return result;
	};

	/**
	 * Returns an array of N array containing the same number of elements
	 * The last group could have less elements.
	 *
	 */
	Utils.getNGroups = function (array, N) {
		return Utils.getGroupsSizeN(array, Math.floor(array.length / N));
	};

	/**
	 * Returns an array of array containing N elements each
	 * The last group could have less elements.
	 *
	 */
	Utils.getGroupsSizeN = function (array, N) {

		var copy = array.slice(0);
		var len = copy.length;
		var originalLen = copy.length;
		var result = [];

		// Init values for the loop algorithm
		var i;
		var idx;
		var group = [];
		var count = 0;
		for (i=0; i < originalLen; i++) {

			// Get a random idx between 0 and array length
			idx = Math.floor(Math.random()*len);

			// Prepare the array container for the elements of a new group
			if (count >= N) {
				result.push(group);
				count = 0;
				group = [];
			}

			// Insert element in the group
			group.push(copy[idx]);

			// Update
			copy.splice(idx,1);
			len = copy.length;
			count++;
		}

		// Add any remaining element
		if (group.length > 0) {
			result.push(group);
		}

		return result;
	};

	/**
	 * Match each element of the array with N random others
	 *
	 */
	Utils.matchN = function (array, N) {
		var result = []
		var len = array.length;
		for (var i = 0 ; i < len ; i++) {
			var copy = array.slice(0);
			copy.splice(i,1);
			var group = Utils.getNRandom(copy,N);
			group.splice(0,0,array[i]);

			//Update
			result.push(group);
			group = [];
		}
		return result;
	};

	/**
	 * http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
	 *
	 */
	Utils.shuffle = function (array, N, callback) {
		var copy = array.slice(0);
		var len = array.length-1; // ! -1
		for (var i = len; i > 0; i--) {
			var j = Math.floor(Math.random(0,1)*i);
			var tmp = copy[j];
			copy[j] = copy[i];
			copy[i] = tmp;
			console.log(copy);
		}
		return copy;
	};

	Utils.getNRandom = function (array, N, callback) {
		return Utils.shuffle(array).slice(0,N);
	};

	Utils.generateCombinations = function (array, r, callback) {
	    function equal(a, b) {
	        for (var i = 0; i < a.length; i++) {
	            if (a[i] != b[i]) return false;
	        }
	        return true;
	    }
	    function values(i, a) {
	        var ret = [];
	        for (var j = 0; j < i.length; j++) ret.push(a[i[j]]);
	        return ret;
	    }
	    var n = array.length;
	    var indices = [];
	    for (var i = 0; i < r; i++) indices.push(i);
	    var final = [];
	    for (var i = n - r; i < n; i++) final.push(i);
	    while (!equal(indices, final)) {
	        callback(values(indices, array));
	        var i = r - 1;
	        while (indices[i] == n - r + i) i -= 1;
	        indices[i] += 1;
	        for (var j = i + 1; j < r; j++) indices[j] = indices[i] + j - i;
	    }
	    callback(values(indices, array));
	}

})('undefined' != typeof node ? node : module.exports);<|endoftext|>


<commit_before>/** @jsx React.DOM */
/**
 * Copyright (c) 2014, Tidepool Project
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the associated License, which is identical to the BSD 2-Clause
 * License as published by the Open Source Initiative at opensource.org.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the License for more details.
 *
 * You should have received a copy of the License along with this program; if
 * not, you can obtain one from Tidepool Project at tidepool.org.
 */

var React = require('react');
var _ = require('lodash');
var cx = require('react/lib/cx');
var ModalOverlay = require('../ModalOverlay');
var InputGroup = require('../inputgroup');

var PatientTeam = React.createClass({
  propTypes: {
    user: React.PropTypes.object,
    patient: React.PropTypes.object,
    pendingInvites: React.PropTypes.array,
    onChangeMemberPermissions: React.PropTypes.func,
    onRemoveMember: React.PropTypes.func,
    onInviteMember: React.PropTypes.func,
    onCancelInvite: React.PropTypes.func,
  },

  getInitialState: function() {
    return {
      showModalOverlay: false,
      checked: 'view'
    };
  },

  renderPermissionOptions: function(value, name) {
    var PermissionInputGroup = React.createClass({
        propTypes: {
          items: React.PropTypes.array
        },
        getInitialState: function() {
          return {
            value: value
          }
        },
        handleChange: function(obj) {
          this.setState({value: obj.value});
        },
        /* jshint ignore:start */
        render: function() {
          return (
            <InputGroup
              name={name}
              items={items}
              type={'radios'}
              value={this.state.value}
              onChange={this.handleChange}/>
          );
        }
    });

    var items = [
      {value: 'view', label: 'View only'},
      {value: 'upload', label: 'View and upload'}
    ];

    /* jshint ignore:start */
    return (
      <PermissionInputGroup
        items={items}
        value={value}/>
    );
    /* jshint ignore:end */
  },

  renderChangeTeamMemberPermissionsDialog: function(member) {
    var self = this;
    var value = member.permissions.admin || member.permissions.upload ? 'upload' : 'view';
    var name = 'permissionOptions'+ member.userid;
    var inputs = this.renderPermissionOptions(value, name);

    var handleChangeMemberPermissions = function() {
      var permissions = {
        view: {},
        note: {}
      };

      if (inputs.state.value === 'upload') {
        permissions.upload = {};
      }

      self.props.onChangeMemberPermissions(self.props.user.userid, member.userid, permissions, function(err) {
        self.setState({
          showModalOverlay: false,
        });
      });
    };

    return (

{member.profile.fullName} is allowed to view and upload your data. If you would like to change that, here is the place.

          {inputs}

          <button className="PatientInfo-button PatientInfo-button--secondary" type="button" onClick={this.overlayClickHandler}>Cancel</button>
          <button className="PatientInfo-button PatientInfo-button--primary" type="submit" onClick={handleChangeMemberPermissions}>Save</button>

    );
  },

  handleChangeTeamMemberPermissions: function(member) {
    var self = this;

    return function() {
      self.setState({
        showModalOverlay: true,
        dialog: self.renderChangeTeamMemberPermissionsDialog(member)
      });
    }
  },

  handleRemoveMember: function(member) {
    var self = this;

    return function() {
      self.props.onRemoveMember(self.props.user.userid, member.userid, function(err) {
          self.setState({
            showModalOverlay: false,
          });
        }
      );
    }
  },

  renderRemoveTeamMemberDialog: function(member) {
    return (

{"Are you sure you want to remove this person? They will no longer be able to see or comment on your data."}

          <button className="PatientInfo-button PatientInfo-button--secondary" type="button" onClick={this.overlayClickHandler}>Cancel</button>
          <button className="PatientInfo-button PatientInfo-button--primary" type="submit" onClick={this.handleRemoveMember(member)}>{"I'm sure, remove them."}</button>

    );
  },

  handleRemoveTeamMember: function(member) {
    var self = this;

    return function() {
      self.setState({
        showModalOverlay: true,
        dialog: self.renderRemoveTeamMemberDialog(member)
      });
    };
  },

  renderTeamMember: function(member) {
    var classes = {
      'icon-permissions': true
    };

    if(member.permissions.admin) {
      classes['icon-permissions-own'] = true;
      title = "You own this data. You can change who else can see and upload data in " + member.profile.fullName + "'s profile page.";
    } else if(member.permissions.upload) {
      classes['icon-permissions-upload'] = true;
      title = "You are allowed to upload data to " + member.profile.fullName + "'s account.";
    } else if(member.permissions.view) {
      classes['icon-permissions-view'] = true;
      title = "You are allowed to see " + member.profile.fullName + "'s data.";
    } else {
      return null;
    }

    var iconClasses = cx(classes);

    /* jshint ignore:start */
    return (

{member.profile.fullName}

    );
    /* jshint ignore:end */
  },

  handleCancelInviteDialog: function(invite) {
    var self = this;

    return function() {
      self.props.onCancelInvite(invite.email, function(err) {
          self.setState({
            showModalOverlay: false,
          });
        }
      );
    }
  },

  renderCancelInviteDialog: function(invite) {
    return (

Are you sure you want to cancel your invitation to {invite.email}?

          <button className="PatientInfo-button PatientInfo-button--secondary" type="button" onClick={this.overlayClickHandler}>Cancel</button>
          <button className="PatientInfo-button PatientInfo-button--primary" type="submit" onClick={this.handleCancelInviteDialog(invite)}>{"I'm sure, cancel it."}</button>

    );
  },

  handleCancelInvite: function(invite) {
    var self = this;

    return function() {
      self.setState({
        showModalOverlay: true,
        dialog: self.renderCancelInviteDialog(invite)
      });
    }
  },

  renderPendingInvite: function(invite) {
    /* jshint ignore:start */
    return (

{invite.email}

Waiting for confirmation

    );
    /* jshint ignore:end */
  },

  renderInviteForm: function() {
    var self = this;

    var handleSubmit = function(email, permissions) {
      self.props.onInviteMember(self.props.user.userid, email, permissions, function(err) {
        self.setState({
          showModalOverlay: false,
        });
      });
    };

    var handleCancel = function() {
      console.log('cancel');
      self.setState({
        invite: false
      });
    };

    var MemberInviteForm = React.createClass({
        propTypes: {
          onSubmit: React.PropTypes.func,
          onCancel: React.PropTypes.func,
          inputs: React.PropTypes.renderable
        },
        getInitialState: function() {
          return {
            validationError: false
          }
        },
        render: function() {
          var self = this;

          var handleSubmit = function(obj) {
            var email = self.refs['email'].getDOMNode().value;

            var validateEmail = function(email) {
              var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
              return re.test(email);
            };

            if (!validateEmail(email)) {
              self.setState({
                validationError: true
              });
              return;
            } else {
              self.setState({
                validationError: false
              });
            }

            var permissions = {
              view: {},
              note: {}
            };

            if (self.props.inputs.state.value === 'upload') {
              permissions.upload = {};
            }

            self.props.onSubmit(email, permissions);
          };

          var error = null;

          if (this.state.validationError) {
            error = 'Invalid email address';
          }

          /* jshint ignore:start */
          return (

                    <input className="PatientInfo-input" id="email" ref="email" placeholder="email" />

                      {this.props.inputs}

                      <button className="PatientInfo-button PatientInfo-button--secondary" type="button" onClick={this.props.onCancel}>Cancel</button>
                      <button className="PatientInfo-button PatientInfo-button--primary" type="submit" onClick={handleSubmit}>Invite</button>

{error}

          );
          /* jshint ignore:end */
        }
    });

    /* jshint ignore:start */
    return(
      <MemberInviteForm
        onSubmit={handleSubmit}
        onCancel={handleCancel}
        inputs={self.renderPermissionOptions('view', 'invitePermissionOptions')}
      />
    );
    /* jshint ignore:end */
  },

  renderInvite: function() {
    var isTeamEmpty = this.props.patient.team.length === 0;
    var self = this;
    var classes = {
      'PatientTeam-member': true,
      'PatientTeam-member--emptyNew': isTeamEmpty,
      'PatientTeam-member--fadeNew': !isTeamEmpty
    };

    classes = cx(classes);

    var handleClick = function() {
      self.setState({
        invite: true
      });
    };

    /* jshint ignore:start */
    return (

Invite new member

    );
    /* jshint ignore:end */
  },

  overlayClickHandler: function() {
    this.setState({
      showModalOverlay: false
    });
  },

  renderModalOverlay: function() {
    /* jshint ignore:start */
    return (
      <ModalOverlay
        show={this.state.showModalOverlay}
        dialog={this.state.dialog}
        overlayClickHandler={this.overlayClickHandler}/>
    );
    /* jshint ignore:end */
  },

  render: function() {
    var members = _.map(this.props.patient.team, this.renderTeamMember);
    var pendingInvites = _.map(this.props.pendingInvites, this.renderPendingInvite);
    var invite = this.state && this.state.invite ? this.renderInviteForm() : this.renderInvite();

    return (

        {members}
        {pendingInvites}
        {invite}
        {this.renderModalOverlay()}

    );
    /* jshint ignore:end */
  }
});

module.exports = PatientTeam;
<commit_msg>jshint prefixes<commit_after>/** @jsx React.DOM */
/**
 * Copyright (c) 2014, Tidepool Project
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the associated License, which is identical to the BSD 2-Clause
 * License as published by the Open Source Initiative at opensource.org.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the License for more details.
 *
 * You should have received a copy of the License along with this program; if
 * not, you can obtain one from Tidepool Project at tidepool.org.
 */

var React = require('react');
var _ = require('lodash');
var cx = require('react/lib/cx');
var ModalOverlay = require('../ModalOverlay');
var InputGroup = require('../inputgroup');

var PatientTeam = React.createClass({
  propTypes: {
    user: React.PropTypes.object,
    patient: React.PropTypes.object,
    pendingInvites: React.PropTypes.array,
    onChangeMemberPermissions: React.PropTypes.func,
    onRemoveMember: React.PropTypes.func,
    onInviteMember: React.PropTypes.func,
    onCancelInvite: React.PropTypes.func,
  },

  getInitialState: function() {
    return {
      showModalOverlay: false,
      checked: 'view'
    };
  },

  renderPermissionOptions: function(value, name) {
    var PermissionInputGroup = React.createClass({
        propTypes: {
          items: React.PropTypes.array
        },
        getInitialState: function() {
          return {
            value: value
          };
        },
        handleChange: function(obj) {
          this.setState({value: obj.value});
        },
        render: function() {
          return (
            /* jshint ignore:start */
            <InputGroup
              name={name}
              items={items}
              type={'radios'}
              value={this.state.value}
              onChange={this.handleChange}/>
              /* jshint ignore:end */
          );
        }
    });

    var items = [
      {value: 'view', label: 'View only'},
      {value: 'upload', label: 'View and upload'}
    ];

    return (
      /* jshint ignore:start */
      <PermissionInputGroup
        items={items}
        value={value}/>
      /* jshint ignore:end */
    );

  },

  renderChangeTeamMemberPermissionsDialog: function(member) {
    var self = this;
    var value = member.permissions.admin || member.permissions.upload ? 'upload' : 'view';
    var name = 'permissionOptions'+ member.userid;
    var inputs = this.renderPermissionOptions(value, name);

    var handleChangeMemberPermissions = function() {
      var permissions = {
        view: {},
        note: {}
      };

      if (inputs.state.value === 'upload') {
        permissions.upload = {};
      }

      self.props.onChangeMemberPermissions(self.props.user.userid, member.userid, permissions, function(err) {
        self.setState({
          showModalOverlay: false,
        });
      });
    };

    return (
      /* jshint ignore:start */

{member.profile.fullName} is allowed to view and upload your data. If you would like to change that, here is the place.

          {inputs}

          <button className="PatientInfo-button PatientInfo-button--secondary" type="button" onClick={this.overlayClickHandler}>Cancel</button>
          <button className="PatientInfo-button PatientInfo-button--primary" type="submit" onClick={handleChangeMemberPermissions}>Save</button>

      /* jshint ignore:end */
    );
  },

  handleChangeTeamMemberPermissions: function(member) {
    var self = this;

    return function() {
      self.setState({
        showModalOverlay: true,
        dialog: self.renderChangeTeamMemberPermissionsDialog(member)
      });
    };
  },

  handleRemoveMember: function(member) {
    var self = this;

    return function() {
      self.props.onRemoveMember(self.props.user.userid, member.userid, function(err) {
          self.setState({
            showModalOverlay: false,
          });
        }
      );
    };
  },

  renderRemoveTeamMemberDialog: function(member) {
    return (
      /* jshint ignore:start */

{"Are you sure you want to remove this person? They will no longer be able to see or comment on your data."}

          <button className="PatientInfo-button PatientInfo-button--secondary" type="button" onClick={this.overlayClickHandler}>Cancel</button>
          <button className="PatientInfo-button PatientInfo-button--primary" type="submit" onClick={this.handleRemoveMember(member)}>{"I'm sure, remove them."}</button>

      /* jshint ignore:end */
    );
  },

  handleRemoveTeamMember: function(member) {
    var self = this;

    return function() {
      self.setState({
        showModalOverlay: true,
        dialog: self.renderRemoveTeamMemberDialog(member)
      });
    };
  },

  renderTeamMember: function(member) {
    var classes = {
      'icon-permissions': true
    };

    if(member.permissions.admin) {
      classes['icon-permissions-own'] = true;
      title = "You own this data. You can change who else can see and upload data in " + member.profile.fullName + "'s profile page.";
    } else if(member.permissions.upload) {
      classes['icon-permissions-upload'] = true;
      title = "You are allowed to upload data to " + member.profile.fullName + "'s account.";
    } else if(member.permissions.view) {
      classes['icon-permissions-view'] = true;
      title = "You are allowed to see " + member.profile.fullName + "'s data.";
    } else {
      return null;
    }

    var iconClasses = cx(classes);

    return (
      /* jshint ignore:start */

{member.profile.fullName}

      /* jshint ignore:end */
    );

  },

  handleCancelInviteDialog: function(invite) {
    var self = this;

    return function() {
      self.props.onCancelInvite(invite.email, function(err) {
          self.setState({
            showModalOverlay: false,
          });
        }
      );
    };
  },

  renderCancelInviteDialog: function(invite) {
    return (
      /* jshint ignore:start */

Are you sure you want to cancel your invitation to {invite.email}?

          <button className="PatientInfo-button PatientInfo-button--secondary" type="button" onClick={this.overlayClickHandler}>Cancel</button>
          <button className="PatientInfo-button PatientInfo-button--primary" type="submit" onClick={this.handleCancelInviteDialog(invite)}>{"I'm sure, cancel it."}</button>

      /* jshint ignore:end */
    );
  },

  handleCancelInvite: function(invite) {
    var self = this;

    return function() {
      self.setState({
        showModalOverlay: true,
        dialog: self.renderCancelInviteDialog(invite)
      });
    };
  },

  renderPendingInvite: function(invite) {

    return (
      /* jshint ignore:start */

{invite.email}

Waiting for confirmation

      /* jshint ignore:end */
    );

  },

  renderInviteForm: function() {
    var self = this;

    var handleSubmit = function(email, permissions) {
      self.props.onInviteMember(self.props.user.userid, email, permissions, function(err) {
        self.setState({
          showModalOverlay: false,
        });
      });
    };

    var handleCancel = function() {
      self.setState({
        invite: false
      });
    };

    var MemberInviteForm = React.createClass({
        propTypes: {
          onSubmit: React.PropTypes.func,
          onCancel: React.PropTypes.func,
          inputs: React.PropTypes.renderable
        },
        getInitialState: function() {
          return {
            validationError: false
          };
        },
        render: function() {
          var self = this;

          var handleSubmit = function(obj) {
            var email = self.refs['email'].getDOMNode().value;

            var validateEmail = function(email) {
              var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
              return re.test(email);
            };

            if (!validateEmail(email)) {
              self.setState({
                validationError: true
              });
              return;
            } else {
              self.setState({
                validationError: false
              });
            }

            var permissions = {
              view: {},
              note: {}
            };

            if (self.props.inputs.state.value === 'upload') {
              permissions.upload = {};
            }

            self.props.onSubmit(email, permissions);
          };

          var error = null;

          if (this.state.validationError) {
            error = 'Invalid email address';
          }

          return (
            /* jshint ignore:start */

                    <input className="PatientInfo-input" id="email" ref="email" placeholder="email" />

                      {this.props.inputs}

                      <button className="PatientInfo-button PatientInfo-button--secondary" type="button" onClick={this.props.onCancel}>Cancel</button>
                      <button className="PatientInfo-button PatientInfo-button--primary" type="submit" onClick={handleSubmit}>Invite</button>

{error}

            /* jshint ignore:end */
          );

        }
    });

    return(
      /* jshint ignore:start */
      <MemberInviteForm
        onSubmit={handleSubmit}
        onCancel={handleCancel}
        inputs={self.renderPermissionOptions('view', 'invitePermissionOptions')}
      />
      /* jshint ignore:end */
    );

  },

  renderInvite: function() {
    var isTeamEmpty = this.props.patient.team.length === 0;
    var self = this;
    var classes = {
      'PatientTeam-member': true,
      'PatientTeam-member--emptyNew': isTeamEmpty,
      'PatientTeam-member--fadeNew': !isTeamEmpty
    };

    classes = cx(classes);

    var handleClick = function() {
      self.setState({
        invite: true
      });
    };

    return (
      /* jshint ignore:start */

Invite new member

      /* jshint ignore:end */
    );

  },

  overlayClickHandler: function() {
    this.setState({
      showModalOverlay: false
    });
  },

  renderModalOverlay: function() {

    return (
      /* jshint ignore:start */
      <ModalOverlay
        show={this.state.showModalOverlay}
        dialog={this.state.dialog}
        overlayClickHandler={this.overlayClickHandler}/>
      /* jshint ignore:end */
    );

  },

  render: function() {
    var members = _.map(this.props.patient.team, this.renderTeamMember);
    var pendingInvites = _.map(this.props.pendingInvites, this.renderPendingInvite);
    var invite = this.state && this.state.invite ? this.renderInviteForm() : this.renderInvite();

    return (
      /* jshint ignore:start */

        {members}
        {pendingInvites}
        {invite}
        {this.renderModalOverlay()}

      /* jshint ignore:end */
    );

  }
});

module.exports = PatientTeam;
<|endoftext|>


<commit_before>import Ember from 'ember';
import DS from 'ember-data';

const { PromiseArray, PromiseObject } = DS;

const { Component, inject, RSVP, computed, isPresent } = Ember;
const { service } = inject;
const { reads, gt, sort } = computed;

export default Component.extend({
  store: service(),
  currentUser: service(),
  tagName: 'div',
  classNameBindings: [':pending-updates-summary', ':small-component', 'alert'],
  alert: computed.gt('updates.length', 0),
  schoolId: null,
  hasMoreThanOneSchool: gt('currentUser.model.schools.length', 1),
  schools: reads('currentUser.model.schools'),
  selectedSchool: computed('currentUser', 'schoolId', function(){
    let defer = RSVP.defer();

    this.get('currentUser').get('model').then(user => {
      user.get('schools').then(schools => {
        if(isPresent(this.get('schoolId'))){
          let school =  schools.find(school => {
            return school.get('id') === this.get('schoolId');
          });
          if(school){
            defer.resolve(school);
            return;
          }
        }
        user.get('school').then(school => {
          defer.resolve(school);
        });
      });
    });

    return PromiseObject.create({
      promise: defer.promise
    });

  }),
  sortSchoolsBy:['title'],
  sortedSchools: sort('schools', 'sortSchoolsBy'),

  updates: computed('selectedSchool', function(){
    let defer = RSVP.defer();
    this.get('selectedSchool').then(school => {
      this.get('store').query('pending-user-update', {
        limit: 1000,
        filters: {
          schools: [school.get('id')]
        }
      }).then(updates => {
        defer.resolve(updates);
      });
    });

    return PromiseArray.create({
      promise: defer.promise
    });
  }),
  actions: {
    changeSelectedSchool: function(schoolId){
      this.set('schoolId', schoolId);
    },
  }
});
<commit_msg>replaced DS.PromiseArray/Object with RSVP.Promise.<commit_after>import Ember from 'ember';

const { Component, inject, RSVP, computed, isPresent } = Ember;
const { service } = inject;
const { Promise } = RSVP;
const { reads, gt, sort } = computed;

export default Component.extend({
  store: service(),
  currentUser: service(),
  tagName: 'div',
  classNameBindings: [':pending-updates-summary', ':small-component', 'alert'],
  alert: computed.gt('updates.length', 0),
  schoolId: null,
  hasMoreThanOneSchool: gt('currentUser.model.schools.length', 1),
  schools: reads('currentUser.model.schools'),

  /**
   * The currently selected school, defaults to the current-user's primary school if none is selected.
   * @property selectedSchool
   * @type {Ember.computed}
   * @public
   */
  selectedSchool: computed('currentUser', 'schoolId', function(){
    return new Promise(resolve => {
      this.get('currentUser').get('model').then(user => {
        user.get('schools').then(schools => {
          if(isPresent(this.get('schoolId'))){
            let school =  schools.find(school => {
              return school.get('id') === this.get('schoolId');
            });
            if(school){
              resolve(school);
              return;
            }
          }
          user.get('school').then(school => {
            resolve(school);
          });
        });
      });
    });
  }),
  sortSchoolsBy:['title'],
  sortedSchools: sort('schools', 'sortSchoolsBy'),

  /**
   * A list of pending user updates.
   * @property updates
   * @type {Ember.computed}
   * @public
   */
  updates: computed('selectedSchool', function(){
    return new Promise(resolve => {
      this.get('selectedSchool').then(school => {
        this.get('store').query('pending-user-update', {
          limit: 1000,
          filters: {
            schools: [school.get('id')]
          }
        }).then(updates => {
          resolve(updates);
        });
      });
    });
  }),

  actions: {
    changeSelectedSchool: function(schoolId){
      this.set('schoolId', schoolId);
    },
  }
});
<|endoftext|>


<commit_before>enyo.kind({
    //* @public
    name: "moon.sample.search.RecentSearchFullSample",
    kind: "FittableRows",
    //* @protected
    autoNumber: false,
    fit: true,
    classes: "moon enyo-unselectable" /* + "background-full-image" */,
    components: [
        {kind: "enyo.Spotlight"},
        {classes: "left-panel", components: [
            {classes: "left-panel-content", components: [
                {content: "01", classes: "left-panel-number"},
                {content: "MAIN MENU", classes: "left-panel-title"}
            ]}
        ]},
        {classes: "right-panel", components: [
             {
                name: "",
                kind: "moon.Panel",
                titleAbove: "02",
                title: "Search",
                classes: "moon-sample-search-RecentSearchFullSample",
                headerComponents: [
                    {kind: "moon.IconButton", classes: "moon-header-delete-button", src: "assets/trash-can-icon.png"}
                ],
                components: [
                    {kind: "FittableColumns", classes: "moon-header-search", style: "width: 100%;", components: [
                        {classes: "moon-header-search-left"},
                        {kind: "moon.InputDecorator", fit: true, style: "", components: [
                            {kind: "moon.Input", placeholder: "Search term", onchange: "inputChanged"},
                            {kind: "Image", src: "../samples/assets/search-input-search.png"}
                        ]},
                        {classes: "moon-header-search-right"},
                    ]},
                    {name: "container", classes: 'body-container'},
                ]
            }
        ]}
    ],

    initComponents: function() {
        var length = 6;
        this.inherited(arguments);
        for (var i=0; i<length; i++) {
            this.$.container.createComponent({
                name: "item"+i, kind: "moon.sample.search.recent.category",
                categoryName: "RECENT SEARCH",
                items: [
                    {text: "RESULT", imageSrc: './assets/default-movie.png'},
                    {text: "RESULT", imageSrc: './assets/default-movie.png'},
                    {text: "RESULT", imageSrc: './assets/default-movie.png'}
                ],
                classes: 'search-recent-category'
            });
        }
    }

    //* @public

    // Do something
});

enyo.kind({
    //* @public
    name: "moon.sample.search.recent.category",
    published: {
        //* Category title
        categoryName: "",
        //* The items of a category
        items: "",
    },
    //* @protected
    classes: "category",
    components: [
        {name: "title", kind: "moon.Item", spotlight: true, classes: 'category-name'},
    ],

    initComponents: function() {
        this.inherited(arguments);
        this.$.title.setContent(this.categoryName);
        if (this.items instanceof Array) {
            for (var item in this.items) {
                this.createComponent({
                    classes: 'item', style: "background-image: url(" + (this.items[item])['imageSrc'] + ");", components: [
                        {content: (this.items[item])['text'], spotlight: true, classes: "item-text"}
                    ]
                });
            }
        }
    }

    //* @public

    // Do something
});
<commit_msg>GF-4277: Remove autoNumber property<commit_after>enyo.kind({
    //* @public
    name: "moon.sample.search.RecentSearchFullSample",
    kind: "FittableRows",
    //* @protected
    fit: true,
    classes: "moon enyo-unselectable" /* + "background-full-image" */,
    components: [
        {kind: "enyo.Spotlight"},
        {classes: "left-panel", components: [
            {classes: "left-panel-content", components: [
                {content: "01", classes: "left-panel-number"},
                {content: "MAIN MENU", classes: "left-panel-title"}
            ]}
        ]},
        {classes: "right-panel", components: [
             {
                name: "",
                kind: "moon.Panel",
                titleAbove: "02",
                title: "Search",
                classes: "moon-sample-search-RecentSearchFullSample",
                headerComponents: [
                    {kind: "moon.IconButton", classes: "moon-header-delete-button", src: "assets/trash-can-icon.png"}
                ],
                components: [
                    {kind: "FittableColumns", classes: "moon-header-search", style: "width: 100%;", components: [
                        {classes: "moon-header-search-left"},
                        {kind: "moon.InputDecorator", fit: true, style: "", components: [
                            {kind: "moon.Input", placeholder: "Search term", onchange: "inputChanged"},
                            {kind: "Image", src: "../samples/assets/search-input-search.png"}
                        ]},
                        {classes: "moon-header-search-right"},
                    ]},
                    {name: "container", classes: 'body-container'},
                ]
            }
        ]}
    ],

    initComponents: function() {
        var length = 6;
        this.inherited(arguments);
        for (var i=0; i<length; i++) {
            this.$.container.createComponent({
                name: "item"+i, kind: "moon.sample.search.recent.category",
                categoryName: "RECENT SEARCH",
                items: [
                    {text: "RESULT", imageSrc: './assets/default-movie.png'},
                    {text: "RESULT", imageSrc: './assets/default-movie.png'},
                    {text: "RESULT", imageSrc: './assets/default-movie.png'}
                ],
                classes: 'search-recent-category'
            });
        }
    }

    //* @public

    // Do something
});

enyo.kind({
    //* @public
    name: "moon.sample.search.recent.category",
    published: {
        //* Category title
        categoryName: "",
        //* The items of a category
        items: "",
    },
    //* @protected
    classes: "category",
    components: [
        {name: "title", kind: "moon.Item", spotlight: true, classes: 'category-name'},
    ],

    initComponents: function() {
        this.inherited(arguments);
        this.$.title.setContent(this.categoryName);
        if (this.items instanceof Array) {
            for (var item in this.items) {
                this.createComponent({
                    classes: 'item', style: "background-image: url(" + (this.items[item])['imageSrc'] + ");", components: [
                        {content: (this.items[item])['text'], spotlight: true, classes: "item-text"}
                    ]
                });
            }
        }
    }

    //* @public

    // Do something
});
<|endoftext|>


<commit_before>var showDownloadLinks = (function ($) {
  return function (options) {
    var typeOfInstallersToShow = options.typeOfInstallersToShow;

    var settingsForAllTypes = {
      stable: {
        download_info_url: "https://download.gocd.org/releases.json",
        download_prefix: "https://download.gocd.org/binaries/",
        version_to_show: function (release) {
          return release["go_version"];
        },
        cloud_info_url: "https://download.gocd.org/cloud.json",
        docker_org: 'gocd'
      },
      experimental: {
        download_info_url: "https://download.gocd.org/experimental/releases.json",
        download_prefix: "https://download.gocd.org/experimental/binaries/",
        version_to_show: function (release) {
          return release["go_full_version"];
        },
        cloud_info_url: "https://download.gocd.org/experimental/cloud.json",
        docker_org: 'gocdexperimental'
      }
    };

    var settings = settingsForAllTypes[typeOfInstallersToShow];

    var dateFilter = R.curry(function (timeInSecondsSinceEpoch) {
      return (
        new Date() - new Date(timeInSecondsSinceEpoch * 1000) <
        3600 * 24 * 366 * 1000
      );
    });

    var releasesLessThanAYearOld = R.filter(
      R.where({
        release_time: dateFilter
      })
    );

    var addURLToFiles = function (release) {
      var addDetailsFrom = R.curry(function (release, analyticsIDPrefix, o) {
        var afterAddingURL = R.assoc(
          "url",
          settings.download_prefix +
          release["go_full_version"] +
          "/" +
          o["file"],
          o
        );
        var afterAddingFilename = R.assoc(
          "filename",
          R.last(o["file"].split("/")),
          afterAddingURL,
          o
        );
        var afterAddingAnalyticsID = R.assoc(
          "analytics_id",
          analyticsIDPrefix + "_" + release["go_full_version"],
          afterAddingFilename,
          o
        );
        return afterAddingAnalyticsID;
      });

      return R.evolve({
          win: {
            server: addDetailsFrom(release, "Windows-Server"),
            agent: addDetailsFrom(release, "Windows-Agent"),
          },
          osx: {
            server: addDetailsFrom(release, "Mac-Server"),
            agent: addDetailsFrom(release, "Mac-Agent")
          },
          deb: {
            server: addDetailsFrom(release, "LinuxDeb-Server"),
            agent: addDetailsFrom(release, "LinuxDeb-Agent")
          },
          rpm: {
            server: addDetailsFrom(release, "LinuxRpm-Server"),
            agent: addDetailsFrom(release, "LinuxRpm-Agent")
          },
          generic: {
            server: addDetailsFrom(release, "Package-Server"),
            agent: addDetailsFrom(release, "Package-Agent")
          }
        },
        release
      );
    };

    var addDisplayVersion = R.curry(function (release) {
      return R.assoc(
        "display_version",
        settings.version_to_show(release),
        release
      );
    });

    var addReleaseDate = R.curry(function (release) {
      return R.assoc(
        "release_date",
        new Date(release["release_time_readable"]).toDateString().substr(4),
        release
      );
    });

    var compareVersions = function (propertyToCompareOn) {
      return function (a, b) {
        var i, diff;

        var segmentsA = a[propertyToCompareOn].replace("-", ".").split(".");
        var segmentsB = b[propertyToCompareOn].replace("-", ".").split(".");

        var l = Math.min(segmentsA.length, segmentsB.length);

        for (i = 0; i < l; i++) {
          diff = parseInt(segmentsB[i], 10) - parseInt(segmentsA[i], 10);
          if (diff) {
            return diff;
          }
        }
        return segmentsA.length - segmentsB.length;
      };
    };

    var showReleases = function (releaseData, cloudData) {
      var addInfo = function (latestRelease) {
        var notes = {
          deb: 'Note: If you prefer to use the APT repository to install, please follow these instructions.',
          rpm: 'Note: If you prefer to use the YUM repository to install, please follow these instructions.',
          generic: 'Note: Zip versions require a Java JRE/JDK of version 11 - 17.'
        };

        for (var key in notes) {
          var installerInfo = R.assoc("info", notes[key], latestRelease[key]);
          latestRelease = R.assoc(key, installerInfo, latestRelease);
        }
        return latestRelease;
      };

      var releases = R.compose(
        releasesLessThanAYearOld,
        R.sort(compareVersions("go_full_version")),
        R.map(addURLToFiles),
        R.map(addDisplayVersion),
        R.map(addReleaseDate)
      )(releaseData[0]);
      var cloudReleases = R.compose(
        releasesLessThanAYearOld,
        R.sort(compareVersions("go_version"))
      )(cloudData[0]);

      var latest_cloud_release = R.head(cloudReleases);
      var other_cloud_releases = R.tail(cloudReleases);
      var latestRelease = addInfo(R.head(releases));
      var template = Handlebars.compile(
        $("#download-revisions-template").html()
      );

      const assocDockerOrg = function (val) {
        return R.assoc('docker_org', settings.docker_org, val);
      };
      // adding the docker organisation
      latest_cloud_release = R.assoc('docker_org', settings.docker_org, latest_cloud_release);
      other_cloud_releases = R.map(assocDockerOrg, other_cloud_releases);

      $("#downloads").html(
        template({
          latest_release: latestRelease,
          all_other_releases: R.tail(releases),
          latest_version: releases[0].go_version,
          latest_cloud_release: latest_cloud_release,
          all_other_cloud_releases: other_cloud_releases
        })
      );

      // add additional padding if there are 32 bit and 64 bit installers to show
      $("#downloads #tab-windows .files:has(.download-files)").css(
        "padding-top",
        "40px"
      );
    };

    var showFailureMessage = function (error) {
      $("#downloads").html(
        '
Sorry. Something went wrong and we could not list the download links. \
        Please report this issue.
'
      );
      console.log("Error: " + error);
    };

    $("#downloads").html($(".loading-message-template").html());

    return $.when(
        downloadOrGetFromCache(settings.download_info_url),
        downloadOrGetFromCache(settings.cloud_info_url)
      )
      .done(showReleases)
      .fail(showFailureMessage);
  };
})(jQuery);

var downloadOrGetFromCache = (function ($) {
  var storedJSON = {};

  return function (url) {
    var deferred = $.Deferred();

    if (storedJSON.hasOwnProperty(url)) {
      deferred.resolve([storedJSON[url], "success"]);
      return deferred.promise();
    }

    return $.getJSON(url).done(function (data) {
      storedJSON[url] = data;
    });
  };
})(jQuery);

var setupShowVerifyChecksumMessage = (function ($) {
  return function () {
    $("body").on("click", "#downloads .verify-checksum", function (evt) {
      var checksumElement = $(evt.currentTarget);
      var template = Handlebars.compile(
        $("#verify-checksum-message-template").html()
      );
      $("#verify-checksum-message").html(
        template({
          filename: checksumElement.data("filename"),
          md5sum: checksumElement.data("md5sum"),
          sha1sum: checksumElement.data("sha1sum"),
          sha256sum: checksumElement.data("sha256sum")
        })
      );
      $("body").addClass("o-h");
    });
  };
})(jQuery);

var determinePackageNameBasedOnOS = function () {
  var userDefinedPackageName = window.location.hash.substr(1);
  var validPackageNames = [
    "zip",
    "windows",
    "osx",
    "debian",
    "redhat",
    "docker"
  ];
  if (
    userDefinedPackageName !== "" &&
    validPackageNames.includes(userDefinedPackageName)
  ) {
    return userDefinedPackageName;
  }

  var userAgent = navigator.userAgent;
  var packageName = "zip";
  if (userAgent.indexOf("Win") !== -1) packageName = "windows";
  if (userAgent.indexOf("Mac") !== -1) packageName = "osx";
  if (userAgent.indexOf("Debian") !== -1) packageName = "debian";
  if (userAgent.indexOf("Ubuntu") !== -1) packageName = "debian";
  if (userAgent.indexOf("RedHat") !== -1) packageName = "redhat";
  if (userAgent.indexOf("CentOS") !== -1) packageName = "redhat";

  return packageName;
};

var switchDownloadType = function (currentInstallerType) {
  $(".release-type input." + currentInstallerType).attr("checked", true);
};

var showHelpLinksFor = (function ($) {
  return function (packageName) {
    var installer_type_to_help_link_type = {
      debian: "linux",
      redhat: "linux",
      windows: "windows",
      zip: "zip",
      osx: "osx"
    };
    var template = Handlebars.compile($("#downloads-help-links").html());

    $("#help-links").html(
      template({
        os: installer_type_to_help_link_type[packageName]
      })
    );
  };
})(jQuery);

Handlebars.registerHelper("size", function (
  array,
  operator,
  expectedSize,
  options
) {
  "use strict";
  if (array == null || array == undefined) {
    return options.inverse(this);
  }

  switch (operator) {
    case "lt":
      return array.length < expectedSize ?
        options.fn(this) :
        options.inverse(this);
    case "lte":
      return array.length <= expectedSize ?
        options.fn(this) :
        options.inverse(this);
    case "eq":
      return array.length === expectedSize ?
        options.fn(this) :
        options.inverse(this);
    case "gt":
      return array.length > expectedSize ?
        options.fn(this) :
        options.inverse(this);
    case "gte":
      return array.length >= expectedSize ?
        options.fn(this) :
        options.inverse(this);
    default:
      throw "Invalid operator " + operator + ".";
      break;
  }
});

$(document).ready(function () {
  setTimeout(showPopup, 100);
});

function showPopup() {
  $(".banner-fixed-bottom").addClass("show-banner");
}
<commit_msg>Improve readability<commit_after>var showDownloadLinks = (function ($) {
  return function (options) {
    var typeOfInstallersToShow = options.typeOfInstallersToShow;

    var settingsForAllTypes = {
      stable: {
        download_info_url: "https://download.gocd.org/releases.json",
        download_prefix: "https://download.gocd.org/binaries/",
        version_to_show: function (release) {
          return release["go_version"];
        },
        cloud_info_url: "https://download.gocd.org/cloud.json",
        docker_org: 'gocd'
      },
      experimental: {
        download_info_url: "https://download.gocd.org/experimental/releases.json",
        download_prefix: "https://download.gocd.org/experimental/binaries/",
        version_to_show: function (release) {
          return release["go_full_version"];
        },
        cloud_info_url: "https://download.gocd.org/experimental/cloud.json",
        docker_org: 'gocdexperimental'
      }
    };

    var settings = settingsForAllTypes[typeOfInstallersToShow];

    var dateFilter = R.curry(function (timeInSecondsSinceEpoch) {
      return (
        new Date() - new Date(timeInSecondsSinceEpoch * 1000) <
        3600 * 24 * 366 * 1000
      );
    });

    var releasesLessThanAYearOld = R.filter(
      R.where({
        release_time: dateFilter
      })
    );

    var addURLToFiles = function (release) {
      var addDetailsFrom = R.curry(function (release, analyticsIDPrefix, o) {
        var afterAddingURL = R.assoc(
          "url",
          settings.download_prefix + release["go_full_version"] + "/" + o["file"],
          o
        );
        var afterAddingFilename = R.assoc(
          "filename",
          R.last(o["file"].split("/")),
          afterAddingURL,
          o
        );
        var afterAddingAnalyticsID = R.assoc(
          "analytics_id",
          analyticsIDPrefix + "_" + release["go_full_version"],
          afterAddingFilename,
          o
        );
        return afterAddingAnalyticsID;
      });

      return R.evolve({
          win: {
            server: addDetailsFrom(release, "Windows-Server"),
            agent: addDetailsFrom(release, "Windows-Agent"),
          },
          osx: {
            server: addDetailsFrom(release, "Mac-Server"),
            agent: addDetailsFrom(release, "Mac-Agent")
          },
          deb: {
            server: addDetailsFrom(release, "LinuxDeb-Server"),
            agent: addDetailsFrom(release, "LinuxDeb-Agent")
          },
          rpm: {
            server: addDetailsFrom(release, "LinuxRpm-Server"),
            agent: addDetailsFrom(release, "LinuxRpm-Agent")
          },
          generic: {
            server: addDetailsFrom(release, "Package-Server"),
            agent: addDetailsFrom(release, "Package-Agent")
          }
        },
        release
      );
    };

    var addDisplayVersion = R.curry(function (release) {
      return R.assoc(
        "display_version",
        settings.version_to_show(release),
        release
      );
    });

    var addReleaseDate = R.curry(function (release) {
      return R.assoc(
        "release_date",
        new Date(release["release_time_readable"]).toDateString().substr(4),
        release
      );
    });

    var compareVersions = function (propertyToCompareOn) {
      return function (a, b) {
        var i, diff;

        var segmentsA = a[propertyToCompareOn].replace("-", ".").split(".");
        var segmentsB = b[propertyToCompareOn].replace("-", ".").split(".");

        var l = Math.min(segmentsA.length, segmentsB.length);

        for (i = 0; i < l; i++) {
          diff = parseInt(segmentsB[i], 10) - parseInt(segmentsA[i], 10);
          if (diff) {
            return diff;
          }
        }
        return segmentsA.length - segmentsB.length;
      };
    };

    var showReleases = function (releaseData, cloudData) {
      var addInfo = function (latestRelease) {
        var notes = {
          deb: 'Note: If you prefer to use the APT repository to install, please follow these instructions.',
          rpm: 'Note: If you prefer to use the YUM repository to install, please follow these instructions.',
          generic: 'Note: Zip versions require a Java JRE/JDK of version 11 - 17.'
        };

        for (var key in notes) {
          var installerInfo = R.assoc("info", notes[key], latestRelease[key]);
          latestRelease = R.assoc(key, installerInfo, latestRelease);
        }
        return latestRelease;
      };

      var releases = R.compose(
        releasesLessThanAYearOld,
        R.sort(compareVersions("go_full_version")),
        R.map(addURLToFiles),
        R.map(addDisplayVersion),
        R.map(addReleaseDate)
      )(releaseData[0]);
      var cloudReleases = R.compose(
        releasesLessThanAYearOld,
        R.sort(compareVersions("go_version"))
      )(cloudData[0]);

      var latest_cloud_release = R.head(cloudReleases);
      var other_cloud_releases = R.tail(cloudReleases);
      var latestRelease = addInfo(R.head(releases));
      var template = Handlebars.compile(
        $("#download-revisions-template").html()
      );

      const assocDockerOrg = function (val) {
        return R.assoc('docker_org', settings.docker_org, val);
      };
      // adding the docker organisation
      latest_cloud_release = R.assoc('docker_org', settings.docker_org, latest_cloud_release);
      other_cloud_releases = R.map(assocDockerOrg, other_cloud_releases);

      $("#downloads").html(
        template({
          latest_release: latestRelease,
          all_other_releases: R.tail(releases),
          latest_version: releases[0].go_version,
          latest_cloud_release: latest_cloud_release,
          all_other_cloud_releases: other_cloud_releases
        })
      );

      // add additional padding if there are 32 bit and 64 bit installers to show
      $("#downloads #tab-windows .files:has(.download-files)").css(
        "padding-top",
        "40px"
      );
    };

    var showFailureMessage = function (error) {
      $("#downloads").html(
        '
Sorry. Something went wrong and we could not list the download links. \
        Please report this issue.
'
      );
      console.log("Error: " + error);
    };

    $("#downloads").html($(".loading-message-template").html());

    return $.when(
        downloadOrGetFromCache(settings.download_info_url),
        downloadOrGetFromCache(settings.cloud_info_url)
      )
      .done(showReleases)
      .fail(showFailureMessage);
  };
})(jQuery);

var downloadOrGetFromCache = (function ($) {
  var storedJSON = {};

  return function (url) {
    var deferred = $.Deferred();

    if (storedJSON.hasOwnProperty(url)) {
      deferred.resolve([storedJSON[url], "success"]);
      return deferred.promise();
    }

    return $.getJSON(url).done(function (data) {
      storedJSON[url] = data;
    });
  };
})(jQuery);

var setupShowVerifyChecksumMessage = (function ($) {
  return function () {
    $("body").on("click", "#downloads .verify-checksum", function (evt) {
      var checksumElement = $(evt.currentTarget);
      var template = Handlebars.compile(
        $("#verify-checksum-message-template").html()
      );
      $("#verify-checksum-message").html(
        template({
          filename: checksumElement.data("filename"),
          md5sum: checksumElement.data("md5sum"),
          sha1sum: checksumElement.data("sha1sum"),
          sha256sum: checksumElement.data("sha256sum")
        })
      );
      $("body").addClass("o-h");
    });
  };
})(jQuery);

var determinePackageNameBasedOnOS = function () {
  var userDefinedPackageName = window.location.hash.substr(1);
  var validPackageNames = [
    "zip",
    "windows",
    "osx",
    "debian",
    "redhat",
    "docker"
  ];
  if (
    userDefinedPackageName !== "" &&
    validPackageNames.includes(userDefinedPackageName)
  ) {
    return userDefinedPackageName;
  }

  var userAgent = navigator.userAgent;
  var packageName = "zip";
  if (userAgent.indexOf("Win") !== -1) packageName = "windows";
  if (userAgent.indexOf("Mac") !== -1) packageName = "osx";
  if (userAgent.indexOf("Debian") !== -1) packageName = "debian";
  if (userAgent.indexOf("Ubuntu") !== -1) packageName = "debian";
  if (userAgent.indexOf("RedHat") !== -1) packageName = "redhat";
  if (userAgent.indexOf("CentOS") !== -1) packageName = "redhat";

  return packageName;
};

var switchDownloadType = function (currentInstallerType) {
  $(".release-type input." + currentInstallerType).attr("checked", true);
};

var showHelpLinksFor = (function ($) {
  return function (packageName) {
    var installer_type_to_help_link_type = {
      debian: "linux",
      redhat: "linux",
      windows: "windows",
      zip: "zip",
      osx: "osx"
    };
    var template = Handlebars.compile($("#downloads-help-links").html());

    $("#help-links").html(
      template({
        os: installer_type_to_help_link_type[packageName]
      })
    );
  };
})(jQuery);

Handlebars.registerHelper("size", function (
  array,
  operator,
  expectedSize,
  options
) {
  "use strict";
  if (array == null || array == undefined) {
    return options.inverse(this);
  }

  switch (operator) {
    case "lt":
      return array.length < expectedSize ?
        options.fn(this) :
        options.inverse(this);
    case "lte":
      return array.length <= expectedSize ?
        options.fn(this) :
        options.inverse(this);
    case "eq":
      return array.length === expectedSize ?
        options.fn(this) :
        options.inverse(this);
    case "gt":
      return array.length > expectedSize ?
        options.fn(this) :
        options.inverse(this);
    case "gte":
      return array.length >= expectedSize ?
        options.fn(this) :
        options.inverse(this);
    default:
      throw "Invalid operator " + operator + ".";
      break;
  }
});

$(document).ready(function () {
  setTimeout(showPopup, 100);
});

function showPopup() {
  $(".banner-fixed-bottom").addClass("show-banner");
}
<|endoftext|>