<commit_before>/* global document window */
import getElements from '../utilities/getElements';
import { focusFirstEl } from '../utilities/elementState';
import { isEscPressed } from '../utilities/keypress';
import isElementVisible from '../utilities/isElementVisible';
import scrollYDirection from '../utilities/scrollYDirection';
import { hideDropDown, showDropDown } from './dropdown';
import debounce from '../node_modules/lodash/debounce';

const addClassOnScroll = (element, scrollPos, scrollPoint, classToToggle) => {
  // If user scrolls past the scrollPoint then add class
  if (scrollPos >= scrollPoint) {
    element.classList.add(classToToggle);
  } else {
    element.classList.remove(classToToggle);
  }
};

/*
* Add or remove the class depending
* on if the user is scrolling up or down
*/
const toggleMenu = scrollDirection => {
  const masthead = document.querySelector('[data-sprk-masthead]');
  if (scrollDirection === 'down') {
    masthead.classList.add('sprk-c-Masthead--hidden');
  } else {
    masthead.classList.remove('sprk-c-Masthead--hidden');
  }
};

/*
* Set initial scroll direction
* If the scroll direction changes
* toggle the masthead visibility
*/
let direction = scrollYDirection();
const checkScrollDirection = debounce(() => {
  const newDirection = scrollYDirection();
  if (direction !== newDirection) {
    toggleMenu(newDirection);
  }
  direction = newDirection;
}, 30);

/*
* If the mobile menu is visible
* add the check scroll event listener
* otherwise remove it
*/
const toggleScrollEvent = isMenuVisible => {
  let attached = false;
  if (isMenuVisible) {
    window.addEventListener('scroll', checkScrollDirection);
    attached = true;
  } else {
    window.removeEventListener('scroll', checkScrollDirection, false);
    attached = false;
  }
  return attached;
};

const toggleMobileNav = (iconContainer, nav, masthead) => {
  document.body.classList.toggle('sprk-u-Overflow--hidden');
  // Don't add height: 100% if site's html &
  // body el already have it (reapplying makes page jump)
  document.documentElement.classList.toggle('sprk-u-Overflow--hidden');
  if (document.documentElement.style.height !== '100%') {
    document.documentElement.classList.add('sprk-u-Height--100');
  }
  if (document.body.style.height !== '100%') {
    document.body.classList.add('sprk-u-Height--100');
  }
  masthead.classList.toggle('sprk-c-Masthead--open');
  iconContainer
    .querySelector('svg')
    .classList.toggle('sprk-c-Menu__icon--open');
  nav.classList.toggle('sprk-u-Display--none');
};

const focusTrap = (isOpen, nav) => {
  if (isOpen) {
    focusFirstEl(nav);
  }
};

const hideMobileNavs = () => {
  document.body.classList.remove('sprk-u-Overflow--hidden');
  document.documentElement.classList.remove('sprk-u-Overflow--hidden');
  document.body.classList.remove('sprk-u-Height--100');
  document.documentElement.classList.remove('sprk-u-Height--100');
  getElements('[data-sprk-mobile-nav]', item => {
    item.classList.add('sprk-u-Display--none');
  });
  getElements('.sprk-c-Menu__icon--open', item => {
    item.classList.remove('sprk-c-Menu__icon--open');
  });
  getElements('.sprk-c-Masthead--open', item => {
    item.classList.remove('sprk-c-Masthead--open');
  });
};

const hideSelectorMask = mastheadSelectorMask => {
  mastheadSelectorMask.classList.remove('sprk-c-MastheadMask');
};

const showSelectorMask = mastheadSelectorMask => {
  mastheadSelectorMask.classList.add('sprk-c-MastheadMask');
};

const bindUIEvents = () => {
  getElements('[data-sprk-mobile-nav-trigger]', element => {
    const mainLayout = document.querySelector('[data-sprk-main]');
    const masthead = document.querySelector('[data-sprk-masthead]');
    const selectorDropdown = document.querySelector(
      '[data-sprk-dropdown="dropdown-selector"]',
    );
    const selectorTrigger = document.querySelector(
      '[data-sprk-dropdown-trigger="dropdown-selector"]',
    );

    const nav = document.querySelector(
      `[data-sprk-mobile-nav="${element.getAttribute(
        'data-sprk-mobile-nav-trigger',
      )}"]`,
    );
    /*
    * Check if the mobile menu is visible
    * on page and set scroll event
    */
    let isMenuVisible;
    window.addEventListener('load', () => {
      isMenuVisible = isElementVisible('.sprk-c-Masthead__menu');
      toggleScrollEvent(isMenuVisible);
    });
    /*
    * If the mobile menu visibility changes
    * toggle scroll event listener
    */
    window.addEventListener('resize', () => {
      console.log(isMenuVisible);
      const newMenuVisibility = isElementVisible('.sprk-c-Masthead__menu');
      if (isMenuVisible !== newMenuVisibility) {
        toggleScrollEvent(newMenuVisibility);
      }
      isMenuVisible = newMenuVisibility;
    });

    element.addEventListener('click', e => {
      e.preventDefault();
      toggleMobileNav(element, nav, masthead);
    });

    window.addEventListener('scroll', () => {
      addClassOnScroll(masthead, window.scrollY, 10, 'sprk-c-Masthead--scroll');
    });

    mainLayout.addEventListener('focusin', () => {
      const isOpen = !document
        .querySelector('.sprk-c-Masthead__narrow-nav')
        .classList.contains('sprk-u-HideWhenJs');
      focusTrap(isOpen, nav);
    });

    if (selectorTrigger && selectorDropdown) {
      const selectorTriggerInDropdown = document.querySelector(
        '[data-sprk-selector-dropdown-trigger="dropdown-selector"]',
      );
      const wideSelectorDropdown = document.querySelector(
        '[data-sprk-dropdown="dropdown-selector-wide"]',
      );
      const wideSelectorTriggerInDropdown = document.querySelector(
        '[data-sprk-selector-dropdown-trigger="dropdown-selector-wide"]',
      );
      const mastheadSelectorMask = document.querySelector(
        '[data-sprk-masthead-mask]',
      );
      const selectorDropdownChoices = selectorDropdown.querySelectorAll(
        '[data-sprk-dropdown-choice]',
      );

      selectorTrigger.addEventListener('click', () => {
        const dropdownIsOpen = selectorDropdown.classList.contains(
          'sprk-c-Dropdown--open',
        );
        if (dropdownIsOpen) {
          hideSelectorMask(mastheadSelectorMask);
        } else {
          showSelectorMask(mastheadSelectorMask);
        }
      });

      selectorTriggerInDropdown.addEventListener('click', () => {
        const dropdownIsOpen = selectorDropdown.classList.contains(
          'sprk-c-Dropdown--open',
        );
        if (dropdownIsOpen) {
          hideSelectorMask(mastheadSelectorMask);
          hideDropDown(selectorDropdown);
        } else {
          showSelectorMask(mastheadSelectorMask);
          showDropDown(selectorDropdown);
        }
      });

      selectorDropdownChoices.forEach(choice => {
        choice.addEventListener('click', () => {
          hideSelectorMask(mastheadSelectorMask);
        });
      });

      wideSelectorTriggerInDropdown.addEventListener('click', () => {
        const dropdownIsOpen = wideSelectorDropdown.classList.contains(
          'sprk-c-Dropdown--open',
        );
        if (dropdownIsOpen) {
          hideDropDown(wideSelectorDropdown);
        } else {
          showDropDown(wideSelectorDropdown);
        }
      });

      document.addEventListener('click', e => {
        if (
          !(
            selectorTrigger.contains(e.target) ||
            selectorDropdown.contains(e.target)
          )
        ) {
          hideSelectorMask(mastheadSelectorMask);
        }
      });

      document.addEventListener('focusin', e => {
        /* istanbul ignore else: jsdom cant fire focusin on an element */
        if (!selectorDropdown.contains(e.target)) {
          hideSelectorMask(mastheadSelectorMask);
          hideDropDown(selectorDropdown);
        }
      });

      document.addEventListener('keydown', e => {
        if (isEscPressed(e)) {
          hideSelectorMask(mastheadSelectorMask);
        }
      });
    }
  });
};

const masthead = () => {
  window.addEventListener('orientationchange', () => {
    hideMobileNavs();
  });
  bindUIEvents();
};

export {
  masthead,
  toggleMobileNav,
  hideMobileNavs,
  focusTrap,
  bindUIEvents,
  addClassOnScroll,
  hideSelectorMask,
  showSelectorMask,
  toggleScrollEvent,
  checkScrollDirection,
  toggleMenu,
};
<commit_msg>update debounce to throttle<commit_after>/* global document window */
import getElements from '../utilities/getElements';
import { focusFirstEl } from '../utilities/elementState';
import { isEscPressed } from '../utilities/keypress';
import isElementVisible from '../utilities/isElementVisible';
import scrollYDirection from '../utilities/scrollYDirection';
import { hideDropDown, showDropDown } from './dropdown';
import throttle from '../node_modules/lodash/throttle';

const addClassOnScroll = (element, scrollPos, scrollPoint, classToToggle) => {
  // If user scrolls past the scrollPoint then add class
  if (scrollPos >= scrollPoint) {
    element.classList.add(classToToggle);
  } else {
    element.classList.remove(classToToggle);
  }
};

/*
* Add or remove the class depending
* on if the user is scrolling up or down
*/
let direction = scrollYDirection();
const toggleMenu = scrollDirection => {
  const masthead = document.querySelector('[data-sprk-masthead]');
  if (scrollDirection === 'down') {
    masthead.classList.add('sprk-c-Masthead--hidden');
  } else {
    masthead.classList.remove('sprk-c-Masthead--hidden');
  }
};

/*
* Set initial scroll direction
* If the scroll direction changes
* toggle the masthead visibility
*/
const checkScrollDirection = throttle(() => {
  const newDirection = scrollYDirection();
  if (direction !== newDirection) {
    toggleMenu(newDirection);
  }
  direction = newDirection;
}, 500);

/*
* If the mobile menu is visible
* add the check scroll event listener
* otherwise remove it
*/
const toggleScrollEvent = isMenuVisible => {
  let attached = false;
  if (!isMenuVisible) {
    const masthead = document.querySelector('[data-sprk-masthead]');
    masthead.classList.remove('sprk-c-Masthead--hidden');
  }
  if (isMenuVisible) {
    window.addEventListener('scroll', checkScrollDirection);
    attached = true;
  } else {
    window.removeEventListener('scroll', checkScrollDirection, false);
    attached = false;
  }
  return attached;
};

const toggleMobileNav = (iconContainer, nav, masthead) => {
  document.body.classList.toggle('sprk-u-Overflow--hidden');
  // Don't add height: 100% if site's html &
  // body el already have it (reapplying makes page jump)
  document.documentElement.classList.toggle('sprk-u-Overflow--hidden');
  if (document.documentElement.style.height !== '100%') {
    document.documentElement.classList.add('sprk-u-Height--100');
  }
  if (document.body.style.height !== '100%') {
    document.body.classList.add('sprk-u-Height--100');
  }
  masthead.classList.toggle('sprk-c-Masthead--open');
  iconContainer
    .querySelector('svg')
    .classList.toggle('sprk-c-Menu__icon--open');
  nav.classList.toggle('sprk-u-Display--none');
};

const focusTrap = (isOpen, nav) => {
  if (isOpen) {
    focusFirstEl(nav);
  }
};

const hideMobileNavs = () => {
  document.body.classList.remove('sprk-u-Overflow--hidden');
  document.documentElement.classList.remove('sprk-u-Overflow--hidden');
  document.body.classList.remove('sprk-u-Height--100');
  document.documentElement.classList.remove('sprk-u-Height--100');
  getElements('[data-sprk-mobile-nav]', item => {
    item.classList.add('sprk-u-Display--none');
  });
  getElements('.sprk-c-Menu__icon--open', item => {
    item.classList.remove('sprk-c-Menu__icon--open');
  });
  getElements('.sprk-c-Masthead--open', item => {
    item.classList.remove('sprk-c-Masthead--open');
  });
};

const hideSelectorMask = mastheadSelectorMask => {
  mastheadSelectorMask.classList.remove('sprk-c-MastheadMask');
};

