<commit_before>/**
 * ngAuth 0.0.1
 * (c) 2014 Sahat Yalkabov <sahat@me.com>
 * License: MIT
 */

(function(window, angular, undefined) {
  'use strict';

  angular.module('ngAuth', [])
    .provider('Auth', function() {

      var config = this.config = {
        logoutRedirect: '/',
        loginRedirect: '/',
        loginUrl: '/auth/login',
        signupUrl: '/auth/signup',
        signupRedirect: '/login',
        userGlobal: 'currentUser',
        providers: {
          facebook: {
            authorizationUrl: 'https://www.facebook.com/dialog/oauth',
            scope: 'scope, email',
            requiredUrlParams: ['display'],
            display: 'popup'
          },
          google: {
            authorizationUrl: 'https://accounts.google.com/o/oauth2/auth',
            scope: ''
          },
          linkedin: {
            authorizationUrl: 'https://www.linkedin.com/uas/oauth2/authorization',
            state: 'STATE'
          }
        }
      };

      // TODO: Use requiredUrlParams instead of passing all properties
      // TODO: pass scope delimiter
      // TODO: default responseType to code if token is obtained on server

      return {
        setProvider: function(params) {
          config.providers[params.name] = config.providers[params.name] || {};
          angular.extend(config.providers[params.name], params);
        },

        $get: function($interval, $timeout, $http, $location, $rootScope, $alert, $q, $injector, $window) {

          // BEGIN OAUTH

          // Popup window.
          var Popup = function() {
            this.popup = null;
          };

          Popup.prototype.open = function(url, keys, options) {
            var deferred = $q.defer();
            // TODO: refactor
            var optionsString = stringifyOptions(prepareOptions(options || {}));
            this.popup = $window.open(url, '*', optionsString);
            this.popup.focus();

            this.createPostMessageHandler(deferred);
            this.pollPopup(deferred);

            return deferred.promise;
          };

          Popup.prototype.pollPopup = function(deferred) {
            var intervalHandler = function() {
              if (this.popup.closed) {
                $interval.cancel(this.polling);
                deferred.reject('Popup was closed by the user.');
              }
              this.requestAuthorizationCode();
            }.bind(this);
            this.polling = $interval(intervalHandler, 35);
          };

          Popup.prototype.requestAuthorizationCode = function() {
            var query = this.popup.location.search.substring(1);
            if (query.indexOf('code') > -1) {
              var code = this.parseQueryString(query).code;
              $window.postMessage(code, $window.location.origin);
              $interval.cancel(this.polling);
              this.popup.close();
            }
          };

          Popup.prototype.createPostMessageHandler = function(deferred) {
            $window.addEventListener('message', function(event) {
              deferred.resolve(event.data);
            }, false);
          };

          Popup.prototype.parseQueryString = function(keyValue) {
            var obj = {}, key, value;
            angular.forEach((keyValue || '').split('&'), function(keyValue) {
              if (keyValue) {
                value = keyValue.split('=');
                key = decodeURIComponent(value[0]);
                obj[key] = angular.isDefined(value[1]) ? decodeURIComponent(value[1]) : true;
              }
            });
            return obj;
          };

          Popup.prototype.close = function() {
            if (this.popup) {
              this.popup.close();
              this.popup = null;
            }
          };

          function prepareOptions(options) {
            var width = options.width || 500;
            var height = options.height || 500;
            return angular.extend({
              left: ((screen.width / 2) - (width / 2)),
              top: ((screen.height / 2) - (height / 2)),
              width: width,
              height: height
            }, options);
          }

          function stringifyOptions(options) {
            var optionsStrings = [];
            for (var key in options) {
              if (options.hasOwnProperty(key)) {
                var value;
                switch (options[key]) {
                  case true:
                    value = '1';
                    break;
                  case false:
                    value = '0';
                    break;
                  default:
                    value = options[key];
                }
                optionsStrings.push(
                  key + '=' + value
                );
              }
            }
            return optionsStrings.join(',');
          }

          var oauthKeys = ['code', 'access_token', 'expires_in'];
          var defaultUrlParams = ['response_type', 'client_id', 'redirect_uri'];

          var Oauth2 = function(config) {
            this.name = config.name;
            this.clientId = config.clientId;
            this.scope = config.scope;
            this.authorizationUrl = config.authorizationUrl;
            this.redirectUri = config.redirectUri;
            this.responseType = 'code';
            this.requiredUrlParams = defaultUrlParams.concat(config.requiredUrlParams);
            this.optionalUrlParams = ['scope'];
          };

          Oauth2.prototype.camelCase = function(name) {
            return name.replace(/([\:\-\_]+(.))/g, function(_, separator, letter, offset) {
              return offset ? letter.toUpperCase() : letter;
            });
          };

          Oauth2.prototype.open = function() {
            var deferred = $q.defer();
            var url = this.buildUrl();
            var popup = new Popup();

            popup.open(url, oauthKeys).then(function(code) {
              this.exchangeForToken(code).then(function(token) {
                deferred.resolve(token);
              });
            }.bind(this));

            return deferred.promise;
          };

          Oauth2.prototype.exchangeForToken = function(code) {
            var params = {
              clientId: config.providers[this.name].clientId,
              redirectUri: $window.location.origin + '/',
              code: code
            };

            return $http.post('/auth/facebook', params);
          };

          Oauth2.prototype.buildUrl = function() {
            var baseUrl = this.authorizationUrl;
            var qs = this.buildQueryString();
            return [baseUrl, qs].join('?');
          };

          Oauth2.prototype.buildQueryString = function() {
            var obj = this;
            var keyValuePairs = [];

            angular.forEach(this.requiredUrlParams, function(paramName) {
              var camelizedName = obj.camelCase(paramName);
              var paramValue = obj[camelizedName];
              keyValuePairs.push([paramName, paramValue]);
            });

            angular.forEach(this.optionalUrlParams, function(paramName) {
              var camelizedName = obj.camelCase(paramName);
              var paramValue = obj[camelizedName];
              keyValuePairs.push([paramName, paramValue]);
            });

            return keyValuePairs.map(function(pair) {
              return pair.join('=');
            }).join('&');
          };

          Oauth2.createProvider = function(providerName) {
            var providerOptions = config.providers[providerName];
            var provider = new Oauth2(providerOptions);
            console.log('MyProv', provider);
            return provider;
          };

          // END OAUTH

          var token = $window.localStorage.token;
          if (token) {
            var payload = JSON.parse($window.atob(token.split('.')[1]));
            $rootScope[config.userGlobal] = payload.user;
          }

          return {
            authenticate: function(providerName, options) {
              var deferred = $q.defer();
              if (!providerName) {
                deferred.reject('Expected a provider named \'' + providerName + '\', did you forget to add it?');
              }
              var provider = Oauth2.createProvider(providerName);

              provider.open(options).then(function() {
                console.log('OPENED')
                deferred.resolve('done');
              });

              return deferred.promise;
            },

            loginOauth: function(provider) {
              provider = provider.trim().toLowerCase();

              switch (provider) {
                case 'facebook':
                  var scope = config.providers.facebook.scope.join(',');
                  FB.login(function(response) {
                    FB.api('/me', function(profile) {
                      // TODO normalize return properties like passport
                      var data = {
                        accessToken: response.authResponse.accessToken,
                        signedRequest: response.authResponse.signedRequest,
                        profile: profile
                      };
                      $http.post(config.providers.facebook.url, data).success(function(token) {
                        var payload = JSON.parse($window.atob(token.split('.')[1]));
                        $window.localStorage.token = token;
                        $rootScope[config.userGlobal] = payload.user;
                        $location.path(config.loginRedirect);
                      });
                    });
                  }, {scope: scope});
                  break;
                case 'google':

                  break;
                case 'linkedin':
                  break;
                default:
                  break;
              }
            },
            login: function(user) {
              return $http.post(config.loginUrl, user).success(function(data) {
                $window.localStorage.token = data.token;
                var payload = JSON.parse($window.atob(data.token.split('.')[1]));
                $rootScope[config.userGlobal] = payload.user;
                $location.path(config.loginRedirect);
              });
            },
            signup: function(user) {
              return $http.post(config.signupUrl, user).success(function() {
                $location.path(config.signupRedirect);
              });
            },
            logout: function() {
              delete $window.localStorage.token;
              $rootScope[config.userGlobal] = null;
              $location.path(config.logoutRedirect);
            },
            isAuthenticated: function() {
              return $rootScope[config.userGlobal];
            }
          };
        }
      };
    })
    .factory('authInterceptor', function($q, $window, $location) {
      return {
        request: function(config) {
          if ($window.localStorage.token) {
            config.headers.Authorization = 'Bearer ' + $window.localStorage.token;
          }
          return config;
        },
        responseError: function(response) {
          if (response.status === 401 || response.status === 403) {
            $location.path('/login');
          }
          return $q.reject(response);
        }
      }
    })
    .config(function($httpProvider) {
      $httpProvider.interceptors.push('authInterceptor');
    })
    .run(function($rootScope, $location) {
      $rootScope.$on('$routeChangeStart', function(event, current, previous) {
        if ($rootScope.currentUser &&
          (current.originalPath === '/login' || current.originalPath === '/signup')) {
          $location.path('/');
        }
        if (current.authenticated && !$rootScope.currentUser) {
          $location.path('/login');
        }
      });
    });
})(window, window.angular);

