<commit_before>// @flow

import debounce from 'lodash/debounce';

import { _handleParticipantError } from '../base/conference';
import { getSourceNameSignalingFeatureFlag } from '../base/config';
import { MEDIA_TYPE } from '../base/media';
import { getLocalParticipant, getParticipantCount } from '../base/participants';
import { StateListenerRegistry } from '../base/redux';
import { getTrackSourceNameByMediaTypeAndParticipant } from '../base/tracks';
import { reportError } from '../base/util';
import {
    getVideoQualityForLargeVideo,
    getVideoQualityForResizableFilmstripThumbnails,
    shouldDisplayTileView
} from '../video-layout';

import { setMaxReceiverVideoQuality } from './actions';
import { VIDEO_QUALITY_LEVELS } from './constants';
import { getReceiverVideoQualityLevel } from './functions';
import logger from './logger';
import { getMinHeightForQualityLvlMap } from './selector';

declare var APP: Object;

/**
 * Handles changes in the visible participants in the filmstrip. The listener is debounced
 * so that the client doesn't end up sending too many bridge messages when the user is
 * scrolling through the thumbnails prompting updates to the selected endpoints.
 */
StateListenerRegistry.register(
    /* selector */ state => state['features/filmstrip'].visibleRemoteParticipants,
    /* listener */ debounce((visibleRemoteParticipants, store) => {
        _updateReceiverVideoConstraints(store);
    }, 100));

StateListenerRegistry.register(
    /* selector */ state => state['features/base/tracks'],
    /* listener */(remoteTracks, store) => {
        _updateReceiverVideoConstraints(store);
    });

/**
 * Handles the use case when the on-stage participant has changed.
 */
StateListenerRegistry.register(
    state => state['features/large-video'].participantId,
    (participantId, store) => {
        _updateReceiverVideoConstraints(store);
    }
);

/**
 * Handles the use case when we have set some of the constraints in redux but the conference object wasn't available
 * and we haven't been able to pass the constraints to lib-jitsi-meet.
 */
StateListenerRegistry.register(
    state => state['features/base/conference'].conference,
    (conference, store) => {
        _updateReceiverVideoConstraints(store);
    }
);

/**
 * Updates the receiver constraints when the layout changes. When we are in stage view we need to handle the
 * on-stage participant differently.
 */
StateListenerRegistry.register(
    /* selector */ state => state['features/video-layout'].tileViewEnabled,
    /* listener */ (tileViewEnabled, store) => {
        _updateReceiverVideoConstraints(store);
    }
);

/**
 * StateListenerRegistry provides a reliable way of detecting changes to
 * lastn state and dispatching additional actions.
 */
StateListenerRegistry.register(
    /* selector */ state => state['features/base/lastn'].lastN,
    /* listener */ (lastN, store) => {
        _updateReceiverVideoConstraints(store);
    });

/**
 * Updates the receiver constraints when the tiles in the resizable filmstrip change dimensions.
 */
StateListenerRegistry.register(
    state => getVideoQualityForResizableFilmstripThumbnails(state),
    (_, store) => {
        _updateReceiverVideoConstraints(store);
    }
);

/**
 * StateListenerRegistry provides a reliable way of detecting changes to
 * maxReceiverVideoQuality and preferredVideoQuality state and dispatching additional actions.
 */
StateListenerRegistry.register(
    /* selector */ state => {
        const {
            maxReceiverVideoQuality,
            preferredVideoQuality
        } = state['features/video-quality'];

        return {
            maxReceiverVideoQuality,
            preferredVideoQuality
        };
    },
    /* listener */ (currentState, store, previousState = {}) => {
        const { maxReceiverVideoQuality, preferredVideoQuality } = currentState;
        const changedPreferredVideoQuality = preferredVideoQuality !== previousState.preferredVideoQuality;
        const changedReceiverVideoQuality = maxReceiverVideoQuality !== previousState.maxReceiverVideoQuality;

        if (changedPreferredVideoQuality) {
            _setSenderVideoConstraint(preferredVideoQuality, store);
            typeof APP !== 'undefined' && APP.API.notifyVideoQualityChanged(preferredVideoQuality);
        }
        changedReceiverVideoQuality && _updateReceiverVideoConstraints(store);
    }, {
        deepEquals: true
    });

/**
 * Implements a state listener in order to calculate max receiver video quality.
 */
StateListenerRegistry.register(
    /* selector */ state => {
        const { reducedUI } = state['features/base/responsive-ui'];
        const _shouldDisplayTileView = shouldDisplayTileView(state);
        const thumbnailSize = state['features/filmstrip']?.tileViewDimensions?.thumbnailSize;
        const participantCount = getParticipantCount(state);

        return {
            displayTileView: _shouldDisplayTileView,
            participantCount,
            reducedUI,
            thumbnailHeight: thumbnailSize?.height
        };
    },
    /* listener */ ({ displayTileView, participantCount, reducedUI, thumbnailHeight }, { dispatch, getState }) => {
        const state = getState();
        const { maxReceiverVideoQuality } = state['features/video-quality'];
        const { maxFullResolutionParticipants = 2 } = state['features/base/config'];

        let newMaxRecvVideoQuality = VIDEO_QUALITY_LEVELS.ULTRA;

        if (reducedUI) {
            newMaxRecvVideoQuality = VIDEO_QUALITY_LEVELS.LOW;
        } else if (displayTileView && !Number.isNaN(thumbnailHeight)) {
            newMaxRecvVideoQuality = getReceiverVideoQualityLevel(thumbnailHeight, getMinHeightForQualityLvlMap(state));

            // Override HD level calculated for the thumbnail height when # of participants threshold is exceeded
            if (maxReceiverVideoQuality !== newMaxRecvVideoQuality && maxFullResolutionParticipants !== -1) {
                const override
                    = participantCount > maxFullResolutionParticipants
                        && newMaxRecvVideoQuality > VIDEO_QUALITY_LEVELS.STANDARD;

                logger.info(`Video quality level for thumbnail height: ${thumbnailHeight}, `
                    + `is: ${newMaxRecvVideoQuality}, `
                    + `override: ${String(override)}, `
                    + `max full res N: ${maxFullResolutionParticipants}`);

                if (override) {
                    newMaxRecvVideoQuality = VIDEO_QUALITY_LEVELS.STANDARD;
                }
            }
        }

        if (maxReceiverVideoQuality !== newMaxRecvVideoQuality) {
            dispatch(setMaxReceiverVideoQuality(newMaxRecvVideoQuality));
        }
    }, {
        deepEquals: true
    });

/**
 * Helper function for updating the preferred sender video constraint, based on the user preference.
 *
 * @param {number} preferred - The user preferred max frame height.
 * @returns {void}
 */
function _setSenderVideoConstraint(preferred, { getState }) {
    const state = getState();
    const { conference } = state['features/base/conference'];

    if (!conference) {
        return;
    }

    logger.info(`Setting sender resolution to ${preferred}`);
    conference.setSenderVideoConstraint(preferred)
        .catch(error => {
            _handleParticipantError(error);
            reportError(error, `Changing sender resolution to ${preferred} failed.`);
        });
}

/**
 * Private helper to calculate the receiver video constraints and set them on the bridge channel.
 *
 * @param {*} store - The redux store.
 * @returns {void}
 */
