<commit_before>// @flow

import { batch } from 'react-redux';

import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app';
import { CONFERENCE_FAILED, CONFERENCE_JOINED } from '../base/conference';
import { JitsiConferenceErrors, JitsiConferenceEvents } from '../base/lib-jitsi-meet';
import { getFirstLoadableAvatarUrl, getParticipantDisplayName } from '../base/participants';
import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
import { playSound, registerSound, unregisterSound } from '../base/sounds';
import { isTestModeEnabled } from '../base/testing';
import {
    NOTIFICATION_TIMEOUT_TYPE,
    NOTIFICATION_TYPE,
    showNotification
} from '../notifications';
import { shouldAutoKnock } from '../prejoin/functions';

import { KNOCKING_PARTICIPANT_ARRIVED_OR_UPDATED } from './actionTypes';
import {
    hideLobbyScreen,
    knockingParticipantLeft,
    openLobbyScreen,
    participantIsKnockingOrUpdated,
    setLobbyModeEnabled,
    startKnocking,
    setPasswordJoinFailed
} from './actions';
import { KNOCKING_PARTICIPANT_SOUND_ID } from './constants';
import { KNOCKING_PARTICIPANT_FILE } from './sounds';

declare var APP: Object;

MiddlewareRegistry.register(store => next => action => {
    switch (action.type) {
    case APP_WILL_MOUNT:
        store.dispatch(registerSound(KNOCKING_PARTICIPANT_SOUND_ID, KNOCKING_PARTICIPANT_FILE));
        break;
    case APP_WILL_UNMOUNT:
        store.dispatch(unregisterSound(KNOCKING_PARTICIPANT_SOUND_ID));
        break;
    case CONFERENCE_FAILED:
        return _conferenceFailed(store, next, action);
    case CONFERENCE_JOINED:
        return _conferenceJoined(store, next, action);
    case KNOCKING_PARTICIPANT_ARRIVED_OR_UPDATED: {
        // We need the full update result to be in the store already
        const result = next(action);

        _findLoadableAvatarForKnockingParticipant(store, action.participant);

        return result;
    }
    }

    return next(action);
});

/**
 * Registers a change handler for state['features/base/conference'].conference to
 * set the event listeners needed for the lobby feature to operate.
 */
StateListenerRegistry.register(
    state => state['features/base/conference'].conference,
    (conference, { dispatch, getState }, previousConference) => {
        if (conference && !previousConference) {
            conference.on(JitsiConferenceEvents.MEMBERS_ONLY_CHANGED, enabled => {
                dispatch(setLobbyModeEnabled(enabled));
            });

            conference.on(JitsiConferenceEvents.LOBBY_USER_JOINED, (id, name) => {
                batch(() => {
                    dispatch(
                        participantIsKnockingOrUpdated({
                            id,
                            name
                        })
                    );
                    dispatch(playSound(KNOCKING_PARTICIPANT_SOUND_ID));
                    if (typeof APP !== 'undefined') {
                        APP.API.notifyKnockingParticipant({
                            id,
                            name
                        });
                    }
                });
            });

            conference.on(JitsiConferenceEvents.LOBBY_USER_UPDATED, (id, participant) => {
                dispatch(
                    participantIsKnockingOrUpdated({
                        ...participant,
                        id
                    })
                );
            });

            conference.on(JitsiConferenceEvents.LOBBY_USER_LEFT, id => {
                dispatch(knockingParticipantLeft(id));
            });

            conference.on(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED, (origin, sender) =>
                _maybeSendLobbyNotification(origin, sender, {
                    dispatch,
                    getState
                })
            );
        }
    }
);

/**
 * Function to handle the conference failed event and navigate the user to the lobby screen
 * based on the failure reason.
 *
 * @param {Object} store - The Redux store.
 * @param {Function} next - The Redux next function.
 * @param {Object} action - The Redux action.
 * @returns {Object}
 */
function _conferenceFailed({ dispatch, getState }, next, action) {
    const { error } = action;
    const state = getState();
    const nonFirstFailure = Boolean(state['features/base/conference'].membersOnly);

    if (error.name === JitsiConferenceErrors.MEMBERS_ONLY_ERROR) {
        if (typeof error.recoverable === 'undefined') {
            error.recoverable = true;
        }

        const result = next(action);

        dispatch(openLobbyScreen());

        if (shouldAutoKnock(state)) {
            dispatch(startKnocking());
        }

        dispatch(setPasswordJoinFailed(nonFirstFailure));

        return result;
    }

    dispatch(hideLobbyScreen());

    if (error.name === JitsiConferenceErrors.CONFERENCE_ACCESS_DENIED) {
        dispatch(
            showNotification({
                appearance: NOTIFICATION_TYPE.ERROR,
                hideErrorSupportLink: true,
                titleKey: 'lobby.joinRejectedMessage'
            }, NOTIFICATION_TIMEOUT_TYPE.LONG)
        );
    }

    return next(action);
}

/**
 * Handles cleanup of lobby state when a conference is joined.
 *
 * @param {Object} store - The Redux store.
 * @param {Function} next - The Redux next function.
 * @param {Object} action - The Redux action.
 * @returns {Object}
 */
function _conferenceJoined({ dispatch }, next, action) {
    dispatch(hideLobbyScreen());

    return next(action);
}

/**
 * Finds the loadable avatar URL and updates the participant accordingly.
 *
 * @param {Object} store - The Redux store.
 * @param {Object} participant - The knocking participant.
 * @returns {void}
 */
function _findLoadableAvatarForKnockingParticipant(store, { id }) {
    const { dispatch, getState } = store;
    const updatedParticipant = getState()['features/lobby'].knockingParticipants.find(p => p.id === id);
    const { disableThirdPartyRequests } = getState()['features/base/config'];

    if (!disableThirdPartyRequests && updatedParticipant && !updatedParticipant.loadableAvatarUrl) {
        getFirstLoadableAvatarUrl(updatedParticipant, store).then(loadableAvatarUrl => {
            if (loadableAvatarUrl) {
                dispatch(
                    participantIsKnockingOrUpdated({
                        loadableAvatarUrl,
                        id
                    })
                );
            }
        });
    }
}

/**
 * Check the endpoint message that arrived through the conference and
 * sends a lobby notification, if the message belongs to the feature.
 *
 * @param {Object} origin - The origin (initiator) of the message.
 * @param {Object} message - The actual message.
 * @param {Object} store - The Redux store.
 * @returns {void}
 */
function _maybeSendLobbyNotification(origin, message, { dispatch, getState }) {
    if (!origin?._id || message?.type !== 'lobby-notify') {
        return;
    }

    const notificationProps: any = {
        descriptionArguments: {
            originParticipantName: getParticipantDisplayName(getState, origin._id),
            targetParticipantName: message.name
        },
        titleKey: 'lobby.notificationTitle'
    };

    switch (message.event) {
    case 'LOBBY-ENABLED':
        notificationProps.descriptionKey = `lobby.notificationLobby${message.value ? 'En' : 'Dis'}abled`;
        break;
    case 'LOBBY-ACCESS-GRANTED':
        notificationProps.descriptionKey = 'lobby.notificationLobbyAccessGranted';
        break;
    case 'LOBBY-ACCESS-DENIED':
        notificationProps.descriptionKey = 'lobby.notificationLobbyAccessDenied';
        break;
    }

    dispatch(
        showNotification(
            notificationProps,
            isTestModeEnabled(getState()) ? NOTIFICATION_TIMEOUT_TYPE.STICKY : NOTIFICATION_TIMEOUT_TYPE.MEDIUM
        )
    );
}
<commit_msg>fix: Fixes correct state in lobby screen on wrong password.<commit_after>// @flow

import { batch } from 'react-redux';

import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app';
import {
    CONFERENCE_FAILED,
    CONFERENCE_JOINED,
    conferenceWillJoin
} from '../base/conference';
import { JitsiConferenceErrors, JitsiConferenceEvents } from '../base/lib-jitsi-meet';
import { getFirstLoadableAvatarUrl, getParticipantDisplayName } from '../base/participants';
import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
import { playSound, registerSound, unregisterSound } from '../base/sounds';
import { isTestModeEnabled } from '../base/testing';
import {
    NOTIFICATION_TIMEOUT_TYPE,
    NOTIFICATION_TYPE,
    showNotification
} from '../notifications';
import { shouldAutoKnock } from '../prejoin/functions';

import { KNOCKING_PARTICIPANT_ARRIVED_OR_UPDATED } from './actionTypes';
import {
    hideLobbyScreen,
    knockingParticipantLeft,
    openLobbyScreen,
    participantIsKnockingOrUpdated,
    setLobbyModeEnabled,
    startKnocking,
    setPasswordJoinFailed
} from './actions';
import { KNOCKING_PARTICIPANT_SOUND_ID } from './constants';
import { KNOCKING_PARTICIPANT_FILE } from './sounds';

declare var APP: Object;

MiddlewareRegistry.register(store => next => action => {
    switch (action.type) {
    case APP_WILL_MOUNT:
        store.dispatch(registerSound(KNOCKING_PARTICIPANT_SOUND_ID, KNOCKING_PARTICIPANT_FILE));
        break;
    case APP_WILL_UNMOUNT:
        store.dispatch(unregisterSound(KNOCKING_PARTICIPANT_SOUND_ID));
        break;
    case CONFERENCE_FAILED:
        return _conferenceFailed(store, next, action);
    case CONFERENCE_JOINED:
        return _conferenceJoined(store, next, action);
    case KNOCKING_PARTICIPANT_ARRIVED_OR_UPDATED: {
        // We need the full update result to be in the store already
        const result = next(action);

        _findLoadableAvatarForKnockingParticipant(store, action.participant);

        return result;
    }
    }

    return next(action);
});

/**
 * Registers a change handler for state['features/base/conference'].conference to
 * set the event listeners needed for the lobby feature to operate.
 */
StateListenerRegistry.register(
    state => state['features/base/conference'].conference,
    (conference, { dispatch, getState }, previousConference) => {
        if (conference && !previousConference) {
            conference.on(JitsiConferenceEvents.MEMBERS_ONLY_CHANGED, enabled => {
                dispatch(setLobbyModeEnabled(enabled));
            });

            conference.on(JitsiConferenceEvents.LOBBY_USER_JOINED, (id, name) => {
                batch(() => {
                    dispatch(
                        participantIsKnockingOrUpdated({
                            id,
                            name
                        })
                    );
                    dispatch(playSound(KNOCKING_PARTICIPANT_SOUND_ID));
                    if (typeof APP !== 'undefined') {
                        APP.API.notifyKnockingParticipant({
                            id,
                            name
                        });
                    }
                });
            });

            conference.on(JitsiConferenceEvents.LOBBY_USER_UPDATED, (id, participant) => {
                dispatch(
                    participantIsKnockingOrUpdated({
                        ...participant,
                        id
                    })
                );
            });

            conference.on(JitsiConferenceEvents.LOBBY_USER_LEFT, id => {
                dispatch(knockingParticipantLeft(id));
            });

            conference.on(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED, (origin, sender) =>
                _maybeSendLobbyNotification(origin, sender, {
                    dispatch,
                    getState
                })
            );
        }
    }
);

/**
 * Function to handle the conference failed event and navigate the user to the lobby screen
 * based on the failure reason.
 *
 * @param {Object} store - The Redux store.
 * @param {Function} next - The Redux next function.
 * @param {Object} action - The Redux action.
 * @returns {Object}
 */
