<commit_before>import { OneInch, ZEROX, ParaSwap, Changelly } from './providers';
import BigNumber from 'bignumber.js';
import Configs from './configs/providersConfigs';
import hasValidDecimals from '@/core/helpers/hasValidDecimals.js';
import { isObject } from 'lodash';

class Swap {
  constructor(web3, chain) {
    this.providers = [
      new OneInch(web3, chain),
      new ZEROX(web3, chain),
      new ParaSwap(web3, chain),
      new Changelly(web3, chain)
    ];
    this.chain = chain;
  }
  getAllTokens() {
    const allTokens = {};
    return this.providers[0].getSupportedTokens().then(baseList => {
      if (baseList && baseList.length > 0) {
        baseList.forEach(t => (allTokens[t.contract] = t));
        return Promise.all(
          this.providers.slice(3).map(p => {
            if (!p.isSupportedNetwork(this.chain)) return Promise.resolve();
            return p.getSupportedTokens().then(tokens => {
              if (tokens && tokens.length > 0) {
                tokens.forEach(t => {
                  if (!allTokens[t.contract]) {
                    allTokens[t.contract] = t;
                  }
                });
              }
            });
          })
        ).then(() => {
          const sorted = Object.values(allTokens)
            .filter(t => isObject(t))
            .sort((a, b) => {
              if (a.name > b.name) return 1;
              return -1;
            });
          return {
            fromTokens: sorted.filter(t => {
              if (!t || !t.contract) return false;
              return t;
            }),
            toTokens: sorted
          };
        });
      }
    });
  }
  getAllQuotes({ fromT, toT, fromAmount }) {
    let allQuotes = [];
    return Promise.all(
      this.providers.map(p => {
        if (!p.isSupportedNetwork(this.chain)) return Promise.resolve();
        return p.getQuote({ fromT, toT, fromAmount }).then(quotes => {
          allQuotes = allQuotes.concat(quotes);
        });
      })
    ).then(() => {
      allQuotes.sort((q1, q2) => {
        if (new BigNumber(q1.amount).gt(new BigNumber(q2.amount))) return -1;
        return 1;
      });
      return allQuotes.map(q => {
        if (Configs.exchangeInfo[q.exchange]) {
          q.exchangeInfo = Configs.exchangeInfo[q.exchange];
        } else {
          q.exchangeInfo = Configs.exchangeInfo.default;
          q.exchangeInfo.name = q.exchange;
        }
        return q;
      });
    });
  }
  getQuotesForSet(arr) {
    const quotes = [];
    const provider = this.providers[3];
    for (let i = 0; i < arr.length; i++) {
      quotes.push(provider.getQuote(arr[i]));
    }
    return Promise.all(quotes);
  }
  getTrade(tradeInfo) {
    for (const p of this.providers) {
      if (p.provider === tradeInfo.provider) return p.getTrade(tradeInfo);
    }
  }
  isValidToAddress(addressInfo) {
    for (const p of this.providers) {
      if (p.provider === addressInfo.provider)
        return p.isValidToAddress(addressInfo);
    }
  }
  executeTrade(tradeInfo, confirmInfo) {
    for (const p of this.providers) {
      if (p.provider === tradeInfo.provider)
        return p.executeTrade(tradeInfo, confirmInfo);
    }
  }
  getMinMaxAmount(tradeInfo) {
    for (const p of this.providers) {
      if (p.provider === tradeInfo.provider)
        return p.getMinMaxAmount(tradeInfo);
    }
  }
  getStatus(statusObj) {
    for (const p of this.providers) {
      if (p.provider === statusObj.provider) return p.getStatus(statusObj);
    }
  }
}

Swap.helpers = {
  hasValidDecimals
};

export default Swap;
<commit_msg>refactor: ♻ baseList undefined and empty check<commit_after>import { OneInch, ZEROX, ParaSwap, Changelly } from './providers';
import BigNumber from 'bignumber.js';
import Configs from './configs/providersConfigs';
import hasValidDecimals from '@/core/helpers/hasValidDecimals.js';
import { isObject } from 'lodash';

class Swap {
  constructor(web3, chain) {
    this.providers = [
      new OneInch(web3, chain),
      new ZEROX(web3, chain),
      new ParaSwap(web3, chain),
      new Changelly(web3, chain)
    ];
    this.chain = chain;
  }
  getAllTokens() {
    const allTokens = {};
    return this.providers[0].getSupportedTokens().then(baseList => {
      if (baseList && baseList.length > 0)
        baseList.forEach(t => (allTokens[t.contract] = t));
      return Promise.all(
        this.providers.slice(3).map(p => {
          if (!p.isSupportedNetwork(this.chain)) return Promise.resolve();
          return p.getSupportedTokens().then(tokens => {
            if (tokens && tokens.length > 0) {
              tokens.forEach(t => {
                if (!allTokens[t.contract]) {
                  allTokens[t.contract] = t;
                }
              });
            }
          });
        })
      ).then(() => {
        const sorted = Object.values(allTokens)
          .filter(t => isObject(t))
          .sort((a, b) => {
            if (a.name > b.name) return 1;
            return -1;
          });
        return {
          fromTokens: sorted.filter(t => {
            if (!t || !t.contract) return false;
            return t;
          }),
          toTokens: sorted
        };
      });
    });
  }
  getAllQuotes({ fromT, toT, fromAmount }) {
    let allQuotes = [];
    return Promise.all(
      this.providers.map(p => {
        if (!p.isSupportedNetwork(this.chain)) return Promise.resolve();
        return p.getQuote({ fromT, toT, fromAmount }).then(quotes => {
          allQuotes = allQuotes.concat(quotes);
        });
      })
    ).then(() => {
      allQuotes.sort((q1, q2) => {
        if (new BigNumber(q1.amount).gt(new BigNumber(q2.amount))) return -1;
        return 1;
      });
      return allQuotes.map(q => {
        if (Configs.exchangeInfo[q.exchange]) {
          q.exchangeInfo = Configs.exchangeInfo[q.exchange];
        } else {
          q.exchangeInfo = Configs.exchangeInfo.default;
          q.exchangeInfo.name = q.exchange;
        }
        return q;
      });
    });
  }
  getQuotesForSet(arr) {
    const quotes = [];
    const provider = this.providers[3];
    for (let i = 0; i < arr.length; i++) {
      quotes.push(provider.getQuote(arr[i]));
    }
    return Promise.all(quotes);
  }
  getTrade(tradeInfo) {
    for (const p of this.providers) {
      if (p.provider === tradeInfo.provider) return p.getTrade(tradeInfo);
    }
  }
  isValidToAddress(addressInfo) {
    for (const p of this.providers) {
      if (p.provider === addressInfo.provider)
        return p.isValidToAddress(addressInfo);
    }
  }
  executeTrade(tradeInfo, confirmInfo) {
    for (const p of this.providers) {
      if (p.provider === tradeInfo.provider)
        return p.executeTrade(tradeInfo, confirmInfo);
    }
  }
  getMinMaxAmount(tradeInfo) {
    for (const p of this.providers) {
      if (p.provider === tradeInfo.provider)
        return p.getMinMaxAmount(tradeInfo);
    }
  }
  getStatus(statusObj) {
    for (const p of this.providers) {
      if (p.provider === statusObj.provider) return p.getStatus(statusObj);
    }
  }
}

Swap.helpers = {
  hasValidDecimals
};

export default Swap;
<|endoftext|>


<commit_before>import AWS from 'aws-sdk';
import config from '../../config/config.json';
import log from '../log';

AWS.config.update(config.AWS.credentials);

function publishToNewPostTopic(subject, message) {
  return new Promise((resolve, reject) => {
    const sns = new AWS.SNS();
    sns.publish({
      TargetArn: config.AWS.SNS.newPostARN,
      Subject: subject,
      Message: message
    }, (error, data) => {
      if (error) {
        log.error({ error }, 'Error publishing to new post SNS topic');
        reject(error);
      } else {
        log.info({ subject, message }, 'Posted to new post SNS Topic');
        resolve(data.MessageId);
      }
    });
  });
}

export default function notifyOfNewBlogs(usersToNewPosts) {
  return new Promise(() => {
    // TODO: throw if usersToNewPosts isnt a list or is of length 0

    if (usersToNewPosts.length === 1) {
      const singleAuthor = usersToNewPosts[0];
      if (singleAuthor.newPosts.length === 1) {
        return publishToNewPostTopic(`${singleAuthor.firstName} ${singleAuthor.lastName} published a new blog post`,
                                     singleAuthor.newPosts[0].title);
      }

      const intro = singleAuthor.newPosts.length > 2 ? 'Including:' : '';
      return publishToNewPostTopic(`${singleAuthor.firstName} ${singleAuthor.lastName} published ${singleAuthor.newPosts.length} new blog posts`,
                                    `${intro} "${singleAuthor.newPosts[0].title}" and "${singleAuthor.newPosts[1].title}"`);
    }

    const numberOfNewPosts = usersToNewPosts.reduce((total, user) => total + user.newPosts.length, 0);
    const intro = usersToNewPosts.length > 2 ? 'Including posts by' : 'Written by';
    return publishToNewPostTopic(`Read ${numberOfNewPosts} new posts by ${usersToNewPosts.length} authors`,
                                 `${intro} ${usersToNewPosts[0].firstName} ${usersToNewPosts[0].lastName} and ${usersToNewPosts[1].firstName} ${usersToNewPosts[1].lastName}`);
  });
}
<commit_msg>Added code to deal with invalid usersToNewPosts object<commit_after>import AWS from 'aws-sdk';
import check from 'check-types';
import config from '../../config/config.json';
import log from '../log';

AWS.config.update(config.AWS.credentials);

function publishToNewPostTopic(subject, message) {
  return new Promise((resolve, reject) => {
    const sns = new AWS.SNS();
    sns.publish({
      TargetArn: config.AWS.SNS.newPostARN,
      Subject: subject,
      Message: message
    }, (error, data) => {
      if (error) {
        log.error({ error }, 'Error publishing to new post SNS topic');
        reject(error);
      } else {
        log.info({ subject, message }, 'Posted to new post SNS Topic');
        resolve(data.MessageId);
      }
    });
  });
}

export default function notifyOfNewBlogs(usersToNewPosts) {
  return new Promise((resolve, reject) => {
    if (!check.array(usersToNewPosts) || usersToNewPosts.length === 0) {
      reject(new Error('Valid array of users with new posts required'));
    }

    if (usersToNewPosts.length === 1) {
      const singleAuthor = usersToNewPosts[0];
      if (singleAuthor.newPosts.length === 1) {
        return publishToNewPostTopic(`${singleAuthor.firstName} ${singleAuthor.lastName} published a new blog post`,
                                     singleAuthor.newPosts[0].title);
      }

      const intro = singleAuthor.newPosts.length > 2 ? 'Including:' : '';
      return publishToNewPostTopic(`${singleAuthor.firstName} ${singleAuthor.lastName} published ${singleAuthor.newPosts.length} new blog posts`,
                                    `${intro} "${singleAuthor.newPosts[0].title}" and "${singleAuthor.newPosts[1].title}"`);
    }

    const numberOfNewPosts = usersToNewPosts.reduce((total, user) => total + user.newPosts.length, 0);
    const intro = usersToNewPosts.length > 2 ? 'Including posts by' : 'Written by';
    return publishToNewPostTopic(`Read ${numberOfNewPosts} new posts by ${usersToNewPosts.length} authors`,
                                 `${intro} ${usersToNewPosts[0].firstName} ${usersToNewPosts[0].lastName} and ${usersToNewPosts[1].firstName} ${usersToNewPosts[1].lastName}`);
  });
}
<|endoftext|>