const showSelectorMask = mastheadSelectorMask => {
  mastheadSelectorMask.classList.add('sprk-c-MastheadMask');
};

const bindUIEvents = () => {
  getElements('[data-sprk-mobile-nav-trigger]', element => {
    const mainLayout = document.querySelector('[data-sprk-main]');
    const masthead = document.querySelector('[data-sprk-masthead]');
    const selectorDropdown = document.querySelector(
      '[data-sprk-dropdown="dropdown-selector"]',
    );
    const selectorTrigger = document.querySelector(
      '[data-sprk-dropdown-trigger="dropdown-selector"]',
    );

    const nav = document.querySelector(
      `[data-sprk-mobile-nav="${element.getAttribute(
        'data-sprk-mobile-nav-trigger',
      )}"]`,
    );
    /*
    * Check if the mobile menu is visible
    * on page and set scroll event
    */
    let isMenuVisible;
    window.addEventListener('load', () => {
      isMenuVisible = isElementVisible('.sprk-c-Masthead__menu');
      toggleScrollEvent(isMenuVisible);
    });
    /*
    * If the mobile menu visibility changes
    * toggle scroll event listener
    */
    window.addEventListener(
      'resize',
      throttle(() => {
        const newMenuVisibility = isElementVisible('.sprk-c-Masthead__menu');
        if (isMenuVisible !== newMenuVisibility) {
          toggleScrollEvent(newMenuVisibility);
        }
        isMenuVisible = newMenuVisibility;
      }, 500),
    );

    element.addEventListener('click', e => {
      e.preventDefault();
      toggleMobileNav(element, nav, masthead);
    });

    window.addEventListener('scroll', () => {
      addClassOnScroll(masthead, window.scrollY, 10, 'sprk-c-Masthead--scroll');
    });

    mainLayout.addEventListener('focusin', () => {
      const isOpen = !document
        .querySelector('.sprk-c-Masthead__narrow-nav')
        .classList.contains('sprk-u-HideWhenJs');
      focusTrap(isOpen, nav);
    });

    if (selectorTrigger && selectorDropdown) {
      const selectorTriggerInDropdown = document.querySelector(
        '[data-sprk-selector-dropdown-trigger="dropdown-selector"]',
      );
      const wideSelectorDropdown = document.querySelector(
        '[data-sprk-dropdown="dropdown-selector-wide"]',
      );
      const wideSelectorTriggerInDropdown = document.querySelector(
        '[data-sprk-selector-dropdown-trigger="dropdown-selector-wide"]',
      );
      const mastheadSelectorMask = document.querySelector(
        '[data-sprk-masthead-mask]',
      );
      const selectorDropdownChoices = selectorDropdown.querySelectorAll(
        '[data-sprk-dropdown-choice]',
      );

      selectorTrigger.addEventListener('click', () => {
        const dropdownIsOpen = selectorDropdown.classList.contains(
          'sprk-c-Dropdown--open',
        );
        if (dropdownIsOpen) {
          hideSelectorMask(mastheadSelectorMask);
        } else {
          showSelectorMask(mastheadSelectorMask);
        }
      });

      selectorTriggerInDropdown.addEventListener('click', () => {
        const dropdownIsOpen = selectorDropdown.classList.contains(
          'sprk-c-Dropdown--open',
        );
        if (dropdownIsOpen) {
          hideSelectorMask(mastheadSelectorMask);
          hideDropDown(selectorDropdown);
        } else {
          showSelectorMask(mastheadSelectorMask);
          showDropDown(selectorDropdown);
        }
      });

      selectorDropdownChoices.forEach(choice => {
        choice.addEventListener('click', () => {
          hideSelectorMask(mastheadSelectorMask);
        });
      });

      wideSelectorTriggerInDropdown.addEventListener('click', () => {
        const dropdownIsOpen = wideSelectorDropdown.classList.contains(
          'sprk-c-Dropdown--open',
        );
        if (dropdownIsOpen) {
          hideDropDown(wideSelectorDropdown);
        } else {
          showDropDown(wideSelectorDropdown);
        }
      });

      document.addEventListener('click', e => {
        if (
          !(
            selectorTrigger.contains(e.target) ||
            selectorDropdown.contains(e.target)
          )
        ) {
          hideSelectorMask(mastheadSelectorMask);
        }
      });

      document.addEventListener('focusin', e => {
        /* istanbul ignore else: jsdom cant fire focusin on an element */
        if (!selectorDropdown.contains(e.target)) {
          hideSelectorMask(mastheadSelectorMask);
          hideDropDown(selectorDropdown);
        }
      });

      document.addEventListener('keydown', e => {
        if (isEscPressed(e)) {
          hideSelectorMask(mastheadSelectorMask);
        }
      });
    }
  });
};

const masthead = () => {
  window.addEventListener('orientationchange', () => {
    hideMobileNavs();
  });
  bindUIEvents();
};

export {
  masthead,
  toggleMobileNav,
  hideMobileNavs,
  focusTrap,
  bindUIEvents,
  addClassOnScroll,
  hideSelectorMask,
  showSelectorMask,
  toggleScrollEvent,
  checkScrollDirection,
  toggleMenu,
};
<|endoftext|>


<commit_before>function bx_menu_slide_inline_custom (sMenu, e, sPosition) {
	var eSlider = $(sMenu);
 	var options = options || {};

	if ('undefined' == typeof(e))
        e = eSlider.data('data-control-btn');

    var eIcon = $(e).find('.sys-icon-a');

	var iRight = $(document).width() - $(e).offset().left - $(e).width();
	if ('#bx-sliding-menu-search' == sMenu)
		iRight = 0;

    var fPositionElement = function (oElement) {
        eSlider.css({
            position: 'absolute',
            top: oElement.outerHeight(true),
            right: iRight
        });
    };

    var fPositionBlock = function () {
        var eBlock = eSlider.parents('.bx-page-block-container');
        eSlider.css({
            position: 'absolute',
            top: eBlock.find('.bx-db-header').outerHeight(true),
            right: iRight
            //width: eBlock.width() TODO: Commited to test. Remove if everything is OK.
        });
    };

    var fPositionSite = function () {
        var eToolbar = $('#bx-toolbar');
        eSlider.css({
            position: 'fixed',
            top: eToolbar.outerHeight(true) + (typeof iToolbarSubmenuTopOffset != 'undefined' ? parseInt(iToolbarSubmenuTopOffset) : 0)+3,
            right: iRight
        });
    };

    var fClose = function () {
        if (eIcon.length)
            (new Marka(eIcon[0])).set(eIcon.attr('data-icon-orig'));
        eSlider.slideUp()
    };

    var fOpen = function () {
        if (eIcon.length) {
            eIcon.attr('data-icon-orig', eIcon.attr('data-icon'));
            (new Marka(eIcon[0])).set('times');
        }

        if(typeof sPosition == 'object')
            fPositionElement(sPosition);
        else if(typeof sPosition == 'string' && sPosition == 'block')
            fPositionBlock();
        else
            fPositionSite();

        eSlider.slideDown();

        eSlider.data('data-control-btn', e);
    };

    if ('undefined' == typeof(sPosition))
        sPosition = 'block';

    if (eSlider.is(':visible')) {
        fClose();

        $(document).off('click.bx-sliding-menu touchend.bx-sliding-menu');
        $(window).off('resize.bx-sliding-menu');
    }
    else {
        bx_menu_slide_close_all_opened();

        $(document).off('click.bx-sliding-menu touchend.bx-sliding-menu');
        $(window).off('resize.bx-sliding-menu');

        fOpen();
        eSlider.find('a').each(function () {
            $(this).off('click.bx-sliding-menu');
            $(this).on('click.bx-sliding-menu', function () {
                fClose();
            });
        });

        setTimeout(function () {

            var iWidthPrev = $(window).width();
            $(window).on('resize.bx-sliding-menu', function () {
                if ($(this).width() == iWidthPrev)
                    return;
                iWidthPrev = $(this).width();
                bx_menu_slide_close_all_opened();
            });

            $(document).on('click.bx-sliding-menu touchend.bx-sliding-menu', function (event) {
                if ($(event.target).parents('.bx-sliding-menu, .bx-sliding-menu-main, .bx-popup-slide-wrapper, .bx-db-header').length || $(event.target).filter('.bx-sliding-menu-main, .bx-popup-slide-wrapper, .bx-db-header').length || e === event.target)
                    event.stopPropagation();
                else
                    bx_menu_slide_close_all_opened();
            });

        }, 10);
    }
}

$( document ).ready(function() {
	$( ".bx-btn" ).click(function() {
		var elm=$(this);
		elm.attr('bx-click-animating', true);
		setTimeout(function() { elm.attr('bx-click-animating', false);}, 1000);
	});
	bIsTablet = $('html').hasClass('bx-media-tablet');
	if (bIsTablet){
		$('#bx-sliding-menu-sys_site').find('.has-submenu').addClass('submenu-closed');
	}
});

function bx_menu_main_click (obj) {
	bIsTablet = $('html').hasClass('bx-media-tablet');
	if (bIsTablet){
		$(obj).parents('#bx-sliding-menu-sys_site').find('.has-submenu').addClass('submenu-closed');
		$(obj).parents('#bx-sliding-menu-sys_site').find('.bx-menu-floating-blocks-submenu').hide();
		if ($(obj).offset().top + $(obj).parents('li.has-submenu:first').find('.bx-menu-floating-blocks-submenu').height() + 10 > $(document).height()){
			var iT = $(document).height() - $(obj).offset().top - $(obj).parents('li.has-submenu:first').find('.bx-menu-floating-blocks-submenu').height() - 10;
			$(obj).parents('li.has-submenu:first').find('.bx-menu-floating-blocks-submenu').css({top: iT});
		}
	}

	if($(obj).parents('li.has-submenu:first').hasClass('submenu-closed')){
		$(obj).parents('li.has-submenu:first').find('.bx-menu-floating-blocks-submenu').hide();
		$(obj).parents('li.has-submenu:first').find('.bx-menu-floating-blocks-submenu').slideDown();
	}
	else{
		$(obj).parents('li.has-submenu:first').find('.bx-menu-floating-blocks-submenu').slideUp();
	}
	$(obj).parents('li.has-submenu:first').toggleClass('submenu-closed');

}<commit_msg>#3211 Decorous: most of menus aren't working in mobile app<commit_after>function bx_menu_slide_inline_custom (sMenu, e, sPosition) {
	var eSlider = $(sMenu);
 	var options = options || {};

	if ('undefined' == typeof(e))
        e = eSlider.data('data-control-btn');

    var eIcon = !e ? null : $(e).find('.sys-icon-a');

	var iRight = !e ? 0 : $(document).width() - $(e).offset().left - $(e).width();
	if ('#bx-sliding-menu-search' == sMenu)
		iRight = 0;

    var fPositionElement = function (oElement) {
        eSlider.css({
            position: 'absolute',
            top: oElement.outerHeight(true),
            right: iRight
        });
    };

    var fPositionBlock = function () {
        var eBlock = eSlider.parents('.bx-page-block-container');
        eSlider.css({
            position: 'absolute',
            top: eBlock.find('.bx-db-header').outerHeight(true),
            right: iRight
            //width: eBlock.width() TODO: Commited to test. Remove if everything is OK.
        });
    };

    var fPositionSite = function () {
        var eToolbar = $('#bx-toolbar');
        eSlider.css({
            position: 'fixed',
            top: eToolbar.outerHeight(true) + (typeof iToolbarSubmenuTopOffset != 'undefined' ? parseInt(iToolbarSubmenuTopOffset) : 0)+3,
            right: iRight
        });
    };

    var fClose = function () {
        if (eIcon && eIcon.length)
            (new Marka(eIcon[0])).set(eIcon.attr('data-icon-orig'));
        eSlider.slideUp()
    };

    var fOpen = function () {
        if (eIcon && eIcon.length) {
            eIcon.attr('data-icon-orig', eIcon.attr('data-icon'));
            (new Marka(eIcon[0])).set('times');
        }

        if(typeof sPosition == 'object')
            fPositionElement(sPosition);
        else if(typeof sPosition == 'string' && sPosition == 'block')
            fPositionBlock();
        else
            fPositionSite();

        eSlider.slideDown();

        eSlider.data('data-control-btn', e);
    };

    if ('undefined' == typeof(sPosition))
        sPosition = 'block';

    if (eSlider.is(':visible')) {
        fClose();

        $(document).off('click.bx-sliding-menu touchend.bx-sliding-menu');
        $(window).off('resize.bx-sliding-menu');
    }
    else {
        bx_menu_slide_close_all_opened();

        $(document).off('click.bx-sliding-menu touchend.bx-sliding-menu');
        $(window).off('resize.bx-sliding-menu');

        fOpen();
        eSlider.find('a').each(function () {
            $(this).off('click.bx-sliding-menu');
            $(this).on('click.bx-sliding-menu', function () {
                fClose();
            });
        });

        setTimeout(function () {

            var iWidthPrev = $(window).width();
            $(window).on('resize.bx-sliding-menu', function () {
                if ($(this).width() == iWidthPrev)
                    return;
                iWidthPrev = $(this).width();
                bx_menu_slide_close_all_opened();
            });

            $(document).on('click.bx-sliding-menu touchend.bx-sliding-menu', function (event) {
                if ($(event.target).parents('.bx-sliding-menu, .bx-sliding-menu-main, .bx-popup-slide-wrapper, .bx-db-header').length || $(event.target).filter('.bx-sliding-menu-main, .bx-popup-slide-wrapper, .bx-db-header').length || e === event.target)
                    event.stopPropagation();
                else
                    bx_menu_slide_close_all_opened();
            });

        }, 10);
    }
}