function _conferenceFailed({ dispatch, getState }, next, action) {
    const { error } = action;
    const state = getState();
    const { membersOnly } = state['features/base/conference'];
    const nonFirstFailure = Boolean(membersOnly);

    if (error.name === JitsiConferenceErrors.MEMBERS_ONLY_ERROR) {
        if (typeof error.recoverable === 'undefined') {
            error.recoverable = true;
        }

        const result = next(action);

        dispatch(openLobbyScreen());

        if (shouldAutoKnock(state)) {
            dispatch(startKnocking());
        }

        // In case of wrong password we need to be in the right state if in the meantime someone allows us to join
        if (nonFirstFailure) {
            dispatch(conferenceWillJoin(membersOnly));
        }

        dispatch(setPasswordJoinFailed(nonFirstFailure));

        return result;
    }

    dispatch(hideLobbyScreen());

    if (error.name === JitsiConferenceErrors.CONFERENCE_ACCESS_DENIED) {
        dispatch(
            showNotification({
                appearance: NOTIFICATION_TYPE.ERROR,
                hideErrorSupportLink: true,
                titleKey: 'lobby.joinRejectedMessage'
            }, NOTIFICATION_TIMEOUT_TYPE.LONG)
        );
    }

    return next(action);
}

/**
 * Handles cleanup of lobby state when a conference is joined.
 *
 * @param {Object} store - The Redux store.
 * @param {Function} next - The Redux next function.
 * @param {Object} action - The Redux action.
 * @returns {Object}
 */
function _conferenceJoined({ dispatch }, next, action) {
    dispatch(hideLobbyScreen());

    return next(action);
}

/**
 * Finds the loadable avatar URL and updates the participant accordingly.
 *
 * @param {Object} store - The Redux store.
 * @param {Object} participant - The knocking participant.
 * @returns {void}
 */
function _findLoadableAvatarForKnockingParticipant(store, { id }) {
    const { dispatch, getState } = store;
    const updatedParticipant = getState()['features/lobby'].knockingParticipants.find(p => p.id === id);
    const { disableThirdPartyRequests } = getState()['features/base/config'];

    if (!disableThirdPartyRequests && updatedParticipant && !updatedParticipant.loadableAvatarUrl) {
        getFirstLoadableAvatarUrl(updatedParticipant, store).then(loadableAvatarUrl => {
            if (loadableAvatarUrl) {
                dispatch(
                    participantIsKnockingOrUpdated({
                        loadableAvatarUrl,
                        id
                    })
                );
            }
        });
    }
}

/**
 * Check the endpoint message that arrived through the conference and
 * sends a lobby notification, if the message belongs to the feature.
 *
 * @param {Object} origin - The origin (initiator) of the message.
 * @param {Object} message - The actual message.
 * @param {Object} store - The Redux store.
 * @returns {void}
 */
function _maybeSendLobbyNotification(origin, message, { dispatch, getState }) {
    if (!origin?._id || message?.type !== 'lobby-notify') {
        return;
    }

    const notificationProps: any = {
        descriptionArguments: {
            originParticipantName: getParticipantDisplayName(getState, origin._id),
            targetParticipantName: message.name
        },
        titleKey: 'lobby.notificationTitle'
    };

    switch (message.event) {
    case 'LOBBY-ENABLED':
        notificationProps.descriptionKey = `lobby.notificationLobby${message.value ? 'En' : 'Dis'}abled`;
        break;
    case 'LOBBY-ACCESS-GRANTED':
        notificationProps.descriptionKey = 'lobby.notificationLobbyAccessGranted';
        break;
    case 'LOBBY-ACCESS-DENIED':
        notificationProps.descriptionKey = 'lobby.notificationLobbyAccessDenied';
        break;
    }

    dispatch(
        showNotification(
            notificationProps,
            isTestModeEnabled(getState()) ? NOTIFICATION_TIMEOUT_TYPE.STICKY : NOTIFICATION_TIMEOUT_TYPE.MEDIUM
        )
    );
}
<|endoftext|>