<commit_before>/**
 * `withData` higher-order component.
 *
 * Site Kit by Google, Copyright 2019 Google LLC
 *
 * 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
 *
 *     https://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.
 */

/**
 * External dependencies
 */
import castArray from 'lodash/castArray';
import each from 'lodash/each';

/**
 * WordPress dependencies
 */
import { addFilter, addAction } from '@wordpress/hooks';
import { Component } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import { getModulesData } from '../../util';
import getNoDataComponent from '../notifications/nodata';
import getDataErrorComponent from '../notifications/data-error';
import getSetupIncompleteComponent from '../notifications/setup-incomplete';
import { TYPE_MODULES } from '../data/constants';

/**
 * Provides data from the API to components. (Legacy HOC.)
 *
 * A Higher order Component that provides data functionality to Components.
 *
 * This function takes a React Component that is data dependent, resolving via the data API.
 *
 * Automatically detects data errors, displaying an error CTA Component. Components can extend the default
 * error handling to enable custom error messaging or data shapes.
 *
 * Components can provide a callback that checks if the data is "zero" - typically when an account is newly established and not yet providing data. In most cases the API returns all 0s, however some APIs may return empty strings or null.
 *
 * Components can optionally include `handleDataError` and `handleDataSuccess` function as props. `handleDataError` will be
 * called with the error message string if there is a data error and called with no string if the data is empty.
 * `handleDataSuccess` will be called when data resolves correctly.
 *
 * @since 1.0.0
 *
 * @param {WPElement} DataDependentComponent The React Component to render once we have its required data.
 * @param {Array}     selectData             An array of data objects to resolve.
 *                                                 Each object includes the following properties:
 *                                                 {string}         type       The data type. Either 'core' or 'modules'.
 *                                                 {string}         identifier The data identifier, for example a module slug.
 *                                                 {string}         datapoint  The datapoint.
 *                                                 {Object?}        data       Optional arguments to pass along.
 *                                                 {number}         priority   The data request priority, used for batching.
 *                                                 {number}         maxAge     How long to cache the data results.
 *                                                 {string | array} context    The context(s) to resolve data, eg 'Dashboard'.
 *
 * @param {WPElement} loadingComponent       A React Component to render while the data is resolving.
 * @param {Object}    layoutOptions          An object with layout options that are passed to the getNoDataComponent and getDataErrorComponent components.
 * @param {Function}  isDataZero             A callback function that is passed the resolved data and returns true
 *                                                 if the data is "zero".
 * @param {Function}  getDataError           A callback function that is passed the resolved data and returns the
 *                                                 error message.
 * @return {WPElement} Component  	Returns React.Components based on data and state.
 *                                  If has data  	  Return DataDependentComponent with data.
 *                                  has no data		  Fallback message when no data.
 *                                  in loading state  Return loadingComponent.
 *                                  has an error	  Returns error.
 *
 */
const withData = (
	DataDependentComponent,
	selectData,
	loadingComponent = null,

	layoutOptions = {
		inGrid: false,
		fullWidth: false,
		createGrid: false,
	},

	// The default isDataZero handler always returns false, Components must define when data is zero.
	// `isDataZero` is passed `returnedData`and `datapoint`.
	isDataZero = () => {
		return false;
	},

	// The default getDataError handler detects data.error and extracts the message from data.error.message or data.error.errors[0].message.
	getDataError = ( data ) => {
		if ( data && data.error ) {
			if ( data.error.message ) {
				return data.error.message;
			}
			if ( data.error.errors && data.error.errors[ 0 ] && data.error.errors[ 0 ].message ) {
				return data.error.errors[ 0 ].message;
			}
			return __( 'Unidentified error', 'google-site-kit' );
		}

		if ( data && data.errors && data.errors[ 0 ] && data.errors[ 0 ].message ) {
			return data.errors[ 0 ].message;
		}

		if ( data && data.error_data ) {
			const errors = Object.values( data.error_data );

			// Catch RateLimitExceeded specifically.
			if ( errors[ 0 ] && 'RateLimitExceeded' === errors[ 0 ].reason ) {
				return __( 'Too many requests have been sent within a given time span. Please reload this page again in a few seconds', 'google-site-kit' );
			}
		}

		if ( data && data.errors ) {
			const errors = Object.values( data.errors );
			if ( errors[ 0 ] && errors[ 0 ][ 0 ] ) {
				return errors[ 0 ][ 0 ];
			}
		}

		// If error is the root of the response, ensure all expected parts are
		// present, just to "be sure" that it is an error. All above error
		// handlers are legacy and are likely never hit, but let's keep them
		// because nobody will ever know.
		if ( data.code && data.message && data.data && data.data.status ) {
			return data.message;
		}

		// No error.
		return false;
	}
) => {
	// ...and returns another component...
	return class NewComponent extends Component {
		constructor( props ) {
			super( props );

			this.state = {
				data: false,
				zeroData: false,
				errorMessage: false,
			};

			addAction(
				'googlesitekit.moduleDataReset',
				'googlesitekit.moduleDataResetHandler',
				() => {
					this.setState( {
						data: false,
						errorMessage: false,
						zeroData: false,
					} );
				}
			);

			/**
			 * Handles a single datapoint returned from the data API.
			 *
			 * Each resolved data point is passed thru this handler to detect errors and zero data conditions, and
			 * to trigger `handleDataError` and `handleDataSuccess` helpers.
			 *
			 * @since 1.0.0
			 *
			 * @param {Object} returnedData The data returned from the API.
			 * @param {Object} requestData  The data object for the request.
			 */
			const handleReturnedData = ( returnedData, requestData ) => {
				// If available, `handleDataError` will be called for errors (with a string) and empty data.
				const {
					handleDataError,
					handleDataSuccess,
				} = this.props;
				const { datapoint, identifier, toState } = requestData;

				// Check to see if the returned data is an error. If so, getDataError will return a string.
				const errorMessage = getDataError( returnedData );
				if ( errorMessage ) {
					// Set an error state on the Component.
					this.setState( {
						errorMessage,
						errorObj: returnedData,
						module: identifier,
					} );

					// If the Component included a `handleDataError` helper, pass it the error message.
					if ( handleDataError ) {
						handleDataError( errorMessage, returnedData );
					}
				} else if ( isDataZero( returnedData, datapoint, requestData ) ) { // No data error, next check for zero data.
					// If we have a `handleDataError` call it without any parameters (indicating empty data).
					if ( handleDataError ) {
						handleDataError( errorMessage, returnedData );
					}

					// Set a zeroData state on the Component.
					this.setState( { zeroData: true } );
				} else if ( handleDataSuccess ) {
					// Success! `handleDataSuccess` will be called (ie. not error or zero).
					handleDataSuccess();
				}

				// Resolve the returned data by setting state on the Component.
				this.setState( {
					requestDataToState: toState,
					data: returnedData,
					datapoint,
					module: identifier,
				} );
			};

			// Resolve all selectedData.
			each( selectData, ( data ) => {
				const { type, identifier } = data || {};
				// Handle single contexts, or arrays of contexts.
				each( castArray( data.context ), ( context ) => {
					/**
					 * Request data for the context.
					 */
					addFilter(
						`googlesitekit.module${ context }DataRequest`,
						`googlesitekit.data${ context }`,
						( moduleData ) => {
							const modulesData = getModulesData();

							if ( TYPE_MODULES === type && ! modulesData[ identifier ]?.setupComplete ) {
								// We need to set the module (slug) here as it is normally set in handleReturnedData.
								this.setState( { module: identifier } );
								return moduleData;
							}

							const callback = ( returnedData ) => {
								handleReturnedData( returnedData, data );
							};

							return moduleData.concat( { ...data, callback } );
						}
					);
				} );
			} );
		}

		render() {
			const {
				data,
				datapoint,
				module,
				zeroData,
				errorMessage,
				errorObj,
				requestDataToState,
			} = this.state;

			const modulesData = getModulesData();
			const { active, setupComplete } = modulesData?.[ module ] || {};

			if ( active && ! setupComplete ) {
				return getSetupIncompleteComponent( module, layoutOptions.inGrid, layoutOptions.fullWidth, layoutOptions.createGrid );
			}

			// Render the loading component until we have data.
			if ( ! data ) {
				return loadingComponent;
			}

			// If we have an error, display the DataErrorComponent.
			if ( errorMessage ) {
				return ( 'string' !== typeof errorMessage ) ? errorMessage : getDataErrorComponent( module, errorMessage, layoutOptions.inGrid, layoutOptions.fullWidth, layoutOptions.createGrid, errorObj );
			}

			// If we have zeroData, display the NoDataComponent.
			if ( zeroData ) {
				const moduleName = module ? modulesData[ module ].name : __( 'Site Kit', 'google-site-kit' );

				return getNoDataComponent( moduleName, layoutOptions.inGrid, layoutOptions.fullWidth, layoutOptions.createGrid );
			}

			// Render the Component when we have data, passing the datapoint.
			return (
				<DataDependentComponent
					data={ data }
					datapoint={ datapoint }
					requestDataToState={ requestDataToState }
					{ ...this.props }
				/>
			);
		}
	};
};

export default withData;
<commit_msg>Use moduleRequiringSetup state.<commit_after>/**
 * `withData` higher-order component.
 *
 * Site Kit by Google, Copyright 2019 Google LLC
 *
 * 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
 *
 *     https://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.
 */

/**
 * External dependencies
 */
import castArray from 'lodash/castArray';
import each from 'lodash/each';

/**
 * WordPress dependencies
 */
import { addFilter, addAction } from '@wordpress/hooks';
import { Component } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import { getModulesData } from '../../util';
import getNoDataComponent from '../notifications/nodata';
import getDataErrorComponent from '../notifications/data-error';
import getSetupIncompleteComponent from '../notifications/setup-incomplete';
import { TYPE_MODULES } from '../data/constants';

/**
 * Provides data from the API to components. (Legacy HOC.)
 *
 * A Higher order Component that provides data functionality to Components.
 *
 * This function takes a React Component that is data dependent, resolving via the data API.
 *
 * Automatically detects data errors, displaying an error CTA Component. Components can extend the default
 * error handling to enable custom error messaging or data shapes.
 *
 * Components can provide a callback that checks if the data is "zero" - typically when an account is newly established and not yet providing data. In most cases the API returns all 0s, however some APIs may return empty strings or null.
 *
 * Components can optionally include `handleDataError` and `handleDataSuccess` function as props. `handleDataError` will be
 * called with the error message string if there is a data error and called with no string if the data is empty.
 * `handleDataSuccess` will be called when data resolves correctly.
 *
 * @since 1.0.0
 *
 * @param {WPElement} DataDependentComponent The React Component to render once we have its required data.
 * @param {Array}     selectData             An array of data objects to resolve.
 *                                                 Each object includes the following properties:
 *                                                 {string}         type       The data type. Either 'core' or 'modules'.
 *                                                 {string}         identifier The data identifier, for example a module slug.
 *                                                 {string}         datapoint  The datapoint.
 *                                                 {Object?}        data       Optional arguments to pass along.
 *                                                 {number}         priority   The data request priority, used for batching.
 *                                                 {number}         maxAge     How long to cache the data results.
 *                                                 {string | array} context    The context(s) to resolve data, eg 'Dashboard'.
 *
 * @param {WPElement} loadingComponent       A React Component to render while the data is resolving.
 * @param {Object}    layoutOptions          An object with layout options that are passed to the getNoDataComponent and getDataErrorComponent components.
 * @param {Function}  isDataZero             A callback function that is passed the resolved data and returns true
 *                                                 if the data is "zero".
 * @param {Function}  getDataError           A callback function that is passed the resolved data and returns the
 *                                                 error message.
 * @return {WPElement} Component  	Returns React.Components based on data and state.
 *                                  If has data  	  Return DataDependentComponent with data.
 *                                  has no data		  Fallback message when no data.
 *                                  in loading state  Return loadingComponent.
 *                                  has an error	  Returns error.
 *
 */
