<commit_before>/*

### withMulti

Paginated items container

Options:

  - collection: the collection to fetch the documents from
  - fragment: the fragment that defines which properties to fetch
  - fragmentName: the name of the fragment, passed to getFragment
  - limit: the number of documents to show initially
  - pollInterval: how often the data should be updated, in ms (set to 0 to disable polling)
  - terms: an object that defines which documents to fetch

Props Received:

  - terms: an object that defines which documents to fetch

Terms object can have the following properties:

  - view: String
  - userId: String
  - cat: String
  - date: String
  - after: String
  - before: String
  - enableTotal: Boolean
  - enableCache: Boolean
  - listId: String
  - query: String # search query
  - postId: String
  - limit: String

*/

import React, { Component } from 'react';
import { withApollo, graphql } from 'react-apollo';
import gql from 'graphql-tag';
import update from 'immutability-helper';
import { getSetting, getFragment, getFragmentName, getCollection, Utils, multiClientTemplate } from 'meteor/vulcan:lib';
import Mingo from 'mingo';
import compose from 'recompose/compose';
import withState from 'recompose/withState';

export default function withMulti(options) {
  // console.log(options)

  const {
    collectionName,
    limit = 10,
    pollInterval = getSetting('pollInterval', 20000),
    enableTotal = true,
    enableCache = false,
    extraQueries,
  } = options;

  const collection = options.collection || getCollection(collectionName);
  const typeName = collection.options.typeName;
  const resolverName = Utils.camelCaseify(Utils.pluralize(typeName));

  let fragment;

  if (options.fragment) {
    fragment = options.fragment;
  } else if (options.fragmentName) {
    fragment = getFragment(options.fragmentName);
  } else {
    fragment = getFragment(`${collection.options.collectionName}DefaultFragment`);
  }

  const fragmentName = getFragmentName(fragment);

  // build graphql query from options
  const query = gql`
    ${multiClientTemplate({ typeName, fragmentName, extraQueries })}
    ${fragment}
  `;

  return compose(
    // wrap component with Apollo HoC to give it access to the store
    withApollo,

    // wrap component with HoC that manages the terms object via its state
    withState('paginationTerms', 'setPaginationTerms', props => {
      // get initial limit from props, or else options
      const paginationLimit = (props.terms && props.terms.limit) || limit;
      const paginationTerms = {
        limit: paginationLimit,
        itemsPerPage: paginationLimit,
      };

      return paginationTerms;
    }),

    // wrap component with graphql HoC
    graphql(
      query,

      {
        alias: `with${Utils.pluralize(typeName)}`,

        // graphql query options
        options({ terms, paginationTerms, client: apolloClient, currentUser }) {
          // get terms from options, then props, then pagination
          const mergedTerms = { ...options.terms, ...terms, ...paginationTerms };

          const graphQLOptions = {
            variables: {
              input: {
                terms: mergedTerms,
                enableCache,
                enableTotal,
              },
            },
            // note: pollInterval can be set to 0 to disable polling (20s by default)
            pollInterval,
            reducer: (previousResults, action) => {
              // see queryReducer function defined below
              return queryReducer(
                typeName,
                previousResults,
                action,
                collection,
                mergedTerms,
                resolverName,
                apolloClient
              );
            },
          };

          if (options.fetchPolicy) {
            graphQLOptions.fetchPolicy = options.fetchPolicy;
          }

          // set to true if running into https://github.com/apollographql/apollo-client/issues/1186
          if (options.notifyOnNetworkStatusChange) {
            graphQLOptions.notifyOnNetworkStatusChange = options.notifyOnNetworkStatusChange;
          }

          return graphQLOptions;
        },

        // define props returned by graphql HoC
        props(props) {
          // see https://github.com/apollographql/apollo-client/blob/master/packages/apollo-client/src/core/networkStatus.ts
          const refetch = props.data.refetch,
            // results = Utils.convertDates(collection, props.data[listResolverName]),
            results = props.data[resolverName] && props.data[resolverName].results,
            totalCount = props.data[resolverName] && props.data[resolverName].totalCount,
            networkStatus = props.data.networkStatus,
            loadingInitial = props.data.networkStatus === 1,
            loading = props.data.networkStatus === 1,
            loadingMore = props.data.networkStatus === 2,
            error = props.data.error,
            propertyName = options.propertyName || 'results';

          if (error) {
            // eslint-disable-next-line no-console
            console.log(error);
          }

          return {
            // see https://github.com/apollostack/apollo-client/blob/master/src/queries/store.ts#L28-L36
            // note: loading will propably change soon https://github.com/apollostack/apollo-client/issues/831
            loading,
            loadingInitial,
            loadingMore,
            [propertyName]: results,
            totalCount,
            refetch,
            networkStatus,
            error,
            count: results && results.length,

            // regular load more (reload everything)
            loadMore(providedTerms) {
              // if new terms are provided by presentational component use them, else default to incrementing current limit once
              const newTerms =
                typeof providedTerms === 'undefined'
                  ? {
                      /*...props.ownProps.terms,*/ ...props.ownProps.paginationTerms,
                      limit: results.length + props.ownProps.paginationTerms.itemsPerPage,
                    }
                  : providedTerms;

              props.ownProps.setPaginationTerms(newTerms);
            },

            // incremental loading version (only load new content)
            // note: not compatible with polling
            loadMoreInc(providedTerms) {
              // get terms passed as argument or else just default to incrementing the offset
              const newTerms =
                typeof providedTerms === 'undefined'
                  ? { ...props.ownProps.terms, ...props.ownProps.paginationTerms, offset: results.length }
                  : providedTerms;

              return props.data.fetchMore({
                variables: { terms: newTerms }, // ??? not sure about 'terms: newTerms'
                updateQuery(previousResults, { fetchMoreResult }) {
                  // no more post to fetch
                  if (!fetchMoreResult.data) {
                    return previousResults;
                  }
                  const newResults = {};
                  newResults[resolverName] = [...previousResults[resolverName], ...fetchMoreResult.data[resolverName]];
                  // return the previous results "augmented" with more
                  return { ...previousResults, ...newResults };
                },
              });
            },

            fragmentName,
            fragment,
            ...props.ownProps, // pass on the props down to the wrapped component
            data: props.data,
          };
        },
      }
    )
  );
}

// define query reducer separately
const queryReducer = (typeName, previousResults, action, collection, mergedTerms, resolverName, apolloClient) => {
  // if collection has no mutations defined, just return previous results
  if (!collection.options.mutations) {
    return previousResults;
  }

  let newResults = previousResults;

  // get mongo selector and options objects based on current terms
  const result = collection.getParameters(mergedTerms, apolloClient);
  const { selector, options } = result;

  const mingoQuery = new Mingo.Query(selector);

  // function to remove a document from a results object, used by edit and remove cases below
  const removeFromResults = (data, document) => {
    const listWithoutDocument = data[resolverName].results.filter(doc => doc._id !== document._id);
    const currentTotalCount = data[resolverName].totalCount;
    const newResults = update(data, {
      [resolverName]: { $set: { results: listWithoutDocument, totalCount: currentTotalCount - 1 } },
    });
    return newResults;
  };

  // add document to a results object
  const addToResults = (data, document) => {
    const listWithDocument = [...data[resolverName].results, document];
    const currentTotalCount = data[resolverName].totalCount;
    const newResults = update(data, {
      [resolverName]: { $set: { results: listWithDocument, totalCount: currentTotalCount + 1 } },
    });
    return newResults;
  };

  // reorder results according to a sort
  const reorderResults = (data, sort) => {
    const list = data[resolverName].results;
    // const convertedList = Utils.convertDates(collection, list); // convert date strings to date objects
    const convertedList = list;
    const cursor = mingoQuery.find(convertedList);
    const sortedList = cursor.sort(sort).all();
    data[resolverName].results = sortedList;
    return data;
  };

  // console.log('// withList reducer');
  // console.log('terms: ', mergedTerms);
  // console.log('selector: ', selector);
  // console.log('options: ', options);
  // console.log('previousResults: ', previousResults);
  // console.log('action: ', action);

  switch (action.operationName) {
    case `create${typeName}`:
      // if new document belongs to current list (based on view selector), add it
      const newDocument = action.result.data[`create${typeName}`].data;
      if (mingoQuery.test(newDocument)) {
        newResults = addToResults(previousResults, newDocument);
        newResults = reorderResults(newResults, options.sort);
      }
      // console.log('** new **')
      // console.log('newDocument: ', newDocument)
      // console.log('belongs to list: ', mingoQuery.test(newDocument))
      break;

    case `update${typeName}`:
      const editedDocument = action.result.data[`update${typeName}`].data;
      if (mingoQuery.test(editedDocument)) {
        // edited document belongs to the list
        if (!_.findWhere(previousResults[resolverName].results, { _id: editedDocument._id })) {
          // if document wasn't already in list, add it
          newResults = addToResults(previousResults, editedDocument);
        }
        newResults = reorderResults(newResults, options.sort);
      } else {
        // if edited doesn't belong to current list anymore (based on view selector), remove it
        newResults = removeFromResults(previousResults, editedDocument);
      }
      // console.log('** edit **')
      // console.log('editedDocument: ', editedDocument)
      // console.log('belongs to list: ', mingoQuery.test(editedDocument))
      // console.log('exists in list: ', !!_.findWhere(previousResults[resolverName].results, {_id: editedDocument._id}))
      break;

    case `delete${typeName}`:
      const removedDocument = action.result.data[`delete${typeName}`].data;
      newResults = removeFromResults(previousResults, removedDocument);
      // console.log('** remove **')
      // console.log('removedDocument: ', removedDocument)
      break;

    default:
      // console.log('** no action **')
      return previousResults;
  }

  // console.log('newResults: ', newResults)
  // console.log('\n\n')

  // copy over arrays explicitely to ensure new sort is taken into account
  return {
    [resolverName]: {
      results: [...newResults[resolverName].results],
      totalCount: newResults[resolverName].totalCount,
      __typename: `Multi${typeName}Output`,
    },
  };
};
<commit_msg>fix: avoid adding multiple times the same document<commit_after>/*

### withMulti

Paginated items container

Options:

  - collection: the collection to fetch the documents from
  - fragment: the fragment that defines which properties to fetch
  - fragmentName: the name of the fragment, passed to getFragment
  - limit: the number of documents to show initially
  - pollInterval: how often the data should be updated, in ms (set to 0 to disable polling)
  - terms: an object that defines which documents to fetch

Props Received:

  - terms: an object that defines which documents to fetch

Terms object can have the following properties:

  - view: String
  - userId: String
  - cat: String
  - date: String
  - after: String
  - before: String
  - enableTotal: Boolean
  - enableCache: Boolean
  - listId: String
  - query: String # search query
  - postId: String
  - limit: String

*/

import React, { Component } from 'react';
import { withApollo, graphql } from 'react-apollo';
import gql from 'graphql-tag';
import update from 'immutability-helper';
import { getSetting, getFragment, getFragmentName, getCollection, Utils, multiClientTemplate } from 'meteor/vulcan:lib';
import Mingo from 'mingo';
import compose from 'recompose/compose';
import withState from 'recompose/withState';
import find from 'lodash/find';