<commit_before>define(function(require) {
  var $ = require('jquery')
  var DateFormat = require('./DateFormat')
  var DateParse = require('./DateParse')
  var EN = require('./locale/EN')
  var DateRange = require('./DateRange')
  var DateTime = require('./DateTime')
  var CalendarBody = require('./CalendarBody')
  var RangeEvents = require('./RangeEvents')
  var SingleDateEvents = require('./SingleDateEvents')

  $.continuousCalendar = {
    "version" : "4.6.2"
  }
  $.fn.continuousCalendar = function(options) {
    return this.each(function() { _continuousCalendar.call($(this), options) })
    function _continuousCalendar(options) {
      var defaults = {
        weeksBefore    : 26,
        weeksAfter     : 26,
        firstDate      : null,
        lastDate       : null,
        startField     : $('input.startDate', this),
        endField       : $('input.endDate', this),
        isPopup        : false,
        selectToday    : false,
        locale         : EN,
        disableWeekends: false,
        disabledDates  : null,
        minimumRange   : -1,
        selectWeek     : false,
        fadeOutDuration: 0,
        callback       : $.noop,
        customScroll   : false,
        scrollOptions  : {
          sizethumb: 'auto'
        },
        theme          : '',
        allowClearDates: false,
        isRange        : false
      }
      var params = $.extend({}, defaults, options)
      var locale = params.locale
      var startDate = fieldDate(params.startField)
      var endDate = fieldDate(params.endField)
      var today = DateTime.today()

      if(params.selectToday) {
        var formattedToday = formatDate(today)
        startDate = today
        endDate = today
        setStartField(formattedToday)
        setEndField(formattedToday)
      }
      var container = this
      var averageCellHeight
      var calendarContainer
      var beforeFirstOpening = true
      var popupBehavior
      var dateBehavior
      var customScrollContainer
      var calendarBody = {}
      var calendarRange
      var disabledDatesList
      var disabledDatesObject

      $(this).addClass('continuousCalendarContainer').addClass(params.theme)
      createCalendar()

      function createCalendar() {
        //TODO change api to take YYYY-MM-DD instead of MM/DD/YYYY and array instead of space separated string
        disabledDatesList = params.disabledDates ? $.map(params.disabledDates.split(' '), function(slashStr) {
          var mdy = slashStr.split('/')
          var year = mdy[2]
          var month = mdy[0]
          var day = mdy[1]
          return [ year, (month.length === 1 ? '0':'') + month, (day.length === 1 ? '0':'') + day].join('-')
        }) : []
        disabledDatesObject = params.disabledDates ? parseDisabledDates(disabledDatesList) : {}
        calendarRange = determineRangeToRenderFormParams(params)
        popupBehavior = popUpBehaviour(params.isPopup)
        dateBehavior = dateBehaviour(params.isRange)
        params.fadeOutDuration = +params.fadeOutDuration
        calendarContainer = getCalendarContainerOrCreateOne()
        calendarContainer.click(function(e) { e.stopPropagation() })
        if($('.startDateLabel', container).isEmpty()) addDateLabels(container, popupBehavior, dateBehavior)
        popupBehavior.initUI()
        dateBehavior.showInitialSelection()
        dateBehavior.performTrigger()
      }

      function initScrollBar() { if(params.customScroll) customScrollContainer = $('.tinyscrollbar', container).tinyscrollbar(params.scrollOptions) }

      function initCalendarTable() {
        if (!calendarBody.scrollContent) {

          calendarBody = $.extend(calendarBody, CalendarBody(calendarContainer, calendarRange, locale,
              params.customScroll, params.disableWeekends, disabledDatesObject))
          bindScrollEvent()

          popupBehavior.initState()
          dateBehavior.addRangeLengthLabel()
          dateBehavior.addDateClearingLabel()
          dateBehavior.initEvents()
          scrollToSelection()
        }
      }

      function determineRangeToRenderFormParams(params) {
        var firstWeekdayOfGivenDate = (startDate || DateTime.today()).getFirstDateOfWeek(locale)
        var rangeStart = dateOrWeek(params.firstDate, -params.weeksBefore * 7)
        var rangeEnd = dateOrWeek(params.lastDate, params.weeksAfter * 7 + 6)

        return  new DateRange(rangeStart, rangeEnd)

        function dateOrWeek(date, week) { return date ? DateParse.parse(date, locale) : firstWeekdayOfGivenDate.plusDays(week)}
      }

      function bindScrollEvent() {
        if(params.customScroll) {
          if(!customScrollContainer) initScrollBar()
          customScrollContainer.bind('scroll', setYearLabel)
        } else {
          var waiting = false
          calendarBody.scrollContent.scroll(function() {
            if (!waiting) {
              setTimeout(function() {
                waiting = false
                setYearLabel()
              }, 250)
              waiting = true
            }
          })
        }
      }

      function parseDisabledDates(dates) {
        var dateMap = {}
        $.each(dates, function(index, date) { dateMap[DateTime.fromIsoDate(date).date] = true })
        return dateMap
      }

      function dateBehaviour(isRange) {
        var basicParams = [container, calendarBody, executeCallback, locale, params, getElemDate, popupBehavior, startDate]
        var rangeParams = [endDate, calendarRange, setStartField, setEndField, formatDate, disabledDatesList]
        return isRange ? RangeEvents.apply(null, basicParams.concat(rangeParams)) : SingleDateEvents.apply(null, basicParams)
      }

      function popUpBehaviour(isPopup) {
        var popUpVersion = {
          initUI               : function() {
            calendarContainer.addClass('popup').hide()
            var icon = $('' + today.getDate() + '').click(toggleCalendar)
            container.prepend(icon)
          },
          initState            : $.noop,
          getContainer         : function(newContainer) { return $('
').append(newContainer); },
          close                : function(cell) { toggleCalendar.call(cell) },
          addDateLabelBehaviour: function(label) {
            label.addClass('clickable')
            label.click(toggleCalendar)
          }
        }

        function toggleCalendar() {
          initCalendarTable()
          if(calendarContainer.is(':visible')) {
            calendarContainer.fadeOut(params.fadeOutDuration)
            $(document).unbind('click.continuousCalendar')
          } else {
            calendarContainer.show()
            if(beforeFirstOpening) {
              initScrollBar()
              calculateCellHeight()
              setYearLabel()
              beforeFirstOpening = false
            }
            dateBehavior.setSelection(fieldDate(params.startField), fieldDate(params.endField))
            scrollToSelection()
            $(document).bind('click.continuousCalendar', toggleCalendar)

          }
          return false
        }

        var inlineVersion = {
          initUI               : initCalendarTable,
          initState            : calculateCellHeightAndInitScroll,
          getContainer         : function(newContainer) {
            return newContainer
          },
          close                : $.noop,
          addDateLabelBehaviour: $.noop
        }
        return isPopup ? popUpVersion : inlineVersion
      }

      function getCalendarContainerOrCreateOne() {
        var existingContainer = $('.continuousCalendar', container)
        if(existingContainer.exists()) {
          return existingContainer
        } else {
          var newContainer = $('
')
          container.append(popupBehavior.getContainer(newContainer))
          return newContainer
        }
      }

      function addDateLabels(container, popupBehavior, dateBehavior) {
        var dateLabelContainer = $('

')
        dateBehavior.addEndDateLabel(dateLabelContainer)
        container.prepend(dateLabelContainer)
        popupBehavior.addDateLabelBehaviour(dateLabelContainer.children())
      }

      function scrollToSelection() {
        var selectionStartOrToday = $('.selected', calendarBody.scrollContent).get(0) || $('.today', calendarBody.scrollContent).get(0)
        if(selectionStartOrToday) {
          var position = selectionStartOrToday.offsetTop - (calendarBody.scrollContent.height() - selectionStartOrToday.offsetHeight) / 2
          if(params.customScroll) {
            var totalHeight = calendarBody.bodyTable.height()
            var maxScroll = totalHeight - calendarBody.scrollContent.height()
            var validPosition = position > maxScroll ? maxScroll : position
            customScrollContainer.tinyscrollbar_update(validPosition > 0 ? validPosition : 0)
          } else {
            calendarBody.scrollContent.scrollTop(position)
          }
        }
      }

      function setYearLabel() {
        var scrollContent = calendarBody.scrollContent.get(0)
        var table = $('table', scrollContent).get(0)
        var scrollTop = params.customScroll ? -$('.overview', calendarContainer).position().top : scrollContent.scrollTop
        var rowNumber = parseInt(scrollTop / averageCellHeight, 10)
        var date = getElemDate(table.rows[rowNumber].cells[2])
        calendarBody.yearTitle.text(date.getFullYear())
      }

      function calculateCellHeightAndInitScroll() {
        initScrollBar()
        calculateCellHeight()
        setYearLabel()
      }

      function calculateCellHeight() { averageCellHeight = parseInt(calendarBody.bodyTable.height() / $('tr', calendarBody.bodyTable).size(), 10) }

      function fieldDate(field) { return field.length > 0 && field.val().length > 0 ? DateParse.parse(field.val(), locale) : null }

      function executeCallback(selection) {
        params.callback.call(container, selection)
        container.trigger('calendarChange', selection)
      }

      function getElemDate(elem) { return calendarBody.dateCellDates[$(elem).closest('[date-cell-index]').attr('date-cell-index')] }

      function setStartField(value) { params.startField.val(value) }

      function setEndField(value) { params.endField.val(value) }

      function formatDate(date) { return date ? DateFormat.shortDateFormat(date, locale) : '' }
    }
  }
  $.fn.calendarRange = function() { return $(this).data('calendarRange') }
  $.fn.exists = function() { return this.length > 0 }
  $.fn.isEmpty = function() { return this.length === 0 }
})
<commit_msg>Add possibility to set date selection as constructor parameter<commit_after>define(function(require) {
  var $ = require('jquery')
  var DateFormat = require('./DateFormat')
  var DateParse = require('./DateParse')
  var EN = require('./locale/EN')
  var DateRange = require('./DateRange')
  var DateTime = require('./DateTime')
  var CalendarBody = require('./CalendarBody')
  var RangeEvents = require('./RangeEvents')
  var SingleDateEvents = require('./SingleDateEvents')

  $.continuousCalendar = {
    "version" : "4.6.2"
  }
  $.fn.continuousCalendar = function(options) {
    return this.each(function() { _continuousCalendar.call($(this), options) })
    function _continuousCalendar(options) {
      var defaults = {
        weeksBefore    : 26,
        weeksAfter     : 26,
        firstDate      : null,
        lastDate       : null,
        startField     : $('input.startDate', this),
        endField       : $('input.endDate', this),
        isPopup        : false,
        selectToday    : false,
        locale         : EN,
        disableWeekends: false,
        disabledDates  : null,
        minimumRange   : -1,
        selectWeek     : false,
        fadeOutDuration: 0,
        callback       : $.noop,
        customScroll   : false,
        scrollOptions  : {
          sizethumb: 'auto'
        },
        theme          : '',
        allowClearDates: false,
        isRange        : false,
        startDate      : null,
        endDate        : null
      }
      var params = $.extend({}, defaults, options)
      var locale = params.locale
      var startDate = fieldDate(params.startField) || params.startDate
      var endDate = fieldDate(params.endField) || params.endDate
      var today = DateTime.today()

      if(params.selectToday) {
        var formattedToday = formatDate(today)
        startDate = today
        endDate = today
        setStartField(formattedToday)
        setEndField(formattedToday)
      }
      var container = this
      var averageCellHeight
      var calendarContainer
      var beforeFirstOpening = true
      var popupBehavior
      var dateBehavior
      var customScrollContainer
      var calendarBody = {}
      var calendarRange
      var disabledDatesList
      var disabledDatesObject

      $(this).addClass('continuousCalendarContainer').addClass(params.theme)
      createCalendar()

      function createCalendar() {
        //TODO change api to take YYYY-MM-DD instead of MM/DD/YYYY and array instead of space separated string
        disabledDatesList = params.disabledDates ? $.map(params.disabledDates.split(' '), function(slashStr) {
          var mdy = slashStr.split('/')
          var year = mdy[2]
          var month = mdy[0]
          var day = mdy[1]
          return [ year, (month.length === 1 ? '0':'') + month, (day.length === 1 ? '0':'') + day].join('-')
        }) : []
        disabledDatesObject = params.disabledDates ? parseDisabledDates(disabledDatesList) : {}
        calendarRange = determineRangeToRenderFormParams(params)
        popupBehavior = popUpBehaviour(params.isPopup)
        dateBehavior = dateBehaviour(params.isRange)
        params.fadeOutDuration = +params.fadeOutDuration
        calendarContainer = getCalendarContainerOrCreateOne()
        calendarContainer.click(function(e) { e.stopPropagation() })
        if($('.startDateLabel', container).isEmpty()) addDateLabels(container, popupBehavior, dateBehavior)
        popupBehavior.initUI()
        dateBehavior.showInitialSelection()
        dateBehavior.performTrigger()
      }

      function initScrollBar() { if(params.customScroll) customScrollContainer = $('.tinyscrollbar', container).tinyscrollbar(params.scrollOptions) }

      function initCalendarTable() {
        if (!calendarBody.scrollContent) {

          calendarBody = $.extend(calendarBody, CalendarBody(calendarContainer, calendarRange, locale,
              params.customScroll, params.disableWeekends, disabledDatesObject))
          bindScrollEvent()

          popupBehavior.initState()
          dateBehavior.addRangeLengthLabel()
          dateBehavior.addDateClearingLabel()
          dateBehavior.initEvents()
          scrollToSelection()
        }
      }

      function determineRangeToRenderFormParams(params) {
        var firstWeekdayOfGivenDate = (startDate || DateTime.today()).getFirstDateOfWeek(locale)
        var rangeStart = dateOrWeek(params.firstDate, -params.weeksBefore * 7)
        var rangeEnd = dateOrWeek(params.lastDate, params.weeksAfter * 7 + 6)

        return  new DateRange(rangeStart, rangeEnd)

        function dateOrWeek(date, week) { return date ? DateParse.parse(date, locale) : firstWeekdayOfGivenDate.plusDays(week)}
      }

      function bindScrollEvent() {
        if(params.customScroll) {
          if(!customScrollContainer) initScrollBar()
          customScrollContainer.bind('scroll', setYearLabel)
        } else {
          var waiting = false
          calendarBody.scrollContent.scroll(function() {
            if (!waiting) {
              setTimeout(function() {
                waiting = false
                setYearLabel()
              }, 250)
              waiting = true
            }
          })
        }
      }

      function parseDisabledDates(dates) {
        var dateMap = {}
        $.each(dates, function(index, date) { dateMap[DateTime.fromIsoDate(date).date] = true })
        return dateMap
      }

      function dateBehaviour(isRange) {
        var basicParams = [container, calendarBody, executeCallback, locale, params, getElemDate, popupBehavior, startDate]
        var rangeParams = [endDate, calendarRange, setStartField, setEndField, formatDate, disabledDatesList]
        return isRange ? RangeEvents.apply(null, basicParams.concat(rangeParams)) : SingleDateEvents.apply(null, basicParams)
      }

      function popUpBehaviour(isPopup) {
        var popUpVersion = {
          initUI               : function() {
            calendarContainer.addClass('popup').hide()
            var icon = $('' + today.getDate() + '').click(toggleCalendar)
            container.prepend(icon)
          },
          initState            : $.noop,
          getContainer         : function(newContainer) { return $('
').append(newContainer); },
          close                : function(cell) { toggleCalendar.call(cell) },
          addDateLabelBehaviour: function(label) {
            label.addClass('clickable')
            label.click(toggleCalendar)
          }
        }

        function toggleCalendar() {
          initCalendarTable()
          if(calendarContainer.is(':visible')) {
            calendarContainer.fadeOut(params.fadeOutDuration)
            $(document).unbind('click.continuousCalendar')
          } else {
            calendarContainer.show()
            if(beforeFirstOpening) {
              initScrollBar()
              calculateCellHeight()
              setYearLabel()
              beforeFirstOpening = false
            }
            dateBehavior.setSelection(fieldDate(params.startField), fieldDate(params.endField))
            scrollToSelection()
            $(document).bind('click.continuousCalendar', toggleCalendar)

          }
          return false
        }

        var inlineVersion = {
          initUI               : initCalendarTable,
          initState            : calculateCellHeightAndInitScroll,
          getContainer         : function(newContainer) {
            return newContainer
          },
          close                : $.noop,
          addDateLabelBehaviour: $.noop
        }
        return isPopup ? popUpVersion : inlineVersion
      }

      function getCalendarContainerOrCreateOne() {
        var existingContainer = $('.continuousCalendar', container)
        if(existingContainer.exists()) {
          return existingContainer
        } else {
          var newContainer = $('
')
          container.append(popupBehavior.getContainer(newContainer))
          return newContainer
        }
      }

      function addDateLabels(container, popupBehavior, dateBehavior) {
        var dateLabelContainer = $('

')
        dateBehavior.addEndDateLabel(dateLabelContainer)
        container.prepend(dateLabelContainer)
        popupBehavior.addDateLabelBehaviour(dateLabelContainer.children())
      }

      function scrollToSelection() {
        var selectionStartOrToday = $('.selected', calendarBody.scrollContent).get(0) || $('.today', calendarBody.scrollContent).get(0)
        if(selectionStartOrToday) {
          var position = selectionStartOrToday.offsetTop - (calendarBody.scrollContent.height() - selectionStartOrToday.offsetHeight) / 2
          if(params.customScroll) {
            var totalHeight = calendarBody.bodyTable.height()
            var maxScroll = totalHeight - calendarBody.scrollContent.height()
            var validPosition = position > maxScroll ? maxScroll : position
            customScrollContainer.tinyscrollbar_update(validPosition > 0 ? validPosition : 0)
          } else {
            calendarBody.scrollContent.scrollTop(position)
          }
        }
      }

      function setYearLabel() {
        var scrollContent = calendarBody.scrollContent.get(0)
        var table = $('table', scrollContent).get(0)
        var scrollTop = params.customScroll ? -$('.overview', calendarContainer).position().top : scrollContent.scrollTop
        var rowNumber = parseInt(scrollTop / averageCellHeight, 10)
        var date = getElemDate(table.rows[rowNumber].cells[2])
        calendarBody.yearTitle.text(date.getFullYear())
      }

      function calculateCellHeightAndInitScroll() {
        initScrollBar()
        calculateCellHeight()
        setYearLabel()
      }

      function calculateCellHeight() { averageCellHeight = parseInt(calendarBody.bodyTable.height() / $('tr', calendarBody.bodyTable).size(), 10) }

      function fieldDate(field) { return field.length > 0 && field.val().length > 0 ? DateParse.parse(field.val(), locale) : null }

      function executeCallback(selection) {
        params.callback.call(container, selection)
        container.trigger('calendarChange', selection)
      }

      function getElemDate(elem) { return calendarBody.dateCellDates[$(elem).closest('[date-cell-index]').attr('date-cell-index')] }

      function setStartField(value) { params.startField.val(value) }

      function setEndField(value) { params.endField.val(value) }

      function formatDate(date) { return date ? DateFormat.shortDateFormat(date, locale) : '' }
    }
  }
  $.fn.calendarRange = function() { return $(this).data('calendarRange') }
  $.fn.exists = function() { return this.length > 0 }
  $.fn.isEmpty = function() { return this.length === 0 }
})
<|endoftext|>


<commit_before>'use strict';

const requireEsm = require('esm')(module);
function getFeatures() {
  const { default: features } = requireEsm('@ember-data/canary-features/addon/default-features.js')
  );

  const FEATURE_OVERRIDES = process.env.EMBER_DATA_FEATURE_OVERRIDE;
  if (FEATURE_OVERRIDES === 'ENABLE_ALL_OPTIONAL') {
    // enable all features with a current value of `null`
    for (let feature in features) {
      let featureValue = features[feature];

      if (featureValue === null) {
        features[feature] = true;
      }
    }
  } else if (FEATURE_OVERRIDES) {
    // enable only the specific features listed in the environment
    // variable (comma separated)
    const forcedFeatures = FEATURE_OVERRIDES.split(',');
    for (let i = 0; i < forcedFeatures.length; i++) {
      let featureName = forcedFeatures[i];

      features[featureName] = true;
    }
  }

  return features;
}

module.exports = getFeatures();
<commit_msg>Update packages/-build-infra/src/features.js<commit_after>'use strict';

const requireEsm = require('esm')(module);
function getFeatures() {
  const { default: features } = requireEsm('@ember-data/canary-features/addon/default-features.js')

  const FEATURE_OVERRIDES = process.env.EMBER_DATA_FEATURE_OVERRIDE;
  if (FEATURE_OVERRIDES === 'ENABLE_ALL_OPTIONAL') {
    // enable all features with a current value of `null`
    for (let feature in features) {
      let featureValue = features[feature];

      if (featureValue === null) {
        features[feature] = true;
      }
    }
  } else if (FEATURE_OVERRIDES) {
    // enable only the specific features listed in the environment
    // variable (comma separated)
    const forcedFeatures = FEATURE_OVERRIDES.split(',');
    for (let i = 0; i < forcedFeatures.length; i++) {
      let featureName = forcedFeatures[i];

      features[featureName] = true;
    }
  }

  return features;
}

module.exports = getFeatures();
<|endoftext|>


<commit_before>import {applyMiddleware, compose, createStore as reduxCreateStore, combineReducers} from 'redux'
import {intlReducer} from 'react-intl-redux'
import _difference from 'lodash/difference'
import _pick from 'lodash/pick'
import createSagaMiddleware from 'redux-saga'
import {fork} from 'redux-saga/effects'
import thunk from 'redux-thunk'

import errorLogging, {sagas as loggingSagas, logError as logErrorAction} from '../errorLogging'
import {autoRestartSaga, createGenerator} from './sagaHelpers'

import input from './input/reducer'

const sagaMiddleware = createSagaMiddleware()

export const createStore = (initialState = {}, reducers, sagas) => {
  let middleware = applyMiddleware(thunk, sagaMiddleware)

  if (__DEBUG__) {
    const devToolsExtension = window.devToolsExtension

    if (typeof devToolsExtension === 'function') {
      middleware = compose(middleware, devToolsExtension())
    }
  }

  const allReducers = {
    ...reducers,
    input,
    errorLogging,
    intl: intlReducer
  }

  reducers = combineReducers(allReducers)

  const store = reduxCreateStore(reducers, initialState, middleware)

  store.allReducers = allReducers
  store.sagas = sagas

  const rootSaga = createGenerator(sagas.map(s => fork(s)))

  sagaMiddleware.run(autoRestartSaga(rootSaga, logErrorAction))
  sagaMiddleware.run(loggingSagas, ['console', 'remote', 'toastr'])

  return store
}

export const hotReloadReducers = (store, reducers) => {
  const allReducers = {
    ...store.allReducers,
    ...reducers
  }
  const combinedReducers = combineReducers(allReducers)
  store.replaceReducer(combinedReducers)
  store.allReducers = allReducers
}

export const injectReducers = (store, reducers) => {
  const newKeys = _difference(Object.keys(reducers), Object.keys(store.allReducers))
  if (newKeys.length > 0) {
    const allReducers = {
      ...store.allReducers,
      ..._pick(reducers, newKeys)
    }
    hotReloadReducers(store, allReducers)
  }
}

export const injectSaga = (store, saga) => {
  if (!store.sagas.includes(saga)) {
    store.sagas.push(saga)
    sagaMiddleware.run(autoRestartSaga(saga, logErrorAction))
  }
}
<commit_msg>refactor(tocco-util): Add default parameter values for createStore()<commit_after>import {applyMiddleware, compose, createStore as reduxCreateStore, combineReducers} from 'redux'
import {intlReducer} from 'react-intl-redux'
import _difference from 'lodash/difference'
import _pick from 'lodash/pick'
import createSagaMiddleware from 'redux-saga'
import {fork} from 'redux-saga/effects'
import thunk from 'redux-thunk'

import errorLogging, {sagas as loggingSagas, logError as logErrorAction} from '../errorLogging'
import {autoRestartSaga, createGenerator} from './sagaHelpers'

import input from './input/reducer'

const sagaMiddleware = createSagaMiddleware()

export const createStore = (initialState = {}, reducers = {}, sagas = []) => {
  let middleware = applyMiddleware(thunk, sagaMiddleware)

  if (__DEBUG__) {
    const devToolsExtension = window.devToolsExtension

    if (typeof devToolsExtension === 'function') {
      middleware = compose(middleware, devToolsExtension())
    }
  }

  const allReducers = {
    ...reducers,
    input,
    errorLogging,
    intl: intlReducer
  }

  reducers = combineReducers(allReducers)

  const store = reduxCreateStore(reducers, initialState, middleware)

  store.allReducers = allReducers
  store.sagas = sagas

  const rootSaga = createGenerator(sagas.map(s => fork(s)))

  sagaMiddleware.run(autoRestartSaga(rootSaga, logErrorAction))
  sagaMiddleware.run(loggingSagas, ['console', 'remote', 'toastr'])

  return store
}

export const hotReloadReducers = (store, reducers) => {
  const allReducers = {
    ...store.allReducers,
    ...reducers
  }
  const combinedReducers = combineReducers(allReducers)
  store.replaceReducer(combinedReducers)
  store.allReducers = allReducers
}

export const injectReducers = (store, reducers) => {
  const newKeys = _difference(Object.keys(reducers), Object.keys(store.allReducers))
  if (newKeys.length > 0) {
    const allReducers = {
      ...store.allReducers,
      ..._pick(reducers, newKeys)
    }
    hotReloadReducers(store, allReducers)
  }
}

export const injectSaga = (store, saga) => {
  if (!store.sagas.includes(saga)) {
    store.sagas.push(saga)
    sagaMiddleware.run(autoRestartSaga(saga, logErrorAction))
  }
}
<|endoftext|>


<commit_before>'use strict';

exports.BattleFormatsData = {
	aegislash: {
		inherit: true,
		tier: "OU",
	},
	blaziken: {
		inherit: true,
		tier: "OU",
	},
	darkrai: {
		inherit: true,
		tier: "OU",
	},
	deoxysdefense: {
		inherit: true,
		tier: "OU",
	},
	deoxysspeed: {
		inherit: true,
		tier: "OU",
	},
	genesect: {
		inherit: true,
		tier: "OU",
	},
	landorus: {
		inherit: true,
		tier: "OU",
	},
	regigigas: {
		inherit: true,
		tier: "Uber",
	},
	slaking: {
		inherit: true,
		tier: "Uber",
	},
	shayminsky: {
		inherit: true,
		tier: "OU",
	},
};
<commit_msg>Mix and Mega: Set Kyurem-Black as Uber<commit_after>'use strict';

exports.BattleFormatsData = {
	aegislash: {
		inherit: true,
		tier: "OU",
	},
	blaziken: {
		inherit: true,
		tier: "OU",
	},
	darkrai: {
		inherit: true,
		tier: "OU",
	},
	deoxysdefense: {
		inherit: true,
		tier: "OU",
	},
	deoxysspeed: {
		inherit: true,
		tier: "OU",
	},
	genesect: {
		inherit: true,
		tier: "OU",
	},
	kyuremblack: {
		inherit: true,
		tier: "Uber",
	},
	landorus: {
		inherit: true,
		tier: "OU",
	},
	regigigas: {
		inherit: true,
		tier: "Uber",
	},
	slaking: {
		inherit: true,
		tier: "Uber",
	},
	shayminsky: {
		inherit: true,
		tier: "OU",
	},
};
<|endoftext|>


<commit_before>import 'react-native';
import React from 'react';
//import Index from './index.android.js';

// Note: test renderer must be required after react-native.
import renderer from 'react-test-renderer';

it('renders correctly', () => {
  const tree = renderer.create(
    <Index />
  );
});
<commit_msg>Update index.android.js<commit_after>import 'react-native';
import React from 'react';
import Index from './index.android.js';

// Note: test renderer must be required after react-native.
import renderer from 'react-test-renderer';

it('renders correctly', () => {
  const tree = renderer.create(
    <Index />
  );
});
<|endoftext|>


<commit_before>#!/usr/bin/env node

/*
  oref0 Nightscout profile update tool

  Checks the ISF / Basal profile in Nightscout and updates the profile if
  necessary to match the profile collected by OpenAPS

  Released under MIT license. See the accompanying LICENSE.txt file for
  full terms and conditions

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.

*/

var crypto = require('crypto');
var request = require('request');
var _ = require('lodash');

if (!module.parent) {

    var argv = require('yargs')
        .usage("$0 profile.json NSURL api-secret [--preview]")
        .option('preview', {
            alias: 'p'
            , describe: "Give a preview of the outcome without uploading"
            , default: false
        })
        .strict(true)
        .help('help');

    function usage() {
        argv.showHelp();
    }

    var params = argv.argv;
    var errors = [];
    var warnings = [];

    var profile_input = params._[0];

    if ([null, '--help', '-h', 'help'].indexOf(profile_input) > 0) {
        usage();
        process.exit(0);
    }

    var nsurl = params._[1];
    var apisecret = params._[2];

    if (!profile_input || !nsurl || !apisecret) {
        usage();
        process.exit(1);
    }

    if (apisecret.length != 40) {
        var shasum = crypto.createHash('sha1');
        shasum.update(String(apisecret));
        apisecret = shasum.digest('hex');
    };

    try {
        var cwd = process.cwd();
        var profiledata = require(cwd + '/' + profile_input);

        // Rudimentary check that the profile is valid

        if (!profiledata.dia
          || profiledata.basalprofile.length < 1
          || profiledata.bg_targets.length < 1
          || profiledata.isfProfile.length < 1 )
          { throw "Profile JSON missing data"; }

    } catch (e) {
        return console.error('Could not parse input data: ', e);
    }

    var options = {
        uri: nsurl + '/api/v1/profile/current'
        , json: true
        , headers: {
            'api-secret': apisecret
        }
    };

    request(options, function(error, res, data) {
        if (error || res.statusCode != 200) {
            console.log('Loading current profile from Nightscout failed');
            process.exit(1);
        }

        var original_profile = data;
        var new_profile = _.cloneDeep(data);

        if (!data.defaultProfile) {
            console.error('Nightscout profile missing data');
            process.exit(1);
        }

        var profile_id = data.defaultProfile;
        var profile_store = new_profile.store[profile_id];

        profile_store.dia = profiledata.dia;

        // Basals

        var new_basal = [];

        _.forEach(profiledata.basalprofile, function(basalentry) {

            var newEntry = {
                time: '' + basalentry.start.substring(0, 5)
                , value: '' + +(Math.round(basalentry.rate + 'e+3') + 'e-3')
                , timeAsSeconds: '' + basalentry.minutes * 60
            };

            new_basal.push(newEntry);

        });

        profile_store.basal = new_basal;

        // BG Targets

        var new_target_low = [];
        var new_target_high = [];

        _.forEach(profiledata.bg_targets.targets, function(target_entry) {

            var time = target_entry.start.substring(0, 5);
            var seconds = parseInt(time.substring(0, 2)) * 60 * 60 + parseInt(time.substring(3, 5)) * 60;
            var low_value = Math.round(target_entry.low);
            var high_value = Math.round(target_entry.high);

            if (new_profile.units == 'mmol' && profiledata.bg_targets.units == 'mg/dL') {
                low_value = +(Math.round(target_entry.low / 18 + 'e+1') + 'e-1');
                high_value = +(Math.round(target_entry.high / 18 + 'e+1') + 'e-1');
            }

            var new_low_entry = {
                time: '' + time
                , value: '' + low_value
                , timeAsSeconds: '' + seconds
            };

            var new_high_entry = {
                time: '' + time
                , value: '' + high_value
                , timeAsSeconds: '' + seconds

            };

            new_target_low.push(new_low_entry);
            new_target_high.push(new_high_entry);
        });

        profile_store.target_low = new_target_low;
        profile_store.target_high = new_target_high;

        // ISF

        var new_sens = [];

        _.forEach(profiledata.isfProfile.sensitivities, function(isf_entry) {

            var value = Math.round(isf_entry.sensitivity);

            if (new_profile.units == 'mmol' && profiledata.isfProfile.units == 'mg/dL') {
                value = +(Math.round(isf_entry.sensitivity / 18 + 'e+1') + 'e-1');
            }

            var new_isf_entry = {
                time: isf_entry.start.substring(0, 5)
                , value: '' + value
                , timeAsSeconds: '' + isf_entry.offset * 60
            };

            new_sens.push(new_isf_entry);
        });

        profile_store.sens = new_sens;

        // Carb ratios

        var new_carb_ratios = [];

        _.forEach(profiledata.carb_ratios.schedule, function(carb_entry) {

            var new_entry = {
                time: carb_entry.start.substring(0, 5)
                , value: '' + carb_entry.ratio
                , timeAsSeconds: '' + carb_entry.offset * 60
            };

            new_carb_ratios.push(new_entry);
        });

        profile_store.carbratio = new_carb_ratios;

        // change dates & remove Mongo ID from new profile to create a new object
        // Inserts the new profile with name "OpenAPS Autosync" to not overwrite
        // human-entered data

        var upload_profile;

        if (profile_id != 'OpenAPS Autosync') {
            upload_profile = _.cloneDeep(data);
        } else {
            upload_profile = new_profile;
        }

        var do_upload = !_.isEqual(original_profile, new_profile);

        if (do_upload) {

            var d = new Date();
            profile_store.startDate = d.toISOString();

            if (profile_id != 'OpenAPS Autosync') {
                upload_profile.defaultProfile = 'OpenAPS Autosync';
                upload_profile.store['OpenAPS Autosync'] = profile_store;
            }

            delete upload_profile._id;

            upload_profile.startDate = profile_store.startDate;
            upload_profile.created_at = profile_store.startDate;
            upload_profile.mills = d.getTime();
        }

        // render preview

        if (params.preview) {

            if (_.isEqual(original_profile, new_profile)) {
                console.log('Profile in Nightscout and OpenAPS are identical');
            } else {
                console.log('Profile in Nightscout and OpenAPS differ');
                console.log('-------------- Nightscout Profile ----------------');
                console.log(JSON.stringify(original_profile, null, 2));
                console.log('-------------- New profile from OpenAPS data ----------------');
                console.log(JSON.stringify(upload_profile, null, 2));
            }

            process.exit(0);
        }

        if (do_upload) {

            console.log('Profile changed, uploading to Nightscout');

            options = {
                uri: nsurl + '/api/v1/profile/'
                , json: true
                , method: 'POST'
                , headers: {
                    'api-secret': apisecret
                }
                , body: upload_profile
            };

            request(options, function(error, res, data) {
                if (error || res.statusCode != 200) {
                    console.log(error);
                    console.log(res.body);
                } else {
                    console.log('Profile uploaded to Nightscout');
                }
            });
        } else {
            console.log('Profiles match, no upload needed');
        }
    });
}
<commit_msg>Added token support for oref0-upload-profile.js (#1084)<commit_after>#!/usr/bin/env node

/*
  oref0 Nightscout profile update tool

  Checks the ISF / Basal profile in Nightscout and updates the profile if
  necessary to match the profile collected by OpenAPS

  Released under MIT license. See the accompanying LICENSE.txt file for
  full terms and conditions

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.

*/

var crypto = require('crypto');
var request = require('request');
var _ = require('lodash');

if (!module.parent) {

    var argv = require('yargs')
        .usage("$0 profile.json NSURL api-secret [--preview]")
        .option('preview', {
            alias: 'p'
            , describe: "Give a preview of the outcome without uploading"
            , default: false
        })
        .strict(true)
        .help('help');

    function usage() {
        argv.showHelp();
    }

    var params = argv.argv;
    var errors = [];
    var warnings = [];

    var profile_input = params._[0];

    if ([null, '--help', '-h', 'help'].indexOf(profile_input) > 0) {
        usage();
        process.exit(0);
    }

    var nsurl = params._[1];
    var apisecret = params._[2];

    if (!profile_input || !nsurl || !apisecret) {
        usage();
        process.exit(1);
    }

    if (!apisecret.startsWith('token=') && apisecret.length != 40) {
        var shasum = crypto.createHash('sha1');
        shasum.update(String(apisecret));
        apisecret = shasum.digest('hex');
    };

    try {
        var cwd = process.cwd();
        var profiledata = require(cwd + '/' + profile_input);

        // Rudimentary check that the profile is valid

        if (!profiledata.dia
          || profiledata.basalprofile.length < 1
          || profiledata.bg_targets.length < 1
          || profiledata.isfProfile.length < 1 )
          { throw "Profile JSON missing data"; }

    } catch (e) {
        return console.error('Could not parse input data: ', e);
    }

    var options = {
        uri: nsurl + '/api/v1/profile/current'
        , json: true
        , headers: {
            'api-secret': apisecret
        }
    };

    request(options, function(error, res, data) {
        if (error || res.statusCode != 200) {
            console.log('Loading current profile from Nightscout failed');
            process.exit(1);
        }

        var original_profile = data;
        var new_profile = _.cloneDeep(data);

        if (!data.defaultProfile) {
            console.error('Nightscout profile missing data');
            process.exit(1);
        }

        var profile_id = data.defaultProfile;
        var profile_store = new_profile.store[profile_id];

        profile_store.dia = profiledata.dia;

        // Basals

        var new_basal = [];

        _.forEach(profiledata.basalprofile, function(basalentry) {

            var newEntry = {
                time: '' + basalentry.start.substring(0, 5)
                , value: '' + +(Math.round(basalentry.rate + 'e+3') + 'e-3')
                , timeAsSeconds: '' + basalentry.minutes * 60
            };

            new_basal.push(newEntry);

        });

        profile_store.basal = new_basal;

        // BG Targets

        var new_target_low = [];
        var new_target_high = [];

        _.forEach(profiledata.bg_targets.targets, function(target_entry) {

            var time = target_entry.start.substring(0, 5);
            var seconds = parseInt(time.substring(0, 2)) * 60 * 60 + parseInt(time.substring(3, 5)) * 60;
            var low_value = Math.round(target_entry.low);
            var high_value = Math.round(target_entry.high);

            if (new_profile.units == 'mmol' && profiledata.bg_targets.units == 'mg/dL') {
                low_value = +(Math.round(target_entry.low / 18 + 'e+1') + 'e-1');
                high_value = +(Math.round(target_entry.high / 18 + 'e+1') + 'e-1');
            }

            var new_low_entry = {
                time: '' + time
                , value: '' + low_value
                , timeAsSeconds: '' + seconds
            };

            var new_high_entry = {
                time: '' + time
                , value: '' + high_value
                , timeAsSeconds: '' + seconds

            };

            new_target_low.push(new_low_entry);
            new_target_high.push(new_high_entry);
        });

        profile_store.target_low = new_target_low;
        profile_store.target_high = new_target_high;

        // ISF

        var new_sens = [];

        _.forEach(profiledata.isfProfile.sensitivities, function(isf_entry) {

            var value = Math.round(isf_entry.sensitivity);

            if (new_profile.units == 'mmol' && profiledata.isfProfile.units == 'mg/dL') {
                value = +(Math.round(isf_entry.sensitivity / 18 + 'e+1') + 'e-1');
            }

            var new_isf_entry = {
                time: isf_entry.start.substring(0, 5)
                , value: '' + value
                , timeAsSeconds: '' + isf_entry.offset * 60
            };

            new_sens.push(new_isf_entry);
        });

        profile_store.sens = new_sens;

        // Carb ratios

        var new_carb_ratios = [];

        _.forEach(profiledata.carb_ratios.schedule, function(carb_entry) {

            var new_entry = {
                time: carb_entry.start.substring(0, 5)
                , value: '' + carb_entry.ratio
                , timeAsSeconds: '' + carb_entry.offset * 60
            };

            new_carb_ratios.push(new_entry);
        });

        profile_store.carbratio = new_carb_ratios;

        // change dates & remove Mongo ID from new profile to create a new object
        // Inserts the new profile with name "OpenAPS Autosync" to not overwrite
        // human-entered data

        var upload_profile;

        if (profile_id != 'OpenAPS Autosync') {
            upload_profile = _.cloneDeep(data);
        } else {
            upload_profile = new_profile;
        }

        var do_upload = !_.isEqual(original_profile, new_profile);

        if (do_upload) {

            var d = new Date();
            profile_store.startDate = d.toISOString();

            if (profile_id != 'OpenAPS Autosync') {
                upload_profile.defaultProfile = 'OpenAPS Autosync';
                upload_profile.store['OpenAPS Autosync'] = profile_store;
            }

            delete upload_profile._id;

            upload_profile.startDate = profile_store.startDate;
            upload_profile.created_at = profile_store.startDate;
            upload_profile.mills = d.getTime();
        }

        // render preview

        if (params.preview) {

            if (_.isEqual(original_profile, new_profile)) {
                console.log('Profile in Nightscout and OpenAPS are identical');
            } else {
                console.log('Profile in Nightscout and OpenAPS differ');
                console.log('-------------- Nightscout Profile ----------------');
                console.log(JSON.stringify(original_profile, null, 2));
                console.log('-------------- New profile from OpenAPS data ----------------');
                console.log(JSON.stringify(upload_profile, null, 2));
            }

            process.exit(0);
        }

        if (do_upload) {
            var nsheaders = {
                'Content-Type': 'application/json'
            };

            console.log('Profile changed, uploading to Nightscout');

            nsurl = nsurl + '/api/v1/profile';

            if (apisecret.startsWith('token=')) {
                nsurl = nsurl + '?' + apisecret;
            } else {
                nsheaders['API-SECRET'] = apisecret;
            }

            options = {
                uri: nsurl
                , json: true
                , method: 'POST'
                , headers: nsheaders
                , body: upload_profile
            };

            request(options, function(error, res, data) {
                if (error || res.statusCode != 200) {
                    console.log(error);
                    console.log(res.body);
                } else {
                    console.log('Profile uploaded to Nightscout');
                }
            });
        } else {
            console.log('Profiles match, no upload needed');
        }
    });
}
<|endoftext|>


<commit_before>/* exported populateCytobands */
function populateCytobands(cytobands){
  var chromPosPattern = new RegExp("^(?:chr)?([1-9]|1[0-9]|2[0-2]|X|Y|MT)$");
  var chrom = document.forms["filters_form"].elements["chrom"].value;
  var chromPos = "";
  if (typeof document.forms["filters_form"].elements["chrom_pos"] != "undefined") {
  	chromPos=document.forms["filters_form"].elements["chrom_pos"].value;
	}

  var chromosome = "";
  console.log("Populate cytobands")
  var matchedChrName = chromPos.match(chromPosPattern)
  if(chrom==="" && chromPos===""){
    startElem.value = "";
    endElem.value = "";
    return //only reset cytoband select element
  // Set the selected chromosome name
  } else if (chrom !== "" && matchedChrName !== null){
    chromosome = matchedChrName[1]
  } else if (chrom === "" && matchedChrName !== null){
    chromosome = matchedChrName[1]
  } else if (chrom == "" && matchedChrName == null) {
    return
  } else {
    chromosome = chrom;
  }

  var chrom_cytobands = cytobands[chromosome]["cytobands"]; // chromosome-specific cytobands

  for (elem of [cytoStart, cytoEnd]) {
    if (elem.options.length > 0){
      elem.options.length = 0; //remove previous select options
    }
    var emptyStart = document.createElement("option");
    emptyStart.textContent = "";
    emptyStart.value = "";
    elem.appendChild(emptyStart); //Add an empty (blank) option to the select
  }

  for(var i = 0; i < chrom_cytobands.length; i++) {
    var opt = chrom_cytobands[i]

    // populate the cytoband start select
    var interval = ["(start:",opt["start"], ")"].join("");
    var optionText = [ chrom, opt["band"], interval ].join(" ");

    // populate the cytoband start select
    var el = document.createElement("option");
    el.textContent = optionText;
    el.value = opt["start"];
    if(startElem.value === el.value){
      el.selected = true;
    }
    cytoStart.appendChild(el);

    var interval = ["(end:",opt["stop"], ")"].join("")
    var optionText = [ chrom, opt["band"], interval ].join(" ");

    var el = document.createElement("option");
    el.textContent = optionText;
    el.value = opt["stop"];
    if(endElem.value === el.value){
      el.selected = true;
    }
    cytoEnd.appendChild(el);
  }
}

/* exported validateForm */
// ValidateForm()
// Controll user input fields (start, end) in varaint filter.
// Verify the format of Chromosome position
//
function validateForm(){
  var start = document.forms["filters_form"].elements["start"].value
  var end = document.forms["filters_form"].elements["end"].value
  if(start || end){
    if(!chrom){
      alert("Chromosome field is required");
      return false;
    }
    else if( !start || !end){
      alert("Both start and end coordinates are required");
      return false;
    }
    else if( (isNaN(start) || isNaN(end)) || Number(end)<Number(start) ){
      alert("Coordinate field not valid");
      return false;
    }
  }
  // Validate Chromosome position form
  //Expected format: <chr number>:<start>-<end>[+-]?<padding>
  var chrom_pos = document.forms["filters_form"].elements["chrom_pos"].value.replaceAll(',', '')
  var chrPosPattern = "^(?:chr)?([1-9]|1[0-9]|2[0-2]|X|Y|MT)(?::([0-9]+)-([0-9]+)([+-]{1}[0-9]+)?)?$";
  if(chrom_pos) {
    if (!RegExp(chrPosPattern).test(chrom_pos)) {
      alert("Invalid format of chromosome position, expected format <chr number>:<start>-<end>[+-]?<padding>");
      return false;
    }
    var chromPosMatch  = chrom_pos.match(chrPosPattern);
    var start = chromPosMatch[2];
    var end = chromPosMatch[3];
    var padding = chromPosMatch[5];
    if (Number(start) < 0 || Number(end) < 0) {
      alert("Invalid coordinates, coordinates must be greater than zero");
      return false;
    } else if (Number(start) > Number(end)) {
      alert("Invalid coordinates, end coordinate must be greater than start");
      return false;
    } else if (Number(padding) < 1) {
      alert("Padding must be greater than zero!")
    }
  }
  return true;
}

/* exported initSearchConstraints */
// syncSearchConstraints(selectorId:HTML-selector, textId:HTML-textfield)
//
// Initialize and synchronize 'startelem' and 'cyto_start', used for setting
// contrsaints when searching variants in cytoband.
function initSearchConstraints(selectorId, textId){
    console.log("init cytoband search: selector and text")
    selectorId.addEventListener("change", function() {
        if(selectorId.options[selectorId.selectedIndex].value === ""){
            textId.value = "";
            return
        }
        // populate textfield
        textId.value = selectorId.options[selectorId.selectedIndex].value
    });
}

/* exported enableDismiss */
function enableDismiss(){
  // before enabling the variant dismiss button
  var selectElem = document.getElementById("dismiss_choices");
  // make sure that user selects at least one dismiss reason
  var selectedOptions = false;
  for (var i = 0; i < selectElem.length; i++) {
      if (selectElem.options[i].selected){
        selectedOptions = true;
        break;
      }
  }
  // make sure that at least one checkbox corresponding to a variant is checked
  var variantCheckboxes = document.getElementsByName("dismiss");
  var checkedVars=false
  for (var i = 0; i < variantCheckboxes.length; i++) {
      if (variantCheckboxes[i].checked){
        checkedVars = true;
        break;
      }
  }
  var btnElem = document.getElementById("dismiss_submit");
  if (selectedOptions & checkedVars) {
    btnElem.disabled = false;
  }
  else{
    btnElem.disabled = true;
  }
}

/* exported eraseChromPosString() */
function eraseChromPosString() {
  // Erase content of chrom_pos field
  document.forms["filters_form"].elements["chrom_pos"].value = "";
}

/* exported updateCoordinateFields */
// Link chromosome position input field with chromosome and cytoband dropdowns.
// Changes to chrom and cytoband dropdowns are reflected in chrom_pos input
// Changes in chrom_pos input are reflected in chrom, start and end fields
function updateCoordinateFields(element) {
  var chrom = document.forms["filters_form"].elements["chrom"];
  var chromPos = document.forms["filters_form"].elements["chrom_pos"];
  var chromPosPattern = "^(?:chr)?([1-9]|1[0-9]|2[0-2]|X|Y|MT)(?::([0-9]+)-([0-9]+)([+-]{1})?([0-9]+)?)?$";
  // parse chromosome position info
  var chrName, startPos, endPos, sign, padding;
  try {
    [_, chrName, startPos, endPos, sign, padding] = chromPos.value.replaceAll(',', '').match(chromPosPattern);
    console.log(`Parsing ChrPos: ${chrName}, coord: ${startPos}-${endPos}, padding: ${sign}${padding}`)
  } catch (err) {
    console.log('ChrPos empty')
  }
  // update elements
  if (element === chrom) {
    // if alterations in chromosome input field triggered the event
    chromPos.value = element.selectedOptions[0].value;
  } else if (element === chromPos && chrName == null) {
    console.log(`ChrPos regexp not matching ${chromPos.value}`)
		chrom.querySelector(`[value=""]`).selected = true;
  } else {
		console.log(chrName)
		chrom.querySelector(`[value="${chrName}"]`).selected = true;
		// set default padding and sign
		padding = padding != null ? padding : 0
		sign = sign != null ? sign : '+'
		// Update start and end input fields
		if (startPos != null) {
			// invert sign expand before starting position
			var newStartPos = eval(`${startPos} ${sign == '+' ? '-' : '+' } ${padding}`);
			newStartPos = newStartPos < 0 ? 0 : newStartPos
			document.forms["filters_form"].elements["start"].value = newStartPos;
		}
		if (endPos != null) {
			var newEndPos = eval(`${endPos} ${sign} ${padding}`);
			newEndPos = newEndPos < 0 ? 0 : newEndPos
			document.forms["filters_form"].elements["end"].value = newEndPos;
		}
	}
}
<commit_msg>Update scout/server/blueprints/variants/static/form_scripts.js<commit_after>/* exported populateCytobands */
function populateCytobands(cytobands){
  var chromPosPattern = new RegExp("^(?:chr)?([1-9]|1[0-9]|2[0-2]|X|Y|MT)$");
  var chrom = document.forms["filters_form"].elements["chrom"].value;
  var chromPos = "";
  if (typeof document.forms["filters_form"].elements["chrom_pos"] !== "undefined") {
  	chromPos=document.forms["filters_form"].elements["chrom_pos"].value;
	}

  var chromosome = "";
  console.log("Populate cytobands")
  var matchedChrName = chromPos.match(chromPosPattern)
  if(chrom==="" && chromPos===""){
    startElem.value = "";
    endElem.value = "";
    return //only reset cytoband select element
  // Set the selected chromosome name
  } else if (chrom !== "" && matchedChrName !== null){
    chromosome = matchedChrName[1]
  } else if (chrom === "" && matchedChrName !== null){
    chromosome = matchedChrName[1]
  } else if (chrom == "" && matchedChrName == null) {
    return
  } else {
    chromosome = chrom;
  }

  var chrom_cytobands = cytobands[chromosome]["cytobands"]; // chromosome-specific cytobands

  for (elem of [cytoStart, cytoEnd]) {
    if (elem.options.length > 0){
      elem.options.length = 0; //remove previous select options
    }
    var emptyStart = document.createElement("option");
    emptyStart.textContent = "";
    emptyStart.value = "";
    elem.appendChild(emptyStart); //Add an empty (blank) option to the select
  }

  for(var i = 0; i < chrom_cytobands.length; i++) {
    var opt = chrom_cytobands[i]

    // populate the cytoband start select
    var interval = ["(start:",opt["start"], ")"].join("");
    var optionText = [ chrom, opt["band"], interval ].join(" ");

    // populate the cytoband start select
    var el = document.createElement("option");
    el.textContent = optionText;
    el.value = opt["start"];
    if(startElem.value === el.value){
      el.selected = true;
    }
    cytoStart.appendChild(el);

    var interval = ["(end:",opt["stop"], ")"].join("")
    var optionText = [ chrom, opt["band"], interval ].join(" ");

    var el = document.createElement("option");
    el.textContent = optionText;
    el.value = opt["stop"];
    if(endElem.value === el.value){
      el.selected = true;
    }
    cytoEnd.appendChild(el);
  }
}

/* exported validateForm */
// ValidateForm()
// Controll user input fields (start, end) in varaint filter.
// Verify the format of Chromosome position
//
function validateForm(){
  var start = document.forms["filters_form"].elements["start"].value
  var end = document.forms["filters_form"].elements["end"].value
  if(start || end){
    if(!chrom){
      alert("Chromosome field is required");
      return false;
    }
    else if( !start || !end){
      alert("Both start and end coordinates are required");
      return false;
    }
    else if( (isNaN(start) || isNaN(end)) || Number(end)<Number(start) ){
      alert("Coordinate field not valid");
      return false;
    }
  }
  // Validate Chromosome position form
  //Expected format: <chr number>:<start>-<end>[+-]?<padding>
  var chrom_pos = document.forms["filters_form"].elements["chrom_pos"].value.replaceAll(',', '')
  var chrPosPattern = "^(?:chr)?([1-9]|1[0-9]|2[0-2]|X|Y|MT)(?::([0-9]+)-([0-9]+)([+-]{1}[0-9]+)?)?$";
  if(chrom_pos) {
    if (!RegExp(chrPosPattern).test(chrom_pos)) {
      alert("Invalid format of chromosome position, expected format <chr number>:<start>-<end>[+-]?<padding>");
      return false;
    }
    var chromPosMatch  = chrom_pos.match(chrPosPattern);
    var start = chromPosMatch[2];
    var end = chromPosMatch[3];
    var padding = chromPosMatch[5];
    if (Number(start) < 0 || Number(end) < 0) {
      alert("Invalid coordinates, coordinates must be greater than zero");
      return false;
    } else if (Number(start) > Number(end)) {
      alert("Invalid coordinates, end coordinate must be greater than start");
      return false;
    } else if (Number(padding) < 1) {
      alert("Padding must be greater than zero!")
    }
  }
  return true;
}

/* exported initSearchConstraints */
// syncSearchConstraints(selectorId:HTML-selector, textId:HTML-textfield)
//
// Initialize and synchronize 'startelem' and 'cyto_start', used for setting
// contrsaints when searching variants in cytoband.
function initSearchConstraints(selectorId, textId){
    console.log("init cytoband search: selector and text")
    selectorId.addEventListener("change", function() {
        if(selectorId.options[selectorId.selectedIndex].value === ""){
            textId.value = "";
            return
        }
        // populate textfield
        textId.value = selectorId.options[selectorId.selectedIndex].value
    });
}

/* exported enableDismiss */
function enableDismiss(){
  // before enabling the variant dismiss button
  var selectElem = document.getElementById("dismiss_choices");
  // make sure that user selects at least one dismiss reason
  var selectedOptions = false;
  for (var i = 0; i < selectElem.length; i++) {
      if (selectElem.options[i].selected){
        selectedOptions = true;
        break;
      }
  }
  // make sure that at least one checkbox corresponding to a variant is checked
  var variantCheckboxes = document.getElementsByName("dismiss");
  var checkedVars=false
  for (var i = 0; i < variantCheckboxes.length; i++) {
      if (variantCheckboxes[i].checked){
        checkedVars = true;
        break;
      }
  }
  var btnElem = document.getElementById("dismiss_submit");
  if (selectedOptions & checkedVars) {
    btnElem.disabled = false;
  }
  else{
    btnElem.disabled = true;
  }
}

/* exported eraseChromPosString() */
function eraseChromPosString() {
  // Erase content of chrom_pos field
  document.forms["filters_form"].elements["chrom_pos"].value = "";
}

/* exported updateCoordinateFields */
// Link chromosome position input field with chromosome and cytoband dropdowns.
// Changes to chrom and cytoband dropdowns are reflected in chrom_pos input
// Changes in chrom_pos input are reflected in chrom, start and end fields
function updateCoordinateFields(element) {
  var chrom = document.forms["filters_form"].elements["chrom"];
  var chromPos = document.forms["filters_form"].elements["chrom_pos"];
  var chromPosPattern = "^(?:chr)?([1-9]|1[0-9]|2[0-2]|X|Y|MT)(?::([0-9]+)-([0-9]+)([+-]{1})?([0-9]+)?)?$";
  // parse chromosome position info
  var chrName, startPos, endPos, sign, padding;
  try {
    [_, chrName, startPos, endPos, sign, padding] = chromPos.value.replaceAll(',', '').match(chromPosPattern);
    console.log(`Parsing ChrPos: ${chrName}, coord: ${startPos}-${endPos}, padding: ${sign}${padding}`)
  } catch (err) {
    console.log('ChrPos empty')
  }
  // update elements
  if (element === chrom) {
    // if alterations in chromosome input field triggered the event
    chromPos.value = element.selectedOptions[0].value;
  } else if (element === chromPos && chrName == null) {
    console.log(`ChrPos regexp not matching ${chromPos.value}`)
		chrom.querySelector(`[value=""]`).selected = true;
  } else {
		console.log(chrName)
		chrom.querySelector(`[value="${chrName}"]`).selected = true;
		// set default padding and sign
		padding = padding != null ? padding : 0
		sign = sign != null ? sign : '+'
		// Update start and end input fields
		if (startPos != null) {
			// invert sign expand before starting position
			var newStartPos = eval(`${startPos} ${sign == '+' ? '-' : '+' } ${padding}`);
			newStartPos = newStartPos < 0 ? 0 : newStartPos
			document.forms["filters_form"].elements["start"].value = newStartPos;
		}
		if (endPos != null) {
			var newEndPos = eval(`${endPos} ${sign} ${padding}`);
			newEndPos = newEndPos < 0 ? 0 : newEndPos
			document.forms["filters_form"].elements["end"].value = newEndPos;
		}
	}
}
<|endoftext|>


<commit_before>'use strict';

module.exports = {

  plugins: [
    'import',
  ],

  rules: {

    /* Best practices */

    'no-duplicate-imports': 2,
    'no-new-require': 1,

    /* ************* */
    /* Plugin import */
    /* ************* */

    // static analysis

    'import/no-unresolved': [2,
      { commonjs: true },
    ],
    'import/named': 2,
    'import/default': 2,
    'import/namespace': 2,

    // Helpful warnings

    'import/export': 2,
    'import/no-named-as-default': 1,
    'import/no-named-as-default-member': 1,
    'import/no-deprecated': 0,
    'import/no-extraneous-dependencies': 2,

    // Module systems

    'import/no-amd': 2,

    // style guide

    'import/imports-first': [1,
      { 'absolute-first': true },
    ],
    'import/no-duplicates': 1,
    'import/no-namespace': 0,

  },

};
<commit_msg>set strict to global in commonjs<commit_after>'use strict';

module.exports = {

  plugins: [
    'import',
  ],

  rules: {

    /* Best practices */

    'no-duplicate-imports': 2,
    'no-new-require': 1,
    'strict': [2, 'global'],

    /* ************* */
    /* Plugin import */
    /* ************* */

    // static analysis

    'import/no-unresolved': [2,
      { commonjs: true },
    ],
    'import/named': 2,
    'import/default': 2,
    'import/namespace': 2,

    // Helpful warnings

    'import/export': 2,
    'import/no-named-as-default': 1,
    'import/no-named-as-default-member': 1,
    'import/no-deprecated': 0,
    'import/no-extraneous-dependencies': 2,

    // Module systems

    'import/no-amd': 2,

    // style guide

    'import/imports-first': [1,
      { 'absolute-first': true },
    ],
    'import/no-duplicates': 1,
    'import/no-namespace': 0,

  },

};
<|endoftext|>


<commit_before>'use strict';

var Deckard = function (container, config) {
	var self = this;
	container = $(container);
	var items = $(container).children();

	var defaultConfig = {
		enablePagination: true,
		enableNavigation: true,
		framesPerFilmstrip: 10
	}

	//Fold the default configuration into the supplied configuration, to fill in any gaps
	if (!config || (typeof config == 'object' && !(config instanceof Array))) {
		config = defaultConfig;
	} else {
		for (var c in defaultConfig) {
			if (!config[c]) {
				config[c] = defaultConfig[c];
			}
		}
	}

	if (items.length) {
		//Get the slide dimensions to fit everything around
		var dim = {
			width: Math.round(parseInt($(items).first().css('width'), 10)),
			height: Math.round(parseInt($(items).first().css('height'), 10))
		};

		//Calculate filmstrip frame sizes
		var frameWidth = Math.round(((dim.width - (config.framesPerFilmstrip - 1) * 10) / config.framesPerFilmstrip)); // (x-1)*10: take into account x-1 right margins; /x: want to fit x frames;
		var frameHeight = Math.round(dim.height * (frameWidth / dim.width)); // Apply the scale factor from frameWidth to frameHeight, to maintain proportions

		//Calculate filmstrip quantity (crumbtrail page quantity)
		var filmstripTotal = Math.ceil(items.length / config.framesPerFilmstrip);
		//TODO: work out if pages overflow width of stage or not, if not, apply centering.
		var crumbtrailTotal = Math.ceil(((filmstripTotal * 10) + ((filmstripTotal - 1) * 20)) / dim.width);
		var crumbtrailWidth = Math.min(dim.width, (filmstripTotal * 10) + ((filmstripTotal - 1) * 20));

		//Write the markup
		var markup = '';
		var presentation = '';
		var navigation = '';
		var pagination = '';
		items.each(function (index, item) {
			presentation += '
';
	    	presentation += 	'
';
    		presentation += 		this.outerHTML;
    		presentation += '
';
	    	presentation += 	'
';

	    	navigation += 	'
';
	    	navigation += 		'
';
	    	navigation += 			'
' + $(item).attr('deckard-slide-label') + '
';
	    	navigation += 		'
';
	    	navigation += 	'
';
		});
		for (var i = 0; i < filmstripTotal; i++) {
			pagination += 	'
';
	    	pagination += 		'
';
	    	pagination += 			'

';
	    	pagination += 		'
';
	    	pagination += 	'
';
		}
		//Write curtains, stage, and belt around items and supply dimensions
		markup +=	'
';
		markup +=	'

';
		markup +=	'
';
		markup +=	'
';
		markup +=	'
';
		markup +=	pagination;
		markup +=	'
';
		markup +=	'
';
		markup +=	'
';
		markup +=	'

';
		markup +=	'
';
		markup +=	'
';
		markup +=	'

';
		markup +=	'
';
		markup +=	'
';
		markup +=	'
';
		markup +=	navigation;
		markup +=	'
';
		markup +=	'
';
		markup +=	'
';
		markup +=	'

';
		markup +=	'
';
		markup +=	'
';
		markup +=	'

';
		markup +=	'
';
		markup +=	'
';
		markup +=	'
';
		markup +=	presentation;
		markup +=	'
';
		markup +=	'
';
		markup +=	'
';
		markup +=	'

';
		markup +=	'
';

		//Overwrite with new markup
		$(container).html(markup);

		var slidedeck = {
			el: $('.deckard .presentation .slidedeck'),
			total: items.length,
			current: 1,
			size: 1,
			isEnabled: true,
			toString: function () { return 'slidedeck'; }
		};
		var filmstrip = {
			el: $('.deckard .navigation .filmstrip'),
			total: filmstripTotal,
			current: 1,
			size: 10,
			isEnabled: true,
			toString: function () { return 'filmstrip'; }
		};
		var crumbtrail = {
			el: $('.deckard .pagination .crumbtrail'),
			total: crumbtrailTotal,
			current: 1,
			size: Math.ceil(dim.width / 30),
			isEnabled: true,
			toString: function () { return 'crumbtrail'; }
		};

		Deckard.mediator.register(slidedeck);
		Deckard.mediator.register(filmstrip);
		Deckard.mediator.register(crumbtrail);

		var trackMoveFactory = function (stream) {
			return function (event, data) {
				if (event === 'move') {
					$(stream.el[0].childNodes).find('.selected').removeClass('selected');
					self.move(stream)(Math.floor((data.current-1) / stream.size));
					$(stream.el[0].childNodes[data.current-1].firstChild).addClass('selected');
				}
			};
		};

		Deckard.mediator.subscribe(slidedeck, null, trackMoveFactory(filmstrip));
		Deckard.mediator.subscribe(filmstrip, null, trackMoveFactory(crumbtrail));

		//Attach move handlers
		$(container).find('.presentation .curtain-right').on('click', function () { self.move(slidedeck)('left'); });
		$(container).find('.presentation .curtain-left').on('click', function () { self.move(slidedeck)('right'); });

		$(container).find('.navigation .curtain-right').on('click', function () { self.move(filmstrip)('left'); });
		$(container).find('.navigation .curtain-left').on('click', function () {self. move(filmstrip)('right'); });

		$(container).find('.pagination .curtain-right').on('click', function () { self.move(crumbtrail)('left'); });
		$(container).find('.pagination .curtain-left').on('click', function () { self.move(crumbtrail)('right'); });

		$(container).find('.presentation').on('swiperight', function () { self.move(slidedeck)('right'); });
		$(container).find('.presentation').on('swipeleft', function () { self.move(slidedeck)('left'); });

		$(container).find('.navigation').on('swiperight', function () { self.move(filmstrip)('right'); });
		$(container).find('.navigation').on('swipeleft', function () { self.move(filmstrip)('left'); });

		$(container).find('.pagination').on('swiperight', function () { self.move(crumbtrail)('right'); });
		$(container).find('.pagination').on('swipeleft', function () { self.move(crumbtrail)('left'); });

		$(container).find('.pagination .stage .belt .crumb-outer').on('click', function () {
			self.move(filmstrip)($(this).index());
		});
		$(container).find('.navigation .stage .belt .frame-outer').on('click', function () {
			self.move(slidedeck)($(this).index());
		});
	}
};

/* Run immediately after script is loaded, and pick up all containers classed as
 * .deckard to wrap with Deckard.
*/
Deckard.prototype.init = function () {
};

Deckard.prototype.move = function (stream) {
	return function (vector) {
		var hasRoom = false;
		var displacement = undefined;
		if (typeof vector === 'string' && vector == 'right') {
			hasRoom = (stream.current > 1);
			displacement = -1;
		} else if (typeof vector === 'string' && vector == 'left') {
			hasRoom = (stream.current < stream.total);
			displacement = +1;
		} else if (typeof vector === 'number' && vector + 1 < stream.current) {
			hasRoom = true;
			displacement = -(stream.current - vector + 1) + 2;
		} else if (typeof vector === 'number' && vector + 1 > stream.current) {
			hasRoom = true;
			displacement = +(vector + 1 - stream.current);
		}
		if (hasRoom && stream.isEnabled) {
			stream.isEnabled = false;
			var position = parseInt(stream.el[0].style.left, 10);
			position = (isNaN(position) ? 0 : position);
			var cardWidth = parseInt($(stream.el[0].firstChild).css('width'), 10) * stream.size;
			//stream.el[0].style.left = (position - (displacement * cardWidth)) + 'px';
			$(stream.el).animate({
				'left': position - (displacement * cardWidth)
			}, {
				queue: false,
				complete: function () {
					stream.current += displacement;
					stream.isEnabled = true;

					Deckard.mediator.publish(stream, 'move', {
						vector: vector,
						hasRoom: hasRoom,
						displacement: displacement,
						current: stream.current
					});
				}
			});
		}
	};
};

Deckard.mediator = {
	subscriptions: {
		'move': []
	},
	register: function (publisher) {
		var registered = false;
		if (publisher && !this.subscriptions[publisher]) {
			this.subscriptions[publisher] = [];
			registered = true;
		}
		return registered;
	},
	publish: function (publisher, event, data) {
		if (publisher && this.subscriptions[publisher]) {
			for (var callback in this.subscriptions[publisher]) {
				this.subscriptions[publisher][callback](event, data);
			}
		}
		if (event && this.subscriptions[event]) {
			for (var callback in this.subscriptions[event]) {
				this.subscriptions[event][callback](event, data);
			}
		}
	},
	subscribe: function (publisher, event, callback) {
		if (publisher && this.subscriptions[publisher]) {
			this.subscriptions[publisher].push(callback);
		}
		if (event && this.subscriptions[event]) {
			this.subscriptions[event].push(callback);
		}
	}
};<commit_msg>Refactor code.<commit_after>'use strict';

var Deckard = function (container, config) {
	var self = this;
	container = $(container);
	var items = $(container).children();

	var defaultConfig = {
		enablePagination: true,
		enableNavigation: true,
		framesPerFilmstrip: 10
	}

	//Fold the default configuration into the supplied configuration, to fill in any gaps
	if (!config || (typeof config == 'object' && !(config instanceof Array))) {
		config = defaultConfig;
	} else {
		for (var c in defaultConfig) {
			if (!config[c]) {
				config[c] = defaultConfig[c];
			}
		}
	}

	if (items.length) {
		//Get the slide dimensions to fit everything around
		var dim = {
			width: Math.round(parseInt($(items).first().css('width'), 10)),
			height: Math.round(parseInt($(items).first().css('height'), 10))
		};

		//Calculate filmstrip frame sizes
		var frameWidth = Math.round(((dim.width - (config.framesPerFilmstrip - 1) * 10) / config.framesPerFilmstrip)); // (x-1)*10: take into account x-1 right margins; /x: want to fit x frames;
		var frameHeight = Math.round(dim.height * (frameWidth / dim.width)); // Apply the scale factor from frameWidth to frameHeight, to maintain proportions

		//Calculate filmstrip quantity (crumbtrail page quantity)
		var filmstripTotal = Math.ceil(items.length / config.framesPerFilmstrip);
		//TODO: work out if pages overflow width of stage or not, if not, apply centering.
		var crumbtrailTotal = Math.ceil(((filmstripTotal * 10) + ((filmstripTotal - 1) * 20)) / dim.width);
		var crumbtrailWidth = Math.min(dim.width, (filmstripTotal * 10) + ((filmstripTotal - 1) * 20));

		//Write the markup
		var markup = '';
		var presentation = '';
		var navigation = '';
		var pagination = '';
		items.each(function (index, item) {
			presentation += '
';
	    	presentation += 	'
';
    		presentation += 		this.outerHTML;
    		presentation += '
';
	    	presentation += 	'
';

	    	navigation += 	'
';
	    	navigation += 		'
';
	    	navigation += 			'
' + $(item).attr('deckard-slide-label') + '
';
	    	navigation += 		'
';
	    	navigation += 	'
';
		});
		for (var i = 0; i < filmstripTotal; i++) {
			pagination += 	'
';
	    	pagination += 		'
';
	    	pagination += 			'

';
	    	pagination += 		'
';
	    	pagination += 	'
';
		}
		//Write curtains, stage, and belt around items and supply dimensions
		markup +=	'
';
		markup +=		'

';
		markup +=		'
';
		markup +=			'
';
		markup +=				'
';
		markup +=					pagination;
		markup +=				'
';
		markup +=			'
';
		markup +=		'
';
		markup +=		'

';
		markup +=	'
';
		markup +=	'
';
		markup +=		'

';
		markup +=		'
';
		markup +=			'
';
		markup +=				'
';
		markup +=					navigation;
		markup +=				'
';
		markup +=			'
';
		markup +=		'
';
		markup +=		'

';
		markup +=	'
';
		markup +=	'
';
		markup +=		'

';
		markup +=		'
';
		markup +=			'
';
		markup +=				'
';
		markup +=					presentation;
		markup +=				'
';
		markup +=			'
';
		markup +=		'
';
		markup +=		'

';
		markup +=	'
';

		//Overwrite with new markup
		$(container).html(markup);

		var slidedeck = {
			el: $('.deckard .presentation .slidedeck'),
			total: items.length,
			current: 1,
			size: 1,
			isEnabled: true,
			toString: function () { return 'slidedeck'; }
		};
		var filmstrip = {
			el: $('.deckard .navigation .filmstrip'),
			total: filmstripTotal,
			current: 1,
			size: 10,
			isEnabled: true,
			toString: function () { return 'filmstrip'; }
		};
		var crumbtrail = {
			el: $('.deckard .pagination .crumbtrail'),
			total: crumbtrailTotal,
			current: 1,
			size: Math.ceil(dim.width / 30),
			isEnabled: true,
			toString: function () { return 'crumbtrail'; }
		};

		Deckard.mediator.register(slidedeck);
		Deckard.mediator.register(filmstrip);
		Deckard.mediator.register(crumbtrail);

		var trackMoveFactory = function (stream) {
			return function (event, data) {
				if (event === 'move') {
					$(stream.el[0].childNodes).find('.selected').removeClass('selected');
					self.move(stream)(Math.floor((data.current-1) / stream.size));
					$(stream.el[0].childNodes[data.current-1].firstChild).addClass('selected');
				}
			};
		};

		Deckard.mediator.subscribe(slidedeck, null, trackMoveFactory(filmstrip));
		Deckard.mediator.subscribe(filmstrip, null, trackMoveFactory(crumbtrail));

		//Attach move handlers
		$(container).find('.presentation .curtain-right').on('click', function () { self.move(slidedeck)('left'); });
		$(container).find('.presentation .curtain-left').on('click', function () { self.move(slidedeck)('right'); });

		$(container).find('.navigation .curtain-right').on('click', function () { self.move(filmstrip)('left'); });
		$(container).find('.navigation .curtain-left').on('click', function () {self. move(filmstrip)('right'); });

		$(container).find('.pagination .curtain-right').on('click', function () { self.move(crumbtrail)('left'); });
		$(container).find('.pagination .curtain-left').on('click', function () { self.move(crumbtrail)('right'); });

		$(container).find('.presentation').on('swiperight', function () { self.move(slidedeck)('right'); });
		$(container).find('.presentation').on('swipeleft', function () { self.move(slidedeck)('left'); });

		$(container).find('.navigation').on('swiperight', function () { self.move(filmstrip)('right'); });
		$(container).find('.navigation').on('swipeleft', function () { self.move(filmstrip)('left'); });

		$(container).find('.pagination').on('swiperight', function () { self.move(crumbtrail)('right'); });
		$(container).find('.pagination').on('swipeleft', function () { self.move(crumbtrail)('left'); });

		$(container).find('.pagination .stage .belt .crumb-outer').on('click', function () {
			self.move(filmstrip)($(this).index());
		});
		$(container).find('.navigation .stage .belt .frame-outer').on('click', function () {
			self.move(slidedeck)($(this).index());
		});
	}
};

/* Run immediately after script is loaded, and pick up all containers classed as
 * .deckard to wrap with Deckard.
*/
Deckard.prototype.init = function () {
};

Deckard.prototype.move = function (stream) {
	return function (vector) {
		var hasRoom = false;
		var displacement = undefined;
		if (typeof vector === 'string' && vector == 'right') {
			hasRoom = (stream.current > 1);
			displacement = -1;
		} else if (typeof vector === 'string' && vector == 'left') {
			hasRoom = (stream.current < stream.total);
			displacement = +1;
		} else if (typeof vector === 'number' && vector + 1 < stream.current) {
			hasRoom = true;
			displacement = -(stream.current - vector + 1) + 2;
		} else if (typeof vector === 'number' && vector + 1 > stream.current) {
			hasRoom = true;
			displacement = +(vector + 1 - stream.current);
		}
		if (hasRoom && stream.isEnabled) {
			stream.isEnabled = false;
			var position = parseInt(stream.el[0].style.left, 10);
			position = (isNaN(position) ? 0 : position);
			var cardWidth = parseInt($(stream.el[0].firstChild).css('width'), 10) * stream.size;
			//stream.el[0].style.left = (position - (displacement * cardWidth)) + 'px';
			$(stream.el).animate({
				'left': position - (displacement * cardWidth)
			}, {
				queue: false,
				complete: function () {
					stream.current += displacement;
					stream.isEnabled = true;

					Deckard.mediator.publish(stream, 'move', {
						vector: vector,
						hasRoom: hasRoom,
						displacement: displacement,
						current: stream.current
					});
				}
			});
		}
	};
};

Deckard.mediator = {
	subscriptions: {
		'move': []
	},
	register: function (publisher) {
		var registered = false;
		if (publisher && !this.subscriptions[publisher]) {
			this.subscriptions[publisher] = [];
			registered = true;
		}
		return registered;
	},
	publish: function (publisher, event, data) {
		if (publisher && this.subscriptions[publisher]) {
			for (var callback in this.subscriptions[publisher]) {
				this.subscriptions[publisher][callback](event, data);
			}
		}
		if (event && this.subscriptions[event]) {
			for (var callback in this.subscriptions[event]) {
				this.subscriptions[event][callback](event, data);
			}
		}
	},
	subscribe: function (publisher, event, callback) {
		if (publisher && this.subscriptions[publisher]) {
			this.subscriptions[publisher].push(callback);
		}
		if (event && this.subscriptions[event]) {
			this.subscriptions[event].push(callback);
		}
	}
};<|endoftext|>


<commit_before>/**
 * The main module
 *
 * @context atl.general
 */
var $ = require('speakeasy/jquery').jQuery;
var images = $.map(
        [ 'alert.jpg', 'bad_ass.jpg', 'thumb_up.jpg' ],
        function(img) {
            return require('speakeasy/resources').getImageUrl(module, img);
        });

$(document).ready(function() {
    var imageIndex = Math.floor(4 * Math.random());
    $('.welcome-message').prepend('

');
    $('#chuckImage').attr('src', images[imageIndex]);

    $('#chuck').bind('click', function() {
        $.ajax({
            url: 'http://api.icndb.com/jokes/random',
            success: function(data) {
                var joke = JSON.parse(data);

                if (joke.type === 'success') {
                    $('#chuck-norris-facts').html(joke.value.joke);
                }
                $('#chuckImage').attr('src', images[imageIndex]);
                imageIndex = (imageIndex + 1) % 3;
            }
        });
    }).trigger('click');
});
<commit_msg>Edit from the UI<commit_after>/**
 * The main module
 *
 * @context atl.general
 */
var $ = require('speakeasy/jquery').jQuery;
var images = $.map(
        [ 'alert.jpg', 'bad_ass.jpg', 'thumb_up.jpg' ],
        function(img) {
            return require('speakeasy/resources').getImageUrl(module, img);
        });

$(document).ready(function() {
    var imageIndex = Math.floor(4 * Math.random());
    $('.welcome-message').prepend('

');
    $('#chuckImage').attr('src', images[imageIndex]);

    $('#chuck').bind('click', function() {
        $.ajax({
            url: 'http://api.icndb.com/jokes/random',
            success: function(data) {
                var joke = JSON.parse(data);

                if (joke.type === 'success') {
                    $('#chuck-norris-facts').html(joke.value.joke);
                }
                imageIndex = (imageIndex + 1) % images.length;
                $('#chuckImage').attr('src', images[imageIndex]);
            }
        });
    }).trigger('click');
});
<|endoftext|>