const withData = (
	DataDependentComponent,
	selectData,
	loadingComponent = null,

	layoutOptions = {
		inGrid: false,
		fullWidth: false,
		createGrid: false,
	},

	// The default isDataZero handler always returns false, Components must define when data is zero.
	// `isDataZero` is passed `returnedData`and `datapoint`.
	isDataZero = () => {
		return false;
	},

	// The default getDataError handler detects data.error and extracts the message from data.error.message or data.error.errors[0].message.
	getDataError = ( data ) => {
		if ( data && data.error ) {
			if ( data.error.message ) {
				return data.error.message;
			}
			if ( data.error.errors && data.error.errors[ 0 ] && data.error.errors[ 0 ].message ) {
				return data.error.errors[ 0 ].message;
			}
			return __( 'Unidentified error', 'google-site-kit' );
		}

		if ( data && data.errors && data.errors[ 0 ] && data.errors[ 0 ].message ) {
			return data.errors[ 0 ].message;
		}

		if ( data && data.error_data ) {
			const errors = Object.values( data.error_data );

			// Catch RateLimitExceeded specifically.
			if ( errors[ 0 ] && 'RateLimitExceeded' === errors[ 0 ].reason ) {
				return __( 'Too many requests have been sent within a given time span. Please reload this page again in a few seconds', 'google-site-kit' );
			}
		}

		if ( data && data.errors ) {
			const errors = Object.values( data.errors );
			if ( errors[ 0 ] && errors[ 0 ][ 0 ] ) {
				return errors[ 0 ][ 0 ];
			}
		}

		// If error is the root of the response, ensure all expected parts are
		// present, just to "be sure" that it is an error. All above error
		// handlers are legacy and are likely never hit, but let's keep them
		// because nobody will ever know.
		if ( data.code && data.message && data.data && data.data.status ) {
			return data.message;
		}

		// No error.
		return false;
	}
) => {
	// ...and returns another component...
	return class NewComponent extends Component {
		constructor( props ) {
			super( props );

			this.state = {
				data: false,
				zeroData: false,
				errorMessage: false,
				moduleRequiringSetup: '',
			};

			addAction(
				'googlesitekit.moduleDataReset',
				'googlesitekit.moduleDataResetHandler',
				() => {
					this.setState( {
						data: false,
						errorMessage: false,
						zeroData: false,
					} );
				}
			);

			/**
			 * Handles a single datapoint returned from the data API.
			 *
			 * Each resolved data point is passed thru this handler to detect errors and zero data conditions, and
			 * to trigger `handleDataError` and `handleDataSuccess` helpers.
			 *
			 * @since 1.0.0
			 *
			 * @param {Object} returnedData The data returned from the API.
			 * @param {Object} requestData  The data object for the request.
			 */
			const handleReturnedData = ( returnedData, requestData ) => {
				// If available, `handleDataError` will be called for errors (with a string) and empty data.
				const {
					handleDataError,
					handleDataSuccess,
				} = this.props;
				const { datapoint, identifier, toState } = requestData;

				// Check to see if the returned data is an error. If so, getDataError will return a string.
				const errorMessage = getDataError( returnedData );
				if ( errorMessage ) {
					// Set an error state on the Component.
					this.setState( {
						errorMessage,
						errorObj: returnedData,
						module: identifier,
					} );

					// If the Component included a `handleDataError` helper, pass it the error message.
					if ( handleDataError ) {
						handleDataError( errorMessage, returnedData );
					}
				} else if ( isDataZero( returnedData, datapoint, requestData ) ) { // No data error, next check for zero data.
					// If we have a `handleDataError` call it without any parameters (indicating empty data).
					if ( handleDataError ) {
						handleDataError( errorMessage, returnedData );
					}

					// Set a zeroData state on the Component.
					this.setState( { zeroData: true } );
				} else if ( handleDataSuccess ) {
					// Success! `handleDataSuccess` will be called (ie. not error or zero).
					handleDataSuccess();
				}

				// Resolve the returned data by setting state on the Component.
				this.setState( {
					requestDataToState: toState,
					data: returnedData,
					datapoint,
					module: identifier,
				} );
			};

			// Resolve all selectedData.
			each( selectData, ( data ) => {
				const { type, identifier } = data || {};
				// Handle single contexts, or arrays of contexts.
				each( castArray( data.context ), ( context ) => {
					/**
					 * Request data for the context.
					 */
					addFilter(
						`googlesitekit.module${ context }DataRequest`,
						`googlesitekit.data${ context }`,
						( moduleData ) => {
							// If any module in the selectData requires setup, set it in the state.
							// This will cause the setup incomplete component to be rendered in all cases.
							if ( TYPE_MODULES === type && ! getModulesData()[ identifier ]?.setupComplete ) {
								this.setState( { moduleRequiringSetup: identifier } );
								return moduleData;
							}

							const callback = ( returnedData ) => {
								handleReturnedData( returnedData, data );
							};

							return moduleData.concat( { ...data, callback } );
						}
					);
				} );
			} );
		}

		render() {
			const {
				data,
				datapoint,
				module,
				zeroData,
				errorMessage,
				errorObj,
				requestDataToState,
				moduleRequiringSetup,
			} = this.state;

			if ( moduleRequiringSetup ) {
				return getSetupIncompleteComponent( moduleRequiringSetup, layoutOptions.inGrid, layoutOptions.fullWidth, layoutOptions.createGrid );
			}

			// Render the loading component until we have data.
			if ( ! data ) {
				return loadingComponent;
			}

			// If we have an error, display the DataErrorComponent.
			if ( errorMessage ) {
				return ( 'string' !== typeof errorMessage ) ? errorMessage : getDataErrorComponent( module, errorMessage, layoutOptions.inGrid, layoutOptions.fullWidth, layoutOptions.createGrid, errorObj );
			}

			// If we have zeroData, display the NoDataComponent.
			if ( zeroData ) {
				const moduleName = getModulesData()[ module ]?.name || __( 'Site Kit', 'google-site-kit' );

				return getNoDataComponent( moduleName, layoutOptions.inGrid, layoutOptions.fullWidth, layoutOptions.createGrid );
			}

			// Render the Component when we have data, passing the datapoint.
			return (
				<DataDependentComponent
					data={ data }
					datapoint={ datapoint }
					requestDataToState={ requestDataToState }
					{ ...this.props }
				/>
			);
		}
	};
};

export default withData;
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react';
import Helmet from 'react-helmet';
import { connect } from 'react-redux';
//
import { Basic, Advanced, Domain, Managers, Utils } from 'czechidm-core';
import { SchemaObjectClassManager, SystemManager } from '../../redux';
import uuid from 'uuid';

const uiKey = 'schema-object-classes-entities-table';
const manager = new SchemaObjectClassManager();
const systemManager = new SystemManager();

class SchemaObjectClasses extends Advanced.AbstractTableContent {

  constructor(props, context) {
    super(props, context);
  }

  getManager() {
    return manager;
  }

  getUiKey() {
    return uiKey;
  }

  getContentKey() {
    return 'acc:content.system.schemaObjectClasses';
  }

  componentDidMount() {
    this.selectNavigationItems(['sys-systems', 'schema-object-classes']);
  }

  showDetail(entity, add) {
    const system = entity._embedded && entity._embedded.system ? entity._embedded.system.id : this.props.params.entityId;
    if (add) {
      const uuidId = uuid.v1();
      this.context.router.push(`/system/${system}/object-classes/${uuidId}/new?new=1&systemId=${system}`);
    } else {
      this.context.router.push(`/system/${system}/object-classes/${entity.id}/detail`);
    }
  }

  save(entity, event) {
    const formEntity = this.refs.form.getData();
    //
    super.save(formEntity, event);
  }

  afterSave(entity, error) {
    if (!error) {
      this.addMessage({ message: this.i18n('save.success', { name: entity.objectClassName }) });
    } else {
      this.addError(error);
    }
    super.afterSave();
  }

  _generateSchema(event) {
    if (event) {
      event.preventDefault();
    }
    this.refs[`confirm-delete`].show(
      this.i18n(`action.generateSchema.message`),
      this.i18n(`action.generateSchema.header`)
    ).then(() => {
      const {entityId} = this.props.params;
      this.setState({
        showLoading: true
      });
      const promise = systemManager.getService().generateSchema(entityId);
      promise.then((json) => {
        this.setState({
          showLoading: false
        });
        this.refs.table.getWrappedInstance().reload();
        this.addMessage({ message: this.i18n('action.generateSchema.success', { name: json.name }) });
      }).catch(ex => {
        this.setState({
          showLoading: false
        });
        this.addError(ex);
        this.refs.table.getWrappedInstance().reload();
      });
    }, () => {
      // Rejected
    });
  }

  render() {
    const { entityId } = this.props.params;
    const { _showLoading } = this.props;
    const { showLoading } = this.state;
    const innerShowLoading = _showLoading || showLoading;
    const forceSearchParameters = new Domain.SearchParameters().setFilter('systemId', entityId);
    return (

        <Helmet title={this.i18n('title')} />
        <Basic.Confirm ref="confirm-delete" level="danger"/>

        <Basic.ContentHeader style={{ marginBottom: 0 }}>
          <Basic.Icon type="fa" icon="object-group"/>
          {' '}

        </Basic.ContentHeader>
        <Basic.PanelBody>
          <Basic.Button
            style={{display: 'block', margin: 'auto'}}
            level="success"
            showLoading={innerShowLoading}
            onClick={this._generateSchema.bind(this)}
            rendered={Managers.SecurityManager.hasAuthority('SYSTEM_UPDATE')}
            title={ this.i18n('generateSchemaBtnTooltip') }>
            <Basic.Icon type="fa" icon="object-group"/>
            {' '}
            { this.i18n('generateSchemaBtn') }
          </Basic.Button>
        </Basic.PanelBody>

        <Basic.ContentHeader>
          <Basic.Icon value="compressed"/>
          {' '}

        </Basic.ContentHeader>
        <Basic.Panel className="no-border last">
          <Advanced.Table
            ref="table"
            uiKey={uiKey}
            showLoading={innerShowLoading}
            manager={this.getManager()}
            forceSearchParameters={forceSearchParameters}
            showRowSelection={Managers.SecurityManager.hasAnyAuthority(['SYSTEM_UPDATE'])}
            actions={
              Managers.SecurityManager.hasAnyAuthority(['SYSTEM_UPDATE'])
              ?
              [{ value: 'delete', niceLabel: this.i18n('action.delete.action'), action: this.onDelete.bind(this), disabled: false }]
              :
              null
            }
            buttons={
              [
                <Basic.Button
                  level="success"
                  key="add_button"
                  className="btn-xs"
                  onClick={this.showDetail.bind(this, { }, true)}
                  rendered={Managers.SecurityManager.hasAnyAuthority(['SYSTEM_UPDATE'])}>
                  <Basic.Icon type="fa" icon="plus"/>
                  {' '}
                  {this.i18n('button.add')}
                </Basic.Button>

              ]
            }
            filter={
              <Advanced.Filter onSubmit={this.useFilter.bind(this)}>
                <Basic.AbstractForm ref="filterForm">
                  <Basic.Row className="last">

                      <Advanced.Filter.TextField
                        ref="objectClassName"
                        placeholder={this.i18n('filter.objectClassName.placeholder')}/>

                      <Advanced.Filter.FilterButtons cancelFilter={this.cancelFilter.bind(this)}/>

                  </Basic.Row>
                </Basic.AbstractForm>
              </Advanced.Filter>
            }>
            <Advanced.Column
              property=""
              header=""
              className="detail-button"
              cell={
                ({ rowIndex, data }) => {
                  return (
                    <Advanced.DetailButton
                      title={this.i18n('button.detail')}
                      onClick={this.showDetail.bind(this, data[rowIndex], false)}/>
                  );
                }
              }/>
            <Advanced.ColumnLink
              to={
                ({ rowIndex, data }) => {
                  this.showDetail(data[rowIndex]);
                }
              }
              property="objectClassName"
              header={this.i18n('acc:entity.SchemaObjectClass.objectClassName')}
              sort />
            <Advanced.Column property="auxiliary" face="boolean" header={this.i18n('acc:entity.SchemaObjectClass.auxiliary')} hidden sort/>
            <Advanced.Column property="container" face="boolean" header={this.i18n('acc:entity.SchemaObjectClass.container')} hidden sort/>
          </Advanced.Table>
        </Basic.Panel>

    );
  }
}