export default function withMulti(options) {
  // console.log(options)

  const {
    collectionName,
    limit = 10,
    pollInterval = getSetting('pollInterval', 20000),
    enableTotal = true,
    enableCache = false,
    extraQueries,
  } = options;

  const collection = options.collection || getCollection(collectionName);
  const typeName = collection.options.typeName;
  const resolverName = Utils.camelCaseify(Utils.pluralize(typeName));

  let fragment;

  if (options.fragment) {
    fragment = options.fragment;
  } else if (options.fragmentName) {
    fragment = getFragment(options.fragmentName);
  } else {
    fragment = getFragment(`${collection.options.collectionName}DefaultFragment`);
  }

  const fragmentName = getFragmentName(fragment);

  // build graphql query from options
  const query = gql`
    ${multiClientTemplate({ typeName, fragmentName, extraQueries })}
    ${fragment}
  `;

  return compose(
    // wrap component with Apollo HoC to give it access to the store
    withApollo,

    // wrap component with HoC that manages the terms object via its state
    withState('paginationTerms', 'setPaginationTerms', props => {
      // get initial limit from props, or else options
      const paginationLimit = (props.terms && props.terms.limit) || limit;
      const paginationTerms = {
        limit: paginationLimit,
        itemsPerPage: paginationLimit,
      };

      return paginationTerms;
    }),

    // wrap component with graphql HoC
    graphql(
      query,

      {
        alias: `with${Utils.pluralize(typeName)}`,

        // graphql query options
        options({ terms, paginationTerms, client: apolloClient, currentUser }) {
          // get terms from options, then props, then pagination
          const mergedTerms = { ...options.terms, ...terms, ...paginationTerms };

          const graphQLOptions = {
            variables: {
              input: {
                terms: mergedTerms,
                enableCache,
                enableTotal,
              },
            },
            // note: pollInterval can be set to 0 to disable polling (20s by default)
            pollInterval,
            reducer: (previousResults, action) => {
              // see queryReducer function defined below
              return queryReducer(
                typeName,
                previousResults,
                action,
                collection,
                mergedTerms,
                resolverName,
                apolloClient
              );
            },
          };

          if (options.fetchPolicy) {
            graphQLOptions.fetchPolicy = options.fetchPolicy;
          }

          // set to true if running into https://github.com/apollographql/apollo-client/issues/1186
          if (options.notifyOnNetworkStatusChange) {
            graphQLOptions.notifyOnNetworkStatusChange = options.notifyOnNetworkStatusChange;
          }

          return graphQLOptions;
        },

        // define props returned by graphql HoC
        props(props) {
          // see https://github.com/apollographql/apollo-client/blob/master/packages/apollo-client/src/core/networkStatus.ts
          const refetch = props.data.refetch,
            // results = Utils.convertDates(collection, props.data[listResolverName]),
            results = props.data[resolverName] && props.data[resolverName].results,
            totalCount = props.data[resolverName] && props.data[resolverName].totalCount,
            networkStatus = props.data.networkStatus,
            loadingInitial = props.data.networkStatus === 1,
            loading = props.data.networkStatus === 1,
            loadingMore = props.data.networkStatus === 2,
            error = props.data.error,
            propertyName = options.propertyName || 'results';

          if (error) {
            // eslint-disable-next-line no-console
            console.log(error);
          }

          return {
            // see https://github.com/apollostack/apollo-client/blob/master/src/queries/store.ts#L28-L36
            // note: loading will propably change soon https://github.com/apollostack/apollo-client/issues/831
            loading,
            loadingInitial,
            loadingMore,
            [propertyName]: results,
            totalCount,
            refetch,
            networkStatus,
            error,
            count: results && results.length,

            // regular load more (reload everything)
            loadMore(providedTerms) {
              // if new terms are provided by presentational component use them, else default to incrementing current limit once
              const newTerms =
                typeof providedTerms === 'undefined'
                  ? {
                      /*...props.ownProps.terms,*/ ...props.ownProps.paginationTerms,
                      limit: results.length + props.ownProps.paginationTerms.itemsPerPage,
                    }
                  : providedTerms;

              props.ownProps.setPaginationTerms(newTerms);
            },

            // incremental loading version (only load new content)
            // note: not compatible with polling
            loadMoreInc(providedTerms) {
              // get terms passed as argument or else just default to incrementing the offset
              const newTerms =
                typeof providedTerms === 'undefined'
                  ? { ...props.ownProps.terms, ...props.ownProps.paginationTerms, offset: results.length }
                  : providedTerms;

              return props.data.fetchMore({
                variables: { terms: newTerms }, // ??? not sure about 'terms: newTerms'
                updateQuery(previousResults, { fetchMoreResult }) {
                  // no more post to fetch
                  if (!fetchMoreResult.data) {
                    return previousResults;
                  }
                  const newResults = {};
                  newResults[resolverName] = [...previousResults[resolverName], ...fetchMoreResult.data[resolverName]];
                  // return the previous results "augmented" with more
                  return { ...previousResults, ...newResults };
                },
              });
            },

            fragmentName,
            fragment,
            ...props.ownProps, // pass on the props down to the wrapped component
            data: props.data,
          };
        },
      }
    )
  );
}

// define query reducer separately
const queryReducer = (typeName, previousResults, action, collection, mergedTerms, resolverName, apolloClient) => {
  // if collection has no mutations defined, just return previous results
  if (!collection.options.mutations) {
    return previousResults;
  }

  let newResults = previousResults;

  // get mongo selector and options objects based on current terms
  const result = collection.getParameters(mergedTerms, apolloClient);
  const { selector, options } = result;

  const mingoQuery = new Mingo.Query(selector);

  // function to remove a document from a results object, used by edit and remove cases below
  const removeFromResults = (data, document) => {
    const listWithoutDocument = data[resolverName].results.filter(doc => doc._id !== document._id);
    const currentTotalCount = data[resolverName].totalCount;
    const newResults = update(data, {
      [resolverName]: { $set: { results: listWithoutDocument, totalCount: currentTotalCount - 1 } },
    });
    return newResults;
  };

  // add document to a results object
  const addToResults = (data, document) => {
    const listWithDocument = [...data[resolverName].results, document];
    const currentTotalCount = data[resolverName].totalCount;
    const newResults = update(data, {
      [resolverName]: { $set: { results: listWithDocument, totalCount: currentTotalCount + 1 } },
    });
    return newResults;
  };

  // reorder results according to a sort
  const reorderResults = (data, sort) => {
    const list = data[resolverName].results;
    // const convertedList = Utils.convertDates(collection, list); // convert date strings to date objects
    const convertedList = list;
    const cursor = mingoQuery.find(convertedList);
    const sortedList = cursor.sort(sort).all();
    data[resolverName].results = sortedList;
    return data;
  };

  // console.log('// withList reducer');
  // console.log('terms: ', mergedTerms);
  // console.log('selector: ', selector);
  // console.log('options: ', options);
  // console.log('previousResults: ', previousResults);
  // console.log('action: ', action);

  switch (action.operationName) {
    case `create${typeName}`:
      // if new document belongs to current list (based on view selector), add it
      const newDocument = action.result.data[`create${typeName}`].data;
      if (mingoQuery.test(newDocument)) {
        if (!find(previousResults[resolverName].results, { _id: newDocument._id })) {
          // make sure it hasn't been already added despite being a create mutation
          // as this reducer may be called several times
          newResults = addToResults(previousResults, newDocument);
        }
        newResults = reorderResults(newResults, options.sort);
      }
      // console.log('** new **')
      // console.log('newDocument: ', newDocument)
      // console.log('belongs to list: ', mingoQuery.test(newDocument))
      break;

    case `update${typeName}`:
      const editedDocument = action.result.data[`update${typeName}`].data;
      if (mingoQuery.test(editedDocument)) {
        // edited document belongs to the list
        if (!find(previousResults[resolverName].results, { _id: editedDocument._id })) {
          // if document wasn't already in list, add it
          newResults = addToResults(previousResults, editedDocument);
        }
        newResults = reorderResults(newResults, options.sort);
      } else {
        // if edited doesn't belong to current list anymore (based on view selector), remove it
        newResults = removeFromResults(previousResults, editedDocument);
      }
      // console.log('** edit **')
      // console.log('editedDocument: ', editedDocument)
      // console.log('belongs to list: ', mingoQuery.test(editedDocument))
      // console.log('exists in list: ', !!_.findWhere(previousResults[resolverName].results, {_id: editedDocument._id}))
      break;

    case `delete${typeName}`:
      const removedDocument = action.result.data[`delete${typeName}`].data;
      newResults = removeFromResults(previousResults, removedDocument);
      // console.log('** remove **')
      // console.log('removedDocument: ', removedDocument)
      break;

    default:
      // console.log('** no action **')
      return previousResults;
  }

  // console.log('newResults: ', newResults)
  // console.log('\n\n')

  // copy over arrays explicitely to ensure new sort is taken into account
  return {
    [resolverName]: {
      results: [...newResults[resolverName].results],
      totalCount: newResults[resolverName].totalCount,
      __typename: `Multi${typeName}Output`,
    },
  };
};
<|endoftext|>


<commit_before>// -------------------------------------------------------------------------- \\
// File: RegExp.js                                                            \\
// Module: IEPatches                                                          \\
// Author: Steven Levithan, Neil Jenkins                                      \\
// License: © 2010–2013 Opera Software ASA. All rights reserved.              \\
// -------------------------------------------------------------------------- \\

/*jshint strict: false */

( function ( undefined ) {

// Fix major issues in IE split() function
// Main bug is the failure to include capture groups in the output.
// Original fix by Steven Levithan (tidied and optimised by Neil Jenkins):
// http://blog.stevenlevithan.com/archives/cross-browser-split
if ('a~b'.split(/(~)/).length !== 3) {
    var nativeSplit = String.prototype.split;
    String.prototype.split = function ( separator, limit ) {
        // If separator is not a regex, use the native split method
        if ( !( separator instanceof RegExp ) ) {
            return nativeSplit.apply( this, arguments );
        }

        var flags = ( separator.global ? 'g' : '' ) +
                    ( separator.ignoreCase ? 'i' : '' ) +
                    ( separator.multiline ? 'm' : '' ),
            separator2 = new RegExp( '^' + separator.source + '$', flags ),
            output = [],
            origLastIndex = separator.lastIndex,
            lastLastIndex = 0,
            i, match, lastLength, emptyMatch;

        /* behavior for limit: if it's...
        - undefined: no limit
        - NaN or zero: return an empty array
        - a positive number: use limit after dropping any decimal
        - a negative number: no limit
        - other: type-convert, then use the above rules
        */
        if ( limit === undefined || +limit < 0 ) {
            limit = 0;
        } else {
            limit = Math.floor( +limit );
            if ( !limit ) {
                return output;
            }
        }

        if ( separator.global ) {
            separator.lastIndex = 0;
        }
        else {
            separator = new RegExp( separator.source, 'g' + flags );
        }

        for ( i = 0;
                ( !limit || i <= limit ) && ( match = separator.exec( this ) );
                i += 1 ) {
            emptyMatch = !match[0].length;

            // Fix IE's infinite-loop-resistant but incorrect lastIndex
            if ( emptyMatch && separator.lastIndex > match.index ) {
                separator.lastIndex -= 1;
            }

            if ( separator.lastIndex > lastLastIndex ) {
                // Fix browsers whose exec methods don't consistently return
                // undefined for non-participating capturing groups
                if ( match.length > 1 ) {
                    match[0].replace( separator2, function () {
                        for ( var j = 1; j < arguments.length - 2; j += 1 ) {
                            if ( arguments[j] === undefined ) {
                                match[j] = undefined;
                            }
                        }
                    });
                }
                output.push( this.slice( lastLastIndex, match.index ) );
                if ( match.length > 1 && match.index < this.length ) {
                    output.push( match.slice( 1 ) );
                }
                // only needed if s.lastIndex === this.length
                lastLength = match[0].length;
                lastLastIndex = separator.lastIndex;
            }

            if ( emptyMatch ) {
                separator.lastIndex += 1; // avoid an infinite loop
            }
        }

        // Since this uses test(), output must be generated before
        // restoring lastIndex
        if ( lastLastIndex === this.length ) {
            if ( !separator.test( '' ) || lastLength ) {
                output.push( '' );
            }
        } else {
            if ( !limit ) {
                output.push( this.slice( lastLastIndex ) );
            }
        }

        // Only needed if s.global, else we're working with a copy of the regex
        separator.lastIndex = origLastIndex;

        return output;
    };
}

}() );
<commit_msg>Fix bug in IE8 reg-exp fix.<commit_after>// -------------------------------------------------------------------------- \\
// File: RegExp.js                                                            \\
// Module: IEPatches                                                          \\
// Author: Steven Levithan, Neil Jenkins                                      \\
// License: © 2010–2013 Opera Software ASA. All rights reserved.              \\
// -------------------------------------------------------------------------- \\