function _updateReceiverVideoConstraints({ getState }) {
    const state = getState();
    const { conference } = state['features/base/conference'];

    if (!conference) {
        return;
    }
    const { lastN } = state['features/base/lastn'];
    const { maxReceiverVideoQuality, preferredVideoQuality } = state['features/video-quality'];
    const { participantId: largeVideoParticipantId } = state['features/large-video'];
    const maxFrameHeight = Math.min(maxReceiverVideoQuality, preferredVideoQuality);
    const { remoteScreenShares } = state['features/video-layout'];
    const { visibleRemoteParticipants } = state['features/filmstrip'];
    const tracks = state['features/base/tracks'];
    const sourceNameSignaling = getSourceNameSignalingFeatureFlag(state);
    const localParticipantId = getLocalParticipant(state).id;

    let receiverConstraints;

    if (sourceNameSignaling) {
        receiverConstraints = {
            constraints: {},
            defaultConstraints: { 'maxHeight': VIDEO_QUALITY_LEVELS.NONE },
            lastN,
            onStageSources: [],
            selectedSources: []
        };
        const visibleRemoteTrackSourceNames = [];
        let largeVideoSourceName;

        if (visibleRemoteParticipants?.size) {
            visibleRemoteParticipants.forEach(participantId => {
                const sourceName = getTrackSourceNameByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, participantId);

                if (sourceName) {
                    visibleRemoteTrackSourceNames.push(sourceName);
                }
            });
        }

        if (localParticipantId !== largeVideoParticipantId) {
            largeVideoSourceName = getTrackSourceNameByMediaTypeAndParticipant(
                tracks, MEDIA_TYPE.VIDEO,
                largeVideoParticipantId
            );
        }

        // Tile view.
        if (shouldDisplayTileView(state)) {
            if (!visibleRemoteTrackSourceNames?.length) {
                return;
            }

            visibleRemoteTrackSourceNames.forEach(sourceName => {
                receiverConstraints.constraints[sourceName] = { 'maxHeight': maxFrameHeight };
            });

            // Prioritize screenshare in tile view.
            if (remoteScreenShares?.length) {
                const remoteScreenShareSourceNames = remoteScreenShares.map(remoteScreenShare =>
                    getTrackSourceNameByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, remoteScreenShare)
                );

                receiverConstraints.selectedSources = remoteScreenShareSourceNames;
            }

        // Stage view.
        } else {
            if (!visibleRemoteTrackSourceNames?.length && !largeVideoSourceName) {
                return;
            }

            if (visibleRemoteTrackSourceNames?.length) {
                const qualityLevel = getVideoQualityForResizableFilmstripThumbnails(state);

                visibleRemoteTrackSourceNames.forEach(sourceName => {
                    receiverConstraints.constraints[sourceName] = { 'maxHeight': qualityLevel };
                });
            }

            if (largeVideoSourceName) {
                let quality = maxFrameHeight;

                if (!remoteScreenShares.find(id => id === largeVideoParticipantId)) {
                    quality = getVideoQualityForLargeVideo();
                }
                receiverConstraints.constraints[largeVideoSourceName] = { 'maxHeight': quality };
                receiverConstraints.onStageSources = [ largeVideoSourceName ];
            }
        }

    } else {
        receiverConstraints = {
            constraints: {},
            defaultConstraints: { 'maxHeight': VIDEO_QUALITY_LEVELS.NONE },
            lastN,
            onStageEndpoints: [],
            selectedEndpoints: []
        };

        // Tile view.
        if (shouldDisplayTileView(state)) {
            if (!visibleRemoteParticipants?.size) {
                return;
            }

            visibleRemoteParticipants.forEach(participantId => {
                receiverConstraints.constraints[participantId] = { 'maxHeight': maxFrameHeight };
            });

            // Prioritize screenshare in tile view.
            remoteScreenShares?.length && (receiverConstraints.selectedEndpoints = remoteScreenShares);

        // Stage view.
        } else {
            if (!visibleRemoteParticipants?.size && !largeVideoParticipantId) {
                return;
            }

            if (visibleRemoteParticipants?.size > 0) {
                const qualityLevel = getVideoQualityForResizableFilmstripThumbnails(state);

                visibleRemoteParticipants.forEach(participantId => {
                    receiverConstraints.constraints[participantId] = { 'maxHeight': qualityLevel };
                });
            }

            if (largeVideoParticipantId) {
                let quality = maxFrameHeight;

                if (!remoteScreenShares.find(id => id === largeVideoParticipantId)) {
                    quality = getVideoQualityForLargeVideo();
                }
                receiverConstraints.constraints[largeVideoParticipantId] = { 'maxHeight': quality };
                receiverConstraints.onStageEndpoints = [ largeVideoParticipantId ];
            }
        }
    }

    try {
        conference.setReceiverConstraints(receiverConstraints);
    } catch (error) {
        _handleParticipantError(error);
        reportError(error, `Failed to set receiver video constraints ${JSON.stringify(receiverConstraints)}`);
    }
}
<commit_msg>fix(video-constraints) Fix calculations (#11161)<commit_after>// @flow

import debounce from 'lodash/debounce';

import { _handleParticipantError } from '../base/conference';
import { getSourceNameSignalingFeatureFlag } from '../base/config';
import { MEDIA_TYPE } from '../base/media';
import { getLocalParticipant, getParticipantCount } from '../base/participants';
import { StateListenerRegistry } from '../base/redux';
import { getTrackSourceNameByMediaTypeAndParticipant } from '../base/tracks';
import { reportError } from '../base/util';
import {
    getVideoQualityForLargeVideo,
    getVideoQualityForResizableFilmstripThumbnails,
    shouldDisplayTileView
} from '../video-layout';

import { setMaxReceiverVideoQuality } from './actions';
import { VIDEO_QUALITY_LEVELS } from './constants';
import { getReceiverVideoQualityLevel } from './functions';
import logger from './logger';
import { getMinHeightForQualityLvlMap } from './selector';

declare var APP: Object;

/**
 * Handles changes in the visible participants in the filmstrip. The listener is debounced
 * so that the client doesn't end up sending too many bridge messages when the user is
 * scrolling through the thumbnails prompting updates to the selected endpoints.
 */
StateListenerRegistry.register(
    /* selector */ state => state['features/filmstrip'].visibleRemoteParticipants,
    /* listener */ debounce((visibleRemoteParticipants, store) => {
        _updateReceiverVideoConstraints(store);
    }, 100));

StateListenerRegistry.register(
    /* selector */ state => state['features/base/tracks'],
    /* listener */(remoteTracks, store) => {
        _updateReceiverVideoConstraints(store);
    });

/**
 * Handles the use case when the on-stage participant has changed.
 */
StateListenerRegistry.register(
    state => state['features/large-video'].participantId,
    (participantId, store) => {
        _updateReceiverVideoConstraints(store);
    }
);

/**
 * Handles the use case when we have set some of the constraints in redux but the conference object wasn't available
 * and we haven't been able to pass the constraints to lib-jitsi-meet.
 */
StateListenerRegistry.register(
    state => state['features/base/conference'].conference,
    (conference, store) => {
        _updateReceiverVideoConstraints(store);
    }
);

/**
 * Updates the receiver constraints when the layout changes. When we are in stage view we need to handle the
 * on-stage participant differently.
 */
StateListenerRegistry.register(
    /* selector */ state => state['features/video-layout'].tileViewEnabled,
    /* listener */ (tileViewEnabled, store) => {
        _updateReceiverVideoConstraints(store);
    }
);

/**
 * StateListenerRegistry provides a reliable way of detecting changes to
 * lastn state and dispatching additional actions.
 */
StateListenerRegistry.register(
    /* selector */ state => state['features/base/lastn'].lastN,
    /* listener */ (lastN, store) => {
        _updateReceiverVideoConstraints(store);
    });

/**
 * Updates the receiver constraints when the tiles in the resizable filmstrip change dimensions.
 */
StateListenerRegistry.register(
    state => getVideoQualityForResizableFilmstripThumbnails(state),
    (_, store) => {
        _updateReceiverVideoConstraints(store);
    }
);

/**
 * StateListenerRegistry provides a reliable way of detecting changes to
 * maxReceiverVideoQuality and preferredVideoQuality state and dispatching additional actions.
 */
StateListenerRegistry.register(
    /* selector */ state => {
        const {
            maxReceiverVideoQuality,
            preferredVideoQuality
        } = state['features/video-quality'];

        return {
            maxReceiverVideoQuality,
            preferredVideoQuality
        };
    },
    /* listener */ (currentState, store, previousState = {}) => {
        const { maxReceiverVideoQuality, preferredVideoQuality } = currentState;
        const changedPreferredVideoQuality = preferredVideoQuality !== previousState.preferredVideoQuality;
        const changedReceiverVideoQuality = maxReceiverVideoQuality !== previousState.maxReceiverVideoQuality;

        if (changedPreferredVideoQuality) {
            _setSenderVideoConstraint(preferredVideoQuality, store);
            typeof APP !== 'undefined' && APP.API.notifyVideoQualityChanged(preferredVideoQuality);
        }
        changedReceiverVideoQuality && _updateReceiverVideoConstraints(store);
    }, {
        deepEquals: true
    });

/**
 * Implements a state listener in order to calculate max receiver video quality.
 */
StateListenerRegistry.register(
    /* selector */ state => {
        const { reducedUI } = state['features/base/responsive-ui'];
        const _shouldDisplayTileView = shouldDisplayTileView(state);
        const thumbnailSize = state['features/filmstrip']?.tileViewDimensions?.thumbnailSize;
        const participantCount = getParticipantCount(state);

        return {
            displayTileView: _shouldDisplayTileView,
            participantCount,
            reducedUI,
            thumbnailHeight: thumbnailSize?.height
        };
    },
    /* listener */ ({ displayTileView, participantCount, reducedUI, thumbnailHeight }, { dispatch, getState }) => {
        const state = getState();
        const { maxReceiverVideoQuality } = state['features/video-quality'];
        const { maxFullResolutionParticipants = 2 } = state['features/base/config'];

        let newMaxRecvVideoQuality = VIDEO_QUALITY_LEVELS.ULTRA;

        if (reducedUI) {
            newMaxRecvVideoQuality = VIDEO_QUALITY_LEVELS.LOW;
        } else if (displayTileView && !Number.isNaN(thumbnailHeight)) {
            newMaxRecvVideoQuality = getReceiverVideoQualityLevel(thumbnailHeight, getMinHeightForQualityLvlMap(state));

            // Override HD level calculated for the thumbnail height when # of participants threshold is exceeded
            if (maxReceiverVideoQuality !== newMaxRecvVideoQuality && maxFullResolutionParticipants !== -1) {
                const override
                    = participantCount > maxFullResolutionParticipants
                        && newMaxRecvVideoQuality > VIDEO_QUALITY_LEVELS.STANDARD;

                logger.info(`Video quality level for thumbnail height: ${thumbnailHeight}, `
                    + `is: ${newMaxRecvVideoQuality}, `
                    + `override: ${String(override)}, `
                    + `max full res N: ${maxFullResolutionParticipants}`);

                if (override) {
                    newMaxRecvVideoQuality = VIDEO_QUALITY_LEVELS.STANDARD;
                }
            }
        }

        if (maxReceiverVideoQuality !== newMaxRecvVideoQuality) {
            dispatch(setMaxReceiverVideoQuality(newMaxRecvVideoQuality));
        }
    }, {
        deepEquals: true
    });

/**
 * Helper function for updating the preferred sender video constraint, based on the user preference.
 *
 * @param {number} preferred - The user preferred max frame height.
 * @returns {void}
 */
function _setSenderVideoConstraint(preferred, { getState }) {
    const state = getState();
    const { conference } = state['features/base/conference'];

    if (!conference) {
        return;
    }

    logger.info(`Setting sender resolution to ${preferred}`);
    conference.setSenderVideoConstraint(preferred)
        .catch(error => {
            _handleParticipantError(error);
            reportError(error, `Changing sender resolution to ${preferred} failed.`);
        });
}

/**
 * Private helper to calculate the receiver video constraints and set them on the bridge channel.
 *
 * @param {*} store - The redux store.
 * @returns {void}
 */
function _updateReceiverVideoConstraints({ getState }) {
    const state = getState();
    const { conference } = state['features/base/conference'];

    if (!conference) {
        return;
    }
    const { lastN } = state['features/base/lastn'];
    const { maxReceiverVideoQuality, preferredVideoQuality } = state['features/video-quality'];
    const { participantId: largeVideoParticipantId } = state['features/large-video'];
    const maxFrameHeight = Math.min(maxReceiverVideoQuality, preferredVideoQuality);
    const { remoteScreenShares } = state['features/video-layout'];
    const { visibleRemoteParticipants } = state['features/filmstrip'];
    const tracks = state['features/base/tracks'];
    const sourceNameSignaling = getSourceNameSignalingFeatureFlag(state);
    const localParticipantId = getLocalParticipant(state).id;

    let receiverConstraints;

    if (sourceNameSignaling) {
        receiverConstraints = {
            constraints: {},
            defaultConstraints: { 'maxHeight': VIDEO_QUALITY_LEVELS.NONE },
            lastN,
            onStageSources: [],
            selectedSources: []
        };
        const visibleRemoteTrackSourceNames = [];
        let largeVideoSourceName;

        if (visibleRemoteParticipants?.size) {
            visibleRemoteParticipants.forEach(participantId => {
                const sourceName = getTrackSourceNameByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, participantId);

                if (sourceName) {
                    visibleRemoteTrackSourceNames.push(sourceName);
                }
            });
        }

        if (localParticipantId !== largeVideoParticipantId) {
            largeVideoSourceName = getTrackSourceNameByMediaTypeAndParticipant(
                tracks, MEDIA_TYPE.VIDEO,
                largeVideoParticipantId
            );
        }

        // Tile view.
        if (shouldDisplayTileView(state)) {
            if (!visibleRemoteTrackSourceNames?.length) {
                return;
            }

            visibleRemoteTrackSourceNames.forEach(sourceName => {
                receiverConstraints.constraints[sourceName] = { 'maxHeight': maxFrameHeight };
            });

            // Prioritize screenshare in tile view.
            if (remoteScreenShares?.length) {
                const remoteScreenShareSourceNames = remoteScreenShares.map(remoteScreenShare =>
                    getTrackSourceNameByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, remoteScreenShare)
                );

                receiverConstraints.selectedSources = remoteScreenShareSourceNames;
            }

        // Stage view.
        } else {
            if (!visibleRemoteTrackSourceNames?.length && !largeVideoSourceName) {
                return;
            }

            if (visibleRemoteTrackSourceNames?.length) {
                const qualityLevel = getVideoQualityForResizableFilmstripThumbnails(state);

                visibleRemoteTrackSourceNames.forEach(sourceName => {
                    receiverConstraints.constraints[sourceName] = { 'maxHeight': Math.min(qualityLevel,
                        maxFrameHeight) };
                });
            }

            if (largeVideoSourceName) {
                let quality = maxFrameHeight;

                if (navigator.product !== 'ReactNative'
                    && !remoteScreenShares.find(id => id === largeVideoParticipantId)) {
                    quality = getVideoQualityForLargeVideo();
                }
                receiverConstraints.constraints[largeVideoSourceName] = { 'maxHeight': quality };
                receiverConstraints.onStageSources = [ largeVideoSourceName ];
            }
        }

    } else {
        receiverConstraints = {
            constraints: {},
            defaultConstraints: { 'maxHeight': VIDEO_QUALITY_LEVELS.NONE },
            lastN,
            onStageEndpoints: [],
            selectedEndpoints: []
        };

        // Tile view.
        if (shouldDisplayTileView(state)) {
            if (!visibleRemoteParticipants?.size) {
                return;
            }

            visibleRemoteParticipants.forEach(participantId => {
                receiverConstraints.constraints[participantId] = { 'maxHeight': maxFrameHeight };
            });

            // Prioritize screenshare in tile view.
            remoteScreenShares?.length && (receiverConstraints.selectedEndpoints = remoteScreenShares);

        // Stage view.
        } else {
            if (!visibleRemoteParticipants?.size && !largeVideoParticipantId) {
                return;
            }

            if (visibleRemoteParticipants?.size > 0) {
                const qualityLevel = getVideoQualityForResizableFilmstripThumbnails(state);

                visibleRemoteParticipants.forEach(participantId => {
                    receiverConstraints.constraints[participantId] = { 'maxHeight': Math.min(qualityLevel,
                        maxFrameHeight) };
                });
            }

            if (largeVideoParticipantId) {
                let quality = maxFrameHeight;

                if (navigator.product !== 'ReactNative'
                    && !remoteScreenShares.find(id => id === largeVideoParticipantId)) {
                    quality = getVideoQualityForLargeVideo();
                }
                receiverConstraints.constraints[largeVideoParticipantId] = { 'maxHeight': quality };
                receiverConstraints.onStageEndpoints = [ largeVideoParticipantId ];
            }
        }
    }

    try {
        conference.setReceiverConstraints(receiverConstraints);
    } catch (error) {
        _handleParticipantError(error);
        reportError(error, `Failed to set receiver video constraints ${JSON.stringify(receiverConstraints)}`);
    }
}
<|endoftext|>