SchemaObjectClasses.propTypes = {
  system: PropTypes.object,
  _showLoading: PropTypes.bool,
};
SchemaObjectClasses.defaultProps = {
  system: null,
  _showLoading: false,
};

function select(state, component) {
  return {
    system: Utils.Entity.getEntity(state, systemManager.getEntityType(), component.params.entityId),
    _showLoading: Utils.Ui.isShowLoading(state, `${uiKey}-detail`),
  };
}

export default connect(select)(SchemaObjectClasses);
<commit_msg>#639 fix: tooltip position<commit_after>import React, { PropTypes } from 'react';
import Helmet from 'react-helmet';
import { connect } from 'react-redux';
//
import { Basic, Advanced, Domain, Managers, Utils } from 'czechidm-core';
import { SchemaObjectClassManager, SystemManager } from '../../redux';
import uuid from 'uuid';

const uiKey = 'schema-object-classes-entities-table';
const manager = new SchemaObjectClassManager();
const systemManager = new SystemManager();

class SchemaObjectClasses extends Advanced.AbstractTableContent {

  constructor(props, context) {
    super(props, context);
  }

  getManager() {
    return manager;
  }

  getUiKey() {
    return uiKey;
  }

  getContentKey() {
    return 'acc:content.system.schemaObjectClasses';
  }

  componentDidMount() {
    this.selectNavigationItems(['sys-systems', 'schema-object-classes']);
  }

  showDetail(entity, add) {
    const system = entity._embedded && entity._embedded.system ? entity._embedded.system.id : this.props.params.entityId;
    if (add) {
      const uuidId = uuid.v1();
      this.context.router.push(`/system/${system}/object-classes/${uuidId}/new?new=1&systemId=${system}`);
    } else {
      this.context.router.push(`/system/${system}/object-classes/${entity.id}/detail`);
    }
  }

  save(entity, event) {
    const formEntity = this.refs.form.getData();
    //
    super.save(formEntity, event);
  }

  afterSave(entity, error) {
    if (!error) {
      this.addMessage({ message: this.i18n('save.success', { name: entity.objectClassName }) });
    } else {
      this.addError(error);
    }
    super.afterSave();
  }

  _generateSchema(event) {
    if (event) {
      event.preventDefault();
    }
    this.refs[`confirm-delete`].show(
      this.i18n(`action.generateSchema.message`),
      this.i18n(`action.generateSchema.header`)
    ).then(() => {
      const {entityId} = this.props.params;
      this.setState({
        showLoading: true
      });
      const promise = systemManager.getService().generateSchema(entityId);
      promise.then((json) => {
        this.setState({
          showLoading: false
        });
        this.refs.table.getWrappedInstance().reload();
        this.addMessage({ message: this.i18n('action.generateSchema.success', { name: json.name }) });
      }).catch(ex => {
        this.setState({
          showLoading: false
        });
        this.addError(ex);
        this.refs.table.getWrappedInstance().reload();
      });
    }, () => {
      // Rejected
    });
  }

  render() {
    const { entityId } = this.props.params;
    const { _showLoading } = this.props;
    const { showLoading } = this.state;
    const innerShowLoading = _showLoading || showLoading;
    const forceSearchParameters = new Domain.SearchParameters().setFilter('systemId', entityId);
    return (

        <Helmet title={this.i18n('title')} />
        <Basic.Confirm ref="confirm-delete" level="danger"/>

        <Basic.ContentHeader style={{ marginBottom: 0 }}>
          <Basic.Icon type="fa" icon="object-group"/>
          {' '}

        </Basic.ContentHeader>
        <Basic.PanelBody>

            <Basic.Button
              level="success"
              showLoading={innerShowLoading}
              onClick={this._generateSchema.bind(this)}
              rendered={Managers.SecurityManager.hasAuthority('SYSTEM_UPDATE')}
              title={ this.i18n('generateSchemaBtnTooltip') }>
              <Basic.Icon type="fa" icon="object-group"/>
              {' '}
              { this.i18n('generateSchemaBtn') }
            </Basic.Button>

        </Basic.PanelBody>

        <Basic.ContentHeader>
          <Basic.Icon value="compressed"/>
          {' '}

        </Basic.ContentHeader>
        <Basic.Panel className="no-border last">
          <Advanced.Table
            ref="table"
            uiKey={uiKey}
            showLoading={innerShowLoading}
            manager={this.getManager()}
            forceSearchParameters={forceSearchParameters}
            showRowSelection={Managers.SecurityManager.hasAnyAuthority(['SYSTEM_UPDATE'])}
            actions={
              Managers.SecurityManager.hasAnyAuthority(['SYSTEM_UPDATE'])
              ?
              [{ value: 'delete', niceLabel: this.i18n('action.delete.action'), action: this.onDelete.bind(this), disabled: false }]
              :
              null
            }
            buttons={
              [
                <Basic.Button
                  level="success"
                  key="add_button"
                  className="btn-xs"
                  onClick={this.showDetail.bind(this, { }, true)}
                  rendered={Managers.SecurityManager.hasAnyAuthority(['SYSTEM_UPDATE'])}>
                  <Basic.Icon type="fa" icon="plus"/>
                  {' '}
                  {this.i18n('button.add')}
                </Basic.Button>

              ]
            }
            filter={
              <Advanced.Filter onSubmit={this.useFilter.bind(this)}>
                <Basic.AbstractForm ref="filterForm">
                  <Basic.Row className="last">

                      <Advanced.Filter.TextField
                        ref="objectClassName"
                        placeholder={this.i18n('filter.objectClassName.placeholder')}/>

                      <Advanced.Filter.FilterButtons cancelFilter={this.cancelFilter.bind(this)}/>

                  </Basic.Row>
                </Basic.AbstractForm>
              </Advanced.Filter>
            }>
            <Advanced.Column
              property=""
              header=""
              className="detail-button"
              cell={
                ({ rowIndex, data }) => {
                  return (
                    <Advanced.DetailButton
                      title={this.i18n('button.detail')}
                      onClick={this.showDetail.bind(this, data[rowIndex], false)}/>
                  );
                }
              }/>
            <Advanced.ColumnLink
              to={
                ({ rowIndex, data }) => {
                  this.showDetail(data[rowIndex]);
                }
              }
              property="objectClassName"
              header={this.i18n('acc:entity.SchemaObjectClass.objectClassName')}
              sort />
            <Advanced.Column property="auxiliary" face="boolean" header={this.i18n('acc:entity.SchemaObjectClass.auxiliary')} hidden sort/>
            <Advanced.Column property="container" face="boolean" header={this.i18n('acc:entity.SchemaObjectClass.container')} hidden sort/>
          </Advanced.Table>
        </Basic.Panel>

    );
  }
}

SchemaObjectClasses.propTypes = {
  system: PropTypes.object,
  _showLoading: PropTypes.bool,
};
SchemaObjectClasses.defaultProps = {
  system: null,
  _showLoading: false,
};

function select(state, component) {
  return {
    system: Utils.Entity.getEntity(state, systemManager.getEntityType(), component.params.entityId),
    _showLoading: Utils.Ui.isShowLoading(state, `${uiKey}-detail`),
  };
}

export default connect(select)(SchemaObjectClasses);
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import Dropzone from 'react-dropzone';
import ApplicationTextField from './ApplicationTextField';
import ApplicationToggle from './ApplicationToggle';
import ApplicationSelectField from './ApplicationSelectField';
import ResumeUploadProgressIndicator from './ResumeUploadProgressIndicator';
import {raceOptions, genderOptions, gradYearOptions, isFirstHackathonOptions } from './ApplicationConsts';

class ApplicationForm extends Component {
    render () {
        const { applicationForm, validation}  = this.props.application;
        const isLoading = this.props.application.loading;
        const isGithubLinked = this.props.user.me && (this.props.user.me.github_user_id !== null);
        let dropzoneRef;
        return (
            <Dropzone
                ref={(node) => { dropzoneRef = node; }}
                disableClick
                multiple={false}
                accept="application/pdf"
                onDrop={this.props.onResumeDrop.bind(this)}
                style={{border: 'none', height: '100%'}}
            >

                      First Name
                      <ApplicationTextField field="first_name"/>

                      Last Name
                      <ApplicationTextField field="last_name"/>

                    School
                    <ApplicationSelectField field="school_id" searchable options={this.props.schools}/>

                      Major
                      <ApplicationTextField field="major"/>

                      Expected Graduation Year
                        <ApplicationSelectField field="grad_year" searchable options={gradYearOptions}/>

                      LinkedIn Username
                      { applicationForm.has_no_linkedin ?

                              <ApplicationTextField field="linkedin" flattenBottomCorners  disabled/>
                              <button onClick={this.props.toggleApplicationFieldValue.bind(this,'has_no_linkedin')} className="opt-out-button">I do actually</button>

                      :

                              <ApplicationTextField field="linkedin" flattenBottomCorners/>
                              <button onClick={this.props.toggleApplicationFieldValue.bind(this,'has_no_linkedin')} className="opt-out-button">No thanks</button>

                      }

                      GitHub Username
                      {
                          applicationForm.has_no_github && !isGithubLinked
                          ?

                              <ApplicationTextField field="github" flattenBottomCorners disabled/>
                              <button onClick={this.props.toggleApplicationFieldValue.bind(this,'has_no_github')} className="opt-out-button">I do actually</button>

                          :

                              <ApplicationTextField field="github" flattenBottomCorners disabled={isGithubLinked}/>
                              {
                                  isGithubLinked
                                  ? <button className="opt-out-button">You signed up with github, so you can't change the username</button>
                                  : <button onClick={this.props.toggleApplicationFieldValue.bind(this,'has_no_github')} className="opt-out-button">No thanks</button>
                              }

                      }

                        Gender
                        <ApplicationSelectField field="gender" options={genderOptions}/>

                        Race
                        <ApplicationSelectField field="race" options={raceOptions}/>

                      Upload Resume (PDF only)
                      <button type="button" onClick={() => { dropzoneRef.open() }} className="application-button">Drop or click to upload</button>
                      <ResumeUploadProgressIndicator/>
                      { applicationForm.resume_uploaded ?
You've uploaded {applicationForm.resume_filename}
 : null }

                        Is this your first hackathon?
                        <ApplicationSelectField field="isFirstHackathon" options={isFirstHackathonOptions}/>

                        <ApplicationToggle field="tandc_1"/>
                        I will be 18 or older by Sept 29, 2017.

                        <ApplicationToggle field="tandc_2"/>
                        I agree to the MLH code of conduct

                        <ApplicationToggle field="tandc_3"/>

                            I agree to the terms of both the

                                MLH Contest Terms and Conditions

                             and the

                                MLH Privacy Policy.

                            Please note that you may receive pre and post-event informational
                            e-mails and occasional messages about hackathons from MLH as per
                            the MLH Privacy Policy.

                    <button disabled={isLoading} onClick={()=>{this.props.saveApplication()}} className="submit">Save</button>

                    {!applicationForm.completed
                        ?

Your application is not complete:

                                {validation.reason_label.map(x=>
{x}
)}

                        : null}

You can edit this until applications are closed.

            </Dropzone>
        );
    }
}