/*jshint strict: false */

( function ( undefined ) {

// Fix major issues in IE split() function
// Main bug is the failure to include capture groups in the output.
// Original fix by Steven Levithan (tidied and optimised by Neil Jenkins):
// http://blog.stevenlevithan.com/archives/cross-browser-split
if ('a~b'.split(/(~)/).length !== 3) {
    var nativeSplit = String.prototype.split;
    String.prototype.split = function ( separator, limit ) {
        // If separator is not a regex, use the native split method
        if ( !( separator instanceof RegExp ) ) {
            return nativeSplit.apply( this, arguments );
        }

        var flags = ( separator.global ? 'g' : '' ) +
                    ( separator.ignoreCase ? 'i' : '' ) +
                    ( separator.multiline ? 'm' : '' ),
            separator2 = new RegExp( '^' + separator.source + '$', flags ),
            output = [],
            origLastIndex = separator.lastIndex,
            lastLastIndex = 0,
            i, match, lastLength, emptyMatch;

        /* behavior for limit: if it's...
        - undefined: no limit
        - NaN or zero: return an empty array
        - a positive number: use limit after dropping any decimal
        - a negative number: no limit
        - other: type-convert, then use the above rules
        */
        if ( limit === undefined || +limit < 0 ) {
            limit = 0;
        } else {
            limit = Math.floor( +limit );
            if ( !limit ) {
                return output;
            }
        }

        if ( separator.global ) {
            separator.lastIndex = 0;
        }
        else {
            separator = new RegExp( separator.source, 'g' + flags );
        }

        for ( i = 0;
                ( !limit || i <= limit ) && ( match = separator.exec( this ) );
                i += 1 ) {
            emptyMatch = !match[0].length;

            // Fix IE's infinite-loop-resistant but incorrect lastIndex
            if ( emptyMatch && separator.lastIndex > match.index ) {
                separator.lastIndex -= 1;
            }

            if ( separator.lastIndex > lastLastIndex ) {
                // Fix browsers whose exec methods don't consistently return
                // undefined for non-participating capturing groups
                if ( match.length > 1 ) {
                    match[0].replace( separator2, function () {
                        for ( var j = 1; j < arguments.length - 2; j += 1 ) {
                            if ( arguments[j] === undefined ) {
                                match[j] = undefined;
                            }
                        }
                    });
                }
                output.push( this.slice( lastLastIndex, match.index ) );
                if ( match.length > 1 && match.index < this.length ) {
                    output.push.apply( output, match.slice( 1 ) );
                }
                // only needed if s.lastIndex === this.length
                lastLength = match[0].length;
                lastLastIndex = separator.lastIndex;
            }

            if ( emptyMatch ) {
                separator.lastIndex += 1; // avoid an infinite loop
            }
        }

        // Since this uses test(), output must be generated before
        // restoring lastIndex
        if ( lastLastIndex === this.length ) {
            if ( !separator.test( '' ) || lastLength ) {
                output.push( '' );
            }
        } else {
            if ( !limit ) {
                output.push( this.slice( lastLastIndex ) );
            }
        }

        // Only needed if s.global, else we're working with a copy of the regex
        separator.lastIndex = origLastIndex;

        return output;
    };
}

}() );
<|endoftext|>


<commit_before>/* global jQuery */

/**
## jquery.flot.hover.js

This plugin is used for mouse hover and tap on a point of plot series.
It supports the following options:
```js
grid: {
    hoverable: false, //to trigger plothover event on mouse hover or tap on a point
    clickable: false //to trigger plotclick event on mouse hover
}
```

It listens to native mouse move event or click, as well as artificial generated
tap and touchevent.

When the mouse is over a point or a tap on a point is performed, that point or
the correscponding bar will be highlighted and a "plothover" event will be generated.

Custom "touchevent" is triggered when any touch interaction is made. Hover plugin
handles this events by unhighlighting all of the previously highlighted points and generates
"plothovercleanup" event to notify any part that is handling plothover (for exemple to cleanup
the tooltip from webcharts).
*/

(function($) {
    'use strict';

    var options = {
        grid: {
            hoverable: false,
            clickable: false
        }
    };

    var browser = $.plot.browser;

    function init(plot) {
        plot.hooks.processOptions.push(initHover);
    }

    function initHover(plot, options) {
        var highlights = [];

        var eventType = {
            click: 'click',
            hover: 'hover'
        }

        var lastMouseMoveEvent = plot.getPlaceholder()[0].lastMouseMoveEvent;

        plot.highlight = highlight;
        plot.unhighlight = unhighlight;

        function bindEvents(plot, eventHolder) {
            var o = plot.getOptions();

            if (o.grid.hoverable || o.grid.clickable) {
                eventHolder[0].addEventListener('touchevent', triggerCleanupEvent, false);
                eventHolder[0].addEventListener('tap', tap.generatePlothoverEvent, false);
            }

            if (options.grid.clickable) {
                eventHolder.click(onClick);
            }

            if (options.grid.hoverable) {
                eventHolder.mousemove(onMouseMove);

                // Use bind, rather than .mouseleave, because we officially
                // still support jQuery 1.2.6, which doesn't define a shortcut
                // for mouseenter or mouseleave.  This was a bug/oversight that
                // was fixed somewhere around 1.3.x.  We can return to using
                // .mouseleave when we drop support for 1.2.6.

                eventHolder.bind("mouseleave", onMouseLeave);
            }
        }

        function shutdown(plot, eventHolder) {
            eventHolder[0].removeEventListener('tap', tap.generatePlothoverEvent);
            eventHolder[0].removeEventListener('tap', triggerCleanupEvent);
            eventHolder.unbind("mousemove", onMouseMove);
            eventHolder.unbind("mouseleave", onMouseLeave);
            eventHolder.unbind("click", onClick);
            highlights = [];
        }

        function doTriggerClickHoverEvent(event, eventType, searchDistance) {
            var series = plot.getData();
            if (event !== undefined
                && series.length > 0
                && series[0].xaxis.c2p !== undefined
                && series[0].yaxis.c2p !== undefined) {
                var eventToTrigger = "plot" + eventType;
                var seriesFlag = eventType + "able";
                triggerClickHoverEvent(eventToTrigger, event,
                    function(i) {
                        return series[i][seriesFlag] !== false;
                    }, searchDistance);
            }
        }

        var tap = {
            generatePlothoverEvent: function (e) {
                var o = plot.getOptions(),
                    newEvent = new CustomEvent('mouseevent');

                //transform from touch event to mouse event format
                newEvent.pageX = e.detail.changedTouches[0].pageX;
                newEvent.pageY = e.detail.changedTouches[0].pageY;
                newEvent.clientX = e.detail.changedTouches[0].clientX;
                newEvent.clientY = e.detail.changedTouches[0].clientY;

                if (o.grid.hoverable) {
                    doTriggerClickHoverEvent(newEvent, eventType.hover, 30);
                }
                return false;
            }
        };

        if (options.grid.hoverable || options.grid.clickable) {
            plot.hooks.bindEvents.push(bindEvents);
            plot.hooks.shutdown.push(shutdown);
            plot.hooks.drawOverlay.push(drawOverlay);
            plot.hooks.processRawData.push(processRawData);
        }

        function onMouseMove(e) {
            lastMouseMoveEvent = e;
            plot.getPlaceholder()[0].lastMouseMoveEvent = e;
            doTriggerClickHoverEvent(e, eventType.hover);
        }

        function onMouseLeave(e) {
            lastMouseMoveEvent = undefined;
            plot.getPlaceholder()[0].lastMouseMoveEvent = undefined;
            triggerClickHoverEvent("plothover", e,
                function(i) {
                    return false;
                });
        }

        function onClick(e) {
            doTriggerClickHoverEvent(e, eventType.click);
        }

        function triggerCleanupEvent() {
            plot.unhighlight();
            plot.getPlaceholder().trigger('plothovercleanup');
        }

        // trigger click or hover event (they send the same parameters
        // so we share their code)
        function triggerClickHoverEvent(eventname, event, seriesFilter, searchDistance) {
            var options = plot.getOptions(),
                offset = plot.offset(),
                page = browser.getPageXY(event),
                canvasX = page.X - offset.left,
                canvasY = page.Y - offset.top,
                pos = plot.c2p({
                    left: canvasX,
                    top: canvasY
                }),
                distance = searchDistance !== undefined ? searchDistance : options.grid.mouseActiveRadius;

            pos.pageX = page.X;
            pos.pageY = page.Y;

            var item = plot.findNearbyItem(canvasX, canvasY, seriesFilter, distance);

            if (item) {
                // fill in mouse pos for any listeners out there
                item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left, 10);
                item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top, 10);
            }

            if (options.grid.autoHighlight) {
                // clear auto-highlights
                for (var i = 0; i < highlights.length; ++i) {
                    var h = highlights[i];
                    if ((h.auto === eventname &&
                        !(item && h.series === item.series &&
                            h.point[0] === item.datapoint[0] &&
                            h.point[1] === item.datapoint[1])) || !item) {
                        unhighlight(h.series, h.point);
                    }
                }

                if (item) {
                    highlight(item.series, item.datapoint, eventname);
                }
            }

            plot.getPlaceholder().trigger(eventname, [pos, item]);
        }

        function highlight(s, point, auto) {
            if (typeof s === "number") {
                s = plot.getData()[s];
            }

            if (typeof point === "number") {
                var ps = s.datapoints.pointsize;
                point = s.datapoints.points.slice(ps * point, ps * (point + 1));
            }

            var i = indexOfHighlight(s, point);
            if (i === -1) {
                highlights.push({
                    series: s,
                    point: point,
                    auto: auto
                });

                plot.triggerRedrawOverlay();
            } else if (!auto) {
                highlights[i].auto = false;
            }
        }

        function unhighlight(s, point) {
            if (s == null && point == null) {
                highlights = [];
                plot.triggerRedrawOverlay();
                return;
            }

            if (typeof s === "number") {
                s = plot.getData()[s];
            }

            if (typeof point === "number") {
                var ps = s.datapoints.pointsize;
                point = s.datapoints.points.slice(ps * point, ps * (point + 1));
            }

            var i = indexOfHighlight(s, point);
            if (i !== -1) {
                highlights.splice(i, 1);

                plot.triggerRedrawOverlay();
            }
        }

        function indexOfHighlight(s, p) {
            for (var i = 0; i < highlights.length; ++i) {
                var h = highlights[i];
                if (h.series === s &&
                    h.point[0] === p[0] &&
                    h.point[1] === p[1]) {
                    return i;
                }
            }

            return -1;
        }

        function processRawData() {
            triggerCleanupEvent();
            doTriggerClickHoverEvent(lastMouseMoveEvent, eventType.hover);
        }

        function drawOverlay(plot, octx, overlay) {
            var plotOffset = plot.getPlotOffset(),
                i, hi;

            octx.save();
            octx.translate(plotOffset.left, plotOffset.top);
            for (i = 0; i < highlights.length; ++i) {
                hi = highlights[i];

                if (hi.series.bars.show) drawBarHighlight(hi.series, hi.point, octx);
                else drawPointHighlight(hi.series, hi.point, octx, plot);
            }
            octx.restore();
        }
    }

    function drawPointHighlight(series, point, octx, plot) {
        var x = point[0],
            y = point[1],
            axisx = series.xaxis,
            axisy = series.yaxis,
            highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString();

        if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) {
            return;
        }

        var pointRadius = series.points.radius + series.points.lineWidth / 2;
        octx.lineWidth = pointRadius;
        octx.strokeStyle = highlightColor;
        var radius = 1.5 * pointRadius;
        x = axisx.p2c(x);
        y = axisy.p2c(y);

        octx.beginPath();
        var symbol = series.points.symbol;
        if (symbol === 'circle') {
            octx.arc(x, y, radius, 0, 2 * Math.PI, false);
        } else if (typeof symbol === 'string' && plot.drawSymbol && plot.drawSymbol[symbol]) {
            plot.drawSymbol[symbol](octx, x, y, radius, false);
        }

        octx.closePath();
        octx.stroke();
    }

    function drawBarHighlight(series, point, octx) {
        var highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString(),
            fillStyle = highlightColor,
            barLeft;

        var barWidth = series.bars.barWidth[0] || series.bars.barWidth;
        switch (series.bars.align) {
            case "left":
                barLeft = 0;
                break;
            case "right":
                barLeft = -barWidth;
                break;
            default:
                barLeft = -barWidth / 2;
        }

        octx.lineWidth = series.bars.lineWidth;
        octx.strokeStyle = highlightColor;

        var fillTowards = series.bars.fillTowards || 0,
            bottom = fillTowards > series.yaxis.min ? Math.min(series.yaxis.max, fillTowards) : series.yaxis.min;

        $.plot.drawSeries.drawBar(point[0], point[1], point[2] || bottom, barLeft, barLeft + barWidth,
            function() {
                return fillStyle;
            }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth);
    }

    $.plot.plugins.push({
        init: init,
        options: options,
        name: 'hover',
        version: '0.1'
    });
})(jQuery);
<commit_msg>Move 'tap' declaration<commit_after>/* global jQuery */