<commit_msg>set redirectUri on facebook provider as part of default config<commit_after>/**
 * ngAuth 0.0.1
 * (c) 2014 Sahat Yalkabov <sahat@me.com>
 * License: MIT
 */

(function(window, angular, undefined) {
  'use strict';

  angular.module('ngAuth', [])
    .provider('Auth', function() {

      var config = this.config = {
        logoutRedirect: '/',
        loginRedirect: '/',
        loginUrl: '/auth/login',
        signupUrl: '/auth/signup',
        signupRedirect: '/login',
        userGlobal: 'currentUser',
        providers: {
          facebook: {
            authorizationUrl: 'https://www.facebook.com/dialog/oauth',
            scope: 'email',
            requiredUrlParams: ['display'],
            display: 'popup',
            redirectUri: 'http://localhost:3000'
          },
          google: {
            authorizationUrl: 'https://accounts.google.com/o/oauth2/auth',
            scope: ''
          },
          linkedin: {
            authorizationUrl: 'https://www.linkedin.com/uas/oauth2/authorization',
            state: 'STATE'
          }
        }
      };

      // TODO: Use requiredUrlParams instead of passing all properties
      // TODO: pass scope delimiter
      // TODO: default responseType to code if token is obtained on server

      return {
        setProvider: function(params) {
          config.providers[params.name] = config.providers[params.name] || {};
          angular.extend(config.providers[params.name], params);
        },

        $get: function($interval, $timeout, $http, $location, $rootScope, $alert, $q, $injector, $window) {

          // BEGIN OAUTH

          // Popup window.
          var Popup = function() {
            this.popup = null;
          };

          Popup.prototype.open = function(url, keys, options) {
            var deferred = $q.defer();
            // TODO: refactor
            var optionsString = stringifyOptions(prepareOptions(options || {}));
            this.popup = $window.open(url, '*', optionsString);
            this.popup.focus();

            this.createPostMessageHandler(deferred);
            this.pollPopup(deferred);

            return deferred.promise;
          };

          Popup.prototype.pollPopup = function(deferred) {
            var intervalHandler = function() {
              if (this.popup.closed) {
                $interval.cancel(this.polling);
                deferred.reject('Popup was closed by the user.');
              }
              this.requestAuthorizationCode();
            }.bind(this);
            this.polling = $interval(intervalHandler, 35);
          };

          Popup.prototype.requestAuthorizationCode = function() {
            var query = this.popup.location.search.substring(1);
            if (query.indexOf('code') > -1) {
              var code = this.parseQueryString(query).code;
              $window.postMessage(code, $window.location.origin);
              $interval.cancel(this.polling);
              this.popup.close();
            }
          };

          Popup.prototype.createPostMessageHandler = function(deferred) {
            $window.addEventListener('message', function(event) {
              deferred.resolve(event.data);
            }, false);
          };

          Popup.prototype.parseQueryString = function(keyValue) {
            var obj = {}, key, value;
            angular.forEach((keyValue || '').split('&'), function(keyValue) {
              if (keyValue) {
                value = keyValue.split('=');
                key = decodeURIComponent(value[0]);
                obj[key] = angular.isDefined(value[1]) ? decodeURIComponent(value[1]) : true;
              }
            });
            return obj;
          };

          Popup.prototype.close = function() {
            if (this.popup) {
              this.popup.close();
              this.popup = null;
            }
          };

          function prepareOptions(options) {
            var width = options.width || 500;
            var height = options.height || 500;
            return angular.extend({
              left: ((screen.width / 2) - (width / 2)),
              top: ((screen.height / 2) - (height / 2)),
              width: width,
              height: height
            }, options);
          }

          function stringifyOptions(options) {
            var optionsStrings = [];
            for (var key in options) {
              if (options.hasOwnProperty(key)) {
                var value;
                switch (options[key]) {
                  case true:
                    value = '1';
                    break;
                  case false:
                    value = '0';
                    break;
                  default:
                    value = options[key];
                }
                optionsStrings.push(
                  key + '=' + value
                );
              }
            }
            return optionsStrings.join(',');
          }

          var oauthKeys = ['code', 'access_token', 'expires_in'];
          var defaultUrlParams = ['response_type', 'client_id', 'redirect_uri'];

          var Oauth2 = function(config) {
            this.name = config.name;
            this.clientId = config.clientId;
            this.scope = config.scope;
            this.authorizationUrl = config.authorizationUrl;
            this.redirectUri = config.redirectUri;
            this.responseType = 'code';
            this.requiredUrlParams = defaultUrlParams.concat(config.requiredUrlParams);
            this.optionalUrlParams = ['scope'];
          };

          Oauth2.prototype.camelCase = function(name) {
            return name.replace(/([\:\-\_]+(.))/g, function(_, separator, letter, offset) {
              return offset ? letter.toUpperCase() : letter;
            });
          };

          Oauth2.prototype.open = function() {
            var deferred = $q.defer();
            var url = this.buildUrl();
            var popup = new Popup();

            popup.open(url, oauthKeys).then(function(code) {
              this.exchangeForToken(code).then(function(token) {
                deferred.resolve(token);
              });
            }.bind(this));

            return deferred.promise;
          };

          Oauth2.prototype.exchangeForToken = function(code) {
            var params = {
              clientId: config.providers[this.name].clientId,
              redirectUri: $window.location.origin + '/',
              code: code
            };

            return $http.post('/auth/facebook', params);
          };

          Oauth2.prototype.buildUrl = function() {
            var baseUrl = this.authorizationUrl;
            var qs = this.buildQueryString();
            return [baseUrl, qs].join('?');
          };

          Oauth2.prototype.buildQueryString = function() {
            var obj = this;
            var keyValuePairs = [];

            angular.forEach(this.requiredUrlParams, function(paramName) {
              var camelizedName = obj.camelCase(paramName);
              var paramValue = obj[camelizedName];
              keyValuePairs.push([paramName, paramValue]);
            });

            angular.forEach(this.optionalUrlParams, function(paramName) {
              var camelizedName = obj.camelCase(paramName);
              var paramValue = obj[camelizedName];
              keyValuePairs.push([paramName, paramValue]);
            });

            return keyValuePairs.map(function(pair) {
              return pair.join('=');
            }).join('&');
          };

          Oauth2.createProvider = function(providerName) {
            var providerOptions = config.providers[providerName];
            var provider = new Oauth2(providerOptions);
            console.log('MyProv', provider);
            return provider;
          };

          // END OAUTH

          var token = $window.localStorage.token;
          if (token) {
            var payload = JSON.parse($window.atob(token.split('.')[1]));
            $rootScope[config.userGlobal] = payload.user;
          }

          return {
            authenticate: function(providerName, options) {
              var deferred = $q.defer();
              if (!providerName) {
                deferred.reject('Expected a provider named \'' + providerName + '\', did you forget to add it?');
              }
              var provider = Oauth2.createProvider(providerName);

              provider.open(options).then(function() {
                console.log('OPENED')
                deferred.resolve('done');
              });

              return deferred.promise;
            },

            loginOauth: function(provider) {
              provider = provider.trim().toLowerCase();

              switch (provider) {
                case 'facebook':
                  var scope = config.providers.facebook.scope.join(',');
                  FB.login(function(response) {
                    FB.api('/me', function(profile) {
                      // TODO normalize return properties like passport
                      var data = {
                        accessToken: response.authResponse.accessToken,
                        signedRequest: response.authResponse.signedRequest,
                        profile: profile
                      };
                      $http.post(config.providers.facebook.url, data).success(function(token) {
                        var payload = JSON.parse($window.atob(token.split('.')[1]));
                        $window.localStorage.token = token;
                        $rootScope[config.userGlobal] = payload.user;
                        $location.path(config.loginRedirect);
                      });
                    });
                  }, {scope: scope});
                  break;
                case 'google':

                  break;
                case 'linkedin':
                  break;
                default:
                  break;
              }
            },
            login: function(user) {
              return $http.post(config.loginUrl, user).success(function(data) {
                $window.localStorage.token = data.token;
                var payload = JSON.parse($window.atob(data.token.split('.')[1]));
                $rootScope[config.userGlobal] = payload.user;
                $location.path(config.loginRedirect);
              });
            },
            signup: function(user) {
              return $http.post(config.signupUrl, user).success(function() {
                $location.path(config.signupRedirect);
              });
            },
            logout: function() {
              delete $window.localStorage.token;
              $rootScope[config.userGlobal] = null;
              $location.path(config.logoutRedirect);
            },
            isAuthenticated: function() {
              return $rootScope[config.userGlobal];
            }
          };
        }
      };
    })
    .factory('authInterceptor', function($q, $window, $location) {
      return {
        request: function(config) {
          if ($window.localStorage.token) {
            config.headers.Authorization = 'Bearer ' + $window.localStorage.token;
          }
          return config;
        },
        responseError: function(response) {
          if (response.status === 401 || response.status === 403) {
            $location.path('/login');
          }
          return $q.reject(response);
        }
      }
    })
    .config(function($httpProvider) {
      $httpProvider.interceptors.push('authInterceptor');
    })
    .run(function($rootScope, $location) {
      $rootScope.$on('$routeChangeStart', function(event, current, previous) {
        if ($rootScope.currentUser &&
          (current.originalPath === '/login' || current.originalPath === '/signup')) {
          $location.path('/');
        }
        if (current.authenticated && !$rootScope.currentUser) {
          $location.path('/login');
        }
      });
    });
})(window, window.angular);