<commit_before>const discounts = [
  {
    company: 'satt',
    discount: '15% off food',
    description:
      'Satt breakfast buffet from 6:30-10:00, lunch buffet from 11:30-14:30 and dinner buffet from 18:00-22:00. Satt also has a brunch on weekends between 11:30 and 14:00. Happy Hour at Satt, everyday between 16:00 and 18:00.',
  },
  {
    company: 'austur',
    discount: 'Drinks: 2 for 1',
    description:
      '2 for 1 of almost everything from 23:00 on Thursday, Friday and Saturday.',
  },
  {
    company: 'islenski-barinn',
    discount: '15% off food and a large beer for 800kr.',
    description: '15% off menu - doesn’t apply to other offers.',
  },
  {
    company: 'subway',
    discount: '10% off food',
    description: null,
  },
  {
    company: 'matarkjallarinn',
    discount: '15% off food',
    description: 'These days we offer a 4 course Food & Fun festival menu.',
  },
  {
    company: 'sjavargrillid',
    discount: '20% off food',
    description: 'Applies both for lunch and dinner menu.',
  },
  {
    company: 'fiskfelagid',
    discount: '10% off food and drinks',
    description: null,
  },
  {
    company: 'xo-food',
    discount: '15% off food and drinks',
    description: null,
  },
  {
    company: 'js-watch',
    discount: '15% off ARC-TIC',
    description: '15% off Iceland ARC-TIC watches. See www.arc-tic.com',
  },
  {
    company: 'tales-from-iceland',
    discount: '25% off',
    description: null,
  },
  {
    company: 'handprjonasambandid',
    discount: '7.5% off',
    description: null,
  },
  {
    company: 'lemon',
    discount: '2 for 1',
    description: null,
  },
  {
    company: 'dominos',
    discount: '30% off',
    description: 'Only applies if ordered online, or through the app, using the code: jsconf',
  },
  {
    company: 'slippbarinn',
    discount: '15% off drinks',
    description: null,
  },
  {
    company: 'zo-on',
    discount: '30% off',
    description: null,
  },
]

export default discounts.sort((a, b) => {
  const companyA = a.company
  const companyB = b.company

  if (companyA < companyB) {
    return -1
  }

  if (companyA > companyB) {
    return 1
  }

  return 0
})
<commit_msg>Add hard rock discount<commit_after>const discounts = [
  {
    company: 'satt',
    discount: '15% off food',
    description:
      'Satt breakfast buffet from 6:30-10:00, lunch buffet from 11:30-14:30 and dinner buffet from 18:00-22:00. Satt also has a brunch on weekends between 11:30 and 14:00. Happy Hour at Satt, everyday between 16:00 and 18:00.',
  },
  {
    company: 'austur',
    discount: 'Drinks: 2 for 1',
    description:
      '2 for 1 of almost everything from 23:00 on Thursday, Friday and Saturday.',
  },
  {
    company: 'islenski-barinn',
    discount: '15% off food and a large beer for 800kr.',
    description: '15% off menu - doesn’t apply to other offers.',
  },
  {
    company: 'subway',
    discount: '10% off food',
    description: null,
  },
  {
    company: 'matarkjallarinn',
    discount: '15% off food',
    description: 'These days we offer a 4 course Food & Fun festival menu.',
  },
  {
    company: 'sjavargrillid',
    discount: '20% off food',
    description: 'Applies both for lunch and dinner menu.',
  },
  {
    company: 'fiskfelagid',
    discount: '10% off food and drinks',
    description: null,
  },
  {
    company: 'xo-food',
    discount: '15% off food and drinks',
    description: null,
  },
  {
    company: 'js-watch',
    discount: '15% off ARC-TIC',
    description: '15% off Iceland ARC-TIC watches. See www.arc-tic.com',
  },
  {
    company: 'tales-from-iceland',
    discount: '25% off',
    description: null,
  },
  {
    company: 'handprjonasambandid',
    discount: '7.5% off',
    description: null,
  },
  {
    company: 'lemon',
    discount: '2 for 1',
    description: null,
  },
  {
    company: 'dominos',
    discount: '30% off',
    description: 'Only applies if ordered online, or through the app, using the code: jsconf',
  },
  {
    company: 'slippbarinn',
    discount: '15% off drinks',
    description: null,
  },
  {
    company: 'zo-on',
    discount: '30% off',
    description: null,
  },
  {
    company: 'hard-rock',
    discount: '20% off',
    description: null,
  },
]

export default discounts.sort((a, b) => {
  const companyA = a.company
  const companyB = b.company

  if (companyA < companyB) {
    return -1
  }

  if (companyA > companyB) {
    return 1
  }

  return 0
})
<|endoftext|>


<commit_before>'use strict';

angular.module('hosts', ['ngRoute'])
    .config(['$routeProvider', function ($routeProvider) {
        $routeProvider.when('/hosts', {
            templateUrl: 'app/hosts/hosts.html',
            controller: 'HostCtrl'
        });
    }])
    .controller('HostCtrl', ['$rootScope', '$scope', '$location', '$timeout', 'HostService', 'Helpers', 'Docker', function ($rootScope, $scope, $location, $timeout, HostService, Helpers, Docker) {
        // do we have previously set ping interval?
        if (!hasOwnProperty.call($rootScope, 'lastPingInterval')) {
            // no, initialize
            $rootScope.lastPingInterval = 60000;
        }
        $scope.pingInterval = $rootScope.lastPingInterval;

        var hosts = [];
        try {
            hosts = HostService.load();
        } catch (err) {
            console.log("Error loading hosts data: " + err);
        }

        hosts.forEach(function (host) {
            host.status = false;
            host.editHostEnabled = false;
            host.selected = false;

            if (!Helpers.isEmpty($rootScope.hostUrl)) {
                host.selected = (host.url == $rootScope.hostUrl);
            }
        });
        $scope.hosts = hosts;

        function pingHost(host) {
            Docker.ping(host.url).get(function () {
                host.status = true;
                if (host.defaultConnection) {
                    selectHost(host);
                    host.selected = true;
                }
            }, function () {
                setDisabledHost(host);
            });
        }

        function selectHost(host) {
            host.selected = true;
            setActiveHost(host);
        }

        function saveHosts() {
            $scope.hosts = hosts;
            HostService.save($scope.hosts);
        }

        function setActiveHost(host) {
            $rootScope.hostUrl = host.url;
            host.lastConnected = new Date();
            saveHosts();
        }

        function setDisabledHost(host) {
            host.status = false;
            host.selected = false;
            if ($rootScope.hostUrl === host.url) {
                $rootScope.hostUrl = null;
            }
        }

        $scope.validateUrl = function (host) {
            var prefix = 'http://';
            if (host.url.substr(0, prefix.length) !== prefix) {
                host.url = prefix + host.url;
            }
            pingHost(host);
        };

        $scope.$on("$destroy", function () {
            $rootScope.tick = false;
        });

        function tick() {
            if ($rootScope.tick == true) {
                hosts.forEach(function (host) {
                    pingHost(host);

                });

                var interval = parseInt($scope.pingInterval);
                if (isNaN(interval) || interval < 1000) {
                    interval = $rootScope.lastPingInterval;
                } else {
                    $rootScope.lastPingInterval = $scope.pingInterval;
                }
                $timeout(tick, interval);
            }
        }

        $scope.setDefaultHost = function (host) {
            var originalState = host.defaultConnection;
            hosts.forEach(function (_host) {
                _host.defaultConnection = false;
            });
            host.defaultConnection = !originalState;
            saveHosts();
        };

        $scope.goContainers = function (host) {
            selectHost(host);
            $location.path('/containers');
        };

        $scope.goHostDetails = function (host) {
            selectHost(host);
            $location.path('/hostDetails');
        };

        $scope.addHost = function () {
            if (!Helpers.isEmpty($scope.newHostName) && !Helpers.isEmpty($scope.newHostUrl)) {
                var host = {};
                host.id = Helpers.newId();
                host.name = $scope.newHostName;
                host.url = $scope.newHostUrl;
                host.created = new Date();
                host.lastConnected = null;
                host.status = false;
                host.defaultConnection = false;
                host.selected = false;
                hosts.push(host);

                saveHosts();
                pingHost(host);
            }
        };

        $scope.saveHost = function (host) {
            if (host.editHostEnabled) {
                host.name = host.editHostName;
                host.url = host.editHostUrl;
                saveHosts();
                pingHost(host);
            } else {
                host.editHostName = host.name;
                host.editHostUrl = host.url;
            }
            host.editHostEnabled = !host.editHostEnabled;
        };

        $scope.removeHost = function (deleteHost) {
            hosts.forEach(function (host, index, object) {
                if (host.id === deleteHost.id) {
                    object.splice(index, 1);
                }
            });
            saveHosts();
        };

        $scope.updateStatus = function () {
            $rootScope.tick = true;
            tick();
        };

        if (!hasOwnProperty.call($rootScope, 'tick') || $rootScope.tick == false) {
            $scope.updateStatus();
        }

    }])