/**
## jquery.flot.hover.js

This plugin is used for mouse hover and tap on a point of plot series.
It supports the following options:
```js
grid: {
    hoverable: false, //to trigger plothover event on mouse hover or tap on a point
    clickable: false //to trigger plotclick event on mouse hover
}
```

It listens to native mouse move event or click, as well as artificial generated
tap and touchevent.

When the mouse is over a point or a tap on a point is performed, that point or
the correscponding bar will be highlighted and a "plothover" event will be generated.

Custom "touchevent" is triggered when any touch interaction is made. Hover plugin
handles this events by unhighlighting all of the previously highlighted points and generates
"plothovercleanup" event to notify any part that is handling plothover (for exemple to cleanup
the tooltip from webcharts).
*/

(function($) {
    'use strict';

    var options = {
        grid: {
            hoverable: false,
            clickable: false
        }
    };

    var browser = $.plot.browser;

    function init(plot) {
        plot.hooks.processOptions.push(initHover);
    }

    function initHover(plot, options) {
        var highlights = [];

        var eventType = {
            click: 'click',
            hover: 'hover'
        }

        var lastMouseMoveEvent = plot.getPlaceholder()[0].lastMouseMoveEvent;

        plot.highlight = highlight;
        plot.unhighlight = unhighlight;

        var tap = {
            generatePlothoverEvent: function (e) {
                var o = plot.getOptions(),
                    newEvent = new CustomEvent('mouseevent');

                //transform from touch event to mouse event format
                newEvent.pageX = e.detail.changedTouches[0].pageX;
                newEvent.pageY = e.detail.changedTouches[0].pageY;
                newEvent.clientX = e.detail.changedTouches[0].clientX;
                newEvent.clientY = e.detail.changedTouches[0].clientY;

                if (o.grid.hoverable) {
                    doTriggerClickHoverEvent(newEvent, eventType.hover, 30);
                }
                return false;
            }
        };

        function bindEvents(plot, eventHolder) {
            var o = plot.getOptions();

            if (o.grid.hoverable || o.grid.clickable) {
                eventHolder[0].addEventListener('touchevent', triggerCleanupEvent, false);
                eventHolder[0].addEventListener('tap', tap.generatePlothoverEvent, false);
            }

            if (options.grid.clickable) {
                eventHolder.click(onClick);
            }

            if (options.grid.hoverable) {
                eventHolder.mousemove(onMouseMove);

                // Use bind, rather than .mouseleave, because we officially
                // still support jQuery 1.2.6, which doesn't define a shortcut
                // for mouseenter or mouseleave.  This was a bug/oversight that
                // was fixed somewhere around 1.3.x.  We can return to using
                // .mouseleave when we drop support for 1.2.6.

                eventHolder.bind("mouseleave", onMouseLeave);
            }
        }

        function shutdown(plot, eventHolder) {
            eventHolder[0].removeEventListener('tap', tap.generatePlothoverEvent);
            eventHolder[0].removeEventListener('tap', triggerCleanupEvent);
            eventHolder.unbind("mousemove", onMouseMove);
            eventHolder.unbind("mouseleave", onMouseLeave);
            eventHolder.unbind("click", onClick);
            highlights = [];
        }

        function doTriggerClickHoverEvent(event, eventType, searchDistance) {
            var series = plot.getData();
            if (event !== undefined
                && series.length > 0
                && series[0].xaxis.c2p !== undefined
                && series[0].yaxis.c2p !== undefined) {
                var eventToTrigger = "plot" + eventType;
                var seriesFlag = eventType + "able";
                triggerClickHoverEvent(eventToTrigger, event,
                    function(i) {
                        return series[i][seriesFlag] !== false;
                    }, searchDistance);
            }
        }

        if (options.grid.hoverable || options.grid.clickable) {
            plot.hooks.bindEvents.push(bindEvents);
            plot.hooks.shutdown.push(shutdown);
            plot.hooks.drawOverlay.push(drawOverlay);
            plot.hooks.processRawData.push(processRawData);
        }

        function onMouseMove(e) {
            lastMouseMoveEvent = e;
            plot.getPlaceholder()[0].lastMouseMoveEvent = e;
            doTriggerClickHoverEvent(e, eventType.hover);
        }

        function onMouseLeave(e) {
            lastMouseMoveEvent = undefined;
            plot.getPlaceholder()[0].lastMouseMoveEvent = undefined;
            triggerClickHoverEvent("plothover", e,
                function(i) {
                    return false;
                });
        }

        function onClick(e) {
            doTriggerClickHoverEvent(e, eventType.click);
        }

        function triggerCleanupEvent() {
            plot.unhighlight();
            plot.getPlaceholder().trigger('plothovercleanup');
        }

        // trigger click or hover event (they send the same parameters
        // so we share their code)
        function triggerClickHoverEvent(eventname, event, seriesFilter, searchDistance) {
            var options = plot.getOptions(),
                offset = plot.offset(),
                page = browser.getPageXY(event),
                canvasX = page.X - offset.left,
                canvasY = page.Y - offset.top,
                pos = plot.c2p({
                    left: canvasX,
                    top: canvasY
                }),
                distance = searchDistance !== undefined ? searchDistance : options.grid.mouseActiveRadius;

            pos.pageX = page.X;
            pos.pageY = page.Y;

            var item = plot.findNearbyItem(canvasX, canvasY, seriesFilter, distance);

            if (item) {
                // fill in mouse pos for any listeners out there
                item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left, 10);
                item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top, 10);
            }

            if (options.grid.autoHighlight) {
                // clear auto-highlights
                for (var i = 0; i < highlights.length; ++i) {
                    var h = highlights[i];
                    if ((h.auto === eventname &&
                        !(item && h.series === item.series &&
                            h.point[0] === item.datapoint[0] &&
                            h.point[1] === item.datapoint[1])) || !item) {
                        unhighlight(h.series, h.point);
                    }
                }

                if (item) {
                    highlight(item.series, item.datapoint, eventname);
                }
            }

            plot.getPlaceholder().trigger(eventname, [pos, item]);
        }

        function highlight(s, point, auto) {
            if (typeof s === "number") {
                s = plot.getData()[s];
            }

            if (typeof point === "number") {
                var ps = s.datapoints.pointsize;
                point = s.datapoints.points.slice(ps * point, ps * (point + 1));
            }

            var i = indexOfHighlight(s, point);
            if (i === -1) {
                highlights.push({
                    series: s,
                    point: point,
                    auto: auto
                });

                plot.triggerRedrawOverlay();
            } else if (!auto) {
                highlights[i].auto = false;
            }
        }

        function unhighlight(s, point) {
            if (s == null && point == null) {
                highlights = [];
                plot.triggerRedrawOverlay();
                return;
            }

            if (typeof s === "number") {
                s = plot.getData()[s];
            }

            if (typeof point === "number") {
                var ps = s.datapoints.pointsize;
                point = s.datapoints.points.slice(ps * point, ps * (point + 1));
            }

            var i = indexOfHighlight(s, point);
            if (i !== -1) {
                highlights.splice(i, 1);

                plot.triggerRedrawOverlay();
            }
        }

        function indexOfHighlight(s, p) {
            for (var i = 0; i < highlights.length; ++i) {
                var h = highlights[i];
                if (h.series === s &&
                    h.point[0] === p[0] &&
                    h.point[1] === p[1]) {
                    return i;
                }
            }

            return -1;
        }

        function processRawData() {
            triggerCleanupEvent();
            doTriggerClickHoverEvent(lastMouseMoveEvent, eventType.hover);
        }

        function drawOverlay(plot, octx, overlay) {
            var plotOffset = plot.getPlotOffset(),
                i, hi;

            octx.save();
            octx.translate(plotOffset.left, plotOffset.top);
            for (i = 0; i < highlights.length; ++i) {
                hi = highlights[i];

                if (hi.series.bars.show) drawBarHighlight(hi.series, hi.point, octx);
                else drawPointHighlight(hi.series, hi.point, octx, plot);
            }
            octx.restore();
        }
    }

    function drawPointHighlight(series, point, octx, plot) {
        var x = point[0],
            y = point[1],
            axisx = series.xaxis,
            axisy = series.yaxis,
            highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString();

        if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) {
            return;
        }

        var pointRadius = series.points.radius + series.points.lineWidth / 2;
        octx.lineWidth = pointRadius;
        octx.strokeStyle = highlightColor;
        var radius = 1.5 * pointRadius;
        x = axisx.p2c(x);
        y = axisy.p2c(y);

        octx.beginPath();
        var symbol = series.points.symbol;
        if (symbol === 'circle') {
            octx.arc(x, y, radius, 0, 2 * Math.PI, false);
        } else if (typeof symbol === 'string' && plot.drawSymbol && plot.drawSymbol[symbol]) {
            plot.drawSymbol[symbol](octx, x, y, radius, false);
        }

        octx.closePath();
        octx.stroke();
    }

    function drawBarHighlight(series, point, octx) {
        var highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString(),
            fillStyle = highlightColor,
            barLeft;

        var barWidth = series.bars.barWidth[0] || series.bars.barWidth;
        switch (series.bars.align) {
            case "left":
                barLeft = 0;
                break;
            case "right":
                barLeft = -barWidth;
                break;
            default:
                barLeft = -barWidth / 2;
        }

        octx.lineWidth = series.bars.lineWidth;
        octx.strokeStyle = highlightColor;

        var fillTowards = series.bars.fillTowards || 0,
            bottom = fillTowards > series.yaxis.min ? Math.min(series.yaxis.max, fillTowards) : series.yaxis.min;

        $.plot.drawSeries.drawBar(point[0], point[1], point[2] || bottom, barLeft, barLeft + barWidth,
            function() {
                return fillStyle;
            }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth);
    }

    $.plot.plugins.push({
        init: init,
        options: options,
        name: 'hover',
        version: '0.1'
    });
})(jQuery);
<|endoftext|>