<|endoftext|>


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

/**
 * External dependencies
 */
import styled from 'styled-components';
import PropTypes from 'prop-types';
import { v4 as uuidv4 } from 'uuid';
import { useState, useCallback, useEffect, useMemo } from 'react';

/**
 * Internal dependencies
 */
import { LOCAL_STORAGE_PREFIX } from '../../../constants';
import panelContext from './context';

export const PANEL_COLLAPSED_THRESHOLD = 10;

const Wrapper = styled.section`
  display: flex;
  flex-direction: column;
  position: relative;
`;

function Panel({
  name,
  children,
  resizeable = false,
  canCollapse = true,
  initialHeight = null,
  ariaLabel = null,
  ariaHidden = false,
}) {
  const persisted = useMemo(() => {
    let parsed = null;
    try {
      const stored = localStorage.getItem(
        `${LOCAL_STORAGE_PREFIX.PANEL}:${name}`,
        'null'
      );
      parsed = JSON.parse(stored);
    } catch (e) {
      // @TODO Add some error handling.
    }
    return parsed;
  }, [name]);
  const [isCollapsed, setIsCollapsed] = useState(
    Boolean(persisted?.isCollapsed)
  );
  const [expandToHeight, setExpandToHeight] = useState(
    persisted?.expandToHeight || initialHeight
  );
  const [height, setHeight] = useState(persisted?.height || initialHeight);
  const [hasTitle, setHasTitle] = useState(false);
  const [manuallyChanged, setManuallyChanged] = useState(false);

  // If supplied with a persistance key, persist height & collapsed state
  useEffect(() => {
    localStorage.setItem(
      `${LOCAL_STORAGE_PREFIX.PANEL}:${name}`,
      JSON.stringify({
        height,
        isCollapsed,
        expandToHeight,
      })
    );
  }, [height, isCollapsed, expandToHeight, name]);

  const confirmTitle = useCallback(() => setHasTitle(true), []);

  const collapse = useCallback(() => {
    if (!canCollapse) {
      return;
    }
    setIsCollapsed(true);
    if (resizeable) {
      setHeight(0);
    }
  }, [resizeable, canCollapse]);

  const expand = useCallback(
    (restoreHeight = true) => {
      setIsCollapsed(false);
      if (restoreHeight && resizeable) {
        setHeight(expandToHeight);
      }
    },
    [resizeable, expandToHeight]
  );

  // Expand panel on first mount if collapse not persisted
  useEffect(() => {
    if (persisted?.isCollapsed) {
      return;
    }
    expand(true);
  }, [canCollapse, expand, persisted]);

  useEffect(() => {
    if (resizeable && height <= PANEL_COLLAPSED_THRESHOLD && !isCollapsed) {
      collapse();
    }
  }, [collapse, height, resizeable, isCollapsed]);

  useEffect(() => {
    if (manuallyChanged || persisted || !resizeable) {
      return;
    }
    setHeight(initialHeight);
    setExpandToHeight(initialHeight);
  }, [manuallyChanged, initialHeight, resizeable, persisted]);

  const manuallySetHeight = useCallback(
    (h) => {
      if (!resizeable) {
        return;
      }
      setManuallyChanged(true);
      setHeight(h);
      if (isCollapsed && h(height) > PANEL_COLLAPSED_THRESHOLD) {
        expand(false);
      }
    },
    [setManuallyChanged, setHeight, height, expand, resizeable, isCollapsed]
  );

  const resetHeight = useCallback(() => {
    setManuallyChanged(false);
    if (isCollapsed) {
      expand(true);
    }
  }, [expand, isCollapsed]);

  const panelContentId = `panel-${name}-${uuidv4()}`;
  const panelTitleId = `panel-title-${name}-${uuidv4()}`;
  const panelTitleReadable = `panel-title-${name}`;

  const contextValue = {
    state: {
      height,
      resizeable,
      isCollapsed,
      panelContentId,
      panelTitleId,
      panelTitleReadable,
      ariaHidden,
    },
    actions: {
      setHeight: manuallySetHeight,
      setExpandToHeight,
      collapse,
      expand,
      resetHeight,
      confirmTitle,
    },
  };

  const ContextProvider = panelContext.Provider;

  const wrapperProps = useMemo(
    () =>
      hasTitle
        ? { 'aria-labelledby': panelTitleId }
        : { 'aria-label': ariaLabel },
    [hasTitle, panelTitleId, ariaLabel]
  );

  return (
    <Wrapper {...wrapperProps} aria-hidden={ariaHidden}>
      <ContextProvider value={contextValue}>{children}</ContextProvider>
    </Wrapper>
  );
}

Panel.propTypes = {
  name: PropTypes.string.isRequired,
  children: PropTypes.node,
  initialHeight: PropTypes.number,
  resizeable: PropTypes.bool,
  canCollapse: PropTypes.bool,
  ariaLabel: PropTypes.string,
  ariaHidden: PropTypes.bool,
  isPersisted: PropTypes.bool,
};

export default Panel;
<commit_msg>only persist after manual change<commit_after>/*
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import styled from 'styled-components';
import PropTypes from 'prop-types';
import { v4 as uuidv4 } from 'uuid';
import { useState, useCallback, useEffect, useMemo } from 'react';

/**
 * Internal dependencies
 */
import { LOCAL_STORAGE_PREFIX } from '../../../constants';
import panelContext from './context';

export const PANEL_COLLAPSED_THRESHOLD = 10;

const Wrapper = styled.section`
  display: flex;
  flex-direction: column;
  position: relative;
`;

function Panel({
  name,
  children,
  resizeable = false,
  canCollapse = true,
  initialHeight = null,
  ariaLabel = null,
  ariaHidden = false,
}) {
  const persisted = useMemo(() => {
    let parsed = null;
    try {
      const stored = localStorage.getItem(
        `${LOCAL_STORAGE_PREFIX.PANEL}:${name}`,
        'null'
      );
      parsed = JSON.parse(stored);
    } catch (e) {
      // @TODO Add some error handling.
    }
    return parsed;
  }, [name]);
  const [isCollapsed, setIsCollapsed] = useState(
    Boolean(persisted?.isCollapsed)
  );
  const [expandToHeight, setExpandToHeight] = useState(
    persisted?.expandToHeight || initialHeight
  );
  const [height, setHeight] = useState(persisted?.height || initialHeight);
  const [hasTitle, setHasTitle] = useState(false);
  const [manuallyChanged, setManuallyChanged] = useState(false);

  const confirmTitle = useCallback(() => setHasTitle(true), []);

  const collapse = useCallback(() => {
    if (!canCollapse) {
      return;
    }
    setIsCollapsed(true);
    setManuallyChanged(true);
    if (resizeable) {
      setHeight(0);
    }
  }, [resizeable, canCollapse]);

  const expand = useCallback(
    (restoreHeight = true) => {
      setIsCollapsed(false);
      if (restoreHeight && resizeable) {
        setHeight(expandToHeight);
      }
    },
    [resizeable, expandToHeight]
  );

  // Expand panel on first mount if collapse not persisted
  useEffect(() => {
    if (persisted?.isCollapsed) {
      return;
    }
    expand(true);
  }, [canCollapse, expand, persisted]);

  useEffect(() => {
    if (resizeable && height <= PANEL_COLLAPSED_THRESHOLD && !isCollapsed) {
      collapse();
    }
  }, [collapse, height, resizeable, isCollapsed]);

  useEffect(() => {
    if (manuallyChanged || persisted || !resizeable) {
      return;
    }
    setHeight(initialHeight);
    setExpandToHeight(initialHeight);
  }, [manuallyChanged, initialHeight, resizeable, persisted]);

  // Persist when user collapses
  useEffect(() => {
    if (!manuallyChanged) {
      return;
    }

    // Persist only when after user interacts
    localStorage.setItem(
      `${LOCAL_STORAGE_PREFIX.PANEL}:${name}`,
      JSON.stringify({
        height,
        isCollapsed,
        expandToHeight,
      })
    );
  }, [name, isCollapsed, height, expandToHeight, manuallyChanged]);

  const manuallySetHeight = useCallback(
    (h) => {
      if (!resizeable) {
        return;
      }
      setManuallyChanged(true);
      setHeight(h);
      if (isCollapsed && h(height) > PANEL_COLLAPSED_THRESHOLD) {
        expand(false);
      }
    },
    [setManuallyChanged, setHeight, height, expand, resizeable, isCollapsed]
  );

  const resetHeight = useCallback(() => {
    setManuallyChanged(false);
    if (isCollapsed) {
      expand(true);
    }
  }, [expand, isCollapsed]);

  const panelContentId = `panel-${name}-${uuidv4()}`;
  const panelTitleId = `panel-title-${name}-${uuidv4()}`;
  const panelTitleReadable = `panel-title-${name}`;

  const contextValue = {
    state: {
      height,
      resizeable,
      isCollapsed,
      panelContentId,
      panelTitleId,
      panelTitleReadable,
      ariaHidden,
    },
    actions: {
      setHeight: manuallySetHeight,
      setExpandToHeight,
      collapse,
      expand,
      resetHeight,
      confirmTitle,
    },
  };

  const ContextProvider = panelContext.Provider;

  const wrapperProps = useMemo(
    () =>
      hasTitle
        ? { 'aria-labelledby': panelTitleId }
        : { 'aria-label': ariaLabel },
    [hasTitle, panelTitleId, ariaLabel]
  );

  return (
    <Wrapper {...wrapperProps} aria-hidden={ariaHidden}>
      <ContextProvider value={contextValue}>{children}</ContextProvider>
    </Wrapper>
  );
}