$( document ).ready(function() {
	$( ".bx-btn" ).click(function() {
		var elm=$(this);
		elm.attr('bx-click-animating', true);
		setTimeout(function() { elm.attr('bx-click-animating', false);}, 1000);
	});
	bIsTablet = $('html').hasClass('bx-media-tablet');
	if (bIsTablet){
		$('#bx-sliding-menu-sys_site').find('.has-submenu').addClass('submenu-closed');
	}
});

function bx_menu_main_click (obj) {
	bIsTablet = $('html').hasClass('bx-media-tablet');
	if (bIsTablet){
		$(obj).parents('#bx-sliding-menu-sys_site').find('.has-submenu').addClass('submenu-closed');
		$(obj).parents('#bx-sliding-menu-sys_site').find('.bx-menu-floating-blocks-submenu').hide();
		if ($(obj).offset().top + $(obj).parents('li.has-submenu:first').find('.bx-menu-floating-blocks-submenu').height() + 10 > $(document).height()){
			var iT = $(document).height() - $(obj).offset().top - $(obj).parents('li.has-submenu:first').find('.bx-menu-floating-blocks-submenu').height() - 10;
			$(obj).parents('li.has-submenu:first').find('.bx-menu-floating-blocks-submenu').css({top: iT});
		}
	}

	if($(obj).parents('li.has-submenu:first').hasClass('submenu-closed')){
		$(obj).parents('li.has-submenu:first').find('.bx-menu-floating-blocks-submenu').hide();
		$(obj).parents('li.has-submenu:first').find('.bx-menu-floating-blocks-submenu').slideDown();
	}
	else{
		$(obj).parents('li.has-submenu:first').find('.bx-menu-floating-blocks-submenu').slideUp();
	}
	$(obj).parents('li.has-submenu:first').toggleClass('submenu-closed');

}
<|endoftext|>


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

/**
 * External dependencies
 */
import invariant from 'invariant';

/**
 * WordPress dependencies
 */
import apiFetch from '@wordpress/api-fetch';
import { addQueryArgs } from '@wordpress/url';

/**
 * Internal dependencies
 */
import {
	deleteItem,
	getItem,
	getKeys,
	setItem,
} from './cache';
import { stringifyObject } from '../../util';

// Specific error to handle here, see below.
import { STORE_NAME as CORE_USER, PERMISSION_SCOPE_ERROR_CODE } from '../datastore/user/constants';

// Caching is enabled by default.
let cachingEnabled = true;

const KEY_SEPARATOR = '::';

/**
 * Create a cache key for a set of type/identifier/datapoint values.
 *
 * @since 1.5.0
 * @private
 *
 * @param {string} type        The data to access. One of 'core' or 'modules'.
 * @param {string} identifier  The data identifier, eg. a module slug like `'search-console'`.
 * @param {string} datapoint   The endpoint to request data from.
 * @param {Object} queryParams Query params to send with the request.
 * @return {string} The cache key to use for this set of values.
 */
export const createCacheKey = ( type, identifier, datapoint, queryParams = {} ) => {
	const keySections = [ type, identifier, datapoint ].filter( ( keySection ) => {
		return !! keySection && keySection.length;
	} );

	if (
		keySections.length === 3 &&
		( !! queryParams ) && ( queryParams.constructor === Object ) &&
		Object.keys( queryParams ).length
	) {
		keySections.push(
			stringifyObject( queryParams )
		);
	}

	return keySections.join( KEY_SEPARATOR );
};

/**
 * Make a request to a WP REST API Site Kit endpoint.
 *
 * @since 1.5.0
 * @private
 *
 * @param {string}  type                The data to access. One of 'core' or 'modules'.
 * @param {string}  identifier          The data identifier, eg. a module slug like `'search-console'`.
 * @param {string}  datapoint           The endpoint to request data from.
 * @param {Object}  options             Optional. Options to pass to the request.
 * @param {number}  options.cacheTTL    The oldest cache data to use, in seconds.
 * @param {Object}  options.bodyParams  Request body data to send. (Eg. used for `POST`/`PUT` request variables.)
 * @param {number}  options.method      HTTP method to use for this request.
 * @param {Object}  options.queryParams Query params to send with the request.
 * @param {boolean} options.useCache    Enable or disable caching for this request only. (Caching is only used for `GET` requests.)
 * @return {Promise} Response of HTTP request.
 */
export const siteKitRequest = async ( type, identifier, datapoint, {
	bodyParams,
	cacheTTL = 3600,
	method = 'GET',
	queryParams,
	useCache = undefined,
} = {} ) => {
	invariant( type, '`type` argument for requests is required.' );
	invariant( identifier, '`identifier` argument for requests is required.' );
	invariant( datapoint, '`datapoint` argument for requests is required.' );

	// Don't check for a `false`-y `useCache` value to ensure we don't fallback
	// to the `usingCache()` behaviour when caching is manually disabled on a
	// per-request basis.
	const useCacheForRequest = method === 'GET' && ( useCache !== undefined ? useCache : usingCache() );

	const cacheKey = createCacheKey( type, identifier, datapoint, queryParams );

	if ( useCacheForRequest ) {
		const { cacheHit, value } = await getItem( cacheKey, cacheTTL );

		if ( cacheHit ) {
			return value;
		}
	}
	// If we're bypassing the cache on GET requests, add the timestamp parameter.
	if ( false === useCacheForRequest && method === 'GET' ) {
		// Add timestamp parameter to ensure that only the first request is preloaded.
		queryParams = { ...queryParams, timestamp: Date.now() };
	}

	// Make an API request to retrieve the results.
	try {
		const response = await apiFetch( {
			data: bodyParams,
			method,
			path: addQueryArgs(
				`/google-site-kit/v1/${ type }/${ identifier }/data/${ datapoint }`,
				queryParams
			),
		} );

		if ( useCacheForRequest ) {
			await setItem( cacheKey, response );
		}

		return response;
	} catch ( error ) {
		// Check to see if this error was a `PERMISSION_SCOPE_ERROR_CODE` error;
		// if so and there is a data store available to dispatch on, dispatch a
		// `setPermissionScopeError()` action.
		// Kind of a hack, but scales to all components.
		if ( error.code === PERMISSION_SCOPE_ERROR_CODE && global.googlesitekit?.data?.dispatch?.( CORE_USER ) ) {
			global.googlesitekit.data.dispatch( CORE_USER ).setPermissionScopeError( error );
		}

		global.console.error( 'Google Site Kit API Error', error );

		throw error;
	}
};

/**
 * Get Google Site Kit data.
 *
 * Makes a request to this site's WordPress REST API, which will in
 * turn make GET requests to the relevant Google services' APIs.
 *
 * This method automatically handles authentication, so no credentials
 * are required to use this method.
 *
 * @since 1.5.0
 *
 * @param {string}  type             The data to access. One of 'core' or 'modules'.
 * @param {string}  identifier       The data identifier, eg. a module slug like `'search-console'`.
 * @param {string}  datapoint        The endpoint to request data from.
 * @param {Object}  data             Data (query params) to send with the request.
 * @param {Object}  options          Extra options for this request.
 * @param {number}  options.cacheTTL The oldest cache data to use, in seconds.
 * @param {boolean} options.useCache Enable or disable caching for this request only.
 * @return {Promise} A promise for the `fetch` request.
 */
export const get = async (
	type,
	identifier,
	datapoint,
	data,
	{ cacheTTL = 3600, useCache = undefined } = {}
) => {
	return siteKitRequest( type, identifier, datapoint, {
		cacheTTL,
		queryParams: data,
		useCache,
	} );
};

/**
 * Set Google Site Kit data.
 *
 * Makes a request to this site's WordPress REST API, which will in
 * turn make requests to the relevant Google services' APIs to save
 * the data sent in the request.
 *
 * This method automatically handles authentication, so no credentials
 * are required to use this method.
 *
 * @since 1.5.0
 *
 * @param {string} type                 The data to access. One of 'core' or 'modules'.
 * @param {string} identifier           The data identifier, eg. a module slug like `'adsense'`.
 * @param {string} datapoint            The endpoint to send data to.
 * @param {Object} data                 Request body data (eg. post data) to send with the request.
 * @param {Object}  options             Extra options for this request.
 * @param {number}  options.method      HTTP method to use for this request.
 * @param {boolean} options.queryParams Query params to send with the request.
 * @return {Promise} A promise for the `fetch` request.
 */
export const set = async (
	type,
	identifier,
	datapoint,
	data,
	{ method = 'POST', queryParams = {} } = {}
) => {
	const response = await siteKitRequest( type, identifier, datapoint, {
		bodyParams: { data },
		method,
		queryParams,
		useCache: false,
	} );

	await invalidateCache( type, identifier, datapoint );

	return response;
};

/**
 * Enable/disable caching.
 *
 * Set the caching to on/off for the entire API library.
 *
 * Individual requests can still be overridden to _disable_ caching,
 * but if caching is turned off it cannot be turned on for a specific request.
 *
 * @since 1.5.0
 *
 * @param {boolean} shouldUseCache Set to `true` to use this cache across requests; set to `false` to disable caching.
 * @return {boolean} The new caching state (`true` for on, `false` for off).
 */
export const setUsingCache = ( shouldUseCache ) => {
	cachingEnabled = !! shouldUseCache;

	return cachingEnabled;
};

/**
 * Get current caching state for the API.
 *
 * @since 1.5.0
 *
 * @return {boolean} The current caching state (`true` for on, `false` for off).
 */
export const usingCache = () => {
	return cachingEnabled;
};

/**
 * Invalidate the cache for a specific datapoint or all data.
 *
 * Invalidate cache data for either a specific datapoint, identifier, type, or
 * all data. The more specificity supplied the more granularly cache data will
 * be invalidated.
 *
 * Calling `invalidateCache()` will invalidate _all_ cached data, while calling
 * `invalidateCache( 'modules', 'adsense' )` will invalidate all AdSense data only.
 *
 * @since 1.5.0
 *
 * @param {string} type       The data type to operate on. One of 'core' or 'modules'.
 * @param {string} identifier The data identifier, eg. a module slug like `'adsense'`.
 * @param {string} datapoint  The endpoint to invalidate cache data for.
 */
export const invalidateCache = async ( type, identifier, datapoint ) => {
	const groupPrefix = createCacheKey( type, identifier, datapoint );

	const allKeys = await getKeys();

	allKeys.forEach( ( key ) => {
		if ( key.indexOf( groupPrefix ) === 0 ) {
			deleteItem( key );
		}
	} );
};

const API = {
	invalidateCache,
	get,
	set,
	setUsingCache,
	usingCache,
};

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