;<commit_msg>0.1.4 - Fix: default connection issue (two green buttons on hosts view)<commit_after>'use strict';

angular.module('hosts', ['ngRoute'])
    .config(['$routeProvider', function ($routeProvider) {
        $routeProvider.when('/hosts', {
            templateUrl: 'app/hosts/hosts.html',
            controller: 'HostCtrl'
        });
    }])
    .controller('HostCtrl', ['$rootScope', '$scope', '$location', '$timeout', 'HostService', 'Helpers', 'Docker', function ($rootScope, $scope, $location, $timeout, HostService, Helpers, Docker) {
        // do we have previously set ping interval?
        if (!hasOwnProperty.call($rootScope, 'lastPingInterval')) {
            // no, initialize
            $rootScope.lastPingInterval = 60000;
        }
        $scope.pingInterval = $rootScope.lastPingInterval;

        var hosts = [];
        try {
            hosts = HostService.load();
        } catch (err) {
            console.log("Error loading hosts data: " + err);
        }

        hosts.forEach(function (host) {
            host.status = false;
            host.editHostEnabled = false;
            host.selected = false;

            if (!Helpers.isEmpty($rootScope.hostUrl)) {
                host.selected = (host.url == $rootScope.hostUrl);
            }
        });
        $scope.hosts = hosts;

        function pingHost(host) {
            Docker.ping(host.url).get(function () {
                host.status = true;
                if (host.defaultConnection && Helpers.isEmpty($rootScope.hostUrl)) {
                    selectHost(host);
                    host.selected = true;
                }
            }, function () {
                setDisabledHost(host);
            });
        }

        function selectHost(host) {
            host.selected = true;
            setActiveHost(host);
        }

        function saveHosts() {
            $scope.hosts = hosts;
            HostService.save($scope.hosts);
        }

        function setActiveHost(host) {
            $rootScope.hostUrl = host.url;
            host.lastConnected = new Date();
            saveHosts();
        }

        function setDisabledHost(host) {
            host.status = false;
            host.selected = false;
            if ($rootScope.hostUrl === host.url) {
                $rootScope.hostUrl = null;
            }
        }

        $scope.validateUrl = function (host) {
            var prefix = 'http://';
            if (host.url.substr(0, prefix.length) !== prefix) {
                host.url = prefix + host.url;
            }
            pingHost(host);
        };

        $scope.$on("$destroy", function () {
            $rootScope.tick = false;
        });

        function tick() {
            if ($rootScope.tick == true) {
                hosts.forEach(function (host) {
                    pingHost(host);

                });

                var interval = parseInt($scope.pingInterval);
                if (isNaN(interval) || interval < 1000) {
                    interval = $rootScope.lastPingInterval;
                } else {
                    $rootScope.lastPingInterval = $scope.pingInterval;
                }
                $timeout(tick, interval);
            }
        }

        $scope.setDefaultHost = function (host) {
            var originalState = host.defaultConnection;
            hosts.forEach(function (_host) {
                _host.defaultConnection = false;
            });
            host.defaultConnection = !originalState;
            saveHosts();
        };

        $scope.goContainers = function (host) {
            selectHost(host);
            $location.path('/containers');
        };

        $scope.goHostDetails = function (host) {
            selectHost(host);
            $location.path('/hostDetails');
        };

        $scope.addHost = function () {
            if (!Helpers.isEmpty($scope.newHostName) && !Helpers.isEmpty($scope.newHostUrl)) {
                var host = {};
                host.id = Helpers.newId();
                host.name = $scope.newHostName;
                host.url = $scope.newHostUrl;
                host.created = new Date();
                host.lastConnected = null;
                host.status = false;
                host.defaultConnection = false;
                host.selected = false;
                hosts.push(host);

                saveHosts();
                pingHost(host);
            }
        };

        $scope.saveHost = function (host) {
            if (host.editHostEnabled) {
                host.name = host.editHostName;
                host.url = host.editHostUrl;
                saveHosts();
                pingHost(host);
            } else {
                host.editHostName = host.name;
                host.editHostUrl = host.url;
            }
            host.editHostEnabled = !host.editHostEnabled;
        };

        $scope.removeHost = function (deleteHost) {
            hosts.forEach(function (host, index, object) {
                if (host.id === deleteHost.id) {
                    object.splice(index, 1);
                }
            });
            saveHosts();
        };

        $scope.updateStatus = function () {
            $rootScope.tick = true;
            tick();
        };

        if (!hasOwnProperty.call($rootScope, 'tick') || $rootScope.tick == false) {
            $scope.updateStatus();
        }

    }])
;<|endoftext|>


<commit_before>const Debug = require('debug')
const path = require('path')
const globalDirs = require('global-dirs')
const { drawBox } = require('@prisma/sdk/dist/drawBox')
const isInstalledGlobally = require('is-installed-globally')
const debug = Debug('preinstall')

const BOLD = '\u001b[1m'
const WHITE_BRIGHT = '\u001b[37;1m'
const RESET = '\u001b[0m'

// returns { pkgManager: 'yarn' | 'npm', pkgPath: string } | null
function isPackageInstalledGlobally(name) {
  try {
    const pkgPath = require.resolve(path.join(globalDirs.yarn.packages, `${name}/package.json`))
    return { pkgManager: 'yarn', pkgPath }
  } catch (_) {
    try {
      const pkgPath = require.resolve(path.join(globalDirs.npm.packages, `${name}/package.json`))
      return { pkgManager: 'npm', pkgPath }
    } catch (_) {
      //
    }
  }
  return null
}

function prismaIsInstalledGlobally() {
  const prismaInstalledGlobally = isPackageInstalledGlobally('prisma')
  if (prismaInstalledGlobally) {
    return {
      ...prismaInstalledGlobally,
      name: 'prisma',
    }
  }

  const prisma2InstalledGlobally = isPackageInstalledGlobally('prisma2')
  if (prisma2InstalledGlobally) {
    return {
      ...prisma2InstalledGlobally,
      name: 'prisma2',
    }
  }

  return null
}

const b = str => BOLD + str + RESET
const white = str => WHITE_BRIGHT + str + RESET

// When running in npx, npm puts this package into a /_npx/ folder. Tested on Win, Mac, Linux
if (__dirname.includes('_npx')) {
  process.exit(0)
}

if (!isInstalledGlobally) {
  process.exit(0)
}

const installedGlobally = prismaIsInstalledGlobally()
debug({ installedGlobally })
if (!installedGlobally) {
  process.exit(0)
}

const pkg = require(installedGlobally.pkgPath)
const parts = pkg.version.split('-')
const isAlpha = parts.length > 1 ? parts[1].split('.') === 'alpha' : false

let message
if (installedGlobally.name === 'prisma2') {
  message = `
The package ${white('prisma2')} has been renamed to ${white('@prisma/cli')}.

Please uninstall ${white('prisma2')} globally first.
Then install ${white('@prisma/cli')} to continue using ${b('Prisma 2.0')}:

   # Uninstall old CLI
   ${white(installedGlobally.pkgManager === 'yarn' ? 'yarn global remove prisma2' : 'npm uninstall -g prisma2')}

   # Install new CLI
   ${white(`npm install @prisma/cli${isAlpha ? '@alpha' : ''} --save-dev`)}

   # Invoke via npx
   ${white('npx prisma --help')}

Learn more here: https://pris.ly/preview025
`
} else {
  message = `
You seem to have a global installation of Prisma 1 package ${white('prisma')}.
As Prisma 2 uses the same executable ${white('prisma')}, this would lead to a conflict.
We created a new Prisma 1 package ${white('prisma1')} with the executable ${white('prisma1')}
to work around this that you can keep using for Prisma 1.

   # Uninstall old Prisma 1 CLI
   ${white(installedGlobally.pkgManager === 'yarn' ? 'yarn global remove prisma2' : 'npm uninstall -g prisma2')}

   # Install new Prisma 1 CLI
   ${white(installedGlobally.pkgManager === 'yarn' ? 'yarn global add prisma1' : 'npm install -g prisma1')}

   # Use the Prisma 1 CLI
   prisma1 --help

Then you can install Prisma 2:

   # Install Prisma 2 CLI
   ${white(`npm install @prisma/cli${isAlpha ? '@alpha' : ''} --save-dev`)}

   # Invoke via npx
   ${white('npx prisma --help')}

Learn more here: https://pris.ly/prisma1
`
}

console.error(drawBox({ str: message, verticalPadding: 1, horizontalPadding: 3 }))
process.exit(1)
<commit_msg>fix preinstall<commit_after>const Debug = require('debug')
const path = require('path')
const globalDirs = require('global-dirs')
const { drawBox } = require('@prisma/sdk/dist/drawBox')
const isInstalledGlobally = require('is-installed-globally')
const debug = Debug('preinstall')

const BOLD = '\u001b[1m'
const WHITE_BRIGHT = '\u001b[37;1m'
const RESET = '\u001b[0m'

// returns { pkgManager: 'yarn' | 'npm', pkgPath: string } | null
function isPackageInstalledGlobally(name) {
  try {
    const pkgPath = require.resolve(path.join(globalDirs.yarn.packages, `${name}/package.json`))
    return { pkgManager: 'yarn', pkgPath }
  } catch (_) {
    try {
      const pkgPath = require.resolve(path.join(globalDirs.npm.packages, `${name}/package.json`))
      return { pkgManager: 'npm', pkgPath }
    } catch (_) {
      //
    }
  }
  return null
}

function prismaIsInstalledGlobally() {
  const prismaInstalledGlobally = isPackageInstalledGlobally('prisma')
  if (prismaInstalledGlobally) {
    return {
      ...prismaInstalledGlobally,
      name: 'prisma',
    }
  }

  const prisma2InstalledGlobally = isPackageInstalledGlobally('prisma2')
  if (prisma2InstalledGlobally) {
    return {
      ...prisma2InstalledGlobally,
      name: 'prisma2',
    }
  }

  return null
}