Panel.propTypes = {
  name: PropTypes.string.isRequired,
  children: PropTypes.node,
  initialHeight: PropTypes.number,
  resizeable: PropTypes.bool,
  canCollapse: PropTypes.bool,
  ariaLabel: PropTypes.string,
  ariaHidden: PropTypes.bool,
  isPersisted: PropTypes.bool,
};

export default Panel;
<|endoftext|>


<commit_before>/**
 * Created by kamalnrf
 */

'use strict';

const msg_me = require('../msg-me');
const connection = require('./handlers/connection');
const newUser = require('./handlers/createUserOperator');
const feedback = require('./handlers/feedback');
const shrImage = require('./handlers/shrImage');

const postback = (bot) => {
    bot.on('postback', (payload, chat) => {
       console.log(payload);

       chooseThePostback(payload, chat);
       if (payload.postback.payload === '_stop') {
           const fbID = payload.sender.id;

           msg_me.isConnected(fbID)
               .then(connected => {
                   if (connected === 'true' || connected === true)
                       msg_me.conectedTo(fbID)
                           .then(recieverID => {
                               msg_me.disconnect(fbID, recieverID);

                               chat.say(`Conversation has ended`);
                               bot.say(recieverID, `Conection has been ended.`);
                           });
                   else
                       chat.say(`You have to be in a conversation to stop a conversation`);
               })
       }
    });

    bot.on('postback:REQ_YES', (payload, chat) => {
        console.log(payload);
        const senderID = payload.sender.id;

        msg_me.whatIsOnHold(senderID)
            .then(recieverID => {
                if (recieverID !== '-1') {
                    if (msg_me.connect(senderID, recieverID) === true) {
                        chat.say(`A connection has been established`);
                        bot.say(recieverID, `A connection has been established`);
                    }
                }else {
                    chat.say(`Your request has been, expired.`);
                }
            });
    });

    bot.on('postback:REQ_NO', (payload, chat) => {
        console.log(payload);
        const senderID = payload.sender.id;

        msg_me.whatIsOnHold(senderID)
            .then(recieverID => {
                if (recieverID !== '-1') {
                    if (msg_me.disconnect(senderID, recieverID) === true) {
                        chat.say(`Ok`);
                        bot.say(recieverID, `Your request has been rejected, try connecting with someone else.`);
                        msg_me.removeQueuedUsers(recieverID);
                    }
                }else {
                    chat.say(`OK.`);
                }
            });
    });
    //----------Online/Offline--------//
    bot.on('postback:online/offline', (payload, chat) => {
        console.log(payload);

        const fbID = payload.sender.id;

        msg_me.isOnline(fbID)
            .then(isOnline => {
                console.log(`isOnline ${isOnline}\nType: ${typeof isOnline}`);
                if (isOnline === 'true' || isOnline === true) {
                    msg_me.turnOffline(fbID)
                        .then(result => result ? chat.say("You’re now Offline. Friends will not be able to connect with you. Please turn back to Online if you want to chat anonymously with your friends.") : chat.say("Something went wrong tryagain"));
                }
                else if (isOnline === false || isOnline === "false") {
                    msg_me.turnOnline(fbID)
                        .then(result => result ? chat.say("You’re now Online. Hold on! Any friend of yours maybe contacting you soon.") : chat.say("Something went wrong tryagain"));

                    msg_me.getAllQueuedUsers(fbID)
                        .then(queuedUsers => {
                            console.log(queuedUsers);
                            queuedUsers.map(element => {
                                msg_me.getMyName(fbID)
                                    .then(name => {
                                        console.log(element);
                                        bot.sendTextMessage(element, `${name} is online. Now you can connect with him.`);
                                    });
                            });
                        });

                    msg_me.removeQueuedUsers(fbID);
                }
                else
                    chat.say("You need to create a user name first.")
                        .then(() => {
                            chat.conversation((convo) => {
                                convo.sendTypingIndicator(1000).then(() => newUser.createUser(convo, payload));
                            })
                        });
            }).catch(error => console.log(error));
    });

    //----------Start a conversation----//
    bot.on('postback:_start', (payload, chat) => {
        console.log(payload);

        const fbID = payload.sender.id;

        msg_me.isConnected(fbID)
            .then(connected => {
                if (connected === 'true' || connected === true)
                    chat.say("When you are in a conversation you can't start a new one.");
                else if (connected === 'false' || connected === false)
                    chat.conversation((convo) => {
                        convo.sendTypingIndicator(1000)
                            .then(() => connection.estConnection(convo, payload, bot))
                            .catch(error => console.log(error));
                    });
                else
                    chat.say("You need to create a username first.")
                        .then(() => {
                            chat.conversation((convo) => {
                                convo.sendTypingIndicator(1000).then(() => newUser.createUser(convo, payload));
                            })
                        });

            }).catch(error => console.log(error));
    });

    //----------My User Name-----------//
    bot.on('postback:myName', (payload, chat) => {
        console.log(payload);

        const fbID = payload.sender.id;

        msg_me.getMyName(fbID)
            .then(userName => {
                if (userName !== null) {
                    msg_me.getMyImage(fbID)
                        .then(link => {
                            if (link === null || link === undefined) {
                                console.log(`link is null`);
                                chat.getUserProfile()
                                    .then((user) => {
                                        shrImage.genImage(user.profile_pic, userName)
                                            .then(image => {
                                                shrImage.getLink(image, userName)
                                                    .then(link => {
                                                        console.log(link);
                                                        msg_me.saveImage(fbID, link);
                                                        chat.say({
                                                            attachment: 'image',
                                                            url: link
                                                        });
                                                        chat.say(`Your username is ${userName}. Share it with your friends.`);
                                                    })
                                            });
                                    });
                            }
                            else {
                                chat.say({
                                    attachment: 'image',
                                    url: link
                                }).then(() => chat.say(`Your username is ${userName}. Share it with your friends.`));
                            }
                        });
                }
                else
                    chat.say("You need to create a username first.")
                        .then(() => {
                            chat.conversation((convo) => {
                                convo.sendTypingIndicator(1000).then(() => newUser.createUser(convo, payload));
                            })
                        });
            })
            .catch(error => {
                console.log(error);
                chat.say("You need to create a username first.")
                    .then(() => {
                        chat.conversation((convo) => {
                            convo.sendTypingIndicator(1000).then(() => newUser.createUser(convo, payload));
                        })
                    });
            })
    });

    //----------Feedback----------//
    /*bot.on('postback:feedback', (payload, chat) => {
       console.log(payload);

       chat.conversation(convo => {
           convo.sendTypingIndicator(1000).then(() => feedback.sendFeedBack(payload, convo));
       })
    });*/

    console.log(`Initialized the postbacks.`);
};

function chooseThePostback (payload, chat){
    switch (payload.postback.payload){
        case 'feedback':
            chat.conversation(convo => {
                convo.sendTypingIndicator(1000).then(() => feedback.sendFeedBack(payload, convo));
            });
            break;
    }
}

module.exports = postback;<commit_msg>patches<commit_after>/**
 * Created by kamalnrf
 */

'use strict';

const msg_me = require('../msg-me');
const connection = require('./handlers/connection');
const newUser = require('./handlers/createUserOperator');
const feedback = require('./handlers/feedback');
const shrImage = require('./handlers/shrImage');

const postback = (bot) => {
    bot.on('postback', (payload, chat) => {
       console.log(payload);

       chooseThePostback(payload, chat);
       if (payload.postback.payload === '_stop') {
           const fbID = payload.sender.id;

           msg_me.isConnected(fbID)
               .then(connected => {
                   if (connected === 'true' || connected === true)
                       msg_me.conectedTo(fbID)
                           .then(recieverID => {
                               msg_me.disconnect(fbID, recieverID);

                               chat.say(`Conversation has ended`);
                               bot.say(recieverID, `Conection has been ended.`);
                           });
                   else
                       chat.say(`You have to be in a conversation to stop a conversation`);
               })
       }
    });

    bot.on('postback:REQ_YES', (payload, chat) => {
        console.log(payload);
        const senderID = payload.sender.id;

        msg_me.whatIsOnHold(senderID)
            .then(recieverID => {
                if (recieverID !== '-1') {
                    if (msg_me.connect(senderID, recieverID) === true) {
                        chat.say(`A connection has been established`);
                        bot.say(recieverID, `A connection has been established`);
                    }
                }else {
                    chat.say(`Your request has been, expired.`);
                }
            });
    });

    bot.on('postback:REQ_NO', (payload, chat) => {
        console.log(payload);
        const senderID = payload.sender.id;

        msg_me.whatIsOnHold(senderID)
            .then(recieverID => {
                if (recieverID !== '-1') {
                    if (msg_me.disconnect(senderID, recieverID) === true) {
                        chat.say(`Ok`);
                        bot.say(recieverID, `Your request has been rejected, try connecting with someone else.`);
                        msg_me.removeQueuedUsers(recieverID);
                    }
                }else {
                    chat.say(`OK.`);
                }
            });
    });
    /*//----------Online/Offline--------//
    bot.on('postback:online/offline', (payload, chat) => {
        console.log(payload);

    });*/

    /*//----------Start a conversation----//
    bot.on('postback:_start', (payload, chat) => {
        console.log(payload);

    });*/

    /*//----------My User Name-----------//
    bot.on('postback:myName', (payload, chat) => {
        console.log(payload);

    });*/

    console.log(`Initialized the postbacks.`);
};