/**
 * External dependencies
 */
import invariant from 'invariant';

/**
 * WordPress dependencies
 */
import apiFetch from '@wordpress/api-fetch';
import { addQueryArgs } from '@wordpress/url';

/**
 * Internal dependencies
 */
import {
	deleteItem,
	getItem,
	getKeys,
	setItem,
} from './cache';
import { stringifyObject } from '../../util';

// Specific error to handle here, see below.
import { STORE_NAME as CORE_USER, PERMISSION_SCOPE_ERROR_CODE } from '../datastore/user/constants';

// Caching is enabled by default.
let cachingEnabled = true;

const KEY_SEPARATOR = '::';

/**
 * Create a cache key for a set of type/identifier/datapoint values.
 *
 * @since 1.5.0
 * @private
 *
 * @param {string} type        The data to access. One of 'core' or 'modules'.
 * @param {string} identifier  The data identifier, eg. a module slug like `'search-console'`.
 * @param {string} datapoint   The endpoint to request data from.
 * @param {Object} queryParams Query params to send with the request.
 * @return {string} The cache key to use for this set of values.
 */
export const createCacheKey = ( type, identifier, datapoint, queryParams = {} ) => {
	const keySections = [ type, identifier, datapoint ].filter( ( keySection ) => {
		return !! keySection && keySection.length;
	} );

	if (
		keySections.length === 3 &&
		( !! queryParams ) && ( queryParams.constructor === Object ) &&
		Object.keys( queryParams ).length
	) {
		keySections.push(
			stringifyObject( queryParams )
		);
	}

	return keySections.join( KEY_SEPARATOR );
};

/**
 * Make a request to a WP REST API Site Kit endpoint.
 *
 * @since 1.5.0
 * @private
 *
 * @param {string}  type                The data to access. One of 'core' or 'modules'.
 * @param {string}  identifier          The data identifier, eg. a module slug like `'search-console'`.
 * @param {string}  datapoint           The endpoint to request data from.
 * @param {Object}  options             Optional. Options to pass to the request.
 * @param {number}  options.cacheTTL    The oldest cache data to use, in seconds.
 * @param {Object}  options.bodyParams  Request body data to send. (Eg. used for `POST`/`PUT` request variables.)
 * @param {number}  options.method      HTTP method to use for this request.
 * @param {Object}  options.queryParams Query params to send with the request.
 * @param {boolean} options.useCache    Enable or disable caching for this request only. (Caching is only used for `GET` requests.)
 * @return {Promise} Response of HTTP request.
 */
export const siteKitRequest = async ( type, identifier, datapoint, {
	bodyParams,
	cacheTTL = 3600,
	method = 'GET',
	queryParams,
	useCache = undefined,
} = {} ) => {
	invariant( type, '`type` argument for requests is required.' );
	invariant( identifier, '`identifier` argument for requests is required.' );
	invariant( datapoint, '`datapoint` argument for requests is required.' );

	// Don't check for a `false`-y `useCache` value to ensure we don't fallback
	// to the `usingCache()` behaviour when caching is manually disabled on a
	// per-request basis.
	const useCacheForRequest = method === 'GET' && ( useCache !== undefined ? useCache : usingCache() );

	const cacheKey = createCacheKey( type, identifier, datapoint, queryParams );

	if ( useCacheForRequest ) {
		const { cacheHit, value } = await getItem( cacheKey, cacheTTL );

		if ( cacheHit ) {
			return value;
		}
	}
	// Add timestamp to the request to act as a cache-buster to ensure a cached response is not returned from either our middleware or the server.
	if ( false === useCacheForRequest && method === 'GET' ) {
		queryParams = { ...queryParams, timestamp: Date.now() };
	}

	// Make an API request to retrieve the results.
	try {
		const response = await apiFetch( {
			data: bodyParams,
			method,
			path: addQueryArgs(
				`/google-site-kit/v1/${ type }/${ identifier }/data/${ datapoint }`,
				queryParams
			),
		} );

		if ( useCacheForRequest ) {
			await setItem( cacheKey, response );
		}

		return response;
	} catch ( error ) {
		// Check to see if this error was a `PERMISSION_SCOPE_ERROR_CODE` error;
		// if so and there is a data store available to dispatch on, dispatch a
		// `setPermissionScopeError()` action.
		// Kind of a hack, but scales to all components.
		if ( error.code === PERMISSION_SCOPE_ERROR_CODE && global.googlesitekit?.data?.dispatch?.( CORE_USER ) ) {
			global.googlesitekit.data.dispatch( CORE_USER ).setPermissionScopeError( error );
		}

		global.console.error( 'Google Site Kit API Error', error );

		throw error;
	}
};

/**
 * Get Google Site Kit data.
 *
 * Makes a request to this site's WordPress REST API, which will in
 * turn make GET requests to the relevant Google services' APIs.
 *
 * This method automatically handles authentication, so no credentials
 * are required to use this method.
 *
 * @since 1.5.0
 *
 * @param {string}  type             The data to access. One of 'core' or 'modules'.
 * @param {string}  identifier       The data identifier, eg. a module slug like `'search-console'`.
 * @param {string}  datapoint        The endpoint to request data from.
 * @param {Object}  data             Data (query params) to send with the request.
 * @param {Object}  options          Extra options for this request.
 * @param {number}  options.cacheTTL The oldest cache data to use, in seconds.
 * @param {boolean} options.useCache Enable or disable caching for this request only.
 * @return {Promise} A promise for the `fetch` request.
 */
export const get = async (
	type,
	identifier,
	datapoint,
	data,
	{ cacheTTL = 3600, useCache = undefined } = {}
) => {
	return siteKitRequest( type, identifier, datapoint, {
		cacheTTL,
		queryParams: data,
		useCache,
	} );
};

/**
 * Set Google Site Kit data.
 *
 * Makes a request to this site's WordPress REST API, which will in
 * turn make requests to the relevant Google services' APIs to save
 * the data sent in the request.
 *
 * This method automatically handles authentication, so no credentials
 * are required to use this method.
 *
 * @since 1.5.0
 *
 * @param {string} type                 The data to access. One of 'core' or 'modules'.
 * @param {string} identifier           The data identifier, eg. a module slug like `'adsense'`.
 * @param {string} datapoint            The endpoint to send data to.
 * @param {Object} data                 Request body data (eg. post data) to send with the request.
 * @param {Object}  options             Extra options for this request.
 * @param {number}  options.method      HTTP method to use for this request.
 * @param {boolean} options.queryParams Query params to send with the request.
 * @return {Promise} A promise for the `fetch` request.
 */
export const set = async (
	type,
	identifier,
	datapoint,
	data,
	{ method = 'POST', queryParams = {} } = {}
) => {
	const response = await siteKitRequest( type, identifier, datapoint, {
		bodyParams: { data },
		method,
		queryParams,
		useCache: false,
	} );

	await invalidateCache( type, identifier, datapoint );

	return response;
};

/**
 * Enable/disable caching.
 *
 * Set the caching to on/off for the entire API library.
 *
 * Individual requests can still be overridden to _disable_ caching,
 * but if caching is turned off it cannot be turned on for a specific request.
 *
 * @since 1.5.0
 *
 * @param {boolean} shouldUseCache Set to `true` to use this cache across requests; set to `false` to disable caching.
 * @return {boolean} The new caching state (`true` for on, `false` for off).
 */
export const setUsingCache = ( shouldUseCache ) => {
	cachingEnabled = !! shouldUseCache;

	return cachingEnabled;
};

/**
 * Get current caching state for the API.
 *
 * @since 1.5.0
 *
 * @return {boolean} The current caching state (`true` for on, `false` for off).
 */
export const usingCache = () => {
	return cachingEnabled;
};

/**
 * Invalidate the cache for a specific datapoint or all data.
 *
 * Invalidate cache data for either a specific datapoint, identifier, type, or
 * all data. The more specificity supplied the more granularly cache data will
 * be invalidated.
 *
 * Calling `invalidateCache()` will invalidate _all_ cached data, while calling
 * `invalidateCache( 'modules', 'adsense' )` will invalidate all AdSense data only.
 *
 * @since 1.5.0
 *
 * @param {string} type       The data type to operate on. One of 'core' or 'modules'.
 * @param {string} identifier The data identifier, eg. a module slug like `'adsense'`.
 * @param {string} datapoint  The endpoint to invalidate cache data for.
 */
export const invalidateCache = async ( type, identifier, datapoint ) => {
	const groupPrefix = createCacheKey( type, identifier, datapoint );

	const allKeys = await getKeys();

	allKeys.forEach( ( key ) => {
		if ( key.indexOf( groupPrefix ) === 0 ) {
			deleteItem( key );
		}
	} );
};

const API = {
	invalidateCache,
	get,
	set,
	setUsingCache,
	usingCache,
};

export default API;
<|endoftext|>


<commit_before>const React = require('react');
const T = require('prop-types');
const StrangeMotion = require('./index');
const { Motion: ReactMotion } = require('react-motion');
const { assignAnimConfig } = require('./utils');

// Component

module.exports = class Motion extends StrangeMotion {

    static propTypes = {
        getAnimController: T.func,
        animConfig: T.object,
        children: T.any.isRequired
    }

    constructor(props) {

        super(props);

        this.setRef = this._setRef.bind(this);
        this.setAnimController = this._setAnimController.bind(this);
    }

    componentWillMount() {

        this.setAnimController(this.props.animConfig);
        this.playProp = 'enter';
    }

    _setAnimController(userAnimConfig) {

        const { animConfig } = this.state;

        const mergedAnimConfig = Object.assign({},
            animConfig,
            userAnimConfig
        );

        const animControllerApi = {
            enter: (animNameOrConfig) => {

                if (typeof animNameOrConfig === 'string') {
                    this.playProp = animNameOrConfig;
                    this.forceUpdate();
                }

                if (typeof animNameOrConfig === 'object') {

                    this.playProp = 'enter';

                    this.assignAnimConfig({ newAnimConfig: {
                        enter: animNameOrConfig
                    }});
                }
            },
            mergeAnimConfig: (animConfig) => {

                console.log('animConfig', JSON.parse(JSON.stringify(animConfig)));

                this.assignAnimConfig({
                    newAnimConfig: animConfig
                });
            },
            replay: () => {

                console.warn('replay not implemented yet, sorry!');
            }
        };

        // Set some aliases for code readability's sake

        animControllerApi.play = animControllerApi.enter;

        this.animController = Object.keys(mergedAnimConfig)
        .reduce((collector, animName) => {

            collector[animName] = (plugins) => {

                animControllerApi.play(animName);
            }
            return collector;
        }, animControllerApi);

        if (this.props.getAnimController) {
            return this.props.getAnimController(this.animController);
        }
    }

    _setRef(refName) {

        return (ref) => {
            this[refName] = ref;
        }
    }

    render() {

        const { children } = this.props;

        // ReactMotion is only built for a single child, so that's what
        // the '[0]' in 'this.getDefaultStyles()[0]' is about

         // 'ref={this.setRef('reactMotion')}' sets the this.reactMotion ref
         // used in strange-motion/index.js

         const newPlayProp = this.playProp || 'enter';

        return (
            <ReactMotion
                defaultStyle={this.getDefaultStyles()[0].style}
                style={this.getStyles(newPlayProp)[0].style}
                ref={this.setRef('reactMotion')}
            >
                {(interpolatedStyles) => {

                    return this.getChildren(interpolatedStyles);
                }}
            </ReactMotion>
        );
    }
};
<commit_msg>Cleanup<commit_after>const React = require('react');
const T = require('prop-types');
const StrangeMotion = require('./index');
const { Motion: ReactMotion } = require('react-motion');
const { assignAnimConfig } = require('./utils');

// Component