//now the redux integration layer
import {
    saveApplication,
    onResumeDrop,
    toggleApplicationFieldValue
} from '../../actions/application';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux'
function mapStateToProps (state) {
    return {
        user: state.user,
        application: state.application,
        schools: state.application.schools.map((school)=>({value: school.id, label: school.name})),
    };
}

const mapDispatchToProps = (dispatch) => {
    return bindActionCreators({
        saveApplication,
        onResumeDrop,
        toggleApplicationFieldValue
    }, dispatch)
};

export default connect(mapStateToProps, mapDispatchToProps)(ApplicationForm);
<commit_msg>add notice when application is complete<commit_after>import React, { Component } from 'react';
import Dropzone from 'react-dropzone';
import ApplicationTextField from './ApplicationTextField';
import ApplicationToggle from './ApplicationToggle';
import ApplicationSelectField from './ApplicationSelectField';
import ResumeUploadProgressIndicator from './ResumeUploadProgressIndicator';
import {raceOptions, genderOptions, gradYearOptions, isFirstHackathonOptions } from './ApplicationConsts';

class ApplicationForm extends Component {
    render () {
        const { applicationForm, validation}  = this.props.application;
        const isLoading = this.props.application.loading;
        const isGithubLinked = this.props.user.me && (this.props.user.me.github_user_id !== null);
        let dropzoneRef;
        return (
            <Dropzone
                ref={(node) => { dropzoneRef = node; }}
                disableClick
                multiple={false}
                accept="application/pdf"
                onDrop={this.props.onResumeDrop.bind(this)}
                style={{border: 'none', height: '100%'}}
            >

                      First Name
                      <ApplicationTextField field="first_name"/>

                      Last Name
                      <ApplicationTextField field="last_name"/>

                    School
                    <ApplicationSelectField field="school_id" searchable options={this.props.schools}/>

                      Major
                      <ApplicationTextField field="major"/>

                      Expected Graduation Year
                        <ApplicationSelectField field="grad_year" searchable options={gradYearOptions}/>

                      LinkedIn Username
                      { applicationForm.has_no_linkedin ?

                              <ApplicationTextField field="linkedin" flattenBottomCorners  disabled/>
                              <button onClick={this.props.toggleApplicationFieldValue.bind(this,'has_no_linkedin')} className="opt-out-button">I do actually</button>

                      :

                              <ApplicationTextField field="linkedin" flattenBottomCorners/>
                              <button onClick={this.props.toggleApplicationFieldValue.bind(this,'has_no_linkedin')} className="opt-out-button">No thanks</button>

                      }

                      GitHub Username
                      {
                          applicationForm.has_no_github && !isGithubLinked
                          ?

                              <ApplicationTextField field="github" flattenBottomCorners disabled/>
                              <button onClick={this.props.toggleApplicationFieldValue.bind(this,'has_no_github')} className="opt-out-button">I do actually</button>

                          :

                              <ApplicationTextField field="github" flattenBottomCorners disabled={isGithubLinked}/>
                              {
                                  isGithubLinked
                                  ? <button className="opt-out-button">You signed up with github, so you can't change the username</button>
                                  : <button onClick={this.props.toggleApplicationFieldValue.bind(this,'has_no_github')} className="opt-out-button">No thanks</button>
                              }

                      }

                        Gender
                        <ApplicationSelectField field="gender" options={genderOptions}/>

                        Race
                        <ApplicationSelectField field="race" options={raceOptions}/>

                      Upload Resume (PDF only)
                      <button type="button" onClick={() => { dropzoneRef.open() }} className="application-button">Drop or click to upload</button>
                      <ResumeUploadProgressIndicator/>
                      { applicationForm.resume_uploaded ?
You've uploaded {applicationForm.resume_filename}
 : null }

                        Is this your first hackathon?
                        <ApplicationSelectField field="isFirstHackathon" options={isFirstHackathonOptions}/>

                        <ApplicationToggle field="tandc_1"/>
                        I will be 18 or older by Sept 29, 2017.

                        <ApplicationToggle field="tandc_2"/>
                        I agree to the MLH code of conduct

                        <ApplicationToggle field="tandc_3"/>

                            I agree to the terms of both the

                                MLH Contest Terms and Conditions

                             and the

                                MLH Privacy Policy.

                            Please note that you may receive pre and post-event informational
                            e-mails and occasional messages about hackathons from MLH as per
                            the MLH Privacy Policy.

You can edit your application until September 22.

                    {!applicationForm.completed
                        ?

Your application is not complete:

                                {validation.reason_label.map(x=>
{x}
)}

                        :
Your application is complete! stay tuned.
}

                    <button disabled={isLoading} onClick={()=>{this.props.saveApplication()}} className="submit">Save</button>

            </Dropzone>
        );
    }
}

//now the redux integration layer
import {
    saveApplication,
    onResumeDrop,
    toggleApplicationFieldValue
} from '../../actions/application';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux'
function mapStateToProps (state) {
    return {
        user: state.user,
        application: state.application,
        schools: state.application.schools.map((school)=>({value: school.id, label: school.name})),
    };
}

const mapDispatchToProps = (dispatch) => {
    return bindActionCreators({
        saveApplication,
        onResumeDrop,
        toggleApplicationFieldValue
    }, dispatch)
};

export default connect(mapStateToProps, mapDispatchToProps)(ApplicationForm);
<|endoftext|>


<commit_before>// Copyright 2014 Globo.com Player authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

var Playback = require('../../base/playback')
var JST = require('../../base/jst')
var Styler = require('../../base/styler')
var Browser = require('../../components/browser')
var seekStringToSeconds = require('../../base/utils').seekStringToSeconds
var Events = require('../../base/events')
var find = require('lodash.find')

class HTML5Video extends Playback {
  get name() { return 'html5_video' }
  get tagName() { return 'video' }
  get template() { return JST.html5_video }

  get attributes() {
    return {
      'data-html5-video': ''
    }
  }

  get events() {
    return {
      'timeupdate': 'timeUpdated',
      'progress': 'progress',
      'ended': 'ended',
      'stalled': 'stalled',
      'waiting': 'waiting',
      'canplaythrough': 'bufferFull',
      'loadedmetadata': 'loadedMetadata',
      'canplay': 'ready',
      'durationchange': 'durationChange',
      'error': 'error'
    }
  }

  constructor(options) {
    super(options)
    this.options = options
    this.src = options.src
    this.el.src = options.src
    this.el.loop = options.loop
    this.firstBuffer = true
    this.isHLS = (this.src.indexOf('m3u8') > -1)
    this.settings = {default: ['seekbar']}
    if (Browser.isSafari) {
      this.setupSafari()
    } else {
      this.el.preload = options.preload ? options.preload: 'metadata'
      this.settings.seekEnabled = true
    }
    this.settings.left = this.isHLS ? ["playstop"] : ["playpause", "position", "duration"]
    this.settings.right = ["fullscreen", "volume"]
  }

  setupSafari() {
    this.el.preload = 'auto'
  }

  loadedMetadata(e) {
    this.durationChange()
    this.trigger(Events.PLAYBACK_LOADEDMETADATA, e.target.duration)
    this.checkInitialSeek()
  }

  durationChange() {
    // we can't figure out if hls resource is VoD or not until it is being loaded or duration has changed.
    // that's why we check it again and update media control accordingly.
    if (this.getPlaybackType() === 'vod') {
      this.settings.left = ["playpause", "position", "duration"]
      this.settings.seekEnabled = true
    }
    this.trigger(Events.PLAYBACK_SETTINGSUPDATE)
  }

  getPlaybackType() {
    return this.isHLS && [0, undefined, Infinity].indexOf(this.el.duration) >= 0 ? 'live' : 'vod'
  }

  isHighDefinitionInUse() {
    return false
  }

  play() {
    this.el.play()
    this.trigger(Events.PLAYBACK_PLAY);
  }

  pause() {
    this.el.pause()
  }

  stop() {
    this.pause()
    if (this.el.readyState !== 0) {
      this.el.currentTime = 0
    }
  }

  volume(value) {
    this.el.volume = value / 100
  }

  mute() {
    this.el.volume = 0
  }

  unmute() {
    this.el.volume = 1
  }

  isMuted() {
    return !!this.el.volume
  }

  isPlaying() {
    return !this.el.paused && !this.el.ended
  }

  ended() {
    this.trigger(Events.PLAYBACK_ENDED, this.name)
    this.trigger(Events.PLAYBACK_TIMEUPDATE, 0, this.el.duration, this.name)
  }

  stalled() {
    if (this.getPlaybackType() === 'vod' && this.el.readyState < this.el.HAVE_FUTURE_DATA) {
      this.trigger(Events.PLAYBACK_BUFFERING, this.name)
    }
  }

  waiting() {
    if(this.el.readyState < this.el.HAVE_FUTURE_DATA) {
      this.trigger(Events.PLAYBACK_BUFFERING, this.name)
    }
  }

  bufferFull() {
    if (this.options.poster && this.firstBuffer) {
      this.firstBuffer = false
      if (!this.isPlaying()) {
        this.el.poster = this.options.poster
      }
    } else {
      this.el.poster = ''
    }
    this.trigger(Events.PLAYBACK_BUFFERFULL, this.name)
  }

  error(event) {
    this.trigger(Events.PLAYBACK_ERROR, this.el.error, this.name)
  }

  destroy() {
    this.stop()
    this.el.src = ''
    this.$el.remove()
  }

  seek(seekBarValue) {
    var time = this.el.duration * (seekBarValue / 100)
    this.seekSeconds(time)
  }

  seekSeconds(time) {
    this.el.currentTime = time
  }

  checkInitialSeek() {
    var seekTime = seekStringToSeconds(window.location.href)
    this.seekSeconds(seekTime)
  }

  getCurrentTime() {
    return this.el.currentTime
  }

  getDuration() {
    return this.el.duration
  }

  timeUpdated() {
    if (this.getPlaybackType() === 'live') {
      this.trigger(Events.PLAYBACK_TIMEUPDATE, 1, 1, this.name)
    } else {
      this.trigger(Events.PLAYBACK_TIMEUPDATE, this.el.currentTime, this.el.duration, this.name)
    }
  }

  progress() {
    if (!this.el.buffered.length) return
    var bufferedPos = 0
    for (var i = 0;  i < this.el.buffered.length; i++) {
      if (this.el.currentTime >= this.el.buffered.start(i) && this.el.currentTime <= this.el.buffered.end(i)) {
        bufferedPos = i
        break
      }
    }
    this.trigger(Events.PLAYBACK_PROGRESS, this.el.buffered.start(bufferedPos), this.el.buffered.end(bufferedPos), this.el.duration, this.name)
  }

  typeFor(src) {
    return (src.indexOf('.m3u8') > 0) ? 'application/vnd.apple.mpegurl' : 'video/mp4'
  }

  ready() {
    this.trigger(Events.PLAYBACK_READY, this.name)
  }