function chooseThePostback (payload, chat){
    switch (payload.postback.payload){
        case 'online/offline':{
            const fbID = payload.sender.id;

            msg_me.isOnline(fbID)
                .then(isOnline => {
                    console.log(`isOnline ${isOnline}\nType: ${typeof isOnline}`);
                    if (isOnline === 'true' || isOnline === true) {
                        msg_me.turnOffline(fbID)
                            .then(result => result ? chat.say("You’re now Offline. Friends will not be able to connect with you. Please turn back to Online if you want to chat anonymously with your friends.") : chat.say("Something went wrong tryagain"));
                    }
                    else if (isOnline === false || isOnline === "false") {
                        msg_me.turnOnline(fbID)
                            .then(result => result ? chat.say("You’re now Online. Hold on! Any friend of yours maybe contacting you soon.") : chat.say("Something went wrong tryagain"));

                        msg_me.getAllQueuedUsers(fbID)
                            .then(queuedUsers => {
                                console.log(queuedUsers);
                                queuedUsers.map(element => {
                                    msg_me.getMyName(fbID)
                                        .then(name => {
                                            console.log(element);
                                            bot.sendTextMessage(element, `${name} is online. Now you can connect with him.`);
                                        });
                                });
                            });

                        msg_me.removeQueuedUsers(fbID);
                    }
                    else
                        chat.say("You need to create a user name first.")
                            .then(() => {
                                chat.conversation((convo) => {
                                    convo.sendTypingIndicator(1000).then(() => newUser.createUser(convo, payload));
                                })
                            });
                }).catch(error => console.log(error));
            break;
        }
        case '_start':{
            const fbID = payload.sender.id;

            msg_me.isConnected(fbID)
                .then(connected => {
                    if (connected === 'true' || connected === true)
                        chat.say("When you are in a conversation you can't start a new one.");
                    else if (connected === 'false' || connected === false)
                        chat.conversation((convo) => {
                            convo.sendTypingIndicator(1000)
                                .then(() => connection.estConnection(convo, payload, bot))
                                .catch(error => console.log(error));
                        });
                    else
                        chat.say("You need to create a username first.")
                            .then(() => {
                                chat.conversation((convo) => {
                                    convo.sendTypingIndicator(1000).then(() => newUser.createUser(convo, payload));
                                })
                            });

                }).catch(error => console.log(error));

            break;
        }
        case 'feedback':
            chat.conversation(convo => {
                convo.sendTypingIndicator(1000).then(() => feedback.sendFeedBack(payload, convo));
            });
            break;
        case 'myName': {
            const fbID = payload.sender.id;

            msg_me.getMyName(fbID)
                .then(userName => {
                    if (userName !== null) {
                        msg_me.getMyImage(fbID)
                            .then(link => {
                                if (link === null || link === undefined) {
                                    console.log(`link is null`);
                                    chat.getUserProfile()
                                        .then((user) => {
                                            shrImage.genImage(user.profile_pic, userName)
                                                .then(image => {
                                                    shrImage.getLink(image, userName)
                                                        .then(link => {
                                                            console.log(link);
                                                            msg_me.saveImage(fbID, link);
                                                            chat.say({
                                                                attachment: 'image',
                                                                url: link
                                                            });
                                                            chat.say(`Your username is ${userName}. Share it with your friends.`);
                                                        })
                                                });
                                        });
                                }
                                else {
                                    chat.say({
                                        attachment: 'image',
                                        url: link
                                    }).then(() => chat.say(`Your username is ${userName}. Share it with your friends.`));
                                }
                            });
                    }
                    else
                        chat.say("You need to create a username first.")
                            .then(() => {
                                chat.conversation((convo) => {
                                    convo.sendTypingIndicator(1000).then(() => newUser.createUser(convo, payload));
                                })
                            });
                })
                .catch(error => {
                    console.log(error);
                    chat.say("You need to create a username first.")
                        .then(() => {
                            chat.conversation((convo) => {
                                convo.sendTypingIndicator(1000).then(() => newUser.createUser(convo, payload));
                            })
                        });
                });
            break;
        }
    }
}

module.exports = postback;<|endoftext|>


<commit_before>'use strict';

var isFunction   = require('es5-ext/function/is-function')
  , assign       = require('es5-ext/object/assign')
  , create       = require('es5-ext/object/create')
  , d            = require('d')
  , lazy         = require('d/lazy')
  , uuid         = require('time-uuid')
  , DbjsError    = require('../error')
  , Event        = require('../event')
  , Instances    = require('./instances')
  , isObjectName = require('../utils/is-object-name')

  , slice = Array.prototype.slice
  , keys = Object.keys, defineProperties = Object.defineProperties
  , defineProperty = Object.defineProperty
  , uniqIdPrefix = 'abcdefghiklmnopqrstuvxyz'[Math.floor(Math.random() * 24)]
  , getById;

getById = function (proto, id) {
	var obj;
	if (!proto.hasOwnProperty('__descendants__')) return null;
	obj = proto.__descendants__.__setData__[id];
	if (obj) return obj;
	keys(proto.__descendants__.__setData__).some(function (key) {
		return (obj = getById(this[key], id));
	}, proto.__descendants__.__setData__);
	return obj || null;
};

module.exports = function (db) {
	var ObjectType = db.Base._extend_('Object')
	  , existingIds = db.objects.__setData__;

	defineProperties(ObjectType, assign({
		_validateExtendInitialize_: d(function (initialize, objProps, nsProps) {
			if (!isFunction(initialize)) {
				nsProps = objProps;
				objProps = initialize;
			} else if (!objProps) {
				objProps = { _initialize_: { value: initialize } };
			} else {
				objProps._initialize_ = { value: initialize };
			}
			return db.Base._validateExtendInitialize_.call(this, nsProps, objProps);
		}),
		is: d(function (value) {
			if (!value) return false;
			if (!(value instanceof this)) return false;
			if (!value.__id__) return false;
			return true;
		}),
		normalize: d(function (value) {
			return this.is(value) ? value : null;
		}),
		validate: d(function (value) {
			if (this.is(value)) return value;
			throw new DbjsError(value + " is not a " + this.__id__, 'INVALID_OBJECT_TYPE');
		}),
		compare: d(function (a, b) {
			return String(a.__id__).localeCompare(b.__id__);
		}),
		_createAndInitialize_: d(function (props) {
			var obj;
			db._postponed_ += 1;
			obj = this._create_(uuid());
			new Event(obj, this.prototype); //jslint: ignore
			obj._initialize_.apply(obj, arguments);
			db._postponed_ -= 1;
			return obj;
		}),
		_validateCreate_: d(function (props) {
			if (props == null) return [];
			return [create(this.prototype)._validateSetProperties_(props)];
		}),
		newNamed: d(function (name) {
			var args, obj;
			if (!isObjectName(name)) {
				throw new DbjsError(name + " is not valid object name", 'INVALID_OBJECT_NAME');
			}
			if (existingIds[name]) {
				throw new DbjsError(name + " name is already used", 'OBJECT_NAME_TAKEN');
			}
			args = slice.call(arguments, 1);
			args = this._validateCreate_.apply(this, args);
			obj = this._create_(name);
			new Event(obj, this.prototype); //jslint: ignore
			obj._initialize_.apply(obj, args);
			if (!db.hasOwnProperty(name)) defineProperty(db, name, d(obj));
			return obj;
		}),
		getById: d(function (id) { return getById(this.prototype, id); }),
		filterByKey: d(function (key, filter) {
			return this.instances.filterByKey(key, filter);
		})
	}, lazy({
		instances: d(function () {
			return new Instances(this);
		}, { cacheName: '__instances__', desc: '' })
	})));

	defineProperties(ObjectType.prototype, {
		_initialize_: d(function (props) {
			if (props == null) return;
			this._setProperties_(props);
		}),
		newUniq: d(function () {
			var desc = this.__descriptorPrototype__;
			if (!desc.nested || !db.isObjectType(desc.type)) {
				throw new DbjsError("newUniq is applicable only to nested maps", 'NON_MAP_UNIQUE');
			}
			return this.get(uniqIdPrefix + uuid());
		})
	});

	defineProperty(db, 'isObjectType', d(function (Type) {
		if (Type === ObjectType) return true;
		return ObjectType.isPrototypeOf(Type);
	}));
};
<commit_msg>Assure prototype passes `is` check<commit_after>'use strict';