<commit_before>//!REMEMBER! the husky took the name of man and the man took the name of husky REMEMBER!!!!
var Aquaplane = {};

Aquaplane.Preloader = function () {};

Aquaplane.Preloader.prototype = {

    init: function () {

        this.input.maxPointers = 1;

        this.scale.pageAlignHorizontally = true;

    },

    preload: function () {

        this.load.path = 'assets/';

        this.load.bitmapFont('fat-and-tiny');
        this.load.bitmapFont('interfont');

        this.load.images([ 'logo']);
        this.load.spritesheet('town', 'town1.png', 700, 700, 22);
        this.load.spritesheet('crack', 'crack.png', 16, 6);
        this.load.spritesheet('husky', 'man.png', 92, 92);
        this.load.spritesheet('man', 'husky.png', 96, 96);
        this.load.spritesheet('zombie', 'zombie.png', 96, 96);
         this.load.spritesheet('zomkabob', 'zomkabob.png', 96, 96);
          this.load.spritesheet('hand', 'hand.png', 32, 32);
    },

    create: function () {

        this.state.start('Aquaplane.MainMenu');

    }

};

Aquaplane.MainMenu = function () {};

Aquaplane.MainMenu.prototype = {

    create: function () {

        var town = this.add.sprite(0, -50, 'town');
        var scroll = town.animations.add('scroll');
        town.animations.play('scroll', 12, true);

        var logo = this.add.image( this.world.centerX, 20, 'logo');
        logo.anchor.x = 0.5;

        var start = this.add.bitmapText(this.world.centerX, 460, 'fat-and-tiny', 'CLICK TO PLAY', 64);
        start.anchor.x = 0.5;
        start.smoothed = false;
        start.tint = 0x990000;

        this.input.onDown.addOnce(this.start, this);

    },

    start: function () {

        this.state.start('Aquaplane.Game');

    }

};

Aquaplane.Game = function (game) {

    this.score = 0;
    this.scoreText = null;

    this.lives = 3;
    this.livesText = null;

    this.speed = 420;
    this.lastKey = 0;
    this.ready = false;

    this.layer = null;
    this.itemDist = ['zomkabob', 'zomkabob', 'zomkabob', 'hand', 'hand', 'hand', 'zombie'];

    this.man = null;
    this.husky = null;
    this.rope = null;

    this.timer = null;
    this.itemInterval = { count: 0, min: 500, max: 1500 };

    this.pauseKey = null;
    this.debugKey = null;
    this.showDebug = false;

};

Aquaplane.Game.prototype = {

    init: function () {

        this.score = 0;
        this.lives = 3;
        this.speed = 420;

        this.ready = false;
        this.lastKey = 0;

        this.timer = this.time.create(false);
        this.itemInterval = { count: 0, min: 500, max: 1500 };

        this.physics.startSystem(Phaser.Physics.P2JS);
        this.physics.p2.gravity.y = 0;

        this.showDebug = false;

    },

    create: function () {

        var town = this.add.sprite(0, -50, 'town');
        var scroll = town.animations.add('scroll');
        town.animations.play('scroll', 12, true);

        this.waterParticle = this.make.bitmapData(2, 2);
        this.waterParticle.rect(0, 0, 2, 2, '#ffffff');
        this.waterParticle.update();

        this.emitter = this.add.emitter(128, 128, 128);
        this.emitter.makeParticles(this.waterParticle);

        this.emitter.gravity = 0;
        this.emitter.setXSpeed(-100, -250);
        this.emitter.setYSpeed(-100, 100);

        this.emitter.setAlpha(1, 0.2, 500);

        this.emitter.flow(500, 20, 2, -1, true);

        this.layer = this.add.group();

        this.man = this.layer.create(0, 0, 'man');
        var man = this.add.sprite(0, 0, 'man');
        var walk = man.animations.add('walk');
            man.animations.play('walk', 12, true)

        this.physics.p2.enable(this.man, false);

        this.man.body.mass = 0.5;
        this.man.body.damping = 0.01;
        this.man.body.fixedRotation = true;
        this.man.body.collideWorldBounds = false;

        this.husky = this.layer.create(0, 0, 'husky');
        var husky = this.add.sprite(0, 0, 'husky');
        var run = husky.animations.add('run');
        husky.animations.play('run', 12, true);

        this.physics.p2.enable(this.husky, false);

        this.husky.body.mass = 0.05;
        this.husky.body.damping = 0.01;
        this.husky.body.fixedRotation = true;
        this.husky.body.collideWorldBounds = false;

        this.manBounds = new Phaser.Rectangle(0, 0, 23, 23);
        this.huskyBounds = new Phaser.Rectangle(0, 0, 24, 24);

        var rev = new p2.RevoluteConstraint(this.man.body.data, this.husky.body.data, {
                localPivotA: [9, 0],
                localPivotB: [2, 0],
                collideConnected: false
            });

        this.physics.p2.world.addConstraint(rev);

        rev.setLimits(this.math.degToRad(-40), this.math.degToRad(40));

        rev.setStiffness(2.0);

        //  Let's create some cracks (harmless eye candy)
        //
        //  Divide screen vertically into 520px / 8 layers = 65px per layer
        //  Place 8 cracks per layer (8*8 total)

        var area = new Phaser.Rectangle(0, 70, this.game.width, 45);

        for (var i = 1; i <= 7; i++)
        {
            for (var w = 0; w < 7; w++)
            {
                var crack = this.layer.create(area.randomX, area.randomY, 'crack', this.rnd.between(0, 2));
                'crack'.anchor.y = -1.5;
                this.physics.arcade.enable(crack);
                crack.body.velocity.x = -120 + (i * -30);
            }

            area.y += 45;
        }

        this.line = new Phaser.Line(this.man.x - 28, this.man.y, this.husky.x + 6, this.husky.y - 1);

        //  The rope that attaches the husky to the man
        this.rope = this.add.graphics(0, 0);

        this.scoreText = this.add.bitmapText(16, 0, 'fat-and-tiny', 'SCORE: 0', 32);
        this.scoreText.smoothed = false;

        this.livesText = this.add.bitmapText(580, 0, 'fat-and-tiny', 'LIVES: ' + this.lives, 32);
        this.livesText.smoothed = false;

        this.cursors = this.input.keyboard.createCursorKeys();

        //  Press P to pause and resume the game
        this.pauseKey = this.input.keyboard.addKey(Phaser.Keyboard.P);
        this.pauseKey.onDown.add(this.togglePause, this);

        //  Press D to toggle the debug display
        this.debugKey = this.input.keyboard.addKey(Phaser.Keyboard.D);
        this.debugKey.onDown.add(this.toggleDebug, this);

        this.bringManOn();

    },

    togglePause: function () {

        this.game.paused = (this.game.paused) ? false : true;

    },

    toggleDebug: function () {

        this.showDebug = (this.showDebug) ? false : true;

    },

    bringManOn: function () {

        this.ready = false;

        this.man.body.x = -64;
        this.man.body.y = 300;

        this.husky.visible = true;
        this.husky.body.x = -264;
        this.husky.body.y = 300;

        this.husky.body.velocity.x = 300;

    },

    manReady: function () {

        this.ready = true;

        this.man.body.setZeroVelocity();

        this.timer.add(this.itemInterval.max, this.releaseItem, this);
        this.timer.start();

    },

    releaseItem: function (x, y) {

        if (x === undefined) { x = 700; }
        if (y === undefined) { y = this.rnd.between(80, 487); }

        var frame = this.rnd.pick(this.itemDist);

        var item = this.layer.getFirstDead(true, x, y, frame);

        this.physics.arcade.enable(item);

        if (frame === 'zombie')
        {
            item.body.setSize(32, 14, 0, 16);
        }
        else
        {
            item.body.setSize(16, 8, 0, 24);
        }

        var i = this.math.snapToFloor(y, 65) / 65;

        item.body.velocity.x = -120 + (i * -30);

        this.itemInterval.count++;

        //  Every 10 new items we'll speed things up a bit
        if (this.itemInterval.min > 100 && this.itemInterval.count % 10 === 0)
        {
            this.itemInterval.min -= 10;
            this.itemInterval.max -= 10;
        }

        //  Is the player idle? Then release another item directly towards them
        if ((this.time.time - this.lastKey) > 200)
        {
            this.lastKey = this.time.time;
            this.releaseItem(700, this.husky.y - 16);
        }
        else
        {
            this.timer.add(this.rnd.between(this.itemInterval.min, this.itemInterval.max), this.releaseItem, this);
        }

    },

    update: function () {

        this.layer.sort('y', Phaser.Group.SORT_ASCENDING);

        if (this.ready)
        {
            this.updateMan();

            //  Score based on their position on the screen
            this.score += (this.math.snapToFloor(this.husky.y, 65) / 65);
            this.scoreText.text = "SCORE: " + this.score;
        }
        else
        {
            if (this.husky.visible)
            {
                if (this.man.x >= 250)
                {
                    this.manReady();
                }
            }
            else
            {
                if (this.man.x >= 832)
                {
                    this.bringManOn();
                }
            }
        }

        this.manBounds.centerOn(this.man.x + 4, this.man.y + 8);
        this.huskyBounds.centerOn(this.husky.x + 2, this.husky.y + 10);

        this.emitter.emitX = this.man.x - 16;
        this.emitter.emitY = this.man.y + 10;

        //  Let's sort and collide
        this.layer.forEachAlive(this.checkItem, this);

    },

    updateMan: function () {

        if (this.man.x < 200)
        {
            this.man.body.setZeroForce();
            this.man.body.x = 200;
        }
        else if (this.man.x > 650)
        {
            this.man.body.setZeroForce();
            this.man.body.x = 650;
        }

        if (this.man.y < 100)
        {
            this.man.body.setZeroForce();
            this.man.body.y = 100;
        }
        else if (this.man.y > 550)
        {
            this.man.body.setZeroForce();
            this.man.body.y = 550;
        }

        if (this.cursors.left.isDown)
        {
            this.man.body.force.x = -this.speed;
            this.lastKey = this.time.time;
        }
        else if (this.cursors.right.isDown)
        {
            this.man.body.force.x = this.speed;
            this.lastKey = this.time.time;
        }

        if (this.cursors.up.isDown)
        {
            this.man.body.force.y = -this.speed;
            this.lastKey = this.time.time;
        }
        else if (this.cursors.down.isDown)
        {
            this.man.body.force.y = this.speed;
            this.lastKey = this.time.time;
        }

    },

    checkItem: function (item) {

        if (item === this.man || item === this.husky)
        {
            return;
        }

        if (item.x < -32)
        {
            if (item.key === 'crack')
            {
                item.x = this.rnd.between(700, 764);
            }
            else
            {
                item.kill();
            }
        }
        else
        {
            //   Check for collision
            if (this.ready && item.key !== 'crack' && this.huskyBounds.intersects(item.body))
            {
                this.loseLife();
            }
        }

    },

    loseLife: function () {

        if (this.lives === 0)
        {
            this.gameOver();
        }
        else
        {
            this.lives--;

            this.livesText.text = "LIVES: " + this.lives;

            this.ready = false;

            //  Kill the dog!
            this.husky.visible = false;

            //  Hide the rope
            this.rope.clear();

            //  Speed the man away
            this.man.body.setZeroVelocity();
            this.man.body.velocity.x = 600;

            this.itemInterval.min += 200;
            this.itemInterval.max += 200;
        }

    },

    gameOver: function () {

        this.state.start('Aquaplane.MainMenu');

    },

    preRender: function () {

        this.line.setTo(this.man.x - 48, this.man.y, this.husky.x + 46, this.husky.y - 1);

        if (this.husky.visible)
        {
            this.rope.clear();
        }

    },

    render: function () {

        if (this.showDebug)
        {
            this.game.debug.geom(this.manBounds);
            this.game.debug.geom(this.huskyBounds);
            this.layer.forEachAlive(this.renderBody, this);
            this.game.debug.geom(this.husky.position, 'rgba(255,255,0,1)');
        }

    },

    renderBody: function (sprite) {

        if (sprite === this.man || sprite === this.husky || sprite.key === 'crack')
        {
            return;
        }

        this.game.debug.body(sprite);

    }

};