const b = str => BOLD + str + RESET
const white = str => WHITE_BRIGHT + str + RESET

// When running in npx, npm puts this package into a /_npx/ folder. Tested on Win, Mac, Linux
if (__dirname.includes('_npx')) {
  process.exit(0)
}

if (!isInstalledGlobally) {
  process.exit(0)
}

const installedGlobally = prismaIsInstalledGlobally()
debug({ installedGlobally })
if (!installedGlobally) {
  process.exit(0)
}

const pkg = require(installedGlobally.pkgPath)
const parts = pkg.version.split('-')
const isAlpha = parts.length > 1 ? parts[1].split('.') === 'alpha' : false

let message
if (installedGlobally.name === 'prisma2') {
  message = `
The package ${white('prisma2')} has been renamed to ${white('@prisma/cli')}.

Please uninstall ${white('prisma2')} globally first.
Then install ${white('@prisma/cli')} to continue using ${b('Prisma 2.0')}:

   # Uninstall old CLI
   ${white(installedGlobally.pkgManager === 'yarn' ? 'yarn global remove prisma2' : 'npm uninstall -g prisma2')}

   # Install new CLI
   ${white(`npm install @prisma/cli${isAlpha ? '@alpha' : ''} --save-dev`)}

   # Invoke via npx
   ${white('npx prisma --help')}

Learn more here: https://pris.ly/preview025
`
} else {
  message = `
You seem to have a global installation of Prisma 1 package ${white('prisma')}.
As Prisma 2 uses the same executable ${white('prisma')}, this would lead to a conflict.

To keep using Prisma 1, install the new package ${white('prisma1')} that we created.
It exposes the executable ${white('prisma1')}.

   # Uninstall old Prisma 1 CLI
   ${white(installedGlobally.pkgManager === 'yarn' ? 'yarn global remove prisma2' : 'npm uninstall -g prisma2')}

   # Install new Prisma 1 CLI
   ${white(installedGlobally.pkgManager === 'yarn' ? 'yarn global add prisma1' : 'npm install -g prisma1')}

   # Use the Prisma 1 CLI
   ${white('prisma1 --help')}

Then you can install Prisma 2:

   # Install Prisma 2 CLI
   ${white(`npm install @prisma/cli${isAlpha ? '@alpha' : ''} --save-dev`)}

   # Invoke via npx
   ${white('npx prisma --help')}

Learn more here: https://pris.ly/prisma1
`
}

console.error(drawBox({ str: message, verticalPadding: 1, horizontalPadding: 3 }))
process.exit(1)
<|endoftext|>


<commit_before>const refresh = require('./lib/refresh');
const bot = require('./bot.js');
const settings = require('./../settings.json');
const modules = require('./modules.js');
const Message = require('./../orm/Message')
const commands = require('./commands');
const request = require('request-promise-native');
const influx = require('./../influx');

let lock = false;
let ready = false;
bot.on('error', (err) => {
    /**
     * Catch errors here
     */
    console.log("Stack Trace: " + err.stack);
})
process.on('unhandledRejection', (err) => {
    console.log("UNHANDLED REJECTION AT " + err.stack);
    if (err.toString().includes('Request to use token, but token was unavailable to the client'))
        process.exit();//restart
});
process.on('uncaughtException', (err) => console.log("UNHANDLED EXCEPTION AT " + err.stack));
bot.on('message', async function (message) {
    /**
     * if locked, reject everything except dm
     */
    new Message({
        messageID: message.id,
        channel: message.channel.id
    }).save();
    if (lock) {
        if (!settings.owners.includes(message.author.id))
            //  if (message.channel.guild)
            return;//not DM
    }
    /**
     * Listen to messages and convert into params
     */
    if (message.member && message.member != null) {
        let muted = message.member.roles.find(function (r) {
            if (r.name.toLowerCase().includes('mute') && !r.name.toLowerCase().includes('non') && !r.name.toLowerCase().includes('test')) return r
        })
        if (muted && message.deletable )
            message.delete();
    }

    if (message.author.bot) return;

    if (message.content.startsWith(settings.identifier)) {
        /**Extracting params */
        let params = message.content.substring(settings.identifier.length).trim();
        params = params.split(settings.delimiter || ' ');
        let cmd = params.shift().trim();
        commands.execute(cmd.toLowerCase(), params, message)
    }
    else {
        //ignore because normal message
    }
});
bot.on('lock', () => { lock = true; });
bot.on('unlock', () => { lock = false; });
bot.on("guildMemberAdd", async function (member) {
    var user = member.user;
    if (member.guild.id === "184536578654339072") {
        if (member.user.bot) return console.log(member.user.tag + " is a bot who joined " + member.guild.name)
        if (refresh(user, true)) {
            user.send("Welcome to the Revive Network\nBecome a verified member and get exclusive benefits by linking your discord account with your Revive account\nTo link, please follow this link\nhttps://battlelog.co/discord_link.php");
        }
    }
});
bot.on("guildMemberRemove", async function (member) {
    var user = member.user;
});
/**
bot.on('disconnect', function(event) {
    if (event.code === 0) return console.error(event);
    process.exit();//force restart
});*/

bot.on('ready', async function () {
    console.log("ReviveBot Ready");
    console.log(process.versions);
    let dbs = await influx.getDatabaseNames();
    console.log(dbs);
    if (!dbs || dbs === null)
        console.log("Cant connect to influx")
    if (!dbs.includes('discord')) {
        console.log("Creating Dicord DB");
    }
    ready = true;
});
bot.on("guildMemberUpdate", async function (member, newMem) {
    let user = member.user;
    if (member.guild && (member.guild.id === "184536578654339072")) {
        let oldMem = member;
        if (!oldMem.roles.has("273105185566359562") && newMem.roles.has("273105185566359562")) return;
        if (!oldMem.roles.has("275317218911322112") && newMem.roles.has("275317218911322112")) return;
        if ((!oldMem.roles.has("184684916833779712") && newMem.roles.has("184684916833779712")) || (!oldMem.roles.has("200849956796497920") && newMem.roles.has("200849956796497920")) || (!oldMem.roles.has("184676864630063104") && newMem.roles.has("184676864630063104")) || (!oldMem.roles.has("286646245198528523") && newMem.roles.has("286646245198528523"))) {
            await request({ uri: 'http://localhost/v0/discord/reverse_link/' + user.id, method: "POST" });
        }
    }
});
setInterval(async function () {
    if (!ready) return;
    const guild = bot.guilds.get("184536578654339072");
    influx.writePoints([
        {
            measurement: 'statistics',
            fields: { count: guild.memberCount },
            tags: { type: 'members' }
        }
    ]).catch(console.log);
    let count = await Message.count();
    if (count)
        influx.writePoints([
            {
                measurement: 'statistics',
                fields: { count: count },
                tags: { type: 'messages' }
            }
        ]).catch(console.log);
    guild.roles.map(r => {
        influx.writePoints([
            {
                measurement: 'statistics',
                fields: { count: r.members.size },
                tags: { type: r.id }
            }
        ]).catch(console.log);
    });
    influx.writePoints([
        {
            measurement: 'statistics',
            fields: { count: guild.presences.filter(p => p.status != 'offline').length },
            tags: { type: "online" }
        }
    ]).catch(console.log);
}, 1000)
<commit_msg>Update listen.js<commit_after>const refresh = require('./lib/refresh');
const bot = require('./bot.js');
const settings = require('./../settings.json');
const modules = require('./modules.js');
const Message = require('./../orm/Message')
const commands = require('./commands');
const request = require('request-promise-native');
const influx = require('./../influx');

let lock = false;
let ready = false;
bot.on('error', (err) => {
    /**
     * Catch errors here
     */
    console.log("Stack Trace: " + err.stack);
})
process.on('unhandledRejection', (err) => {
    console.log("UNHANDLED REJECTION AT " + err.stack);
    if (err.toString().includes('Request to use token, but token was unavailable to the client'))
        process.exit();//restart
});
process.on('uncaughtException', (err) => console.log("UNHANDLED EXCEPTION AT " + err.stack));
bot.on('message', async function (message) {
    /**
     * if locked, reject everything except dm
     */
    new Message({
        messageID: message.id,
        channel: message.channel.id
    }).save();
    if (lock) {
        if (!settings.owners.includes(message.author.id))
            //  if (message.channel.guild)
            return;//not DM
    }
    /**
     * Listen to messages and convert into params
     */
    if (message.member && message.member != null) {
        let muted = message.member.roles.find(function (r) {
            if (r.name.toLowerCase().includes('mute') && !r.name.toLowerCase().includes('non') && !r.name.toLowerCase().includes('test')) return r
        })
        if (muted && message.deletable )
            message.delete();
    }

    if (message.author.bot) return;

    if (message.content.startsWith(settings.identifier)) {
        /**Extracting params */
        let params = message.content.substring(settings.identifier.length).trim();
        params = params.split(settings.delimiter || ' ');
        let cmd = params.shift().trim();
        commands.execute(cmd.toLowerCase(), params, message)
    }
    else {
        //ignore because normal message
    }
});
bot.on('lock', () => { lock = true; });
bot.on('unlock', () => { lock = false; });
bot.on("guildMemberAdd", async function (member) {
    var user = member.user;
    if (member.guild.id === "184536578654339072") {
        if (member.user.bot) return console.log(member.user.tag + " is a bot who joined " + member.guild.name)
        if (refresh(user, true)) {
            user.send("Welcome to the Revive Network\nBecome a verified member and get exclusive benefits by linking your discord account with your Revive account\nTo link, please follow this link\nhttps://battlelog.co/discord_link.php");
        }
    }
});
bot.on("guildMemberRemove", async function (member) {
    var user = member.user;
});
/**
bot.on('disconnect', function(event) {
    if (event.code === 0) return console.error(event);
    process.exit();//force restart
});*/