var isFunction   = require('es5-ext/function/is-function')
  , assign       = require('es5-ext/object/assign')
  , create       = require('es5-ext/object/create')
  , d            = require('d')
  , lazy         = require('d/lazy')
  , uuid         = require('time-uuid')
  , DbjsError    = require('../error')
  , Event        = require('../event')
  , Instances    = require('./instances')
  , isObjectName = require('../utils/is-object-name')

  , slice = Array.prototype.slice
  , keys = Object.keys, defineProperties = Object.defineProperties
  , defineProperty = Object.defineProperty
  , uniqIdPrefix = 'abcdefghiklmnopqrstuvxyz'[Math.floor(Math.random() * 24)]
  , getById;

getById = function (proto, id) {
	var obj;
	if (!proto.hasOwnProperty('__descendants__')) return null;
	obj = proto.__descendants__.__setData__[id];
	if (obj) return obj;
	keys(proto.__descendants__.__setData__).some(function (key) {
		return (obj = getById(this[key], id));
	}, proto.__descendants__.__setData__);
	return obj || null;
};

module.exports = function (db) {
	var ObjectType = db.Base._extend_('Object')
	  , existingIds = db.objects.__setData__;

	defineProperties(ObjectType, assign({
		_validateExtendInitialize_: d(function (initialize, objProps, nsProps) {
			if (!isFunction(initialize)) {
				nsProps = objProps;
				objProps = initialize;
			} else if (!objProps) {
				objProps = { _initialize_: { value: initialize } };
			} else {
				objProps._initialize_ = { value: initialize };
			}
			return db.Base._validateExtendInitialize_.call(this, nsProps, objProps);
		}),
		is: d(function (value) {
			if (!value) return false;
			if (value === this.prototype) return true;
			if (!(value instanceof this)) return false;
			if (!value.__id__) return false;
			return true;
		}),
		normalize: d(function (value) {
			return this.is(value) ? value : null;
		}),
		validate: d(function (value) {
			if (this.is(value)) return value;
			throw new DbjsError(value + " is not a " + this.__id__, 'INVALID_OBJECT_TYPE');
		}),
		compare: d(function (a, b) {
			return String(a.__id__).localeCompare(b.__id__);
		}),
		_createAndInitialize_: d(function (props) {
			var obj;
			db._postponed_ += 1;
			obj = this._create_(uuid());
			new Event(obj, this.prototype); //jslint: ignore
			obj._initialize_.apply(obj, arguments);
			db._postponed_ -= 1;
			return obj;
		}),
		_validateCreate_: d(function (props) {
			if (props == null) return [];
			return [create(this.prototype)._validateSetProperties_(props)];
		}),
		newNamed: d(function (name) {
			var args, obj;
			if (!isObjectName(name)) {
				throw new DbjsError(name + " is not valid object name", 'INVALID_OBJECT_NAME');
			}
			if (existingIds[name]) {
				throw new DbjsError(name + " name is already used", 'OBJECT_NAME_TAKEN');
			}
			args = slice.call(arguments, 1);
			args = this._validateCreate_.apply(this, args);
			obj = this._create_(name);
			new Event(obj, this.prototype); //jslint: ignore
			obj._initialize_.apply(obj, args);
			if (!db.hasOwnProperty(name)) defineProperty(db, name, d(obj));
			return obj;
		}),
		getById: d(function (id) { return getById(this.prototype, id); }),
		filterByKey: d(function (key, filter) {
			return this.instances.filterByKey(key, filter);
		})
	}, lazy({
		instances: d(function () {
			return new Instances(this);
		}, { cacheName: '__instances__', desc: '' })
	})));

	defineProperties(ObjectType.prototype, {
		_initialize_: d(function (props) {
			if (props == null) return;
			this._setProperties_(props);
		}),
		newUniq: d(function () {
			var desc = this.__descriptorPrototype__;
			if (!desc.nested || !db.isObjectType(desc.type)) {
				throw new DbjsError("newUniq is applicable only to nested maps", 'NON_MAP_UNIQUE');
			}
			return this.get(uniqIdPrefix + uuid());
		})
	});

	defineProperty(db, 'isObjectType', d(function (Type) {
		if (Type === ObjectType) return true;
		return ObjectType.isPrototypeOf(Type);
	}));
};
<|endoftext|>


<commit_before>import { GridError } from '../infrastructure/error';
import { getFactory } from '../services/value';
import { identity, isUndefined } from '../utility/kit';

function hashColumnKeyFactory(model) {
  const { columnKey } = model.selection();
  if (columnKey === identity) {
    return column => column.key;
  }

  // TODO: investigate if is it necessary to use JSON.stringify here
  return identity;
}

function hashRowKeyFactory(model) {
  const { rowKey } = model.selection();
  if (rowKey === identity) {
    const columns = model.columnList().line;
    const index = columns.findIndex(column => column.type === 'id');
    if (index >= 0) {
      const idColumn = columns[index];
      const getId = getFactory(idColumn);
      return getId;
    }

    const { rows } = model.data();
    return row => rows.indexOf(row);
  }

  // TODO: investigate if is it necessary to use JSON.stringify here
  return identity;
}

function hashKeyFactory(model) {
  const selectionState = model.selection();
  switch (selectionState.unit) {
    case 'row':
      return hashRowKeyFactory(model);
    case 'column':
      return hashColumnKeyFactory(model);
    case 'cell': {
      const hashColumnKey = hashColumnKeyFactory(model);
      const hashRowKey = hashRowKeyFactory(model);
      return key => `${hashColumnKey(key.column)}[${hashRowKey(key.row)}]`;
    }
    case 'mix': {
      const hashColumnKey = hashColumnKeyFactory(model);
      const hashRowKey = hashRowKeyFactory(model);
      return (key, entry) => {
        if (!entry.unit) {
          return key;
        }

        switch (entry.unit) {
          case 'column':
            return hashColumnKey(key);
          case 'row':
            return hashRowKey(key);
          case 'cell':
            return `${hashColumnKey(key.column)}[${hashRowKey(key.row)}]`;
          default:
            throw new GridError('selection.service', `Invalid unit ${entry.unit}`);
        }
      };
    }
    default:
      throw new GridError('selection.service', `Invalid unit ${selectionState.unit}`);
  }
}

function cellMatchFactory() {
  return (x, y) => x.column === y.column && x.row === y.row;
}

function keySelector(unit, rowKey, columnKey) {
  switch (unit) {
    case 'row':
      return rowKey;
    case 'column':
      return columnKey;
    case 'cell':
      return entry => {
        if (entry.row && entry.column) {
          return {
            row: rowKey(entry.row),
            column: columnKey(entry.column)
          };
        }

        return entry;
      };
    default:
      throw new GridError('selection.state', `Invalid unit ${unit}`);
  }
}

function lookupColumnFactory(model, selectKey) {
  const { columnKey } = model.selection();
  if (columnKey === identity) {
    return identity;
  }

  const columns = model.columnList().line;
  return items => {
    const result = [];
    columns.forEach(column => {
      const columnKey = selectKey(column);
      const found = items.indexOf(columnKey) > -1;
      if (found) {
        result.push(column);
      }
    });

    return result;
  };
}

function lookupRowFactory(model, selectKey) {
  const { rowKey } = model.selection();
  if (rowKey === identity) {
    return identity;
  }

  const { rows } = model.data();
  return items => {
    const result = [];
    rows.forEach(row => {
      const rowKey = selectKey(row);
      const found = items.indexOf(rowKey) > -1;
      if (found) {
        result.push(row);
      }
    });

    return result;
  };
}

function lookupCellFactory(model, selectKey) {
  const { rowKey, columnKey } = model.selection();
  if (rowKey === identity && columnKey === identity) {
    return identity;
  }

  const { rows } = model.data();
  const columns = model.columnList().line;
  const match = cellMatchFactory();
  return items => {
    const result = [];
    columns.forEach(column => {
      rows.forEach(row => {
        const cell = {
          column: column,
          row: row
        };

        const index = items.findIndex(item => match(item, selectKey(cell)));
        if (index >= 0) {
          result.push(cell);
        }
      });
    });
    return result;
  };
}

export class SelectionService {
  constructor(model) {
    this.model = model;
  }

  lookup(items, unit) {
    let entries = [];
    if (items.length === 0) {
      return entries;
    }

    const { model } = this;
    if (isUndefined(unit)) {
      unit = model.selection().unit;
    }

    switch (unit) {
      case 'column': {
        const selectKey = this.keyFactory('column');
        const lookup = lookupColumnFactory(model, selectKey);
        entries = lookup(items);
        break;
      }
      case 'row': {
        const selectKey = this.keyFactory('row');
        const lookup = lookupRowFactory(model, selectKey);
        entries = lookup(items);
        break;
      }
      case 'cell': {
        const selectKey = this.keyFactory('cell');
        const lookup = lookupCellFactory(model, selectKey);
        entries = lookup(items);
        break;
      }
      case 'mix': {
        const rowKeys = items.filter(key => key.unit === 'row').map(key => key.item);
        const columnKeys = items.filter(key => key.unit === 'column').map(key => key.item);
        const cellKeys = items.filter(key => key.unit === 'cell').map(key => key.item);

        entries.push(...this.lookup(rowKeys, 'row').map(entry => ({ item: entry, unit: 'row' })));
        entries.push(...this.lookup(columnKeys, 'column').map(entry => ({ item: entry, unit: 'column' })));
        entries.push(...this.lookup(cellKeys, 'cell').map(entry => ({ item: entry, unit: 'cell' })));
        break;
      }
      default:
        throw new GridError('selection.state', `Invalid unit ${unit}`);
    }

    return entries;
  }