var game = new Phaser.Game(700, 525, Phaser.AUTO, 'game');

game.state.add('Aquaplane.Preloader', Aquaplane.Preloader);
game.state.add('Aquaplane.MainMenu', Aquaplane.MainMenu);
game.state.add('Aquaplane.Game', Aquaplane.Game);

game.state.start('Aquaplane.Preloader');
<commit_msg>Create game.js<commit_after>//!REMEMBER! the husky took the name of man and the man took the name of husky REMEMBER!!!!
var Aquaplane = {};

Aquaplane.Preloader = function () {};

Aquaplane.Preloader.prototype = {

    init: function () {

        this.input.maxPointers = 1;

        this.scale.pageAlignHorizontally = true;

    },

    preload: function () {

        this.load.path = 'assets/';

        this.load.bitmapFont('fat-and-tiny');
        this.load.bitmapFont('interfont');

        this.load.images([ 'logo']);
        this.load.spritesheet('town', 'town1.png', 700, 700, 22);
        this.load.spritesheet('crack', 'crack.png', 16, 6);
        this.load.spritesheet('husky', 'man.png', 92, 92);
        this.load.spritesheet('man', 'husky.png', 96, 96);
        this.load.spritesheet('zombie', 'zombie.png', 96, 96);
         this.load.spritesheet('zomkabob', 'zomkabob.png', 96, 96);
          this.load.spritesheet('hand', 'hand.png', 32, 32);
    },

    create: function () {

        this.state.start('Aquaplane.MainMenu');

    }

};

Aquaplane.MainMenu = function () {};

Aquaplane.MainMenu.prototype = {

    create: function () {

        var town = this.add.sprite(0, -50, 'town');
        var scroll = town.animations.add('scroll');
        town.animations.play('scroll', 12, true);

        var logo = this.add.image( this.world.centerX, 20, 'logo');
        logo.anchor.x = 0.5;

        var start = this.add.bitmapText(this.world.centerX, 460, 'fat-and-tiny', 'CLICK TO PLAY', 64);
        start.anchor.x = 0.5;
        start.smoothed = false;
        start.tint = 0x990000;

        this.input.onDown.addOnce(this.start, this);

    },

    start: function () {

        this.state.start('Aquaplane.Game');

    }

};

Aquaplane.Game = function (game) {

    this.score = 0;
    this.scoreText = null;

    this.lives = 3;
    this.livesText = null;

    this.speed = 420;
    this.lastKey = 0;
    this.ready = false;

    this.layer = null;
    this.itemDist = ['zomkabob', 'zomkabob', 'zomkabob', 'hand', 'hand', 'hand', 'zombie'];

    this.man = null;
    this.husky = null;
    this.rope = null;

    this.timer = null;
    this.itemInterval = { count: 0, min: 500, max: 1500 };

    this.pauseKey = null;
    this.debugKey = null;
    this.showDebug = false;

};

Aquaplane.Game.prototype = {

    init: function () {

        this.score = 0;
        this.lives = 3;
        this.speed = 420;

        this.ready = false;
        this.lastKey = 0;

        this.timer = this.time.create(false);
        this.itemInterval = { count: 0, min: 500, max: 1500 };

        this.physics.startSystem(Phaser.Physics.P2JS);
        this.physics.p2.gravity.y = 0;

        this.showDebug = false;

    },

    create: function () {

        var town = this.add.sprite(0, -50, 'town');
        var scroll = town.animations.add('scroll');
        town.animations.play('scroll', 12, true);

        this.waterParticle = this.make.bitmapData(2, 2);
        this.waterParticle.rect(0, 0, 2, 2, '#ffffff');
        this.waterParticle.update();

        this.emitter = this.add.emitter(128, 128, 128);
        this.emitter.makeParticles(this.waterParticle);

        this.emitter.gravity = 0;
        this.emitter.setXSpeed(-100, -250);
        this.emitter.setYSpeed(-100, 100);

        this.emitter.setAlpha(1, 0.2, 500);

        this.emitter.flow(500, 20, 2, -1, true);

        this.layer = this.add.group();

        this.man = this.layer.create(0, 0, 'man');
        var man = this.add.sprite(0, 0, 'man');
        var walk = man.animations.add('walk');
            man.animations.play('walk', 12, true)

        this.physics.p2.enable(this.man, false);

        this.man.body.mass = 0.5;
        this.man.body.damping = 0.01;
        this.man.body.fixedRotation = true;
        this.man.body.collideWorldBounds = false;

        this.husky = this.layer.create(0, 0, 'husky');
        var husky = this.add.sprite(0, 0, 'husky');
        var run = husky.animations.add('run');
        husky.animations.play('run', 12, true);

        this.physics.p2.enable(this.husky, false);

        this.husky.body.mass = 0.05;
        this.husky.body.damping = 0.01;
        this.husky.body.fixedRotation = true;
        this.husky.body.collideWorldBounds = false;

        this.manBounds = new Phaser.Rectangle(0, 0, 23, 23);
        this.huskyBounds = new Phaser.Rectangle(0, 0, 24, 24);

        var rev = new p2.RevoluteConstraint(this.man.body.data, this.husky.body.data, {
                localPivotA: [9, 0],
                localPivotB: [2, 0],
                collideConnected: false
            });

        this.physics.p2.world.addConstraint(rev);

        rev.setLimits(this.math.degToRad(-40), this.math.degToRad(40));

        rev.setStiffness(2.0);

        //  Let's create some cracks (harmless eye candy)
        //
        //  Divide screen vertically into 520px / 8 layers = 65px per layer
        //  Place 8 cracks per layer (8*8 total)

        var area = new Phaser.Rectangle(0, 70, this.game.width, 45);

        for (var i = 1; i <= 7; i++)
        {
            for (var w = 0; w < 7; w++)
            {
                var crack = this.layer.create(area.randomX, area.randomY, 'crack', this.rnd.between(0, 2));
                'crack'.anchor.y = -1.5;
                this.physics.arcade.enable(crack);
                crack.body.velocity.x = -120 + (i * -30);
            }

            area.y += 45;
        }

        this.line = new Phaser.Line(this.man.x - 28, this.man.y, this.husky.x + 6, this.husky.y - 1);

        //  The rope that attaches the husky to the man
        this.rope = this.add.graphics(0, 0);

        this.scoreText = this.add.bitmapText(16, 0, 'fat-and-tiny', 'SCORE: 0', 32);
        this.scoreText.smoothed = false;

        this.livesText = this.add.bitmapText(580, 0, 'fat-and-tiny', 'LIVES: ' + this.lives, 32);
        this.livesText.smoothed = false;

        this.cursors = this.input.keyboard.createCursorKeys();

        //  Press P to pause and resume the game
        this.pauseKey = this.input.keyboard.addKey(Phaser.Keyboard.P);
        this.pauseKey.onDown.add(this.togglePause, this);

        //  Press D to toggle the debug display
        this.debugKey = this.input.keyboard.addKey(Phaser.Keyboard.D);
        this.debugKey.onDown.add(this.toggleDebug, this);

        this.bringManOn();

    },

    togglePause: function () {

        this.game.paused = (this.game.paused) ? false : true;

    },

    toggleDebug: function () {

        this.showDebug = (this.showDebug) ? false : true;

    },

    bringManOn: function () {

        this.ready = false;

        this.man.body.x = -64;
        this.man.body.y = 300;

        this.husky.visible = true;
        this.husky.body.x = -264;
        this.husky.body.y = 300;

        this.husky.body.velocity.x = 300;

    },

    manReady: function () {

        this.ready = true;

        this.man.body.setZeroVelocity();

        this.timer.add(this.itemInterval.max, this.releaseItem, this);
        this.timer.start();

    },

    releaseItem: function (x, y) {

        if (x === undefined) { x = 700; }
        if (y === undefined) { y = this.rnd.between(80, 487); }

        var frame = this.rnd.pick(this.itemDist);

        var item = this.layer.getFirstDead(true, x, y, frame);

        this.physics.arcade.enable(item);

        if (frame === 'zombie')
        {
            item.body.setSize(32, 14, 0, 16);
        }
        else
        {
            item.body.setSize(16, 8, 0, 24);
        }

        var i = this.math.snapToFloor(y, 65) / 65;

        item.body.velocity.x = -120 + (i * -30);

        this.itemInterval.count++;

        //  Every 10 new items we'll speed things up a bit
        if (this.itemInterval.min > 100 && this.itemInterval.count % 10 === 0)
        {
            this.itemInterval.min -= 10;
            this.itemInterval.max -= 10;
        }

        //  Is the player idle? Then release another item directly towards them
        if ((this.time.time - this.lastKey) > 200)
        {
            this.lastKey = this.time.time;
            this.releaseItem(700, this.husky.y - 16);
        }
        else
        {
            this.timer.add(this.rnd.between(this.itemInterval.min, this.itemInterval.max), this.releaseItem, this);
        }

    },

    update: function () {

        this.layer.sort('y', Phaser.Group.SORT_ASCENDING);

        if (this.ready)
        {
            this.updateMan();

            //  Score based on their position on the screen
            this.score += (this.math.snapToFloor(this.husky.y, 65) / 65);
            this.scoreText.text = "SCORE: " + this.score;
        }
        else
        {
            if (this.husky.visible)
            {
                if (this.man.x >= 250)
                {
                    this.manReady();
                }
            }
            else
            {
                if (this.man.x >= 832)
                {
                    this.bringManOn();
                }
            }
        }

        this.manBounds.centerOn(this.man.x + 4, this.man.y + 8);
        this.huskyBounds.centerOn(this.husky.x + 2, this.husky.y + 10);

        this.emitter.emitX = this.man.x - 16;
        this.emitter.emitY = this.man.y + 10;

        //  Let's sort and collide
        this.layer.forEachAlive(this.checkItem, this);

    },

    updateMan: function () {

        if (this.man.x < 200)
        {
            this.man.body.setZeroForce();
            this.man.body.x = 200;
        }
        else if (this.man.x > 650)
        {
            this.man.body.setZeroForce();
            this.man.body.x = 650;
        }

        if (this.man.y < 100)
        {
            this.man.body.setZeroForce();
            this.man.body.y = 100;
        }
        else if (this.man.y > 520)
        {
            this.man.body.setZeroForce();
            this.man.body.y = 520;
        }

        if (this.cursors.left.isDown)
        {
            this.man.body.force.x = -this.speed;
            this.lastKey = this.time.time;
        }
        else if (this.cursors.right.isDown)
        {
            this.man.body.force.x = this.speed;
            this.lastKey = this.time.time;
        }

        if (this.cursors.up.isDown)
        {
            this.man.body.force.y = -this.speed;
            this.lastKey = this.time.time;
        }
        else if (this.cursors.down.isDown)
        {
            this.man.body.force.y = this.speed;
            this.lastKey = this.time.time;
        }

    },

    checkItem: function (item) {

        if (item === this.man || item === this.husky)
        {
            return;
        }

        if (item.x < -32)
        {
            if (item.key === 'crack')
            {
                item.x = this.rnd.between(700, 764);
            }
            else
            {
                item.kill();
            }
        }
        else
        {
            //   Check for collision
            if (this.ready && item.key !== 'crack' && this.huskyBounds.intersects(item.body))
            {
                this.loseLife();
            }
        }

    },

    loseLife: function () {

        if (this.lives === 0)
        {
            this.gameOver();
        }
        else
        {
            this.lives--;

            this.livesText.text = "LIVES: " + this.lives;

            this.ready = false;

            //  Kill the dog!
            this.husky.visible = false;

            //  Hide the rope
            this.rope.clear();

            //  Speed the man away
            this.man.body.setZeroVelocity();
            this.man.body.velocity.x = 600;

            this.itemInterval.min += 200;
            this.itemInterval.max += 200;
        }

    },

    gameOver: function () {

        this.state.start('Aquaplane.MainMenu');

    },

    preRender: function () {

        this.line.setTo(this.man.x - 48, this.man.y, this.husky.x + 46, this.husky.y - 1);

        if (this.husky.visible)
        {
            this.rope.clear();
        }

    },

    render: function () {

        if (this.showDebug)
        {
            this.game.debug.geom(this.manBounds);
            this.game.debug.geom(this.huskyBounds);
            this.layer.forEachAlive(this.renderBody, this);
            this.game.debug.geom(this.husky.position, 'rgba(255,255,0,1)');
        }

    },

    renderBody: function (sprite) {

        if (sprite === this.man || sprite === this.husky || sprite.key === 'crack')
        {
            return;
        }

        this.game.debug.body(sprite);

    }

};