module.exports = class Motion extends StrangeMotion {

    static propTypes = {
        getAnimController: T.func,
        animConfig: T.object,
        children: T.any.isRequired
    }

    constructor(props) {

        super(props);

        this.setRef = this._setRef.bind(this);
        this.setAnimController = this._setAnimController.bind(this);
    }

    componentWillMount() {

        this.setAnimController(this.props.animConfig);
        this.playProp = 'enter';
    }

    _setAnimController(userAnimConfig) {

        const { animConfig } = this.state;

        const mergedAnimConfig = Object.assign({},
            animConfig,
            userAnimConfig
        );

        const animControllerApi = {
            enter: (animNameOrConfig) => {

                if (typeof animNameOrConfig === 'string') {
                    this.playProp = animNameOrConfig;
                    this.forceUpdate();
                }

                if (typeof animNameOrConfig === 'object') {

                    this.playProp = 'enter';

                    this.assignAnimConfig({ newAnimConfig: {
                        enter: animNameOrConfig
                    }});
                }
            },
            mergeAnimConfig: (animConfig) => {

                this.assignAnimConfig({
                    newAnimConfig: animConfig
                });
            },
            replay: () => {

                console.warn('replay not implemented yet, sorry!');
            }
        };

        // Set some aliases for code readability's sake

        animControllerApi.play = animControllerApi.enter;

        this.animController = Object.keys(mergedAnimConfig)
        .reduce((collector, animName) => {

            collector[animName] = (plugins) => {

                animControllerApi.play(animName);
            }
            return collector;
        }, animControllerApi);

        if (this.props.getAnimController) {
            return this.props.getAnimController(this.animController);
        }
    }

    _setRef(refName) {

        return (ref) => {
            this[refName] = ref;
        }
    }

    render() {

        const { children } = this.props;

        // ReactMotion is only built for a single child, so that's what
        // the '[0]' in 'this.getDefaultStyles()[0]' is about

         // 'ref={this.setRef('reactMotion')}' sets the this.reactMotion ref
         // used in strange-motion/index.js

         const newPlayProp = this.playProp || 'enter';

        return (
            <ReactMotion
                defaultStyle={this.getDefaultStyles()[0].style}
                style={this.getStyles(newPlayProp)[0].style}
                ref={this.setRef('reactMotion')}
            >
                {(interpolatedStyles) => {

                    return this.getChildren(interpolatedStyles);
                }}
            </ReactMotion>
        );
    }
};
<|endoftext|>


<commit_before>var provDb = db.getSiblingDB('core_provision');

var files = listFiles('./daemon_grpconf');
for(var i = 0; i < files.length; i++) {
	load(files[i].name);
}

provDb.daemon_grpconf.drop();

var records = core_daemon_grpconf;
provDb.daemon_grpconf.insert(records);

/* Indexes for daemons */
provDb.daemon_grpconf.ensureIndex({daemonConfigGroup: 1}, {unique: true});
provDb.daemon_grpconf.ensureIndex({'daemon': 1}, {unique: true});
<commit_msg>Removed indexing on daemon in daemon_grpconf collection.<commit_after>var provDb = db.getSiblingDB('core_provision');

var files = listFiles('./daemon_grpconf');
for(var i = 0; i < files.length; i++) {
	load(files[i].name);
}

provDb.daemon_grpconf.drop();

var records = core_daemon_grpconf;
provDb.daemon_grpconf.insert(records);

/* Indexes for daemons */
provDb.daemon_grpconf.ensureIndex({daemonConfigGroup: 1}, {unique: true});
<|endoftext|>


<commit_before>/**
 * Browserify tasks: create javascript bundles.
 * We are using several transforms, plugins and advanced features.
 *
 * Using 'factor-bundle' to split the final file in several files (bundles),
 * moving common modules (and rarely updated) to a 'common' file and keeping
 * separated entry points smaller.
 *
 * Using 'exorcise' to extract the 'source map' of each bundle to another file
 *
 * Using 'common-shakeify' to remove 'dead code' because of unused modules
 * features (also called 'tree shaking'; not to confuse with the kind of removal
 * of 'dead code' done by uglify and warned by linting --that we should prevent)
 */
'use strict';
var merge = require('deepmerge');
var notify = require('grunt-notify/lib/notify-lib');
var notifySettings = require('./notify.js');
// Using exorcist to extract source-maps from files.
// We use the API directly rather than the 'grunt-exorcise'
// (used in the past, removed when commiting this comment)
// because is the only way to make it works with watch[ify] option.
var exorcist = require('exorcist');
var browserifyBundles = require('./shared/browserifyBundles');
require('common-shakeify');

module.exports = function(grunt) {
    /// External parameters
    /**
     * Whether enable the fullPaths option in Browserify.
     * False by default, useful to be enabled when the result needs to be
     * analyzed with tools like 'discify'.
     * @private {Boolean}
     */
    var fullPaths = !!grunt.option('fullPaths');
    /**
     * Whether current environment is 'development', in order to enable
     * features like source-maps (Browserify debug mode).
     * IMPORTANT: This parameter is shared with other tasks and settings, should
     * keep the same on every use for consistent results (see '--dev').
     * @private {Boolean}
     */
    var dev = !!grunt.option('dev');
    /**
     Browserify config
     **/
    var bconfig = {};

    // Constants defining the source and destination paths for the
    // files involved in the appCommon set-up
    /**
     * Destination for the common modules file.
     * It's the main target for the Browserify task.
     */
    var COMMON_DEST = './build/assets/js/common.js';
    /**
     * Destintation for the common modules source-map file.
     */
    var COMMON_DEST_MAP = COMMON_DEST + '.map';
    /**
     * Source of the App bundle
     */
    var APP_SOURCE = './source/js/app.js';
    /**
     * Destination of the App bundle
     */
    var APP_DEST = './build/assets/js/app.js';
    /**
     * Destintation for the App bundle source-map file.
     */
    var APP_DEST_MAP = APP_DEST + '.map';
    /**
     * Source of the Landing Page bundle
     */
    var LANDING_PAGE_SOURCE = './source/js/landingPage.js';
    /**
     * Destination of the Landing Page bundle.
     * Renamed as 'welcome' for the result file.
     */
    var LANDING_PAGE_DEST = './build/assets/js/welcome.js';
    /**
     * Destintation for the Landing Page bundle source-map file.
     */
    var LANDING_PAGE_DEST_MAP = LANDING_PAGE_DEST + '.map';

    // Utility to send a desktop notification
    var sendRebuildNotification = function() {
        notify(notifySettings.browserify.options);
    };

    /**
        Generates the [app, landingPage] bundles,
        extracting the common parts out.
    **/
    var appCommonBaseSettings = browserifyBundles.create(
        grunt, {
            dest: COMMON_DEST,
            map: dev && COMMON_DEST_MAP
        }, [{
            source: APP_SOURCE,
            dest: APP_DEST,
            map: dev && APP_DEST_MAP
        }, {
            source: LANDING_PAGE_SOURCE,
            dest: LANDING_PAGE_DEST,
            map: dev && LANDING_PAGE_DEST_MAP
        }],
        sendRebuildNotification
    );
    bconfig.appCommon = merge(appCommonBaseSettings, {
        options: {
            browserifyOptions: {
                fullPaths: fullPaths
            }
        }
    });

    bconfig.watchAppCommon = merge(bconfig.appCommon, {
        options: {
            watch: true
        }
    });

    /// TESTS
    /**
     * Source of the App bundle
     */
    var TESTS_SOURCE = './source/test/**/*.js';
    /**
     * Destination of the App bundle
     */
    var TESTS_DEST = './build/assets/js/tests.js';
    /**
     * Destintation for the App bundle source-map file.
     */
    var TESTS_DEST_MAP = TESTS_DEST + '.map';

    /**
        Tests bundle
    **/
    bconfig.tests = {
        'src': [
            TESTS_SOURCE
        ],
        'dest': TESTS_DEST,
        'options': {
            'browserifyOptions': {
                'debug': true,
                fullPaths: fullPaths
            },
            plugin: [
                'common-shakeify'
            ],
            preBundleCB: function(b) {
                b.on('bundle', function() {
                    // Exorcist integration
                    b.pipeline.get('wrap').push(exorcist(TESTS_DEST_MAP));
                });
            }
        }
    };

    return bconfig;
};
<commit_msg>Simplified set-up of Browserify (removed unneded constants, now the settings object is clear)<commit_after>/**
 * Browserify tasks: create javascript bundles.
 * We are using several transforms, plugins and advanced features.
 *
 * Using 'factor-bundle' to split the final file in several files (bundles),
 * moving common modules (and rarely updated) to a 'common' file and keeping
 * separated entry points smaller.
 *
 * Using 'exorcise' to extract the 'source map' of each bundle to another file
 *
 * Using 'common-shakeify' to remove 'dead code' because of unused modules
 * features (also called 'tree shaking'; not to confuse with the kind of removal
 * of 'dead code' done by uglify and warned by linting --that we should prevent)
 */
'use strict';
var merge = require('deepmerge');
var notify = require('grunt-notify/lib/notify-lib');
var notifySettings = require('./notify.js');
// Using exorcist to extract source-maps from files.
// We use the API directly rather than the 'grunt-exorcise'
// (used in the past, removed when commiting this comment)
// because is the only way to make it works with watch[ify] option.
var exorcist = require('exorcist');
var browserifyBundles = require('./shared/browserifyBundles');
require('common-shakeify');

module.exports = function(grunt) {
    /// External parameters
    /**
     * Whether enable the fullPaths option in Browserify.
     * False by default, useful to be enabled when the result needs to be
     * analyzed with tools like 'discify'.
     * @private {Boolean}
     */
    var fullPaths = !!grunt.option('fullPaths');
    /**
     * Whether current environment is 'development', in order to enable
     * features like source-maps (Browserify debug mode).
     * IMPORTANT: This parameter is shared with other tasks and settings, should
     * keep the same on every use for consistent results (see '--dev').
     * @private {Boolean}
     */
    var dev = !!grunt.option('dev');
    /**
     Browserify config
     **/
    var bconfig = {};

    // Utility to send a desktop notification
    var sendRebuildNotification = function() {
        notify(notifySettings.browserify.options);
    };

    /**
        Generates the [app, landingPage] bundles,
        extracting the common parts out.
    **/
    var appCommonBaseSettings = browserifyBundles.create(
        grunt, {
            dest: './build/assets/js/common.js',
            map: dev && './build/assets/js/common.js.map'
        }, [{
            source: './source/js/app.js',
            dest: './build/assets/js/app.js',
            map: dev && './build/assets/js/app.js.map'
        }, {
            source: './source/js/landingPage.js',
            dest: './build/assets/js/welcome.js',
            map: dev && './build/assets/js/welcome.js.map'
        }],
        sendRebuildNotification
    );
    bconfig.appCommon = merge(appCommonBaseSettings, {
        options: {
            browserifyOptions: {
                fullPaths: fullPaths
            }
        }
    });

    bconfig.watchAppCommon = merge(bconfig.appCommon, {
        options: {
            watch: true
        }
    });

    /// TESTS
    /**
     * Source of the App bundle
     */
    var TESTS_SOURCE = './source/test/**/*.js';
    /**
     * Destination of the App bundle
     */
    var TESTS_DEST = './build/assets/js/tests.js';
    /**
     * Destintation for the App bundle source-map file.
     */
    var TESTS_DEST_MAP = TESTS_DEST + '.map';

    /**
        Tests bundle
    **/
    bconfig.tests = {
        'src': [
            TESTS_SOURCE
        ],
        'dest': TESTS_DEST,
        'options': {
            'browserifyOptions': {
                'debug': true,
                fullPaths: fullPaths
            },
            plugin: [
                'common-shakeify'
            ],
            preBundleCB: function(b) {
                b.on('bundle', function() {
                    // Exorcist integration
                    b.pipeline.get('wrap').push(exorcist(TESTS_DEST_MAP));
                });
            }
        }
    };

    return bconfig;
};
<|endoftext|>


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

const functions = require('firebase-functions');
const cookieParser = require('cookie-parser');
const crypto = require('crypto');

// Firebase Setup
const admin = require('firebase-admin');
// @ts-ignore
const serviceAccount = require('./service-account.json');
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: `https://${process.env.GCLOUD_PROJECT}.firebaseio.com`,
});

// Spotify OAuth 2 setup
// TODO: Configure the `spotify.client_id` and `spotify.client_secret` Google Cloud environment variables.
const SpotifyWebApi = require('spotify-web-api-node');
const Spotify = new SpotifyWebApi({
  clientId: functions.config().spotify.client_id,
  clientSecret: functions.config().spotify.client_secret,
  redirectUri: `https://${process.env.GCLOUD_PROJECT}.firebaseapp.com/popup.html`,
});