  map(entries) {
    const selectionState = this.model.selection();
    const selectKey = this.keyFactory();
    switch (selectionState.unit) {
      case 'column':
      case 'row':
      case 'cell':
        return entries.map(selectKey);
      case 'mix':
        return entries.map(entry => ({
          unit: entry.unit,
          item: selectKey(entry)
        }));
      default:
        throw new GridError('selection.state', `Invalid unit ${selectionState.unit}`);
    }
  }

  keyFactory(selectionUnit) {
    const { rowKey, columnKey, unit } = this.model.selection();

    selectionUnit = selectionUnit || unit;
    switch (selectionUnit) {
      case 'column':
      case 'row':
      case 'cell':
        return keySelector(selectionUnit, rowKey, columnKey);
      case 'mix': {
        const selectCellKey = keySelector('cell', rowKey, columnKey);
        const selectRowKey = keySelector('row', rowKey, columnKey);
        const selectColumnKey = keySelector('column', rowKey, columnKey);

        return entry => {
          if (!entry.unit) {
            return identity;
          }

          switch (entry.unit) {
            case 'column':
              return selectColumnKey(entry.item);
            case 'row':
              return selectRowKey(entry.item);
            case 'cell':
              return selectCellKey(entry.item);
            default:
              throw new GridError('selection.service', `Invalid unit ${entry.unit}`);
          }
        };
      }
      default:
        throw new GridError('selection.service', `Invalid unit ${selectionUnit}`);
    }
  }

  hashFactory() {
    const selectKey = this.keyFactory();
    const selectHash = hashKeyFactory(this.model);
    return entry => {
      const key = selectKey(entry);
      const hashKey = selectHash(key, entry);
      return hashKey;
    };
  }
}
<commit_msg>remove data item from selection items when it was deleted<commit_after>import { GridError } from '../infrastructure/error';
import { getFactory } from '../services/value';
import { identity, isUndefined } from '../utility/kit';

function hashColumnKeyFactory(model) {
  const { columnKey } = model.selection();
  if (columnKey === identity) {
    return column => column.key;
  }

  // TODO: investigate if is it necessary to use JSON.stringify here
  return identity;
}

function hashRowKeyFactory(model) {
  const { rowKey } = model.selection();
  if (rowKey === identity) {
    const columns = model.columnList().line;
    const index = columns.findIndex(column => column.type === 'id');
    if (index >= 0) {
      const idColumn = columns[index];
      const getId = getFactory(idColumn);
      return getId;
    }

    const { rows } = model.data();
    return row => rows.indexOf(row);
  }

  // TODO: investigate if is it necessary to use JSON.stringify here
  return identity;
}

function hashKeyFactory(model) {
  const selectionState = model.selection();
  switch (selectionState.unit) {
    case 'row':
      return hashRowKeyFactory(model);
    case 'column':
      return hashColumnKeyFactory(model);
    case 'cell': {
      const hashColumnKey = hashColumnKeyFactory(model);
      const hashRowKey = hashRowKeyFactory(model);
      return key => `${hashColumnKey(key.column)}[${hashRowKey(key.row)}]`;
    }
    case 'mix': {
      const hashColumnKey = hashColumnKeyFactory(model);
      const hashRowKey = hashRowKeyFactory(model);
      return (key, entry) => {
        if (!entry.unit) {
          return key;
        }

        switch (entry.unit) {
          case 'column':
            return hashColumnKey(key);
          case 'row':
            return hashRowKey(key);
          case 'cell':
            return `${hashColumnKey(key.column)}[${hashRowKey(key.row)}]`;
          default:
            throw new GridError('selection.service', `Invalid unit ${entry.unit}`);
        }
      };
    }
    default:
      throw new GridError('selection.service', `Invalid unit ${selectionState.unit}`);
  }
}

function cellMatchFactory() {
  return (x, y) => x.column === y.column && x.row === y.row;
}

function keySelector(unit, rowKey, columnKey) {
  switch (unit) {
    case 'row':
      return rowKey;
    case 'column':
      return columnKey;
    case 'cell':
      return entry => {
        if (entry.row && entry.column) {
          return {
            row: rowKey(entry.row),
            column: columnKey(entry.column)
          };
        }

        return entry;
      };
    default:
      throw new GridError('selection.state', `Invalid unit ${unit}`);
  }
}

function lookupColumnFactory(model, selectKey) {
  const columns = model.columnList().line;
  return items => {
    const result = [];

    columns.forEach(column => {
      const columnKey = selectKey(column);
      const found = items.indexOf(columnKey) >= 0;
      if (found) {
        result.push(column);
      }
    });

    return result;
  };
}

function lookupRowFactory(model, selectKey) {
  const { rows } = model.data();
  return items => {
    const result = [];

    rows.forEach(row => {
      const rowKey = selectKey(row);
      const found = items.indexOf(rowKey) >= 0;
      if (found) {
        result.push(row);
      }
    });

    return result;
  };
}

function lookupCellFactory(model, selectKey) {
  const { rows } = model.data();
  const columns = model.columnList().line;
  const match = cellMatchFactory();

  return items => {
    const result = [];

    columns.forEach(column => {
      rows.forEach(row => {
        const cell = {
          column: column,
          row: row
        };

        const index = items.findIndex(item => match(item, selectKey(cell)));
        if (index >= 0) {
          result.push(cell);
        }
      });
    });

    return result;
  };
}

export class SelectionService {
  constructor(model) {
    this.model = model;
  }

  lookup(items, unit) {
    let entries = [];
    if (items.length === 0) {
      return entries;
    }

    const { model } = this;
    if (isUndefined(unit)) {
      unit = model.selection().unit;
    }

    switch (unit) {
      case 'column': {
        const selectKey = this.keyFactory('column');
        const lookup = lookupColumnFactory(model, selectKey);
        entries = lookup(items);
        break;
      }
      case 'row': {
        const selectKey = this.keyFactory('row');
        const lookup = lookupRowFactory(model, selectKey);
        entries = lookup(items);
        break;
      }
      case 'cell': {
        const selectKey = this.keyFactory('cell');
        const lookup = lookupCellFactory(model, selectKey);
        entries = lookup(items);
        break;
      }
      case 'mix': {
        const rowKeys = items.filter(key => key.unit === 'row').map(key => key.item);
        const columnKeys = items.filter(key => key.unit === 'column').map(key => key.item);
        const cellKeys = items.filter(key => key.unit === 'cell').map(key => key.item);

        entries.push(...this.lookup(rowKeys, 'row').map(entry => ({ item: entry, unit: 'row' })));
        entries.push(...this.lookup(columnKeys, 'column').map(entry => ({ item: entry, unit: 'column' })));
        entries.push(...this.lookup(cellKeys, 'cell').map(entry => ({ item: entry, unit: 'cell' })));
        break;
      }
      default:
        throw new GridError('selection.state', `Invalid unit ${unit}`);
    }

    return entries;
  }

  map(entries) {
    const selectionState = this.model.selection();
    const selectKey = this.keyFactory();
    switch (selectionState.unit) {
      case 'column':
      case 'row':
      case 'cell':
        return entries.map(selectKey);
      case 'mix':
        return entries.map(entry => ({
          unit: entry.unit,
          item: selectKey(entry)
        }));
      default:
        throw new GridError('selection.state', `Invalid unit ${selectionState.unit}`);
    }
  }

  keyFactory(selectionUnit) {
    const { rowKey, columnKey, unit } = this.model.selection();

    selectionUnit = selectionUnit || unit;
    switch (selectionUnit) {
      case 'column':
      case 'row':
      case 'cell':
        return keySelector(selectionUnit, rowKey, columnKey);
      case 'mix': {
        const selectCellKey = keySelector('cell', rowKey, columnKey);
        const selectRowKey = keySelector('row', rowKey, columnKey);
        const selectColumnKey = keySelector('column', rowKey, columnKey);

        return entry => {
          if (!entry.unit) {
            return identity;
          }

          switch (entry.unit) {
            case 'column':
              return selectColumnKey(entry.item);
            case 'row':
              return selectRowKey(entry.item);
            case 'cell':
              return selectCellKey(entry.item);
            default:
              throw new GridError('selection.service', `Invalid unit ${entry.unit}`);
          }
        };
      }
      default:
        throw new GridError('selection.service', `Invalid unit ${selectionUnit}`);
    }
  }

  hashFactory() {
    const selectKey = this.keyFactory();
    const selectHash = hashKeyFactory(this.model);
    return entry => {
      const key = selectKey(entry);
      const hashKey = selectHash(key, entry);
      return hashKey;
    };
  }
}
<|endoftext|>


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

'use strict';

// MAIN //