var game = new Phaser.Game(700, 525, Phaser.AUTO, 'game');

game.state.add('Aquaplane.Preloader', Aquaplane.Preloader);
game.state.add('Aquaplane.MainMenu', Aquaplane.MainMenu);
game.state.add('Aquaplane.Game', Aquaplane.Game);

game.state.start('Aquaplane.Preloader');
<|endoftext|>


<commit_before>//conditions for winning
// 1-2-3, 4-5-6, 7-8-9
// 1-4-7, 2-5-8, 3-6-9
// 1-5-9, 3-5-7

var blues = [];
var reds = [];

var blueMove = function(){

  //ALERT Blue player to move!
  $('#p1').show();
  $('#p2').hide();

  // register blue players input
  $('.square').click(function(){
    var $result = $(this).attr('class');
    //alert($result);
    blues.push($(this).attr('id'));
    $(this).click(false);
    $(this).toggleClass('filledBlue');

    console.log(blues);

    blueCounter();

  });

  // check if blue wins:
  //    yes --> reset
  //    no --> prompt red player to move
};

var redMove = function(){

  //ALERT red player to move!
  $('#p2').show();
  $('#p1').hide();

  // register blue players input
  $('.square').click(function(){
    var $result = $(this).attr('class');
    //alert($result);
    reds.push($(this).attr('id'));
    $(this).click(false);
    $(this).toggleClass('filledRed');

    console.log(reds);

    redCounter();

  });

  // check if red wins:
  //    yes --> reset
  //    no --> prompt blue player to move

};

var blueCounter = function(){
  if(
    ($('.one').hasClass('filledBlue') && $('.two').hasClass('filledBlue') && $('.three').hasClass('filledBlue'))
    ||
    ($('.four').hasClass('filledBlue') && $('.five').hasClass('filledBlue') && $('.six').hasClass('filledBlue'))
    ||
    ($('.seven').hasClass('filledBlue') && $('.eight').hasClass('filledBlue') && $('.nine').hasClass('filledBlue'))

    ||

    ($('.one').hasClass('filledBlue') && $('.four').hasClass('filledBlue') && $('.seven').hasClass('filledBlue'))
    ||
    ($('.two').hasClass('filledBlue') && $('.five').hasClass('filledBlue') && $('.eight').hasClass('filledBlue'))
    ||
    ($('.three').hasClass('filledBlue') && $('.six').hasClass('filledBlue') && $('.nine').hasClass('filledBlue'))

    ||

    ($('.one').hasClass('filledBlue') && $('.five').hasClass('filledBlue') && $('.nine').hasClass('filledBlue'))
    ||
    ($('.three').hasClass('filledBlue') && $('.five').hasClass('filledBlue') && $('.three').hasClass('filledBlue'))

  ){
    alert('A WINNER IS YOU!');
    reset();
  }
};

var redCounter = function(){
  if(
    ($('.one').hasClass('filledRed') && $('.two').hasClass('filledRed') && $('.three').hasClass('filledRed'))
    ||
    ($('.four').hasClass('filledRed') && $('.five').hasClass('filledRed') && $('.six').hasClass('filledRed'))
    ||
    ($('.seven').hasClass('filledRed') && $('.eight').hasClass('filledRed') && $('.nine').hasClass('filledRed'))

    ||

    ($('.one').hasClass('filledRed') && $('.four').hasClass('filledRed') && $('.seven').hasClass('filledRed'))
    ||
    ($('.two').hasClass('filledRed') && $('.five').hasClass('filledRed') && $('.eight').hasClass('filledRed'))
    ||
    ($('.three').hasClass('filledRed') && $('.six').hasClass('filledRed') && $('.nine').hasClass('filledRed'))

    ||

    ($('.one').hasClass('filledRed') && $('.five').hasClass('filledRed') && $('.nine').hasClass('filledRed'))
    ||
    ($('.three').hasClass('filledRed') && $('.five').hasClass('filledRed') && $('.three').hasClass('filledRed'))

  ){
    alert('A WINNER IS YOU!');
    reset();
  }

};

var reset = function(){
  $('.square').removeClass('filledBlue');
  $('.square').removeClass('filledRed');
  blues = [];
  reds=[];
};
<commit_msg>realized checking conditions of player wins is built into the counter function, moved comments accordingly. All that's left now is how to switch between blue and red<commit_after>//conditions for winning
// 1-2-3, 4-5-6, 7-8-9
// 1-4-7, 2-5-8, 3-6-9
// 1-5-9, 3-5-7

var blues = []; //stores blue players moves
var reds = []; //stores red players moves

var blueMove = function(){

  //ALERT Blue player to move!
  $('#p1').show();
  $('#p2').hide();

  // register blue players input
  $('.square').click(function(){
    var $result = $(this).attr('class');
    //alert($result);
    blues.push($(this).attr('id'));
    $(this).click(false);
    $(this).toggleClass('filledBlue');

    console.log(blues);

    // check if blue wins:
    //    yes --> reset (built into counter function)
    blueCounter();

  });

    //    no --> prompt red player to move

};

var redMove = function(){

  //ALERT red player to move!
  $('#p2').show();
  $('#p1').hide();

  // register blue players input
  $('.square').click(function(){
    var $result = $(this).attr('class');
    //alert($result);
    reds.push($(this).attr('id'));
    $(this).click(false);
    $(this).toggleClass('filledRed');

    console.log(reds);
    // check if red wins:
    //    yes --> reset (built into counter function)
    redCounter();

  });

  //    no --> prompt blue player to move

};

var blueCounter = function(){
  if(
    ($('.one').hasClass('filledBlue') && $('.two').hasClass('filledBlue') && $('.three').hasClass('filledBlue'))
    ||
    ($('.four').hasClass('filledBlue') && $('.five').hasClass('filledBlue') && $('.six').hasClass('filledBlue'))
    ||
    ($('.seven').hasClass('filledBlue') && $('.eight').hasClass('filledBlue') && $('.nine').hasClass('filledBlue'))

    ||

    ($('.one').hasClass('filledBlue') && $('.four').hasClass('filledBlue') && $('.seven').hasClass('filledBlue'))
    ||
    ($('.two').hasClass('filledBlue') && $('.five').hasClass('filledBlue') && $('.eight').hasClass('filledBlue'))
    ||
    ($('.three').hasClass('filledBlue') && $('.six').hasClass('filledBlue') && $('.nine').hasClass('filledBlue'))

    ||

    ($('.one').hasClass('filledBlue') && $('.five').hasClass('filledBlue') && $('.nine').hasClass('filledBlue'))
    ||
    ($('.three').hasClass('filledBlue') && $('.five').hasClass('filledBlue') && $('.three').hasClass('filledBlue'))

  ){
    alert('A WINNER IS YOU!');
    reset();
  }
};

var redCounter = function(){
  if(
    ($('.one').hasClass('filledRed') && $('.two').hasClass('filledRed') && $('.three').hasClass('filledRed'))
    ||
    ($('.four').hasClass('filledRed') && $('.five').hasClass('filledRed') && $('.six').hasClass('filledRed'))
    ||
    ($('.seven').hasClass('filledRed') && $('.eight').hasClass('filledRed') && $('.nine').hasClass('filledRed'))

    ||

    ($('.one').hasClass('filledRed') && $('.four').hasClass('filledRed') && $('.seven').hasClass('filledRed'))
    ||
    ($('.two').hasClass('filledRed') && $('.five').hasClass('filledRed') && $('.eight').hasClass('filledRed'))
    ||
    ($('.three').hasClass('filledRed') && $('.six').hasClass('filledRed') && $('.nine').hasClass('filledRed'))

    ||

    ($('.one').hasClass('filledRed') && $('.five').hasClass('filledRed') && $('.nine').hasClass('filledRed'))
    ||
    ($('.three').hasClass('filledRed') && $('.five').hasClass('filledRed') && $('.three').hasClass('filledRed'))

  ){
    alert('A WINNER IS YOU!');
    reset();
  }

};

var reset = function(){
  $('.square').removeClass('filledBlue');
  $('.square').removeClass('filledRed');
  blues = [];
  reds=[];
};
<|endoftext|>


<commit_before>function sub(a, b) {
	return {
		x: a.x - b.x,
		y: a.y - b.y
	};
}
function add(a, b) {
	return {
		x: a.x + b.x,
		y: a.y + b.y
	};
}

function mul(a, b) {
	return {
		x: a.x * b,
		y: a.y * b
	};
}

function clamp(a, b) {
	return {
		x: a.x > b.x ? b.x : (a.x < 0 ? 0 : a.x ),
		y: a.y > b.y ? b.y : (a.y < 0 ? 0 : a.y )
	}
}

function rotate(a, b) {
	var s = Math.sin(b), c = Math.cos(b);
	return {
		x: c * a.x - s * a.y,
		y: s * a.x + c * a.y
	};
}