  render() {
    var style = Styler.getStyleFor(this.name)
    this.$el.html(this.template({ src: this.src, type: this.typeFor(this.src) }))
    this.$el.append(style)
    setTimeout(() => this.options.autoPlay && this.play(), 0);
    if (this.el.readyState === this.el.HAVE_ENOUGH_DATA) {
      this.ready()
    }
    return this
  }
}

HTML5Video.canPlay = function(resource) {
  var mimetypes = {
    'mp4': ["avc1.42E01E", "avc1.58A01E", "avc1.4D401E", "avc1.64001E", "mp4v.20.8", "mp4v.20.240", "mp4a.40.2"].map(
      (codec) => { return 'video/mp4; codecs="' + codec + ', mp4a.40.2"'}),
    'ogg': ['video/ogg; codecs="theora, vorbis"', 'video/ogg; codecs="dirac"', 'video/ogg; codecs="theora, speex"'],
    '3gpp': ['video/3gpp; codecs="mp4v.20.8, samr"'],
    'webm': ['video/webm; codecs="vp8, vorbis"'],
    'mkv': ['video/x-matroska; codecs="theora, vorbis"'],
    'm3u8': ['application/x-mpegURL']
  }
  mimetypes['ogv'] = mimetypes['ogg']
  mimetypes['3gp'] = mimetypes['3gpp']

  var resourceParts = resource.split('?')[0].match(/.*\.(.*)$/) || []
  if ((resourceParts.length > 1) && (mimetypes[resourceParts[1]] !== undefined)) {
    var v = document.createElement('video')
    return !!find(mimetypes[resourceParts[1]], (ext) => { return !!v.canPlayType(ext).replace(/no/, '') })
  }
  return false
}