/**
* Returns a cookie string for a provided name-value pair.
*
* @private
* @param {string} name - cookie name
* @param {string} value - cookie value
* @param {Object} [options] - cookie options
* @param {string} [options.path] - cookie path
* @param {string} [options.domain] - cookie domain
* @param {number} [options.maxAge] - maximum age (in seconds; takes precedence over `expire`)
* @param {(string|Date)} [options.expires] - cookie expiration date
* @param {boolean} [options.secure] - boolean indicating whether the cookie may only be transmitted over a secure protocol (e.g., HTTPS)
* @param {string} [options.samesite] - specifies whether the browser should send this cookie along with cross-site requests
* @returns {(string|null)} cookie value (or null)
*/
function cookieString( name, value, options ) {
	var opts;
	var keys;
	var tmp;
	var k;
	var v;
	var i;

	opts = {
		'path': '/',
		'max-age': 31536000, // 60*60*24*365 (1 year)
		'secure': true,
		'samesite': 'strict'
	};
	if ( arguments.length > 2 ) {
		if ( options.path ) {
			opts.path = options.path;
		}
		if ( options.domain ) {
			opts.domain = options.domain;
		}
		if ( typeof options.maxAge === 'number' ) {
			opts[ 'max-age' ] = options.maxAge;
		}
		if ( options.expires ) {
			if ( options.expires instanceof Date ) {
				opts.expires = options.expires.toUTCString();
			} else {
				opts.expires = options.expires;
			}
		}
		if ( typeof options.secure === 'boolean' ) {
			opts.secure = options.secure;
		}
		if ( options.samesite ) {
			opts.samesite = options.samesite;
		}
	}
	tmp = [ name + '=' + encodeURIComponent( value ) ];
	keys = Object.keys( opts );
	for ( i = 0; i < keys.length; i++ ) {
		k = keys[ i ];
		v = opts[ k ];
		if ( k === 'secure' && v ) {
			tmp.push( k );
		} else {
			tmp.push( k + '=' + v );
		}
	}
	return tmp.join( '; ' );
}

// EXPORTS //

module.exports = cookieString;
<commit_msg>Update path<commit_after>/**
* @license Apache-2.0
*
* Copyright (c) 2022 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

// MAIN //

/**
* Returns a cookie string for a provided name-value pair.
*
* @private
* @param {string} name - cookie name
* @param {string} value - cookie value
* @param {Object} [options] - cookie options
* @param {string} [options.path] - cookie path
* @param {string} [options.domain] - cookie domain
* @param {number} [options.maxAge] - maximum age (in seconds; takes precedence over `expire`)
* @param {(string|Date)} [options.expires] - cookie expiration date
* @param {boolean} [options.secure] - boolean indicating whether the cookie may only be transmitted over a secure protocol (e.g., HTTPS)
* @param {string} [options.samesite] - specifies whether the browser should send this cookie along with cross-site requests
* @returns {(string|null)} cookie value (or null)
*/
function cookieString( name, value, options ) {
	var opts;
	var keys;
	var tmp;
	var k;
	var v;
	var i;

	opts = {
		'path': '/docs/api',
		'max-age': 31536000, // 60*60*24*365 (1 year)
		'secure': true,
		'samesite': 'strict'
	};
	if ( arguments.length > 2 ) {
		if ( options.path ) {
			opts.path = options.path;
		}
		if ( options.domain ) {
			opts.domain = options.domain;
		}
		if ( typeof options.maxAge === 'number' ) {
			opts[ 'max-age' ] = options.maxAge;
		}
		if ( options.expires ) {
			if ( options.expires instanceof Date ) {
				opts.expires = options.expires.toUTCString();
			} else {
				opts.expires = options.expires;
			}
		}
		if ( typeof options.secure === 'boolean' ) {
			opts.secure = options.secure;
		}
		if ( options.samesite ) {
			opts.samesite = options.samesite;
		}
	}
	tmp = [ name + '=' + encodeURIComponent( value ) ];
	keys = Object.keys( opts );
	for ( i = 0; i < keys.length; i++ ) {
		k = keys[ i ];
		v = opts[ k ];
		if ( k === 'secure' && v ) {
			tmp.push( k );
		} else {
			tmp.push( k + '=' + v );
		}
	}
	return tmp.join( '; ' );
}

// EXPORTS //

module.exports = cookieString;
<|endoftext|>


<commit_before>export default DS.Model.extend({
  title: DS.attr('string'),
  description: DS.attr('string'),
  mentors: DS.hasMany('mentor'),
  timeSlots: DS.hasMany('time-slot'),

  room: function () {
    var room;
    this.get('timeSlots').forEach(function (timeSlot) {
      room = timeSlot.get('room');
    });
    return room;
  }.property('timeSlots.@each'),

  day: function () {
    var day;
    this.get('timeSlots').forEach(function (timeSlot) {
      day = timeSlot.get('day');
    });
    return day;
  }.property('timeSlots.@each'),

  startTime: function () {
    var startTime;
    this.get('timeSlots').forEach(function (timeSlot) {
      if (!startTime) {
        startTime = timeSlot.get('startTime');
      } else {
        if (moment(timeSlot.get('startTime')) < moment(startTime)) {
          startTime = timeSlot.get('startTime');
        }
      }
    });
    return startTime;
  }.property('timeSlots.@each'),

  endTime: function () {
    var endTime;
    this.get('timeSlots').forEach(function (timeSlot) {
      if (!endTime) {
        endTime = timeSlot.get('endTime');
      } else {
        if (moment(timeSlot.get('endTime')) > moment(endTime)) {
          endTime = timeSlot.get('endTime');
        }
      }
    });
    return endTime;
  }.property('timeSlots.@each'),

  startTimeDay: function () {
    return moment(this.get('startTime')).format('dddd');
  }.property('startTime'),

  startTimeHour: function () {
    return moment(this.get('startTime')).format('HH:mm');
  }.property('startTime'),

  endTimeHour: function () {
    return moment(this.get('endTime')).format('HH:mm');
  }.property('endTime'),

  isLongerThanOneTimeSlot: function () {
    return this.get('timeSlots').length > 1;
  }.property('timeSlots'),

  numberOfTimeSlots: function () {
    return this.get('timeSlots').length;
  }.property('timeSlots'),

  collidesWithWorkshop: function (workshop) {
    var collides = false;
    this.get('timeSlots').forEach(function (thisTimeSlot) {
      var thisDay = thisTimeSlot.get('day');
      var thisOrder = thisTimeSlot.get('order');
      workshop.get('timeSlots').forEach(function (workShopTimeSlot) {
        if(thisDay === workShopTimeSlot.get('day') && thisOrder === workShopTimeSlot.get('order')) {
          collides = true;
        }
      });
    });
    return collides;
  }
});
<commit_msg>Workshop model.<commit_after>export default DS.Model.extend({
  title: DS.attr('string'),
  description: DS.attr('string'),
  mentors: DS.hasMany('mentor'),
  timeSlots: DS.hasMany('time-slot'),
  attendeesCount: DS.attr('number'),
  maxAttendees: DS.attr('number'),
  placesLeft: DS.attr('number'),

  room: function () {
    var room;
    this.get('timeSlots').forEach(function (timeSlot) {
      room = timeSlot.get('room');
    });
    return room;
  }.property('timeSlots.@each'),

  day: function () {
    var day;
    this.get('timeSlots').forEach(function (timeSlot) {
      day = timeSlot.get('day');
    });
    return day;
  }.property('timeSlots.@each'),

  startTime: function () {
    var startTime;
    this.get('timeSlots').forEach(function (timeSlot) {
      if (!startTime) {
        startTime = timeSlot.get('startTime');
      } else {
        if (moment(timeSlot.get('startTime')) < moment(startTime)) {
          startTime = timeSlot.get('startTime');
        }
      }
    });
    return startTime;
  }.property('timeSlots.@each'),

  endTime: function () {
    var endTime;
    this.get('timeSlots').forEach(function (timeSlot) {
      if (!endTime) {
        endTime = timeSlot.get('endTime');
      } else {
        if (moment(timeSlot.get('endTime')) > moment(endTime)) {
          endTime = timeSlot.get('endTime');
        }
      }
    });
    return endTime;
  }.property('timeSlots.@each'),

  startTimeDay: function () {
    return moment(this.get('startTime')).format('dddd');
  }.property('startTime'),

  startTimeHour: function () {
    return moment(this.get('startTime')).format('HH:mm');
  }.property('startTime'),

  endTimeHour: function () {
    return moment(this.get('endTime')).format('HH:mm');
  }.property('endTime'),

  isLongerThanOneTimeSlot: function () {
    return this.get('timeSlots').length > 1;
  }.property('timeSlots'),

  numberOfTimeSlots: function () {
    return this.get('timeSlots').length;
  }.property('timeSlots'),

  collidesWithWorkshop: function (workshop) {
    var collides = false;
    this.get('timeSlots').forEach(function (thisTimeSlot) {
      var thisDay = thisTimeSlot.get('day');
      var thisOrder = thisTimeSlot.get('order');
      workshop.get('timeSlots').forEach(function (workShopTimeSlot) {
        if(thisDay === workShopTimeSlot.get('day') && thisOrder === workShopTimeSlot.get('order')) {
          collides = true;
        }
      });
    });
    return collides;
  }
});
<|endoftext|>