// Scopes to request.
const OAUTH_SCOPES = ['user-read-email'];

/**
 * Redirects the User to the Spotify authentication consent screen. Also the 'state' cookie is set for later state
 * verification.
 */
exports.redirect = functions.https.onRequest((req, res) => {
  cookieParser()(req, res, () => {
    const state = req.cookies.state || crypto.randomBytes(20).toString('hex');
    console.log('Setting verification state:', state);
    res.cookie('state', state.toString(), {maxAge: 3600000, secure: true, httpOnly: true});
    const authorizeURL = Spotify.createAuthorizeURL(OAUTH_SCOPES, state.toString());
    res.redirect(authorizeURL);
  });
});

/**
 * Exchanges a given Spotify auth code passed in the 'code' URL query parameter for a Firebase auth token.
 * The request also needs to specify a 'state' query parameter which will be checked against the 'state' cookie.
 * The Firebase custom auth token is sent back in a JSONP callback function with function name defined by the
 * 'callback' query parameter.
 */
exports.token = functions.https.onRequest((req, res) => {
  try {
    cookieParser()(req, res, () => {
      console.log('Received verification state:', req.cookies.state);
      console.log('Received state:', req.query.state);
      if (!req.cookies.state) {
        throw new Error('State cookie not set or expired. Maybe you took too long to authorize. Please try again.');
      } else if (req.cookies.state !== req.query.state) {
        throw new Error('State validation failed');
      }
      console.log('Received auth code:', req.query.code);
      Spotify.authorizationCodeGrant(req.query.code, (error, data) => {
        if (error) {
          throw error;
        }
        console.log('Received Access Token:', data.body['access_token']);
        Spotify.setAccessToken(data.body['access_token']);

        Spotify.getMe(async (error, userResults) => {
          if (error) {
            throw error;
          }
          console.log('Auth code exchange result received:', userResults);
          // We have a Spotify access token and the user identity now.
          const accessToken = data.body['access_token'];
          const spotifyUserID = userResults.body['id'];
          const profilePic = userResults.body['images'][0]['url'];
          const userName = userResults.body['display_name'];
          const email = userResults.body['email'];

          // Create a Firebase account and get the Custom Auth Token.
          const firebaseToken = await createFirebaseAccount(spotifyUserID, userName, profilePic, email, accessToken);
          // Serve an HTML page that signs the user in and updates the user profile.
          res.jsonp({token: firebaseToken});
        });
      });
    });
  } catch (error) {
    res.jsonp({error: error.toString});
  }
  return null;
});

/**
 * Creates a Firebase account with the given user profile and returns a custom auth token allowing
 * signing-in this account.
 * Also saves the accessToken to the datastore at /spotifyAccessToken/$uid
 *
 * @returns {Promise<string>} The Firebase custom auth token in a promise.
 */
async function createFirebaseAccount(spotifyID, displayName, photoURL, email, accessToken) {
  // The UID we'll assign to the user.
  const uid = `spotify:${spotifyID}`;

  // Save the access token to the Firebase Realtime Database.
  const databaseTask = admin.database().ref(`/spotifyAccessToken/${uid}`).set(accessToken);

  // Create or update the user account.
  const userCreationTask = admin.auth().updateUser(uid, {
    displayName: displayName,
    photoURL: photoURL,
    email: email,
    emailVerified: true,
  }).catch((error) => {
    // If user does not exists we create it.
    if (error.code === 'auth/user-not-found') {
      return admin.auth().createUser({
        uid: uid,
        displayName: displayName,
        photoURL: photoURL,
        email: email,
        emailVerified: true,
      });
    }
    throw error;
  });

  // Wait for all async tasks to complete, then generate and return a custom auth token.
  await Promise.all([userCreationTask, databaseTask]);
  // Create a Firebase custom auth token.
  const token = await admin.auth().createCustomToken(uid);
  console.log('Created Custom token for UID "', uid, '" Token:', token);
  return token;
}
<commit_msg>give full error like #423 (#812)<commit_after>/**
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';

const functions = require('firebase-functions');
const cookieParser = require('cookie-parser');
const crypto = require('crypto');

// Firebase Setup
const admin = require('firebase-admin');
// @ts-ignore
const serviceAccount = require('./service-account.json');
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: `https://${process.env.GCLOUD_PROJECT}.firebaseio.com`,
});

// Spotify OAuth 2 setup
// TODO: Configure the `spotify.client_id` and `spotify.client_secret` Google Cloud environment variables.
const SpotifyWebApi = require('spotify-web-api-node');
const Spotify = new SpotifyWebApi({
  clientId: functions.config().spotify.client_id,
  clientSecret: functions.config().spotify.client_secret,
  redirectUri: `https://${process.env.GCLOUD_PROJECT}.firebaseapp.com/popup.html`,
});

// Scopes to request.
const OAUTH_SCOPES = ['user-read-email'];

/**
 * Redirects the User to the Spotify authentication consent screen. Also the 'state' cookie is set for later state
 * verification.
 */
exports.redirect = functions.https.onRequest((req, res) => {
  cookieParser()(req, res, () => {
    const state = req.cookies.state || crypto.randomBytes(20).toString('hex');
    console.log('Setting verification state:', state);
    res.cookie('state', state.toString(), {maxAge: 3600000, secure: true, httpOnly: true});
    const authorizeURL = Spotify.createAuthorizeURL(OAUTH_SCOPES, state.toString());
    res.redirect(authorizeURL);
  });
});

/**
 * Exchanges a given Spotify auth code passed in the 'code' URL query parameter for a Firebase auth token.
 * The request also needs to specify a 'state' query parameter which will be checked against the 'state' cookie.
 * The Firebase custom auth token is sent back in a JSONP callback function with function name defined by the
 * 'callback' query parameter.
 */
exports.token = functions.https.onRequest((req, res) => {
  try {
    cookieParser()(req, res, () => {
      console.log('Received verification state:', req.cookies.state);
      console.log('Received state:', req.query.state);
      if (!req.cookies.state) {
        throw new Error('State cookie not set or expired. Maybe you took too long to authorize. Please try again.');
      } else if (req.cookies.state !== req.query.state) {
        throw new Error('State validation failed');
      }
      console.log('Received auth code:', req.query.code);
      Spotify.authorizationCodeGrant(req.query.code, (error, data) => {
        if (error) {
          throw error;
        }
        console.log('Received Access Token:', data.body['access_token']);
        Spotify.setAccessToken(data.body['access_token']);

        Spotify.getMe(async (error, userResults) => {
          if (error) {
            throw error;
          }
          console.log('Auth code exchange result received:', userResults);
          // We have a Spotify access token and the user identity now.
          const accessToken = data.body['access_token'];
          const spotifyUserID = userResults.body['id'];
          const profilePic = userResults.body['images'][0]['url'];
          const userName = userResults.body['display_name'];
          const email = userResults.body['email'];

          // Create a Firebase account and get the Custom Auth Token.
          const firebaseToken = await createFirebaseAccount(spotifyUserID, userName, profilePic, email, accessToken);
          // Serve an HTML page that signs the user in and updates the user profile.
          res.jsonp({token: firebaseToken});
        });
      });
    });
  } catch (error) {
    res.jsonp({error: error.toString()});
  }
  return null;
});

/**
 * Creates a Firebase account with the given user profile and returns a custom auth token allowing
 * signing-in this account.
 * Also saves the accessToken to the datastore at /spotifyAccessToken/$uid
 *
 * @returns {Promise<string>} The Firebase custom auth token in a promise.
 */
async function createFirebaseAccount(spotifyID, displayName, photoURL, email, accessToken) {
  // The UID we'll assign to the user.
  const uid = `spotify:${spotifyID}`;

  // Save the access token to the Firebase Realtime Database.
  const databaseTask = admin.database().ref(`/spotifyAccessToken/${uid}`).set(accessToken);

  // Create or update the user account.
  const userCreationTask = admin.auth().updateUser(uid, {
    displayName: displayName,
    photoURL: photoURL,
    email: email,
    emailVerified: true,
  }).catch((error) => {
    // If user does not exists we create it.
    if (error.code === 'auth/user-not-found') {
      return admin.auth().createUser({
        uid: uid,
        displayName: displayName,
        photoURL: photoURL,
        email: email,
        emailVerified: true,
      });
    }
    throw error;
  });

  // Wait for all async tasks to complete, then generate and return a custom auth token.
  await Promise.all([userCreationTask, databaseTask]);
  // Create a Firebase custom auth token.
  const token = await admin.auth().createCustomToken(uid);
  console.log('Created Custom token for UID "', uid, '" Token:', token);
  return token;
}
<|endoftext|>


<commit_before>/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View
} from 'react-native';

export default class strava extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          Welcome to React Native!
        </Text>
        <Text style={styles.instructions}>
          To get started, edit index.ios.js
        </Text>
        <Text style={styles.instructions}>
          Press Cmd+R to reload,{'\n'}
          Cmd+D or shake for dev menu
        </Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
});

AppRegistry.registerComponent('strava', () => strava);
<commit_msg>fix ios index file<commit_after>'use strict';
import React, { AppRegistry } from 'react-native';
import App from './app';

AppRegistry.registerComponent('strava', () => App);<|endoftext|>


<commit_before>'use strict';