bot.on('ready', async function () {
    console.log("ReviveBot Ready");
    console.log(process.versions);
    let dbs = await influx.getDatabaseNames();
    console.log(dbs);
    if (!dbs || dbs === null)
        console.log("Cant connect to influx")
    if (!dbs.includes('discord')) {
        console.log("Creating Dicord DB");
    }
    ready = true;
});
bot.on("guildMemberUpdate", async function (member, newMem) {
    let user = member.user;
    if (member.guild && (member.guild.id === "184536578654339072")) {
        let oldMem = member;
        if (!oldMem.roles.has("273105185566359562") && newMem.roles.has("273105185566359562")) return;
        if (!oldMem.roles.has("275317218911322112") && newMem.roles.has("275317218911322112")) return;
        if ((!oldMem.roles.has("184684916833779712") && newMem.roles.has("184684916833779712")) || (!oldMem.roles.has("200849956796497920") && newMem.roles.has("200849956796497920")) || (!oldMem.roles.has("184676864630063104") && newMem.roles.has("184676864630063104")) || (!oldMem.roles.has("286646245198528523") && newMem.roles.has("286646245198528523"))) {
            await request({ uri: 'http://localhost/v0/discord/reverse_link/' + user.id, method: "POST" });
        }
    }
});
setInterval(async function () {
    if (!ready) return;
    const guild = bot.guilds.get("184536578654339072");
    influx.writePoints([
        {
            measurement: 'statistics',
            fields: { count: guild.memberCount },
            tags: { type: 'members' }
        }
    ]).catch(console.log);
    let count = await Message.count();
    if (count)
        influx.writePoints([
            {
                measurement: 'statistics',
                fields: { count: count },
                tags: { type: 'messages' }
            }
        ]).catch(console.log);
    guild.roles.map(r => {
        influx.writePoints([
            {
                measurement: 'statistics',
                fields: { count: r.members.size },
                tags: { type: r.id }
            }
        ]).catch(console.log);
    });
    influx.writePoints([
        {
            measurement: 'statistics',
            fields: { count: guild.presences.filter(p => p.status != 'offline').size },
            tags: { type: "online" }
        }
    ]).catch(console.log);
}, 1000)
<|endoftext|>


<commit_before>// Requires
var inherits = require("util").inherits;
var EventEmitter = require("events").EventEmitter;

// Utility function wrapping find command
var find = require('./find');

function Watcher(dirname, period, filter) {
    if(!(this instanceof Watcher)) {
        return new Watcher(dirname, period);
    }

    // Polling period
    this.period = period;

    // Directy to monitor
    this.dirname = dirname;

    // File filter
    this.filter = filter || defaultFilter;

    // Intervals to track
    this.dumpTimeout = null;
    this.modifiedTimeout = null;

    // Bind poll methods
    this.pollDump = this.pollDump.bind(this);
    this.pollModified = this.pollModified.bind(this);

    // Bind handler methods
    this.dumpHandler = this.dumpHandler.bind(this);
    this.deletedHandler = this.deletedHandler.bind(this);
    this.createdHandler = this.createdHandler.bind(this);
    this.modifiedHandler = this.modifiedHandler.bind(this);

    // Buffered data
    this.buffer = {
        /*
        created: [],
        deleted: [],
        modified: [],
        */
    };

    // Previous dumped tree
    this.prevTree = null;

    // Stopped state
    this.stopped = true;

    Watcher.super_.call(this);
}
inherits(Watcher, EventEmitter);

Watcher.prototype.start = function() {
    this.stopped = false;
    return this.poll();
};

Watcher.prototype.poll = function() {
    // Watcher is stopped, no longer poll
    if(this.stopped) {
        return this;
    }

    this.dumpTimeout = this.pollDump(this.dumpHandler);
    this.modifiedTimeout = this.pollModified(this.modifiedHandler);
    return this;
};

Watcher.prototype.stop = function() {
    this.stopped = true;
    clearTimeout(this.dumpTimeout);
    clearTimeout(this.modifiedTimeout);
    return this;
};

Watcher.prototype.cleanup = function() {
    return this.stop()
    .removeAllListeners('change')
    .removeAllListeners('created')
    .removeAllListeners('deleted')
    .removeAllListeners('modified');
};

Watcher.prototype.handle = function(type, files) {
    // Set changes to buffer
    this.buffer[type] = files;

    // Adjust buffer, apply corrections
    // 1. Remove created files from modified files
    if(this.buffer.created && this.buffer.modified) {
        this.buffer.modified = arrayDiff(this.buffer.modified, this.buffer.created);
    }

    // Ready to flush ?
    if(!(
        this.buffer.deleted &&
        this.buffer.created &&
        this.buffer.modified
    )) {
        return;
    }

    // Do we have data to flush ?
    if (
            this.buffer.created.length > 0 ||
            this.buffer.deleted.length > 0 ||
            this.buffer.modified.length > 0
    ) {
        // Flush buffer
        this.emit('change', this.buffer);

        // This code could be more generic
        // But I've kept as such for simplicity and readibility

        // Check if individual changes needed emitted
        if(this.buffer.created.length > 0) {
            this.emit('created', this.buffer.created);
        }
        if(this.buffer.deleted.length > 0) {
            this.emit('deleted', this.buffer.deleted);
        }
        if(this.buffer.modified.length > 0) {
            this.emit('modified', this.buffer.modified);
        }
    }

    // Clear buffer
    this.buffer = {};

    // Now start polling again
    this.poll();
};

Watcher.prototype.dumpHandler = function(err, diffs) {
    this.deletedHandler(err, err ? null : diffs[0]);
    this.createdHandler(err, err ? null : diffs[1]);
};

Watcher.prototype.modifiedHandler = function(err, files) {
    if(err) {
        return this.emit('error', err);
    }
    return this.handle('modified', files);
};

Watcher.prototype.createdHandler = function(err, files) {
    if(err) {
        return this.emit('error', err);
    }
    return this.handle('created', files);
};

Watcher.prototype.deletedHandler = function(err, files) {
    if(err) {
        return this.emit('error', err);
    }
    return this.handle('deleted', files);
};

Watcher.prototype.pollModified = function(cb) {
    var that = this;

    var shouldPrune = true;

    return setTimeout(function() {
        find.modifiedSince(that.dirname, 1, shouldPrune, function(err, files) {
            cb(err, files.filter(that.filter));
        });
    }, this.period * 1000);
};

Watcher.prototype.pollDump = function(cb) {
    var that = this;

    // Should be prune common unimportant folders ?
    // Pruning is forced by default
    // TODO: provide option to deactivate
    var shouldPrune = true;

    // Poll
    return setTimeout(function() {
        find.dump(that.dirname, shouldPrune, function(err, files) {
            // Start
            var t1 = Date.now();

            var tree = files.filter(that.filter);

            if(err) {
                return cb(err, []);
            } else if(!that.prevTree) {
                // Get first initial tree
                that.prevTree = tree;
                // Continue
                that.pollDump(cb);
                return;
            }

            // Middle
            var t2 = Date.now();

            var d = dualDiff(that.prevTree, tree);

            // End
            var t3 = Date.now();

            console.log('filter took', t2 - t1);
            console.log('diff took', t3 - t2);
            console.log('Total', t3 - t1);
            console.log('# total', files.length);
            console.log('# filtered', tree.length);
            console.log();

            // Retun data
            cb(null, d);

            // Make current tree the previous
            that.prevTree = tree;
        });
    }, this.period/2 * 1000);
};

function defaultFilter(filepath) {
    // Ignore files/folders starting with "."
    return filepath.match(/(^\.)|(\/\.)|(\\\.)/) === null;
}

// Utility diff function
// TODO: improve speed
function arrayDiff(a1, a2) {
  var o1={}, o2={}, diff=[], i, len, k;
  for (i=0, len=a1.length; i<len; i++) { o1[a1[i]] = true; }
  for (i=0, len=a2.length; i<len; i++) { o2[a2[i]] = true; }
  for (k in o1) { if (!(k in o2)) { diff.push(k); } }
  //for (k in o2) { if (!(k in o1)) { diff.push(k); } }
  return diff;
}

// Returns both the left and right diff seperately
function dualDiff(a1, a2) {
  var o1={}, o2={}, diff1=[], diff2=[], i, len, k;
  for (i=0, len=a1.length; i<len; i++) { o1[a1[i]] = true; }
  for (i=0, len=a2.length; i<len; i++) { o2[a2[i]] = true; }
  for (k in o1) { if (!(k in o2)) { diff1.push(k); } }
  for (k in o2) { if (!(k in o1)) { diff2.push(k); } }
  return [diff1, diff2];
}

// Exports
module.exports = Watcher;
<commit_msg>Remove debug logs<commit_after>// Requires
var inherits = require("util").inherits;
var EventEmitter = require("events").EventEmitter;

// Utility function wrapping find command
var find = require('./find');

function Watcher(dirname, period, filter) {
    if(!(this instanceof Watcher)) {
        return new Watcher(dirname, period);
    }

    // Polling period
    this.period = period;

    // Directy to monitor
    this.dirname = dirname;

    // File filter
    this.filter = filter || defaultFilter;

    // Intervals to track
    this.dumpTimeout = null;
    this.modifiedTimeout = null;

    // Bind poll methods
    this.pollDump = this.pollDump.bind(this);
    this.pollModified = this.pollModified.bind(this);

    // Bind handler methods
    this.dumpHandler = this.dumpHandler.bind(this);
    this.deletedHandler = this.deletedHandler.bind(this);
    this.createdHandler = this.createdHandler.bind(this);
    this.modifiedHandler = this.modifiedHandler.bind(this);

    // Buffered data
    this.buffer = {
        /*
        created: [],
        deleted: [],
        modified: [],
        */
    };

    // Previous dumped tree
    this.prevTree = null;

    // Stopped state
    this.stopped = true;

    Watcher.super_.call(this);
}
inherits(Watcher, EventEmitter);

Watcher.prototype.start = function() {
    this.stopped = false;
    return this.poll();
};

Watcher.prototype.poll = function() {
    // Watcher is stopped, no longer poll
    if(this.stopped) {
        return this;
    }

    this.dumpTimeout = this.pollDump(this.dumpHandler);
    this.modifiedTimeout = this.pollModified(this.modifiedHandler);
    return this;
};

Watcher.prototype.stop = function() {
    this.stopped = true;
    clearTimeout(this.dumpTimeout);
    clearTimeout(this.modifiedTimeout);
    return this;
};

Watcher.prototype.cleanup = function() {
    return this.stop()
    .removeAllListeners('change')
    .removeAllListeners('created')
    .removeAllListeners('deleted')
    .removeAllListeners('modified');
};

Watcher.prototype.handle = function(type, files) {
    // Set changes to buffer
    this.buffer[type] = files;

    // Adjust buffer, apply corrections
    // 1. Remove created files from modified files
    if(this.buffer.created && this.buffer.modified) {
        this.buffer.modified = arrayDiff(this.buffer.modified, this.buffer.created);
    }

    // Ready to flush ?
    if(!(
        this.buffer.deleted &&
        this.buffer.created &&
        this.buffer.modified
    )) {
        return;
    }

    // Do we have data to flush ?
    if (
            this.buffer.created.length > 0 ||
            this.buffer.deleted.length > 0 ||
            this.buffer.modified.length > 0
    ) {
        // Flush buffer
        this.emit('change', this.buffer);

        // This code could be more generic
        // But I've kept as such for simplicity and readibility

        // Check if individual changes needed emitted
        if(this.buffer.created.length > 0) {
            this.emit('created', this.buffer.created);
        }
        if(this.buffer.deleted.length > 0) {
            this.emit('deleted', this.buffer.deleted);
        }
        if(this.buffer.modified.length > 0) {
            this.emit('modified', this.buffer.modified);
        }
    }

    // Clear buffer
    this.buffer = {};

    // Now start polling again
    this.poll();
};