var ply = {
	pos: {
		x: 50,
		y: 50
	},
	dirn: 0,
	dir: { x: 1, y: 0 },
	draw: function(ctx, isOffset) {
		var x, y, dir;
		if (isOffset) {
			x = 0, y = 0, dir = {x: 0, y: 1};
		} else {
			x = this.pos.x, y = this.pos.y, dir = this.dir;
		}
		// Direction line
		dir = mul(dir, 10);
		ctx.strokeStyle = 'rgba(0, 0, 0, 0.2)';
		ctx.lineWidth = 1;
		ctx.beginPath();
		ctx.moveTo(x, y);
		ctx.lineTo(x + dir.x, y + dir.y);
		ctx.stroke();
		// Lil guy
		ctx.fillStyle = 'blue';
		ctx.fillRect(x-1, y - 1, 2, 2);
	}
};

var wall = {
	a: {
		x: 70,
		y: 70
	},
	b: {
		x: 70,
		y: 20
	},
	draw: function(ctx, offset, offsetAng) {
		var a = this.a, b = this.b;

		if (offset) {
			a = sub(a, offset);
			b = sub(b, offset);
			a = rotate(a, offsetAng);
			b = rotate(b, offsetAng);
		}

		ctx.beginPath();
		ctx.strokeStyle = 'yellow';
		ctx.lineWidth = 2;
		ctx.moveTo(a.x, a.y);
		ctx.lineTo(b.x, b.y);
		ctx.stroke();
	},
	// I have no clue what this is doing!
	drawBork: function(ctx, offset, offsetAng) {
		var a = sub(this.a, offset), b = sub(this.b, offset);
		var s = Math.sin(offsetAng), c = Math.cos(offsetAng);

		var ax, ay, az, bx, by, bz;

		ax = a.x, ay = a.y, bx = b.x, by = b.y;

		// "Rotation"
		az = ax * c + ay * s,
		bz = bx * c + by * s,
		ax = ax * s - ay * c,
		bx = bx * s - by * c;

		// "Perspective transform"
		var axp, bxp, ayp1, byp1, ayp2, byp2;

		axp = -ax * 16 / az,
		ayp1 = -50 / az,
		ayp2 = 50 / az,
		bxp = -bx * 16 / bz,
		byp1 = -50 / bz,
		byp2 = 50 / bz;

		ctx.beginPath();
		ctx.strokeStyle = 'yellow';
		ctx.lineWidth = 2;

		// Top
		ctx.moveTo(50 + axp, 50 + ayp1);
		ctx.lineTo(50 + bxp, 50 + byp1);
		// Bottom
		ctx.moveTo(50 + axp, 50 + ayp2);
		ctx.lineTo(50 + bxp, 50 + byp2);
		// Left
		ctx.moveTo(50 + axp, 50 + ayp1);
		ctx.lineTo(50 + axp, 50 + ayp2);
		// Right
		ctx.moveTo(50 + bxp, 50 + byp1);
		ctx.lineTo(50 + bxp, 50 + byp2);

		ctx.stroke();
	}
};

var ctx;

function setup() {
	var canvas = document.getElementById('canvas');
	ctx = canvas.getContext('2d');
	ctx.scale(2, 2);
}

function viewport(x, y, width, height) {
	ctx.translate(x, y);
	ctx.strokeStyle = 'red';
	ctx.fillStyle = '#eee';
	ctx.lineWidth = 1;
	ctx.fillRect(0, 0, width, height);
	ctx.strokeRect(0, 0, width, height);
}

function plyInput(dtime) {
	// Naive implemetnation
	if (keys.up) {
		ply.pos = add(ply.pos, ply.dir);
	} else if (keys.down) {
		ply.pos = sub(ply.pos, ply.dir);
	}

	var val = dtime / 200;
	if (keys.left) {
		ply.dirn -= val;
	} else if (keys.right) {
		ply.dirn += val;
	}
	ply.dir = {
		x: Math.sin(ply.dirn),
		y: Math.cos(ply.dirn)
	};

	ply.pos = clamp(ply.pos, { x: 100, y: 100 });
}

function drawRaw(ctx) {
	ctx.save()
	viewport(5, 5, 100, 100);
	// Draw Wall
	wall.draw(ctx, null);
	// Draw ply
	ply.draw(ctx);
	// End viewport #1
	ctx.restore();
}

function drawOffset(ctx) {
	ctx.save()
	viewport(110, 5, 100, 100);
	ctx.translate(50, 50);
	ctx.rotate(Math.PI);
	// Draw Wall
	wall.draw(ctx, ply.pos, ply.dirn);
	// Draw ply
	ply.draw(ctx, true);
	// End viewport #2
	ctx.restore();
}

function drawBork(ctx) {
	ctx.save()
	viewport(220, 5, 100, 100);
	ctx.translate(50, 50);
	ctx.rotate(Math.PI);
	// Draw Wall
	wall.drawBork(ctx, ply.pos, ply.dirn);
	// End viewport #2
	ctx.restore();
}

function loop(dtime) {
	plyInput(dtime);

	drawRaw(ctx);
	drawOffset(ctx);
	drawBork(ctx);
}

var last = 0;
window.requestAnimationFrame(function rawLoop(now) {
	window.requestAnimationFrame(rawLoop);
	// Skip the first frame
	if ( ! last ) {
		last = now;
		return;
	}
	var dtime = last - now;
	last = now;
	loop(dtime);
});

setup();
<commit_msg>Attempt to de-bork a bit<commit_after>function sub(a, b) {
	return {
		x: a.x - b.x,
		y: a.y - b.y
	};
}
function add(a, b) {
	return {
		x: a.x + b.x,
		y: a.y + b.y
	};
}

function mul(a, b) {
	return {
		x: a.x * b,
		y: a.y * b
	};
}

function clamp(a, b) {
	return {
		x: a.x > b.x ? b.x : (a.x < 0 ? 0 : a.x ),
		y: a.y > b.y ? b.y : (a.y < 0 ? 0 : a.y )
	}
}

function rotate(a, b) {
	var s = Math.sin(b), c = Math.cos(b);
	return {
		x: c * a.x - s * a.y,
		y: s * a.x + c * a.y
	};
}

var ply = {
	pos: {
		x: 50,
		y: 50
	},
	dirn: 0,
	dir: { x: 1, y: 0 },
	draw: function(ctx, isOffset) {
		var x, y, dir;
		if (isOffset) {
			x = 0, y = 0, dir = {x: 0, y: 1};
		} else {
			x = this.pos.x, y = this.pos.y, dir = this.dir;
		}
		// Direction line
		dir = mul(dir, 10);
		ctx.strokeStyle = 'rgba(0, 0, 0, 0.2)';
		ctx.lineWidth = 1;
		ctx.beginPath();
		ctx.moveTo(x, y);
		ctx.lineTo(x + dir.x, y + dir.y);
		ctx.stroke();
		// Lil guy
		ctx.fillStyle = 'blue';
		ctx.fillRect(x-1, y - 1, 2, 2);
	}
};

var wall = {
	a: {
		x: 70,
		y: 70
	},
	b: {
		x: 70,
		y: 20
	},
	draw: function(ctx, offset, offsetAng) {
		var a = this.a, b = this.b;

		if (offset) {
			a = sub(a, offset);
			b = sub(b, offset);
			a = rotate(a, offsetAng);
			b = rotate(b, offsetAng);
		}

		ctx.beginPath();
		ctx.strokeStyle = 'yellow';
		ctx.lineWidth = 2;
		ctx.moveTo(a.x, a.y);
		ctx.lineTo(b.x, b.y);
		ctx.stroke();
	},
	// I have no clue what this is doing!
	drawBork: function(ctx, offset, offsetAng) {
		var a = sub(this.a, offset), b = sub(this.b, offset);
		var s = Math.sin(offsetAng), c = Math.cos(offsetAng);

		var ax, ay, az, bx, by, bz;

		ax = a.x, ay = a.y, bx = b.x, by = b.y;

		// "Rotation"
// 		az = ax * c + ay * s,
// 		bz = bx * c + by * s,
// 		ax = ax * s - ay * c,
// 		bx = bx * s - by * c;
		ar = rotate(a, -offsetAng)
		br = rotate(b, -offsetAng)
		az = ar.y,
		bz = br.y,
		ax = ar.x,
		bx = br.x;

		// "Perspective transform"
		var axp, bxp, ayp1, byp1, ayp2, byp2;

		var height = 50;

		axp = -ax * 16 / az,
		ayp1 = -height / az,
		ayp2 = height / az,
		bxp = -bx * 16 / bz,
		byp1 = -height / bz,
		byp2 = height / bz;

		ctx.beginPath();
		ctx.strokeStyle = 'yellow';
		ctx.lineWidth = 2;

		// Top
		ctx.moveTo(axp,  ayp1);
		ctx.lineTo(bxp,  byp1);
		// Bottom
		ctx.moveTo( axp,  ayp2);
		ctx.lineTo( bxp,  byp2);
		// Left
		ctx.moveTo( axp,  ayp1);
		ctx.lineTo( axp,  ayp2);
		// Right
		ctx.moveTo( bxp,  byp1);
		ctx.lineTo( bxp,  byp2);

		ctx.stroke();
	}
};

var ctx;

function setup() {
	var canvas = document.getElementById('canvas');
	ctx = canvas.getContext('2d');
	ctx.scale(2, 2);
}

function viewport(x, y, width, height) {
	ctx.translate(x, y);
	ctx.strokeStyle = 'red';
	ctx.fillStyle = '#eee';
	ctx.lineWidth = 1;
	ctx.fillRect(0, 0, width, height);
	ctx.strokeRect(0, 0, width, height);
}

function plyInput(dtime) {
	// Naive implemetnation
	if (keys.up) {
		ply.pos = add(ply.pos, ply.dir);
	} else if (keys.down) {
		ply.pos = sub(ply.pos, ply.dir);
	}

	var val = dtime / 200;
	if (keys.left) {
		ply.dirn -= val;
	} else if (keys.right) {
		ply.dirn += val;
	}
	ply.dir = {
		x: Math.sin(ply.dirn),
		y: Math.cos(ply.dirn)
	};

	ply.pos = clamp(ply.pos, { x: 100, y: 100 });
}

function drawRaw(ctx) {
	ctx.save()
	viewport(5, 5, 100, 100);
	// Draw Wall
	wall.draw(ctx, null);
	// Draw ply
	ply.draw(ctx);
	// End viewport #1
	ctx.restore();
}

function drawOffset(ctx) {
	ctx.save()
	viewport(110, 5, 100, 100);
	ctx.translate(50, 50);
	ctx.rotate(Math.PI);
	// Draw Wall
	wall.draw(ctx, ply.pos, ply.dirn);
	// Draw ply
	ply.draw(ctx, true);
	// End viewport #2
	ctx.restore();
}

function drawBork(ctx) {
	ctx.save()
	viewport(220, 5, 100, 100);
	ctx.translate(50, 50);
	ctx.rotate(Math.PI);
	// Draw Wall
	wall.drawBork(ctx, ply.pos, ply.dirn);
	// End viewport #2
	ctx.restore();
}

function loop(dtime) {
	plyInput(dtime);

	drawBork(ctx);
	drawRaw(ctx);
	drawOffset(ctx);
}

var last = 0;
window.requestAnimationFrame(function rawLoop(now) {
	window.requestAnimationFrame(rawLoop);
	// Skip the first frame
	if ( ! last ) {
		last = now;
		return;
	}
	var dtime = last - now;
	last = now;
	loop(dtime);
});

setup();
<|endoftext|>