const names = [
  [
    // Month: January
    ['Laimnesis','Solvita','Solvija'],
    ['Indulis','Ivo','Iva','Ivis'],
    ['Miervaldis','Miervalda','Ringolds'],
    ['Spodra','Ilva','Ilvita'],
    ['Sīmanis','Zintis'],
    ['Spulga','Arnita'],
    ['Rota','Zigmārs','Juliāns','Digmārs'],
    ['Gatis','Ivanda'],
    ['Kaspars','Aksels','Alta'],
    ['Tatjana','Dorisa'],
    ['Smaida','Franciska'],
    ['Reinis','Reina','Reinholds','Renāts'],
    ['Harijs','Ārijs','Āris','Aira'],
    ['Roberts','Roberta','Raitis','Raits'],
    ['Fēlikss','Felicita'],
    ['Lidija','Lida'],
    ['Tenis','Dravis'],
    ['Antons','Antis','Antonijs'],
    ['Andulis','Alnis'],
    ['Oļģerts','Orests','Aļģirds','Aļģis'],
    ['Agnese','Agnija','Agne'],
    ['Austris'],
    ['Grieta','Strauta','Rebeka'],
    ['Krišs','Ksenija','Eglons','Egle'],
    ['Zigurds','Sigurds','Sigvards'],
    ['Ansis','Agnis','Agneta'],
    ['Ilze','Ildze','Izolde'],
    ['Kārlis','Spodris'],
    ['Aivars','Valērijs','Bille'],
    ['Tīna','Valentīna','Pārsla'],
    ['Tekla','Violeta']
  ],
  [
    // Month: February
    ['Brigita','Indra','Indars','Indris'],
    ['Spīdola','Sonora'],
    ['Aīda','Ida','Vida'],
    ['Daila','Veronika','Dominiks'],
    ['Agate','Selga','Silga','Sinilga'],
    ['Dace','Dārta','Dora'],
    ['Nelda','Rihards','Ričards','Rišards'],
    ['Aldona','Česlavs'],
    ['Simona','Apolonija'],
    ['Paulīne','Paula','Jasmīna'],
    ['Laima','Laimdota'],
    ['Karlīna','Līna'],
    ['Malda','Melita'],
    ['Valentīns'],
    ['Alvils','Olafs','Aloizs','Olavs'],
    ['Jūlija','Džuljeta'],
    ['Donats','Konstance'],
    ['Kora','Kintija'],
    ['Zane','Zuzanna'],
    ['Vitauts','Smuidra','Smuidris'],
    ['Eleonora','Ariadne'],
    ['Ārija','Rigonda','Adrians','Adriāna','Adrija'],
    ['Haralds','Almants'],
    ['Diāna','Dina','Dins'],
    ['Alma','Annemarija'],
    ['Evelīna','Aurēlija','Mētra'],
    ['Līvija','Līva','Andra'],
    ['Skaidrīte','Justs','Skaidra'],
    ['–']
  ],
  [
    // Month: March
    ['Ivars','Ilgvars'],
    ['Lavīze','Luīze','Laila'],
    ['Tālis','Tālavs','Marts'],
    ['Alise','Auce','Enija'],
    ['Austra','Aurora'],
    ['Vents','Centis','Gotfrīds'],
    ['Ella','Elmīra'],
    ['Dagmāra','Marga','Margita'],
    ['Ēvalds'],
    ['Silvija','Laimrota','Liliāna'],
    ['Konstantīns','Agita'],
    ['Aija','Aiva','Aivis'],
    ['Ernests','Balvis'],
    ['Matilde','Ulrika'],
    ['Amilda','Amalda','Imalda'],
    ['Guntis','Guntars','Guntris'],
    ['Ģertrūde','Gerda'],
    ['Ilona','Adelīna'],
    ['Jāzeps','Juzefa'],
    ['Made','Irbe'],
    ['Una','Unigunde','Dzelme','Benedikts','Benedikta'],
    ['Tamāra','Dziedra','Gabriels','Gabriela'],
    ['Mirdza','Žanete','Žanna'],
    ['Kazimirs','Izidors'],
    ['Māra','Mārīte','Marita','Mare','Ģedimins'],
    ['Eiženija','Ženija'],
    ['Gustavs','Gusts','Tālrīts','Saulis'],
    ['Gunta','Ginta','Gunda'],
    ['Aldonis','Agija'],
    ['Nanija','Ilgmārs'],
    ['Gvido','Atvars']
  ],
  [
    // Month: April
    ['Dagnis','Dagne'],
    ['Irmgarde'],
    ['Daira','Dairis','Daiva','Daivis'],
    ['Valda','Herta','Ārvalda','Ārvalds','Ārvaldis'],
    ['Vija','Vidaga','Aivija'],
    ['Zinta','Vīlips','Filips','Dzinta'],
    ['Zina','Zinaīda','Helmuts'],
    ['Edgars','Danute','Dana','Dans'],
    ['Valērija','Žubīte','Alla'],
    ['Anita','Anitra','Zīle','Annika'],
    ['Hermanis','Vilmārs'],
    ['Jūlijs','Ainis'],
    ['Egils','Egīls','Nauris'],
    ['Strauja','Gudrīte'],
    ['Aelita','Gastons'],
    ['Mintauts','Alfs','Bernadeta'],
    ['Rūdolfs','Viviāna','Rūdis'],
    ['Laura','Jadviga'],
    ['Vēsma','Fanija'],
    ['Mirta','Ziedīte'],
    ['Marģers','Anastasija'],
    ['Armands','Armanda'],
    ['Jurģis','Juris','Georgs'],
    ['Visvaldis','Nameda','Ritvaldis','Ritums'],
    ['Līksma','Bārbala'],
    ['Alīna','Sandris','Rūsiņš'],
    ['Tāle','Raimonda','Raina','Klementīne'],
    ['Gundega','Terēze'],
    ['Vilnis','Raimonds','Laine'],
    ['Lilija','Liāna']
  ],
  [
    // Month: May
    ['Ziedonis'],
    ['Zigmunds','Sigmunds','Zigismunds'],
    ['Gints','Uvis'],
    ['Vizbulīte','Viola','Vijolīte'],
    ['Ģirts','Ģederts'],
    ['Gaidis','Didzis'],
    ['Henriete','Henrijs','Jete','Enriko'],
    ['Staņislavs','Staņislava','Stefānija'],
    ['Klāvs','Einārs','Ervīns'],
    ['Maija','Paija'],
    ['Milda','Karmena','Manfreds'],
    ['Valija','Ināra','Ina','Inārs'],
    ['Irēna','Irīna','Ira','Iraīda'],
    ['Krišjānis','Elfa','Aivita','Elvita'],
    ['Sofija','Taiga','Airita','Arita'],
    ['Edvīns','Edijs'],
    ['Herberts','Dailis','Umberts'],
    ['Inese','Inesis','Ēriks'],
    ['Lita','Sibilla','Teika'],
    ['Venta','Salvis','Selva'],
    ['Ernestīne','Ingmārs','Akvelīna'],
    ['Emīlija'],
    ['Leontīne','Leokādija','Lonija','Ligija'],
    ['Ilvija','Marlēna','Ziedone'],
    ['Anšlavs','Junora'],
    ['Edvards','Edvarts','Eduards','Varis'],
    ['Dzidra','Gunita','Loreta','Dzidris'],
    ['Vilis','Vilhelms'],
    ['Maksis','Maksims','Raivis','Raivo'],
    ['Vitolds','Lolita','Letīcija'],
    ['Alīda','Jūsma']
  ],
  [
    // Month: June
    ['Biruta','Mairita','Bernedīne'],
    ['Lība','Emma'],
    ['Inta','Ineta','Intra'],
    ['Elfrīda','Sintija','Sindija'],
    ['Igors','Margots','Ingvars'],
    ['Ingrīda','Ardis'],
    ['Gaida','Arnis','Arno'],
    ['Frīdis','Frīda','Mundra'],
    ['Ligita','Gita'],
    ['Malva','Anatols','Anatolijs'],
    ['Ingus','Mairis','Vidvuds'],
    ['Nora','Lenora','Ija'],
    ['Zigfrīds','Ainārs','Uva'],
    ['Tija','Saiva','Sentis','Santis','Saivis'],
    ['Baņuta','Žermēna','Vilija','Vits'],
    ['Justīne','Juta'],
    ['Artūrs','Artis'],
    ['Alberts','Madis'],
    ['Viktors','Nils'],
    ['Rasma','Rasa','Maira'],
    ['Emīls','Egita','Monvīds'],
    ['Ludmila','Laimdots','Laimiņš'],
    ['Līga'],
    ['Jānis'],
    ['Milija','Maiga'],
    ['Ausma','Inguna','Ingūna','Inguns','Ausmis'],
    ['Malvīne','Malvis'],
    ['Viesturs','Kitija','Viestards'],
    ['Pēteris','Pāvils','Pauls','Paulis'],
    ['Tālivaldis','Mareks']
  ],
  [
    // Month: July
    ['Imants','Rimants','Ingars','Intars'],
    ['Lauma','Ilvars','Halina'],
    ['Benita','Everita','Verita','Emerita'],
    ['Ulvis','Uldis','Sandis','Sandijs'],
    ['Andžs','Andžejs','Edīte','Esmeralda'],
    ['Anrijs','Arkādijs'],
    ['Alda','Maruta'],
    ['Antra','Adele','Ada'],
    ['Zaiga','Asne','Asna'],
    ['Lija','Olīvija','Olivers','Odrija'],
    ['Leonora','Svens'],
    ['Indriķis','Ints','Namejs'],
    ['Margrieta','Margarita'],
    ['Oskars','Ritvars','Anvars'],
    ['Egons','Egmonts','Egija','Henriks','Heinrihs'],
    ['Hermīne','Estere','Liepa'],
    ['Aleksis','Aleksejs','Alekss'],
    ['Rozālija','Roze'],
    ['Jautrīte','Kamila','Digna','Sāra'],
    ['Ritma','Ramona'],
    ['Meldra','Meldris','Melisa'],
    ['Marija','Marika','Marina'],
    ['Magda','Magone','Mērija','Magdalēna'],
    ['Kristīne','Kristīna','Krista','Kristiāna','Kristiāns'],
    ['Jēkabs','Žaklīna'],
    ['Anna','Ance','Annija'],
    ['Marta','Dita','Dite'],
    ['Cecīlija','Cilda'],
    ['Edmunds','Edžus','Vidmants'],
    ['Valters','Renārs','Regnārs'],
    ['Rūta','Ruta','Angelika','Sigita']
  ],
  [
    // Month: August
    ['Albīns','Albīna'],
    ['Normunds','Stefans'],
    ['Augusts'],
    ['Romāns','Romualds','Romualda'],
    ['Osvalds','Arvils'],
    ['Askolds','Aisma'],
    ['Alfrēds','Madars','Fredis'],
    ['Mudīte','Vladislavs','Vladislava'],
    ['Madara','Genoveva','Genovefa'],
    ['Brencis','Audris','Inuta','Audra'],
    ['Olga','Zita','Liega','Zigita'],
    ['Vizma','Klāra'],
    ['Elvīra','Velga','Rēzija'],
    ['Zelma','Zemgus','Virma'],
    ['Zenta','Dzelde','Zelda'],
    ['Astra','Astrīda'],
    ['Vineta','Oļegs'],
    ['Liene','Helēna','Elena','Ellena','Liena'],
    ['Melānija','Imanta'],
    ['Bernhards','Boriss','Rojs'],
    ['Janīna','Linda'],
    ['Rudīte','Everts'],
    ['Vitālijs','Ralfs','Valgudis'],
    ['Bērtulis','Boļeslavs'],
    ['Ludvigs','Ludis','Ivonna','Patrīcija','Patriks'],
    ['Natālija','Tālija','Broņislavs','Broņislava'],
    ['Žanis','Jorens','Alens'],
    ['Auguste','Guste'],
    ['Armīns','Vismants','Aiga'],
    ['Alvis','Jolanta','Samanta'],
    ['Vilma','Aigars']
  ]
];
<commit_msg>Add - sep. & oct. names<commit_after>'use strict';