Watcher.prototype.dumpHandler = function(err, diffs) {
    this.deletedHandler(err, err ? null : diffs[0]);
    this.createdHandler(err, err ? null : diffs[1]);
};

Watcher.prototype.modifiedHandler = function(err, files) {
    if(err) {
        return this.emit('error', err);
    }
    return this.handle('modified', files);
};

Watcher.prototype.createdHandler = function(err, files) {
    if(err) {
        return this.emit('error', err);
    }
    return this.handle('created', files);
};

Watcher.prototype.deletedHandler = function(err, files) {
    if(err) {
        return this.emit('error', err);
    }
    return this.handle('deleted', files);
};

Watcher.prototype.pollModified = function(cb) {
    var that = this;

    var shouldPrune = true;

    return setTimeout(function() {
        find.modifiedSince(that.dirname, 1, shouldPrune, function(err, files) {
            cb(err, files.filter(that.filter));
        });
    }, this.period * 1000);
};

Watcher.prototype.pollDump = function(cb) {
    var that = this;

    // Should be prune common unimportant folders ?
    // Pruning is forced by default
    // TODO: provide option to deactivate
    var shouldPrune = true;

    // Poll
    return setTimeout(function() {
        find.dump(that.dirname, shouldPrune, function(err, files) {
            var tree = files.filter(that.filter);

            if(err) {
                return cb(err, []);
            } else if(!that.prevTree) {
                // Get first initial tree
                that.prevTree = tree;
                // Continue
                that.pollDump(cb);
                return;
            }

            // Get deleted and created files
            var d = dualDiff(that.prevTree, tree);

            // Retun data
            cb(null, d);

            // Make current tree the previous
            that.prevTree = tree;
        });
    }, this.period/2 * 1000);
};

function defaultFilter(filepath) {
    // Ignore files/folders starting with "."
    return filepath.match(/(^\.)|(\/\.)|(\\\.)/) === null;
}

// Utility diff function
// TODO: improve speed
function arrayDiff(a1, a2) {
  var o1={}, o2={}, diff=[], i, len, k;
  for (i=0, len=a1.length; i<len; i++) { o1[a1[i]] = true; }
  for (i=0, len=a2.length; i<len; i++) { o2[a2[i]] = true; }
  for (k in o1) { if (!(k in o2)) { diff.push(k); } }
  //for (k in o2) { if (!(k in o1)) { diff.push(k); } }
  return diff;
}

// Returns both the left and right diff seperately
function dualDiff(a1, a2) {
  var o1={}, o2={}, diff1=[], diff2=[], i, len, k;
  for (i=0, len=a1.length; i<len; i++) { o1[a1[i]] = true; }
  for (i=0, len=a2.length; i<len; i++) { o2[a2[i]] = true; }
  for (k in o1) { if (!(k in o2)) { diff1.push(k); } }
  for (k in o2) { if (!(k in o1)) { diff2.push(k); } }
  return [diff1, diff2];
}

// Exports
module.exports = Watcher;
<|endoftext|>


<commit_before>import { combineReducers } from 'redux'

function tasks(tasks = [], action) {
  switch (action.type) {
    case 'TASKS_EMPTY':
      return []
    case 'TASKS_UPDATE':
      const tasksById = {}

      // Add the existing tasks
      tasks.forEach(task => (tasksById[task.id] = task))

      // Update tasks with new values and add new tasks
      action.tasks.forEach(task => {
        tasksById[task.id] = Object.assign({}, tasksById[task.id], task)
      })

      const updatedTasks = Object.keys(tasksById)
        .map(taskId => tasksById[taskId])
        .sort((a, b) => b.updatedAt - a.updatedAt) // Sort by updatedAt DESC

      return updatedTasks
    case 'TASKS_SELECT':
      return tasks.map(task => {
        if (task.id === action.task.id) {
          return Object.assign({}, task, { isSelected: true })
        }
        return task
      })
    case 'TASKS_DESELECT':
      return tasks.map(task => {
        if (task.id === action.task.id) {
          return Object.assign({}, task, { isSelected: false })
        }
        return task
      })
    case 'TASKS_SNOOZE':
      return tasks.map(task => {
        if (task.isSelected) {
          return Object.assign({}, task, { snooze: true })
        }
        return task
      })
    default:
      return tasks
  }
}

module.exports = combineReducers({
  tasks,
})
<commit_msg>Refactor reducer<commit_after>import { combineReducers } from 'redux'

function updateTasks(tasks, action) {
  const tasksById = {}

  // Add the existing tasks
  tasks.forEach(task => (tasksById[task.id] = task))

  // Update tasks with new values and add new tasks
  action.tasks.forEach(task => {
    tasksById[task.id] = Object.assign({}, tasksById[task.id], task)
  })

  const updatedTasks = Object.keys(tasksById)
    .map(taskId => tasksById[taskId])
    .sort((a, b) => b.updatedAt - a.updatedAt) // Sort by updatedAt DESC

  return updatedTasks
}

function selectTasks(tasks, action) {
  return tasks.map(task => {
    if (task.id === action.task.id) {
      return Object.assign({}, task, { isSelected: true })
    }
    return task
  })
}

function deselectTasks(tasks, action) {
  return tasks.map(task => {
    if (task.id === action.task.id) {
      return Object.assign({}, task, { isSelected: false })
    }
    return task
  })
}

function snoozeTasks(tasks) {
  return tasks.map(task => {
    if (task.isSelected) {
      return Object.assign({}, task, { snooze: true })
    }
    return task
  })
}

function tasksReducer(tasks = [], action) {
  switch (action.type) {
    case 'TASKS_EMPTY':
      return []
    case 'TASKS_UPDATE':
      return updateTasks(tasks, action)
    case 'TASKS_SELECT':
      return selectTasks(tasks, action)
    case 'TASKS_DESELECT':
      return deselectTasks(tasks, action)
    case 'TASKS_SNOOZE':
      return snoozeTasks(tasks)
    default:
      return tasks
  }
}

module.exports = combineReducers({
  tasks: tasksReducer,
})
<|endoftext|>


<commit_before>import React, {PropTypes} from 'react';

const SlackConfig = React.createClass({
  propTypes: {
    config: PropTypes.shape({
      options: PropTypes.shape({
        url: PropTypes.bool.isRequired,
        channel: PropTypes.string.isRequired,
      }).isRequired,
    }).isRequired,
    onSave: PropTypes.func.isRequired,
    onTest: PropTypes.func.isRequired,
  },

  getInitialState() {
    return {
      testEnabled: !!this.props.config.options.url,
    };
  },

  componentWillReceiveProps(nextProps) {
    this.setState({
      testEnabled: !!nextProps.config.options.url,
    });
  },

  handleSaveAlert(e) {
    e.preventDefault();

    const properties = {
      url: this.url.value,
      channel: this.channel.value,
    };

    this.props.onSave(properties);
  },

  render() {
    const {url, channel} = this.props.config.options;

    return (

Slack Alert

        <form onSubmit={this.handleSaveAlert}>

                Post alerts to a Slack channel.

                Slack Webhook URL (see more on Slack webhooks)
                <input className="form-control" id="slack-url" type="text" ref={(r) => this.url = r} defaultValue={url || ''}></input>
                Note: a value of true indicates that the Slack channel has been set

                Slack Channel (optional)
                <input className="form-control" id="slack-channel" type="text" placeholder="#alerts" ref={(r) => this.channel = r} defaultValue={channel || ''}></input>

              Send Test Message

              <button className="btn btn-block btn-primary" type="submit">Save</button>

        </form>

    );
  },
});

export default SlackConfig;
<commit_msg>Switch order of save and test buttons for slack<commit_after>import React, {PropTypes} from 'react';

const SlackConfig = React.createClass({
  propTypes: {
    config: PropTypes.shape({
      options: PropTypes.shape({
        url: PropTypes.bool.isRequired,
        channel: PropTypes.string.isRequired,
      }).isRequired,
    }).isRequired,
    onSave: PropTypes.func.isRequired,
    onTest: PropTypes.func.isRequired,
  },

  getInitialState() {
    return {
      testEnabled: !!this.props.config.options.url,
    };
  },

  componentWillReceiveProps(nextProps) {
    this.setState({
      testEnabled: !!nextProps.config.options.url,
    });
  },

  handleSaveAlert(e) {
    e.preventDefault();

    const properties = {
      url: this.url.value,
      channel: this.channel.value,
    };

    this.props.onSave(properties);
  },

  render() {
    const {url, channel} = this.props.config.options;

    return (

Slack Alert

        <form onSubmit={this.handleSaveAlert}>

                Post alerts to a Slack channel.

                Slack Webhook URL (see more on Slack webhooks)
                <input className="form-control" id="slack-url" type="text" ref={(r) => this.url = r} defaultValue={url || ''}></input>
                Note: a value of true indicates that the Slack channel has been set

                Slack Channel (optional)
                <input className="form-control" id="slack-channel" type="text" placeholder="#alerts" ref={(r) => this.channel = r} defaultValue={channel || ''}></input>

              <button className="btn btn-block btn-primary" type="submit">Save</button>

              Send Test Message

        </form>

    );
  },
});

export default SlackConfig;
<|endoftext|>


<commit_before>if (typeof require === "function") {
    var bigInt = require("big-integer");
    var getRandomValues = require('get-random-values');
    var UTF8 = require('utf-8');
}

var _sssa_utils = (function (root) {
    var prime = bigInt("115792089237316195423570985008687907853269984665640564039457584007913129639747");

    function random() {
        var bytes = new Uint8Array(32),
            string = "",
            i = 0;

        getRandomValues(bytes)
        for (i in bytes) {
            string += Array((2 - bytes[i].toString(16).length) + 1).join(0) + bytes[i].toString(16);
        }

        return bigInt(string, 16);
    }

    function split_ints(secrets) {
        var result = [],
            working = [],
            i = 0,
            hex_data = "";

        working = UTF8.setBytesFromString(secrets);

        for (i in working) {
            hex_data += Array((2 - working[i].toString(16).length) + 1).join(0) + working[i].toString(16);
        }

        for (i = 0; i < hex_data.length/64; i++) {
            if ((i+1)*64 < hex_data.length) {
                result[i] = bigInt(hex_data.substring(i*64, (i+1)*64), 16);
            } else {
                result[i] = bigInt(hex_data.substring(i*64) + Array(((i+1)*64 - hex_data.length)+1).join(0), 16);
            }
        }

        return result;
    }

    function merge_ints(secrets) {
        var hex_data = "",
            bytes = [],
            temp = "",
            i = 0;

        for (i in secrets) {
            temp = secrets[i].toString(16);
            temp = Array(64 - temp.length + 1).join(0) + temp;
            hex_data += temp;
        }

        hex_data = hex_data.replace(/(00){1,}$/, '');

        for (i = 0; i < hex_data.length/2; i++) {
            bytes.push(parseInt(hex_data.substring(i*2, (i+1)*2), 16));
        }

        return UTF8.getStringFromBytes(bytes);
    }

    function evaluate_polynomial(coefficients, value) {
        var result = bigInt(coefficients[0]),
            i = 0,
            tmp = bigInt(0);

        for (i = 0; i < coefficients.length; i++) {
            result = result.add(value.modPow(s, prime).multiply(coefficients[i]).mod(prime));
        }

        return result.mod(prime);
    }

    function to_base64(number) {
        var hex_data = number.toString(16),
            result = "",
            i = 0;

        hex_data = Array(64 - hex_data.length + 1).join('0') + hex_data;

        for (i = 0; i < hex_data.length/2; i++) {
            result += String.fromCharCode(parseInt(hex_data.substring(i*2, (i+1)*2), 16));
        }

        return btoa(result);
    }

    function from_base64(number) {
        var bytes = atob(number),
            hex_data = "",
            tmp = "",
            i = 0;

        for (i = 0; i < bytes.length; i++) {
            temp = bytes.charCodeAt(i).toString(16);
            temp = Array(2 - (temp.length % 3) + 1).join(0) + temp;
            hex_data += temp;
        }

        hex_data = hex_data.replace(/^(00){1,}/, '');

        return bigInt(hex_data, 16);
    }

    return {
        'random': random,
        'split_ints': split_ints,
        'merge_ints': merge_ints,
        'to_base64': to_base64,
        'from_base64': from_base64,
    }
}(this));