module.exports = HTML5Video
<commit_msg>html5 video: add mime-type parameter support to canPlay (refs #399)<commit_after>// Copyright 2014 Globo.com Player authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

var Playback = require('../../base/playback')
var JST = require('../../base/jst')
var Styler = require('../../base/styler')
var Browser = require('../../components/browser')
var seekStringToSeconds = require('../../base/utils').seekStringToSeconds
var Events = require('../../base/events')
var find = require('lodash.find')

class HTML5Video extends Playback {
  get name() { return 'html5_video' }
  get tagName() { return 'video' }
  get template() { return JST.html5_video }

  get attributes() {
    return {
      'data-html5-video': ''
    }
  }

  get events() {
    return {
      'timeupdate': 'timeUpdated',
      'progress': 'progress',
      'ended': 'ended',
      'stalled': 'stalled',
      'waiting': 'waiting',
      'canplaythrough': 'bufferFull',
      'loadedmetadata': 'loadedMetadata',
      'canplay': 'ready',
      'durationchange': 'durationChange',
      'error': 'error'
    }
  }

  constructor(options) {
    super(options)
    this.options = options
    this.src = options.src
    this.el.src = options.src
    this.el.loop = options.loop
    this.firstBuffer = true
    this.isHLS = (this.src.indexOf('m3u8') > -1)
    this.settings = {default: ['seekbar']}
    if (Browser.isSafari) {
      this.setupSafari()
    } else {
      this.el.preload = options.preload ? options.preload: 'metadata'
      this.settings.seekEnabled = true
    }
    this.settings.left = this.isHLS ? ["playstop"] : ["playpause", "position", "duration"]
    this.settings.right = ["fullscreen", "volume"]
  }

  setupSafari() {
    this.el.preload = 'auto'
  }

  loadedMetadata(e) {
    this.durationChange()
    this.trigger(Events.PLAYBACK_LOADEDMETADATA, e.target.duration)
    this.checkInitialSeek()
  }

  durationChange() {
    // we can't figure out if hls resource is VoD or not until it is being loaded or duration has changed.
    // that's why we check it again and update media control accordingly.
    if (this.getPlaybackType() === 'vod') {
      this.settings.left = ["playpause", "position", "duration"]
      this.settings.seekEnabled = true
    }
    this.trigger(Events.PLAYBACK_SETTINGSUPDATE)
  }

  getPlaybackType() {
    return this.isHLS && [0, undefined, Infinity].indexOf(this.el.duration) >= 0 ? 'live' : 'vod'
  }

  isHighDefinitionInUse() {
    return false
  }

  play() {
    this.el.play()
    this.trigger(Events.PLAYBACK_PLAY);
  }

  pause() {
    this.el.pause()
  }

  stop() {
    this.pause()
    if (this.el.readyState !== 0) {
      this.el.currentTime = 0
    }
  }

  volume(value) {
    this.el.volume = value / 100
  }

  mute() {
    this.el.volume = 0
  }

  unmute() {
    this.el.volume = 1
  }

  isMuted() {
    return !!this.el.volume
  }

  isPlaying() {
    return !this.el.paused && !this.el.ended
  }

  ended() {
    this.trigger(Events.PLAYBACK_ENDED, this.name)
    this.trigger(Events.PLAYBACK_TIMEUPDATE, 0, this.el.duration, this.name)
  }

  stalled() {
    if (this.getPlaybackType() === 'vod' && this.el.readyState < this.el.HAVE_FUTURE_DATA) {
      this.trigger(Events.PLAYBACK_BUFFERING, this.name)
    }
  }

  waiting() {
    if(this.el.readyState < this.el.HAVE_FUTURE_DATA) {
      this.trigger(Events.PLAYBACK_BUFFERING, this.name)
    }
  }

  bufferFull() {
    if (this.options.poster && this.firstBuffer) {
      this.firstBuffer = false
      if (!this.isPlaying()) {
        this.el.poster = this.options.poster
      }
    } else {
      this.el.poster = ''
    }
    this.trigger(Events.PLAYBACK_BUFFERFULL, this.name)
  }

  error(event) {
    this.trigger(Events.PLAYBACK_ERROR, this.el.error, this.name)
  }

  destroy() {
    this.stop()
    this.el.src = ''
    this.$el.remove()
  }

  seek(seekBarValue) {
    var time = this.el.duration * (seekBarValue / 100)
    this.seekSeconds(time)
  }

  seekSeconds(time) {
    this.el.currentTime = time
  }

  checkInitialSeek() {
    var seekTime = seekStringToSeconds(window.location.href)
    this.seekSeconds(seekTime)
  }

  getCurrentTime() {
    return this.el.currentTime
  }

  getDuration() {
    return this.el.duration
  }

  timeUpdated() {
    if (this.getPlaybackType() === 'live') {
      this.trigger(Events.PLAYBACK_TIMEUPDATE, 1, 1, this.name)
    } else {
      this.trigger(Events.PLAYBACK_TIMEUPDATE, this.el.currentTime, this.el.duration, this.name)
    }
  }

  progress() {
    if (!this.el.buffered.length) return
    var bufferedPos = 0
    for (var i = 0;  i < this.el.buffered.length; i++) {
      if (this.el.currentTime >= this.el.buffered.start(i) && this.el.currentTime <= this.el.buffered.end(i)) {
        bufferedPos = i
        break
      }
    }
    this.trigger(Events.PLAYBACK_PROGRESS, this.el.buffered.start(bufferedPos), this.el.buffered.end(bufferedPos), this.el.duration, this.name)
  }

  typeFor(src) {
    return (src.indexOf('.m3u8') > 0) ? 'application/vnd.apple.mpegurl' : 'video/mp4'
  }

  ready() {
    this.trigger(Events.PLAYBACK_READY, this.name)
  }

  render() {
    var style = Styler.getStyleFor(this.name)
    this.$el.html(this.template({ src: this.src, type: this.typeFor(this.src) }))
    this.$el.append(style)
    setTimeout(() => this.options.autoPlay && this.play(), 0);
    if (this.el.readyState === this.el.HAVE_ENOUGH_DATA) {
      this.ready()
    }
    return this
  }
}

HTML5Video.canPlay = function(resource, mimeType) {
  var mimetypes = {
    'mp4': ["avc1.42E01E", "avc1.58A01E", "avc1.4D401E", "avc1.64001E", "mp4v.20.8", "mp4v.20.240", "mp4a.40.2"].map(
      (codec) => { return 'video/mp4; codecs="' + codec + ', mp4a.40.2"'}),
    'ogg': ['video/ogg; codecs="theora, vorbis"', 'video/ogg; codecs="dirac"', 'video/ogg; codecs="theora, speex"'],
    '3gpp': ['video/3gpp; codecs="mp4v.20.8, samr"'],
    'webm': ['video/webm; codecs="vp8, vorbis"'],
    'mkv': ['video/x-matroska; codecs="theora, vorbis"'],
    'm3u8': ['application/x-mpegURL']
  }
  mimetypes['ogv'] = mimetypes['ogg']
  mimetypes['3gp'] = mimetypes['3gpp']

  var resourceParts = resource.split('?')[0].match(/.*\.(.*)$/) || []
  if ((resourceParts.length > 1) && (mimetypes[resourceParts[1]] !== undefined)) {
    var v = document.createElement('video')
    return !!find(mimetypes[resourceParts[1]], (ext) => { return !!v.canPlayType(ext).replace(/no/, '') })
  } else if (mimeType) {
    var v = document.createElement('video')
    return !!v.canPlayType(mimeType).replace(/no/, '')
  }
  return false
}

module.exports = HTML5Video
<|endoftext|>


<commit_before>import { forEach } from '../../util'

export function generateChangelog ({ commits, file, version, url, bugs, previousFile }) {
  return new Promise((resolve) => {
    const sections = {
      breaks: [], // special section to highlight breaking changes
      feat: [],
      fix: [],
      perf: []
    }

    const titles = {
      breaks: 'Breaking Changes',
      feat: 'Features',
      fix: 'Bug Fixes',
      perf: 'Performance Improvements'
    }

    file.write(`# ${version} (${currentDate()})\n---\n\n`)

    forEach(commits, function (commit) {
      if (isCommitBreakingChange(commit)) {
        sections.breaks.push(commit)
      } else {
        sections[commit.type] = sections[commit.type] || []
        sections[commit.type].push(commit)
      }
    })

    forEach(Object.keys(sections), function (section) {
      const sectionCommits = sections[section]
      const title = titles[section]

      if (!sectionCommits.length) return

      file.write(`\n## ${title}\n\n`)

      forEach(sectionCommits, function (commit) {
        file.write(`    - ${commit.header} ${linkToCommit(commit.hash, url)}`)
        file.write(`\n`)
      })
    })

    file.write(previousFile)

    resolve(file)
  })
}

function linkToCommit (hash, url) {
  return `[${hash.substr(0, 8)}](${url}/commits/${hash}\)`
}

function currentDate () {
  const now = new Date()
  const pad = function (i) {
    return ('0' + i).substr(-2)
  }
  return `${now.getFullYear()}-` +
         `${pad(now.getMonth() + 1)}-` +
         `${pad(now.getDate())}`
}

function isCommitBreakingChange (commit) {
  return (typeof commit.footer === 'string' &&
    commit.footer.indexOf('BREAKING CHANGE') !== -1)
}
<commit_msg>fix(northbrook): add space between generated output<commit_after>import { forEach } from '../../util'

export function generateChangelog ({ commits, file, version, url, bugs, previousFile }) {
  return new Promise((resolve) => {
    const sections = {
      breaks: [], // special section to highlight breaking changes
      feat: [],
      fix: [],
      perf: []
    }

    const titles = {
      breaks: 'Breaking Changes',
      feat: 'Features',
      fix: 'Bug Fixes',
      perf: 'Performance Improvements'
    }

    file.write(`# ${version} (${currentDate()})\n---\n\n`)

    forEach(commits, function (commit) {
      if (isCommitBreakingChange(commit)) {
        sections.breaks.push(commit)
      } else {
        sections[commit.type] = sections[commit.type] || []
        sections[commit.type].push(commit)
      }
    })

    forEach(Object.keys(sections), function (section) {
      const sectionCommits = sections[section]
      const title = titles[section]

      if (!sectionCommits.length) return

      file.write(`\n## ${title}\n\n`)

      forEach(sectionCommits, function (commit) {
        file.write(`    - ${commit.header} ${linkToCommit(commit.hash, url)}`)
        file.write(`\n`)
      })
    })

    file.write('\n\n')
    file.write(previousFile)

    resolve(file)
  })
}

function linkToCommit (hash, url) {
  return `[${hash.substr(0, 8)}](${url}/commits/${hash}\)`
}

function currentDate () {
  const now = new Date()
  const pad = function (i) {
    return ('0' + i).substr(-2)
  }
  return `${now.getFullYear()}-` +
         `${pad(now.getMonth() + 1)}-` +
         `${pad(now.getDate())}`
}

function isCommitBreakingChange (commit) {
  return (typeof commit.footer === 'string' &&
    commit.footer.indexOf('BREAKING CHANGE') !== -1)
}
<|endoftext|>


<commit_before>/***
|''Requires''|TiddlySpaceConfig|
***/
//{{{
(function($) {

var ns = config.extensions.tiddlyspace;

var cmd = config.commands.publishTiddlerRevision = {
	text: "publish",
	tooltip: "Make this revision public",
	errorMsg: "Error publishing %0: %1",

	isEnabled: function(tiddler) {
		if(readOnly || !store.tiddlerExists(tiddler.title)) {
			return false;
		}
		var space = ns.determineSpace(tiddler, true);
		return space && space.name == ns.currentSpace.name && space.type == "private";
	},
	handler: function(ev, src, title) {
		var callback = function(context, userParams) {
			if(context.status) {
				ns.spawnPublicTiddler(context.tiddler, src);
			} else {
				displayMessage(cmd.errorMsg.format([title, context.statusText]));
			}
		};
		this.publishTiddler(title, callback);
	},
	publishTiddler: function(title, callback) {
		var original = store.getTiddler(title);
		var space = ns.determineSpace(original);
		var tiddler = $.extend(new Tiddler(title), original);
		tiddler.fields = $.extend({}, original.fields, {
			"server.workspace": "bags/%0_public".format([space.name]),
			"server.page.revision": "false"
		});
		var adaptor = tiddler.getAdaptor();
		adaptor.putTiddler(tiddler, null, null, callback);
	}
};

})(jQuery);
//}}}
<commit_msg>added support for publishing binary tiddlers<commit_after>/***
|''Requires''|TiddlySpaceConfig|
***/
//{{{
(function($) {

var ns = config.extensions.tiddlyspace;

var cmd = config.commands.publishTiddlerRevision = {
	text: "publish",
	tooltip: "Make this revision public",
	errorMsg: "Error publishing %0: %1",

	isEnabled: function(tiddler) {
		if(readOnly || !store.tiddlerExists(tiddler.title)) {
			return false;
		}
		var space = ns.determineSpace(tiddler, true);
		return space && space.name == ns.currentSpace.name && space.type == "private";
	},
	handler: function(ev, src, title) {
		var callback = function(context, userParams) {
			if(context.status) {
				ns.spawnPublicTiddler(context.tiddler, src);
			} else {
				displayMessage(cmd.errorMsg.format([title, context.statusText]));
			}
		};
		this.publishTiddler(title, callback);
	},
	publishTiddler: function(title, callback) {
		var original = store.getTiddler(title);
		var space = ns.determineSpace(original);
		var adaptor = tiddler.getAdaptor();
		var publish = function(original, callback) {
			var tiddler = $.extend(new Tiddler(original.title), original);
			tiddler.fields = $.extend({}, original.fields, {
				"server.workspace": "bags/%0_public".format([space.name]),
				"server.page.revision": "false"
			});
			adaptor.putTiddler(tiddler, null, null, callback);
		};
		// ensure binary tiddlers contain authentic body
		if(!original.fields["server.content-type"]) {
			publish(original, callback);
		} else {
			var _callback = function(context, userParams) {
				publish(context.tiddler, callback);
			};
			var context = {
				host: original.fields["server.host"],
				workspace: original.fields["server.workspace"]
			};
			adaptor.getTiddler(original.title, context, null, _callback);
		}
	}
};

})(jQuery);
//}}}
<|endoftext|>


<commit_before>(function (window, document, undefined) {
    'use strict';

    var headings = ['N', 'E', 'S', 'W'],
        Compass;

    Compass = function (cockpit) {
        console.log("Adding Compass to Artificial Horizon.");

        // Instance variables
        this.cockpit = cockpit;

        // Add required UI elements
        $('#video-container').append('

');
        var div = $('#compass').get(0);

        // Listen to navdata updates
        var compass = this;
        this.cockpit.socket.on('navdata', function(data) {
            if (!jQuery.isEmptyObject(data)) {
                requestAnimationFrame(function() {
                    compass.moveTo(data.hdgd);
                });
            }

        });

        // Setup compass canvas
        var divRect = div.getBoundingClientRect(),
            ctx, x, i, needle;
        div.style.position = 'absolute';
       // div.style.bottom = '0px';
        div.style.backgroundImage = '-webkit-radial-gradient(50% 50%, circle cover, rgb(68, 68, 68) 0%, black 100%)';

        this.visibleWidth = divRect.width*(360/120); // divRect.width;
        this.canvas = document.createElement('canvas');
        this.canvas.width = this.visibleWidth * 1.5;
        this.canvas.height = divRect.height;
        this.canvas.style.position = 'absolute';
        this.canvas.className = 'hud';

        div.style.overflow = 'hidden';

        ctx = this.canvas.getContext('2d');

        x = 0;
        ctx.textAlign = 'center';
        for (i = 0; i < 36 * 2; i += 1.5) {
            ctx.beginPath();
            ctx.moveTo(x, 0);

            if (i % 9 === 0) {
                ctx.fillStyle = 'white';
                ctx.font = 'bold';
                ctx.fillText(headings[i / 9 % 4], x, 24);
                ctx.strokeStyle = 'white';
                ctx.lineTo(x, 10);
                ctx.lineWidth = 2;
            } else if (i % 3 === 0) {
                ctx.fillStyle = '#CCC';
                ctx.font = 'normal';
                ctx.fillText(i % 36, x, 24);
                ctx.strokeStyle = 'white';
                ctx.lineWidth = 1;
                ctx.lineTo(x, 7);
            } else {
                ctx.strokeStyle = 'white';
                ctx.lineTo(x, 5);
                ctx.lineWidth = 0.5;
            }
            ctx.stroke();
            x += this.visibleWidth / 24;
        }
        div.appendChild(this.canvas);

        needle = document.createElement('canvas');
        needle.width = 15;
        needle.height = 15;
        needle.style.top = 0;

        needle.style.left = Math.floor(this.visibleWidth / 2 - needle.width / 2) + 'px';
        needle.style.position = 'absolute';
        ctx = needle.getContext('2d');
        ctx.fillStyle = 'red';
        ctx.moveTo(0, 0);
        ctx.lineTo(Math.ceil(needle.width / 2), needle.height);
        ctx.lineTo(needle.width, 0);
        ctx.lineTo(0, 0);
        ctx.fill();
        div.appendChild(needle);
        this.moveTo(0);
    };

    Compass.prototype.moveTo = function (angle) {
        var offset,
            compass = this;
        while (angle > 180) {
            angle -= 360;
        }
        while (angle < -180) {
            angle += 360;
        }
        offset = - angle * (this.visibleWidth / 360);
        offset -= (this.visibleWidth / 2);

        // '-webkit-transform'
        window.requestAnimationFrame(function () {
            compass.canvas.getContext('2d').scale((10),1);

            compass.canvas.style.webkitTransform = 'translateX(' + offset + 'px)';
        });
    };
    window.Cockpit.plugins.push(Compass);

}(window, document, undefined));
<commit_msg>Fixed #218; Changed compass to true 120 degree view and center line added back<commit_after>(function (window, document, undefined) {
    'use strict';

    var headings = ['N', 'E', 'S', 'W'],
        Compass;

    Compass = function (cockpit) {
        console.log("Adding Compass to Artificial Horizon.");

        // Instance variables
        this.cockpit = cockpit;

        // Add required UI elements
        $('#video-container').append('

');
        var div = $('#compass').get(0);

        // Listen to navdata updates
        var compass = this;
        this.cockpit.socket.on('navdata', function(data) {
            if (!jQuery.isEmptyObject(data)) {
                requestAnimationFrame(function() {
                    compass.moveTo(data.hdgd);
                });
            }

        });

        // Setup compass canvas
        var divRect = div.getBoundingClientRect(),
            ctx, x, i, needle;
        div.style.position = 'absolute';
       // div.style.bottom = '0px';
        div.style.backgroundImage = '-webkit-radial-gradient(50% 50%, circle cover, rgb(68, 68, 68) 0%, black 100%)';

        this.visibleWidth = divRect.width*(720/120); // divRect.width;
        this.canvas = document.createElement('canvas');
        this.canvas.width = this.visibleWidth * 2;
        this.canvas.height = divRect.height;
        this.canvas.style.position = 'absolute';
        this.canvas.className = 'hud';

        div.style.overflow = 'hidden';

        ctx = this.canvas.getContext('2d');

        x = 0;
        ctx.textAlign = 'center';
        for (i = 0; i < 360 * 2; i += 1) {
            ctx.beginPath();
            ctx.moveTo(x, 0);

            if (i % 90 === 0) {
                ctx.fillStyle = 'white';
                ctx.font = 'bold';
                ctx.fillText(headings[i / 90 % 4], x, 24);
                ctx.strokeStyle = 'white';
                ctx.lineTo(x, 10);
                ctx.lineWidth = 2;
            } else if (i % 10 === 0) {
                ctx.fillStyle = '#CCC';
                ctx.font = 'normal';
                ctx.fillText(i % 360, x, 24);
                ctx.strokeStyle = 'white';
                ctx.lineWidth = 1;
                ctx.lineTo(x, 7);
            } else {
                ctx.strokeStyle = 'white';
                ctx.lineTo(x, 5);
                ctx.lineWidth = 0.5;
            }
            ctx.stroke();
            x += this.visibleWidth / 720;
        }
        div.appendChild(this.canvas);

        needle = document.createElement('canvas');
        needle.width = 15;
        needle.height = 15;
        needle.style.top = 0;

        needle.style.left = Math.floor(this.visibleWidth / 2 * (120/720) - needle.width / 2) + 'px';
        needle.style.position = 'absolute';
        ctx = needle.getContext('2d');
        ctx.fillStyle = 'red';
        ctx.moveTo(0, 0);
        ctx.lineTo(Math.ceil(needle.width / 2), needle.height);
        ctx.lineTo(needle.width, 0);
        ctx.lineTo(0, 0);
        ctx.fill();
        div.appendChild(needle);
        this.moveTo(0);
    };

    Compass.prototype.moveTo = function (angle) {
        var offset,
            compass = this;
        while (angle > 180) {
            angle -= 360;
        }
        while (angle < -180) {
            angle += 360;
        }
        offset = - angle * (this.visibleWidth / 720);
        offset -= (this.visibleWidth / 2);

        // '-webkit-transform'
        window.requestAnimationFrame(function () {
           // compass.canvas.getContext('2d').scale((10),1);
           compass.canvas.style.webkitTransform = 'scale(,1)' + offset + 'px)';

            compass.canvas.style.webkitTransform = 'translateX(' + offset + 'px)';
        });
    };
    window.Cockpit.plugins.push(Compass);

}(window, document, undefined));
<|endoftext|>


<commit_before>/* eslint-disable no-param-reassign */
/* eslint-disable class-methods-use-this */
const { BadRequest, Forbidden } = require('@feathersjs/errors');
const logger = require('../../../logger');

const { userModel } = require('../model');
const roleModel = require('../../role/model');

const getCurrentUser = id => userModel.findById(id)
	.select('schoolId')
	.populate('roles')
	.lean()
	.exec();

const getAllUsers = (ref, schoolId, role, sortObject) => ref.app.service('users').find({
	query: {
		schoolId,
		roles: role.toString(),
		$limit: sortObject.$limit,
		$skip: sortObject.$skip,
		$sort: sortObject.$sort,
		$select: ['firstName', 'lastName', 'email', 'createdAt', 'importHash'],
	},
});

const getRoles = () => roleModel.find()
	.select('name')
	.lean()
	.exec();

const getClasses = (app, schoolId, schoolYearId) => app.service('classes')
	.find({
		query: {
			schoolId,
			$or: [
				{ year: schoolYearId },
				{ year: { $exists: false } },
			],
			$limit: 1000,
		},
	})
	.then(classes => classes.data)
	.catch((err) => {
		logger.warning(`Can not execute app.service("classes").find for ${schoolId}`, err);
		return err;
	});

const findConsents = (ref, userIds, $limit) => ref.app.service('/consents')
	.find({
		query: {
			userId: { $in: userIds },
			$limit,
			$select: [
				'userId',
				'userConsent.form',
				'userConsent.privacyConsent',
				'userConsent.termsOfUseConsent',
				'parentConsents.parentId',
				'parentConsents.form',
				'parentConsents.privacyConsent',
				'parentConsents.termsOfUseConsent'],
		},
	})
	.then(consents => consents.data);

class AdminUsers {
	constructor(role) {
		this.role = role || {};
		this.docs = {};
	}

	async find(params) {
		//  const { app } = this;
		try {
			const currentUserId = params.account.userId.toString();

			// fetch base data
			const [currentUser, roles] = await Promise.all([getCurrentUser(currentUserId), getRoles()]);
			const { schoolId } = currentUser;

			const currentSchool = await this.app.service('schools').get(schoolId);
			const currentYear = currentSchool.years.activeYear._id;

			// permission check
			if (!currentUser.roles.some(role => ['teacher', 'administrator', 'superhero'].includes(role.name))) {
				throw new Forbidden();
			}
			// fetch data that are scoped to schoolId
			const studentRole = (roles.filter(role => role.name === this.role))[0];
			const [usersData, classes] = await Promise.all(
				[
					getAllUsers(this, schoolId, studentRole._id, (params.query || {})),
					getClasses(this.app, schoolId, currentYear),
				],
			);
			const { total } = usersData;
			const users = usersData.data;
			const userIds = users.map(user => user._id.toString());
			const consents = await findConsents(this, userIds, (params.query || {}).$limit).then((data) => {
				// rebuild consent to object for faster sorting
				const out = {};
				data.forEach((e) => {
					out[e.userId.toString()] = e;
				});
				return out;
			});
			// bsonId to stringId that it can use .includes for is in test
			classes.forEach((c) => {
				c.userIds = c.userIds.map(id => id.toString());
			});

			// patch classes and consent into user
			users.map((user) => {
				user.classes = [];
				const userId = user._id.toString();
				user.consent = consents[userId] || {};
				classes.forEach((c) => {
					if (c.userIds.includes(userId)) {
						user.classes.push(c.displayName);
					}
				});
				return user;
			});

			const filteredUsers = users.filter((user) => {
				const { consentStatus } = params.query || {};

				if ((consentStatus || {}).$in) {
					const userStatus = user.consent.consentStatus || 'missing';
					return consentStatus.$in.includes(userStatus);
				}
				return true;
			});
			return {
				total,
				limit: (params.query || {}).$limit,
				skip: (params.query || {}).$skip,
				data: filteredUsers,
			};
		} catch (err) {
			logger.warning(err);
			if ((err || {}).code === 403) {
				throw new Forbidden('You have not the permission to execute this.');
			}
			throw new BadRequest('Can not fetch data.');
		}
	}

	setup(app) {
		this.app = app;
	}
}

module.exports = AdminUsers;
<commit_msg>rename getCurrentUser helper<commit_after>/* eslint-disable no-param-reassign */
/* eslint-disable class-methods-use-this */
const { BadRequest, Forbidden } = require('@feathersjs/errors');
const logger = require('../../../logger');

const { userModel } = require('../model');
const roleModel = require('../../role/model');

const getCurrentUserInfo = id => userModel.findById(id)
	.select('schoolId')
	.populate('roles')
	.lean()
	.exec();

const getAllUsers = (ref, schoolId, role, sortObject) => ref.app.service('users').find({
	query: {
		schoolId,
		roles: role.toString(),
		$limit: sortObject.$limit,
		$skip: sortObject.$skip,
		$sort: sortObject.$sort,
		$select: ['firstName', 'lastName', 'email', 'createdAt', 'importHash'],
	},
});

const getRoles = () => roleModel.find()
	.select('name')
	.lean()
	.exec();

const getClasses = (app, schoolId, schoolYearId) => app.service('classes')
	.find({
		query: {
			schoolId,
			$or: [
				{ year: schoolYearId },
				{ year: { $exists: false } },
			],
			$limit: 1000,
		},
	})
	.then(classes => classes.data)
	.catch((err) => {
		logger.warning(`Can not execute app.service("classes").find for ${schoolId}`, err);
		return err;
	});

const findConsents = (ref, userIds, $limit) => ref.app.service('/consents')
	.find({
		query: {
			userId: { $in: userIds },
			$limit,
			$select: [
				'userId',
				'userConsent.form',
				'userConsent.privacyConsent',
				'userConsent.termsOfUseConsent',
				'parentConsents.parentId',
				'parentConsents.form',
				'parentConsents.privacyConsent',
				'parentConsents.termsOfUseConsent'],
		},
	})
	.then(consents => consents.data);

class AdminUsers {
	constructor(role) {
		this.role = role || {};
		this.docs = {};
	}

	async find(params) {
		//  const { app } = this;
		try {
			const currentUserId = params.account.userId.toString();

			// fetch base data
			const [currentUser, roles] = await Promise.all([getCurrentUserInfo(currentUserId), getRoles()]);
			const { schoolId } = currentUser;

			const currentSchool = await this.app.service('schools').get(schoolId);
			const currentYear = currentSchool.years.activeYear._id;

			// permission check
			if (!currentUser.roles.some(role => ['teacher', 'administrator', 'superhero'].includes(role.name))) {
				throw new Forbidden();
			}
			// fetch data that are scoped to schoolId
			const studentRole = (roles.filter(role => role.name === this.role))[0];
			const [usersData, classes] = await Promise.all(
				[
					getAllUsers(this, schoolId, studentRole._id, (params.query || {})),
					getClasses(this.app, schoolId, currentYear),
				],
			);
			const { total } = usersData;
			const users = usersData.data;
			const userIds = users.map(user => user._id.toString());
			const consents = await findConsents(this, userIds, (params.query || {}).$limit).then((data) => {
				// rebuild consent to object for faster sorting
				const out = {};
				data.forEach((e) => {
					out[e.userId.toString()] = e;
				});
				return out;
			});
			// bsonId to stringId that it can use .includes for is in test
			classes.forEach((c) => {
				c.userIds = c.userIds.map(id => id.toString());
			});

			// patch classes and consent into user
			users.map((user) => {
				user.classes = [];
				const userId = user._id.toString();
				user.consent = consents[userId] || {};
				classes.forEach((c) => {
					if (c.userIds.includes(userId)) {
						user.classes.push(c.displayName);
					}
				});
				return user;
			});

			const filteredUsers = users.filter((user) => {
				const { consentStatus } = params.query || {};

				if ((consentStatus || {}).$in) {
					const userStatus = user.consent.consentStatus || 'missing';
					return consentStatus.$in.includes(userStatus);
				}
				return true;
			});
			return {
				total,
				limit: (params.query || {}).$limit,
				skip: (params.query || {}).$skip,
				data: filteredUsers,
			};
		} catch (err) {
			logger.warning(err);
			if ((err || {}).code === 403) {
				throw new Forbidden('You have not the permission to execute this.');
			}
			throw new BadRequest('Can not fetch data.');
		}
	}

	setup(app) {
		this.app = app;
	}
}

module.exports = AdminUsers;
<|endoftext|>


<commit_before><commit_msg>Implement server<commit_after>var express = require('express');
var server = express();

server.get('/', function(request, response) {
  response.sendFile('./index.html', {root: __dirname}, function(error) {
    if (error) {
      console.log(error);
      response.status(error.status).end();
    };
  });
});

server.use(express.static('.'));

server.listen(3000, function() {
  console.log('Server is listening on port 3000');
});<|endoftext|>


<commit_before>const roles = require('../../config/roles'),
    table = require('text-table'),
    Discord = require('discord.js'),
    moment = require('moment');

moment.locale('de');

exports.run = (bot, message, args) => {
    let text = '**Nutzer ohne Rollen:**';

    let tableContent = ['Tag', 'ID', 'Joined', '-----', '------------------', '------------------'];

    bot.server.fetchMembers().then(guild => {
        guild.members.filter(member => {
            console.log(member.user.tag + " " + member.roles.size);

            return member.roles.size <= 1;
        }).sort((a, b) => {
            return moment(a.joinedAt) - moment(b.joinedAt);
        }).forEach(member => {
            tableContent.push(member.user.tag, member.id, `${moment(member.joinedAt).format('L LT')} (${moment(member.joinedAt).fromNow()})`);
        });

        let commandsTable = [],
            columns = 3;
        for (let ix = 0; ix < tableContent.length; ix += columns)
            commandsTable.push(tableContent.slice(ix, ix + columns));

        text += '```' + table(commandsTable, {hsep: '    '}) + '```';

        message.channel.send(text);
    });
};

exports.config = {
    aliases: ['nr'],
    server: true,
    role: roles.moderator
};

exports.help = {
    name: 'noroles',
    description: 'Zeigt alle Mitglieder des Servers ohne Rolle an.',
    usage: ['!noroles']
};<commit_msg>testing stuff<commit_after>const roles = require('../../config/roles'),
    table = require('text-table'),
    Discord = require('discord.js'),
    moment = require('moment');

moment.locale('de');

exports.run = (bot, message, args) => {
    let text = '**Nutzer ohne Rollen:**';

    let tableContent = ['Tag', 'ID', 'Joined', '-----', '------------------', '------------------'];

    bot.server.fetchMembers().then(guild => {
        guild.members.filter(member => {
            return member.roles.size <= 1;
        }).sort((a, b) => {
            return moment(a.joinedAt) - moment(b.joinedAt);
        }).forEach(member => {
            tableContent.push(member.user.tag, member.id, `${moment(member.joinedAt).format('L LT')} (${moment(member.joinedAt).fromNow()})`);
        });

        let commandsTable = [],
            columns = 3;
        for (let ix = 0; ix < tableContent.length; ix += columns)
            commandsTable.push(tableContent.slice(ix, ix + columns));

        text += '```' + table(commandsTable, {hsep: '    '}) + '```';

        console.log(text);
        message.channel.send(text);
    });
};

exports.config = {
    aliases: ['nr'],
    server: true,
    role: roles.moderator
};

exports.help = {
    name: 'noroles',
    description: 'Zeigt alle Mitglieder des Servers ohne Rolle an.',
    usage: ['!noroles']
};<|endoftext|>