const names = [
  [
    // Month: January
    ['Laimnesis','Solvita','Solvija'],
    ['Indulis','Ivo','Iva','Ivis'],
    ['Miervaldis','Miervalda','Ringolds'],
    ['Spodra','Ilva','Ilvita'],
    ['Sīmanis','Zintis'],
    ['Spulga','Arnita'],
    ['Rota','Zigmārs','Juliāns','Digmārs'],
    ['Gatis','Ivanda'],
    ['Kaspars','Aksels','Alta'],
    ['Tatjana','Dorisa'],
    ['Smaida','Franciska'],
    ['Reinis','Reina','Reinholds','Renāts'],
    ['Harijs','Ārijs','Āris','Aira'],
    ['Roberts','Roberta','Raitis','Raits'],
    ['Fēlikss','Felicita'],
    ['Lidija','Lida'],
    ['Tenis','Dravis'],
    ['Antons','Antis','Antonijs'],
    ['Andulis','Alnis'],
    ['Oļģerts','Orests','Aļģirds','Aļģis'],
    ['Agnese','Agnija','Agne'],
    ['Austris'],
    ['Grieta','Strauta','Rebeka'],
    ['Krišs','Ksenija','Eglons','Egle'],
    ['Zigurds','Sigurds','Sigvards'],
    ['Ansis','Agnis','Agneta'],
    ['Ilze','Ildze','Izolde'],
    ['Kārlis','Spodris'],
    ['Aivars','Valērijs','Bille'],
    ['Tīna','Valentīna','Pārsla'],
    ['Tekla','Violeta']
  ],
  [
    // Month: February
    ['Brigita','Indra','Indars','Indris'],
    ['Spīdola','Sonora'],
    ['Aīda','Ida','Vida'],
    ['Daila','Veronika','Dominiks'],
    ['Agate','Selga','Silga','Sinilga'],
    ['Dace','Dārta','Dora'],
    ['Nelda','Rihards','Ričards','Rišards'],
    ['Aldona','Česlavs'],
    ['Simona','Apolonija'],
    ['Paulīne','Paula','Jasmīna'],
    ['Laima','Laimdota'],
    ['Karlīna','Līna'],
    ['Malda','Melita'],
    ['Valentīns'],
    ['Alvils','Olafs','Aloizs','Olavs'],
    ['Jūlija','Džuljeta'],
    ['Donats','Konstance'],
    ['Kora','Kintija'],
    ['Zane','Zuzanna'],
    ['Vitauts','Smuidra','Smuidris'],
    ['Eleonora','Ariadne'],
    ['Ārija','Rigonda','Adrians','Adriāna','Adrija'],
    ['Haralds','Almants'],
    ['Diāna','Dina','Dins'],
    ['Alma','Annemarija'],
    ['Evelīna','Aurēlija','Mētra'],
    ['Līvija','Līva','Andra'],
    ['Skaidrīte','Justs','Skaidra'],
    ['–']
  ],
  [
    // Month: March
    ['Ivars','Ilgvars'],
    ['Lavīze','Luīze','Laila'],
    ['Tālis','Tālavs','Marts'],
    ['Alise','Auce','Enija'],
    ['Austra','Aurora'],
    ['Vents','Centis','Gotfrīds'],
    ['Ella','Elmīra'],
    ['Dagmāra','Marga','Margita'],
    ['Ēvalds'],
    ['Silvija','Laimrota','Liliāna'],
    ['Konstantīns','Agita'],
    ['Aija','Aiva','Aivis'],
    ['Ernests','Balvis'],
    ['Matilde','Ulrika'],
    ['Amilda','Amalda','Imalda'],
    ['Guntis','Guntars','Guntris'],
    ['Ģertrūde','Gerda'],
    ['Ilona','Adelīna'],
    ['Jāzeps','Juzefa'],
    ['Made','Irbe'],
    ['Una','Unigunde','Dzelme','Benedikts','Benedikta'],
    ['Tamāra','Dziedra','Gabriels','Gabriela'],
    ['Mirdza','Žanete','Žanna'],
    ['Kazimirs','Izidors'],
    ['Māra','Mārīte','Marita','Mare','Ģedimins'],
    ['Eiženija','Ženija'],
    ['Gustavs','Gusts','Tālrīts','Saulis'],
    ['Gunta','Ginta','Gunda'],
    ['Aldonis','Agija'],
    ['Nanija','Ilgmārs'],
    ['Gvido','Atvars']
  ],
  [
    // Month: April
    ['Dagnis','Dagne'],
    ['Irmgarde'],
    ['Daira','Dairis','Daiva','Daivis'],
    ['Valda','Herta','Ārvalda','Ārvalds','Ārvaldis'],
    ['Vija','Vidaga','Aivija'],
    ['Zinta','Vīlips','Filips','Dzinta'],
    ['Zina','Zinaīda','Helmuts'],
    ['Edgars','Danute','Dana','Dans'],
    ['Valērija','Žubīte','Alla'],
    ['Anita','Anitra','Zīle','Annika'],
    ['Hermanis','Vilmārs'],
    ['Jūlijs','Ainis'],
    ['Egils','Egīls','Nauris'],
    ['Strauja','Gudrīte'],
    ['Aelita','Gastons'],
    ['Mintauts','Alfs','Bernadeta'],
    ['Rūdolfs','Viviāna','Rūdis'],
    ['Laura','Jadviga'],
    ['Vēsma','Fanija'],
    ['Mirta','Ziedīte'],
    ['Marģers','Anastasija'],
    ['Armands','Armanda'],
    ['Jurģis','Juris','Georgs'],
    ['Visvaldis','Nameda','Ritvaldis','Ritums'],
    ['Līksma','Bārbala'],
    ['Alīna','Sandris','Rūsiņš'],
    ['Tāle','Raimonda','Raina','Klementīne'],
    ['Gundega','Terēze'],
    ['Vilnis','Raimonds','Laine'],
    ['Lilija','Liāna']
  ],
  [
    // Month: May
    ['Ziedonis'],
    ['Zigmunds','Sigmunds','Zigismunds'],
    ['Gints','Uvis'],
    ['Vizbulīte','Viola','Vijolīte'],
    ['Ģirts','Ģederts'],
    ['Gaidis','Didzis'],
    ['Henriete','Henrijs','Jete','Enriko'],
    ['Staņislavs','Staņislava','Stefānija'],
    ['Klāvs','Einārs','Ervīns'],
    ['Maija','Paija'],
    ['Milda','Karmena','Manfreds'],
    ['Valija','Ināra','Ina','Inārs'],
    ['Irēna','Irīna','Ira','Iraīda'],
    ['Krišjānis','Elfa','Aivita','Elvita'],
    ['Sofija','Taiga','Airita','Arita'],
    ['Edvīns','Edijs'],
    ['Herberts','Dailis','Umberts'],
    ['Inese','Inesis','Ēriks'],
    ['Lita','Sibilla','Teika'],
    ['Venta','Salvis','Selva'],
    ['Ernestīne','Ingmārs','Akvelīna'],
    ['Emīlija'],
    ['Leontīne','Leokādija','Lonija','Ligija'],
    ['Ilvija','Marlēna','Ziedone'],
    ['Anšlavs','Junora'],
    ['Edvards','Edvarts','Eduards','Varis'],
    ['Dzidra','Gunita','Loreta','Dzidris'],
    ['Vilis','Vilhelms'],
    ['Maksis','Maksims','Raivis','Raivo'],
    ['Vitolds','Lolita','Letīcija'],
    ['Alīda','Jūsma']
  ],
  [
    // Month: June
    ['Biruta','Mairita','Bernedīne'],
    ['Lība','Emma'],
    ['Inta','Ineta','Intra'],
    ['Elfrīda','Sintija','Sindija'],
    ['Igors','Margots','Ingvars'],
    ['Ingrīda','Ardis'],
    ['Gaida','Arnis','Arno'],
    ['Frīdis','Frīda','Mundra'],
    ['Ligita','Gita'],
    ['Malva','Anatols','Anatolijs'],
    ['Ingus','Mairis','Vidvuds'],
    ['Nora','Lenora','Ija'],
    ['Zigfrīds','Ainārs','Uva'],
    ['Tija','Saiva','Sentis','Santis','Saivis'],
    ['Baņuta','Žermēna','Vilija','Vits'],
    ['Justīne','Juta'],
    ['Artūrs','Artis'],
    ['Alberts','Madis'],
    ['Viktors','Nils'],
    ['Rasma','Rasa','Maira'],
    ['Emīls','Egita','Monvīds'],
    ['Ludmila','Laimdots','Laimiņš'],
    ['Līga'],
    ['Jānis'],
    ['Milija','Maiga'],
    ['Ausma','Inguna','Ingūna','Inguns','Ausmis'],
    ['Malvīne','Malvis'],
    ['Viesturs','Kitija','Viestards'],
    ['Pēteris','Pāvils','Pauls','Paulis'],
    ['Tālivaldis','Mareks']
  ],
  [
    // Month: July
    ['Imants','Rimants','Ingars','Intars'],
    ['Lauma','Ilvars','Halina'],
    ['Benita','Everita','Verita','Emerita'],
    ['Ulvis','Uldis','Sandis','Sandijs'],
    ['Andžs','Andžejs','Edīte','Esmeralda'],
    ['Anrijs','Arkādijs'],
    ['Alda','Maruta'],
    ['Antra','Adele','Ada'],
    ['Zaiga','Asne','Asna'],
    ['Lija','Olīvija','Olivers','Odrija'],
    ['Leonora','Svens'],
    ['Indriķis','Ints','Namejs'],
    ['Margrieta','Margarita'],
    ['Oskars','Ritvars','Anvars'],
    ['Egons','Egmonts','Egija','Henriks','Heinrihs'],
    ['Hermīne','Estere','Liepa'],
    ['Aleksis','Aleksejs','Alekss'],
    ['Rozālija','Roze'],
    ['Jautrīte','Kamila','Digna','Sāra'],
    ['Ritma','Ramona'],
    ['Meldra','Meldris','Melisa'],
    ['Marija','Marika','Marina'],
    ['Magda','Magone','Mērija','Magdalēna'],
    ['Kristīne','Kristīna','Krista','Kristiāna','Kristiāns'],
    ['Jēkabs','Žaklīna'],
    ['Anna','Ance','Annija'],
    ['Marta','Dita','Dite'],
    ['Cecīlija','Cilda'],
    ['Edmunds','Edžus','Vidmants'],
    ['Valters','Renārs','Regnārs'],
    ['Rūta','Ruta','Angelika','Sigita']
  ],
  [
    // Month: August
    ['Albīns','Albīna'],
    ['Normunds','Stefans'],
    ['Augusts'],
    ['Romāns','Romualds','Romualda'],
    ['Osvalds','Arvils'],
    ['Askolds','Aisma'],
    ['Alfrēds','Madars','Fredis'],
    ['Mudīte','Vladislavs','Vladislava'],
    ['Madara','Genoveva','Genovefa'],
    ['Brencis','Audris','Inuta','Audra'],
    ['Olga','Zita','Liega','Zigita'],
    ['Vizma','Klāra'],
    ['Elvīra','Velga','Rēzija'],
    ['Zelma','Zemgus','Virma'],
    ['Zenta','Dzelde','Zelda'],
    ['Astra','Astrīda'],
    ['Vineta','Oļegs'],
    ['Liene','Helēna','Elena','Ellena','Liena'],
    ['Melānija','Imanta'],
    ['Bernhards','Boriss','Rojs'],
    ['Janīna','Linda'],
    ['Rudīte','Everts'],
    ['Vitālijs','Ralfs','Valgudis'],
    ['Bērtulis','Boļeslavs'],
    ['Ludvigs','Ludis','Ivonna','Patrīcija','Patriks'],
    ['Natālija','Tālija','Broņislavs','Broņislava'],
    ['Žanis','Jorens','Alens'],
    ['Auguste','Guste'],
    ['Armīns','Vismants','Aiga'],
    ['Alvis','Jolanta','Samanta'],
    ['Vilma','Aigars']
  ],
  [
    // Month: September
    ['Ilmārs','Iluta','Austrums'],
    ['Elīza','Lizete','Zete'],
    ['Berta','Bella'],
    ['Dzintra','Dzintara','Dzintars'],
    ['Klaudija','Persijs','Vaida'],
    ['Maigonis','Magnuss','Mariuss'],
    ['Regīna','Ermīns'],
    ['Ilga'],
    ['Bruno','Telma'],
    ['Jausma','Albertīne'],
    ['Signe','Signija'],
    ['Erna','Evita','Eva'],
    ['Iza','Izabella'],
    ['Sanita','Santa','Sanda','Sanija','Sandija'],
    ['Sandra','Gunvaldis','Gunvaris','Sondra'],
    ['Asja','Asnate','Dāgs'],
    ['Vera','Vaira','Vairis'],
    ['Liesma','Elita','Alita'],
    ['Verners','Muntis'],
    ['Guntra','Ginters','Marianna'],
    ['Modris','Matīss','Mariss'],
    ['Māris','Mārica','Maigurs'],
    ['Vanda','Veneranda','Venija'],
    ['Agris','Agrita'],
    ['Rodrigo','Rauls'],
    ['Gundars','Kurts','Knuts'],
    ['Ādolfs','Ilgonis'],
    ['Sergejs','Svetlana','Lana'],
    ['Miķelis','Mikus','Miks','Mihails'],
    ['Elma','Menarda','Elna']
  ],
  [
    // Month: October
    ['Zanda','Lāsma','Zandis'],
    ['Ilma','Skaidris'],
    ['Elza','Ilizana'],
    ['Modra','Francis','Dmitrijs'],
    ['Amālija','Amēlija'],
    ['Monika','Zilgma','Zilga'],
    ['Daumants','Druvvaldis'],
    ['Aina','Anete'],
    ['Elga','Helga','Elgars'],
    ['Arvīds','Arvis','Druvis'],
    ['Monta','Tince','Silva'],
    ['Valfrīds','Kira'],
    ['Irma','Mirga'],
    ['Vilhelmīne','Minna'],
    ['Eda','Hedviga','Helvijs'],
    ['Daiga','Dinija','Dinārs'],
    ['Gaits','Karīna','Gaitis'],
    ['Rolands','Rolanda','Ronalds','Erlends','Lūkass'],
    ['Elīna','Drosma','Drosmis'],
    ['Leonīds','Leonīda'],
    ['Urzula','Severīns'],
    ['Īrisa','Irīda','Airisa'],
    ['Daina','Dainis','Dainida'],
    ['Renāte','Modrīte','Mudrīte'],
    ['Beāte','Beatrise'],
    ['Amanda','Kaiva','Amanta'],
    ['Lilita','Irita','Ita'],
    ['Ņina','Ninona','Antoņina','Oksana'],
    ['Laimonis','Elvijs','Elva','Elvis','Laimis'],
    ['Nadīna','Ulla','Adīna'],
    ['Valts','Rinalds','Rinalda']
  ]
];
<|endoftext|>