var _sssa = (function(root) {
    var utils = _sssa_utils;

    function create(minimum, shares, raw) {
        if (minimum < shares) {
            return;
        }

        var secret = utils.split_int(raw),
            numbers = [bigInt(0)],
            polynomial = [],
            result = [],
            i = 0,
            j = 1;

        for (i in secret) {
            polynomial.push([secret[i]]);
            for (j = 1; j < minimum; j++) {
                value = util.random();
                while (value in numbers) {
                    value = util.random();
                }
                numbers.push(value);

                polynomial[i].push(value);
            }
        }

        for (i = 0; i < shares; i++) {
            for (j in secret) {
                value = util.random();
                while (value in numbers) {
                    value = util.random();
                }
                numbers.push(value);

                if (typeof result[i] !== typeof "string") {
                    result[i] = "";
                } else {
                    result[i] += utils.to_base64(value);
                    result[i] += utils.to_base64(utils.evaluate_polynomial(polynomial[j], value));
                }
            }
        }

        return result;
    }

    function combine(shares) {
        var secrets = [],
            share = "",
            count = 0,
            cshare = "",
            secret = [],
            origin = bigInt(0),
            originy = bigInt(0),
            numerator = bigInt(1),
            denominator = bigInt(1),
            i = 0,
            j = 0,
            k = 0;

        for (i in shares) {
            if (shares[i].length % 88 != 0) {
                return;
            }

            share = shares[i];
            count = share.length / 88;
            secrets[i] = [];

            for (j = 0; j < count; j++) {
                cshare = share.substring(j*88, (j+1)*88);
                secrets[i][j] = [utils.from_base64(cshare.substring(0, 44)), utils.from_base64(cshare.substring(44))];
            }
        }

        for (j = 0; j < secrets[0].length; j++) {
            secret[j] = bigInt(0);
            for (i in secrets) {
                origin = secrets[i][j][0];
                originy = secrets[i][j][1];
                numerator = bigInt(1);
                denominator = bigInt(1);

                for (k in secrets) {
                    if (k !== i) {
                        numerator = numerator.multiply(secrets[k][j][0].multiply(-1)).mod(utils.prime);
                        denominator = denominator.multiply(origin.subtract(secrets[k][j][0])).mod(utils.prime);
                    }
                }

                secret[j] = secret[j].add(originy.multiply(numerator).mod(utils.prime).multiply(denominator).mod(utils.prime)).mod(utils.prime);
            }
        }

        return utils.merge_int(secret);
    }

    return sssa = {
        'create': create,
        'combine': combine
    };
}(this));

// Node.js check
if (typeof module !== "undefined" && module.hasOwnProperty("exports")) {
    var sssa = _sssa;
    module.exports = sssa;
} else {
    sssa = _sssa;
}
<commit_msg>Finished library; broken changes<commit_after>if (typeof require === "function") {
    var bigInt = require("big-integer");
    var getRandomValues = require('get-random-values');
    var UTF8 = require('utf-8');
}

var _sssa_utils = (function (root) {
    var prime = bigInt("115792089237316195423570985008687907853269984665640564039457584007913129639747");

    function random() {
        var bytes = new Uint8Array(32),
            string = "",
            i = 0;

        getRandomValues(bytes)
        for (i in bytes) {
            string += Array((2 - bytes[i].toString(16).length) + 1).join(0) + bytes[i].toString(16);
        }

        return bigInt(string, 16);
    }

    function split_ints(secrets) {
        var result = [],
            working = [],
            i = 0,
            hex_data = "";

        working = UTF8.setBytesFromString(secrets);

        for (i in working) {
            hex_data += Array((2 - working[i].toString(16).length) + 1).join(0) + working[i].toString(16);
        }

        for (i = 0; i < hex_data.length/64; i++) {
            if ((i+1)*64 < hex_data.length) {
                result[i] = bigInt(hex_data.substring(i*64, (i+1)*64), 16);
            } else {
                result[i] = bigInt(hex_data.substring(i*64) + Array(((i+1)*64 - hex_data.length)+1).join(0), 16);
            }
        }

        return result;
    }

    function merge_ints(secrets) {
        var hex_data = "",
            bytes = [],
            temp = "",
            i = 0;

        for (i in secrets) {
            temp = secrets[i].toString(16);
            temp = Array(64 - temp.length + 1).join(0) + temp;
            hex_data += temp;
        }

        hex_data = hex_data.replace(/(00){1,}$/, '');

        for (i = 0; i < hex_data.length/2; i++) {
            bytes.push(parseInt(hex_data.substring(i*2, (i+1)*2), 16));
        }

        return UTF8.getStringFromBytes(bytes);
    }

    function evaluate_polynomial(coefficients, value) {
        var result = bigInt(coefficients[0]),
            i = 0,
            tmp = bigInt(0);

        for (i = 0; i < coefficients.length; i++) {
            result = result.add(value.modPow(s, prime).multiply(coefficients[i]).mod(prime));
        }

        return result.mod(prime);
    }

    function to_base64(number) {
        var hex_data = number.toString(16),
            result = "",
            i = 0;

        hex_data = Array(64 - hex_data.length + 1).join('0') + hex_data;

        for (i = 0; i < hex_data.length/2; i++) {
            result += String.fromCharCode(parseInt(hex_data.substring(i*2, (i+1)*2), 16));
        }

        return btoa(result);
    }

    function from_base64(number) {
        var bytes = atob(number),
            hex_data = "",
            tmp = "",
            i = 0;

        for (i = 0; i < bytes.length; i++) {
            temp = bytes.charCodeAt(i).toString(16);
            temp = Array(2 - (temp.length % 3) + 1).join(0) + temp;
            hex_data += temp;
        }

        hex_data = hex_data.replace(/^(00){1,}/, '');

        return bigInt(hex_data, 16);
    }

    function gcd(a, b) {
        if (b.compare(bigInt(0)) == 0) {
            return [a, bigInt(1), bigInt(0)];
        }

        n = a.divide(b);
        c = a.mod(b).add(b).mod(b);
        r = gcd(b, c);

        return [r[0], r[2], r[1].subtract(r[2].multiply(n))];
    }

    function mod_inverse(number) {
        var value = gcd(prime, number.mod(prime));
        var remainder = value[2];

        if (number.compare(0) == -1) {
            remainder = remainder.multiply(-1);
        }

        console.log(remainder.toString());

        return remainder.mod(prime).add(prime).mod(prime);
    }

    return {
        'prime': prime,
        'random': random,
        'split_ints': split_ints,
        'merge_ints': merge_ints,
        'to_base64': to_base64,
        'from_base64': from_base64,
        'gcd': gcd,
        'mod_inverse': mod_inverse,
    }
}(this));

var _sssa = (function(root) {
    var utils = _sssa_utils;

    function create(minimum, shares, raw) {
        if (minimum < shares) {
            return;
        }

        var secret = utils.split_int(raw),
            numbers = [bigInt(0)],
            polynomial = [],
            result = [],
            i = 0,
            j = 1;

        for (i in secret) {
            polynomial.push([secret[i]]);
            for (j = 1; j < minimum; j++) {
                value = util.random();
                while (value in numbers) {
                    value = util.random();
                }
                numbers.push(value);

                polynomial[i].push(value);
            }
        }

        for (i = 0; i < shares; i++) {
            for (j in secret) {
                value = util.random();
                while (value in numbers) {
                    value = util.random();
                }
                numbers.push(value);

                if (typeof result[i] !== typeof "string") {
                    result[i] = "";
                } else {
                    result[i] += utils.to_base64(value);
                    result[i] += utils.to_base64(utils.evaluate_polynomial(polynomial[j], value));
                }
            }
        }

        return result;
    }

    function combine(shares) {
        var secrets = [],
            share = "",
            count = 0,
            cshare = "",
            secret = [],
            origin = bigInt(0),
            originy = bigInt(0),
            numerator = bigInt(1),
            denominator = bigInt(1),
            i = 0,
            j = 0,
            k = 0;

        for (i in shares) {
            if (shares[i].length % 88 != 0) {
                return;
            }

            share = shares[i];
            count = share.length / 88;
            secrets[i] = [];

            for (j = 0; j < count; j++) {
                cshare = share.substring(j*88, (j+1)*88);
                secrets[i][j] = [utils.from_base64(cshare.substring(0, 44)), utils.from_base64(cshare.substring(44))];
            }
        }

        for (j = 0; j < secrets[0].length; j++) {
            secret[j] = bigInt(0);
            for (i in secrets) {
                origin = secrets[i][j][0];
                originy = secrets[i][j][1];
                numerator = bigInt(1);
                denominator = bigInt(1);

                for (k in secrets) {
                    if (k !== i) {
                        numerator = numerator.multiply(secrets[k][j][0].multiply(-1)).mod(utils.prime);
                        denominator = denominator.multiply(origin.subtract(secrets[k][j][0])).mod(utils.prime);
                    }
                }

                secret[j] = secret[j].add(originy.multiply(numerator).mod(utils.prime).multiply(denominator).mod(utils.prime)).mod(utils.prime);
            }
        }

        return utils.merge_int(secret);
    }

    return sssa = {
        'create': create,
        'combine': combine
    };
}(this));

// Node.js check
if (typeof module !== "undefined" && module.hasOwnProperty("exports")) {
    var sssa = _sssa;
    module.exports = sssa;
} else {
    sssa = _sssa;
}
<|endoftext|>


<commit_before><commit_msg>Halma (resources)<commit_after><|endoftext|>