<commit_before>/* eslint-disable no-await-in-loop */
/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2020
 */

import { ToastAndroid } from 'react-native';
import { generateUUID } from 'react-native-database';

import { UIDatabase } from '../database';
import { Sensor } from '../database/DataTypes';
import { createRecord } from '../database/utilities';
import { MILLISECONDS } from '../utilities';
import { chunk } from '../utilities/chunk';

import { vaccineStrings } from '../localization';
import { PageActions } from '../pages/dataTableUtilities/actions';
import { ROUTES } from '../navigation';

export const TEMPERATURE_SYNC_ACTIONS = {
  OPEN_MODAL: 'TemperatureSync/openModal',
  CLOSE_MODAL: 'TemperatureSync/closeModal',
  ERROR_NO_SENSORS: 'TemperatureSync/errorNoSensors',

  START_SYNC: 'TemperatureSync/startSync',
  COMPLETE_SYNC: 'TemperatureSync/completeSync',

  SCAN_START: 'TemperatureSync/scanStart',
  SCAN_COMPLETE: 'TemperatureSync/scanComplete',
  SCAN_ERROR: 'TemperatureSync/scanError',

  DOWNLOAD_LOGS_START: 'TemperatureSync/downloadLogsStart',
  DOWNLOAD_LOGS_COMPLETE: 'TemperatureSync/downloadLogsComplete',
  DOWNLOAD_LOGS_ERROR: 'TemperatureSync/downloadLogsError',

  START_RESETTING_ADVERTISEMENT_FREQUENCY: 'TemperatureSync/startResettingAdvertisementFrequency',
  ERROR_RESETTING_ADVERTISEMENT_FREQUENCY: 'TemperatureSync/errorResettingAdvertisementFrequency',
  COMPLETE_RESETTING_ADVERTISEMENT_FREQUENCY:
    'TemperatureSync/completeResettingAdvertisementFrequency',
  START_RESETTING_LOG_FREQUENCY: 'TemperatureSync/startResettingLogFrequency',
  COMPLETE_RESETTING_LOG_FREQUENCY: 'TemperatureSync/completeResettingLogFrequency',
  ERROR_RESETTING_LOG_FREQUENCY: 'TemperatureSync/errorResettingLogFrequency',

  START_SAVING_TEMPERATURE_LOGS: 'TemperatureSync/startSavingTemperatureLogs',
  COMPLETE_SAVING_TEMPERATURE_LOGS: 'TemperatureSync/completeSavingTemperatureLogs',

  UPDATE_SENSOR_PROGRESS: 'TemperatureSync/updateSensorProgress',
};

const openModal = () => ({ type: TEMPERATURE_SYNC_ACTIONS.OPEN_MODAL });
const closeModal = () => ({ type: TEMPERATURE_SYNC_ACTIONS.CLOSE_MODAL });

const scanStart = () => ({ type: TEMPERATURE_SYNC_ACTIONS.SCAN_START });
const scanComplete = () => ({ type: TEMPERATURE_SYNC_ACTIONS.SCAN_COMPLETE });
const scanError = () => ({ type: TEMPERATURE_SYNC_ACTIONS.SCAN_ERROR });

const updateSensors = sensorAdvertisements => dispatch => {
  const isArray = Array.isArray(sensorAdvertisements);

  if (!isArray) dispatch(scanError());
  if (isArray && !sensorAdvertisements.length) dispatch(scanError());

  if (isArray && sensorAdvertisements.length) {
    sensorAdvertisements.forEach(({ macAddress, batteryLevel }) => {
      UIDatabase.write(() => {
        UIDatabase.update('Sensor', {
          id: generateUUID(),
          ...UIDatabase.get('Sensor', macAddress, 'macAddress'),
          macAddress,
          batteryLevel,
        });
      });
    });
  }
};

const startSensorScan = () => async dispatch => {
  await dispatch(scanForSensors());
  dispatch(PageActions.refreshData(ROUTES.VACCINE_ADMIN_PAGE));
};

const scanForSensors = () => async dispatch => {
  dispatch(scanStart());

  const sensorResult = await Sensor.startScan();
  const { success, data } = sensorResult;

  dispatch(updateSensors(data));

  if (success) {
    ToastAndroid.show(
      vaccineStrings.formatString(vaccineStrings.found_sensors, data.length),
      ToastAndroid.LONG
    );
    dispatch(scanComplete());
  } else {
    ToastAndroid.show(vaccineStrings.could_not_find_sensors, ToastAndroid.LONG);
  }
};

const downloadLogsError = () => ({ type: TEMPERATURE_SYNC_ACTIONS.DOWNLOAD_LOGS_ERROR });
const downloadLogsStart = () => ({ type: TEMPERATURE_SYNC_ACTIONS.DOWNLOAD_LOGS_START });
const downloadLogsComplete = () => ({
  type: TEMPERATURE_SYNC_ACTIONS.DOWNLOAD_LOGS_COMPLETE,
});

const downloadLogs = sensor => async dispatch => {
  dispatch(downloadLogsStart());

  const downloadedLogsResult = (await sensor?.downloadLogs()) ?? {};
  const { success = false, data = [] } = downloadedLogsResult;

  if (success && data?.[0]?.logs) {
    const sensorLogs = data[0]?.logs;
    const timeNow = new Date().getTime();

    if (Array.isArray(sensorLogs)) {
      UIDatabase.write(() =>
        sensorLogs.forEach(({ temperature }, i) => {
          const timestamp = timeNow - (i + 1) * MILLISECONDS.FIVE_MINUTES;
          createRecord(UIDatabase, 'SensorLog', temperature, new Date(timestamp), sensor);
        })
      );
    }

    dispatch(downloadLogsComplete());
  } else {
    dispatch(downloadLogsError());
  }

  return new Promise(resolver => resolver(success));
};

const startResettingAdvertisementFrequency = () => ({
  type: TEMPERATURE_SYNC_ACTIONS.START_RESETTING_ADVERTISEMENT_FREQUENCY,
});
const completeResettingAdvertisementFrequency = () => ({
  type: TEMPERATURE_SYNC_ACTIONS.COMPLETE_RESETTING_ADVERTISEMENT_FREQUENCY,
});
const errorResettingAdvertisementFrequency = () => ({
  type: TEMPERATURE_SYNC_ACTIONS.ERROR_RESETTING_ADVERTISEMENT_FREQUENCY,
});

const resetAdvertisementFrequency = sensor => async dispatch => {
  dispatch(startResettingAdvertisementFrequency());

  const resettingAdvertisementFrequencyResult = await sensor.resetAdvertisementFrequency();

  const { success } = resettingAdvertisementFrequencyResult;

  if (success) dispatch(completeResettingAdvertisementFrequency());
  else dispatch(errorResettingAdvertisementFrequency());

  return new Promise(resolver => resolver(success));
};

const startResettingLogFrequency = () => ({
  type: TEMPERATURE_SYNC_ACTIONS.START_RESETTING_LOG_FREQUENCY,
});
const completeResettingLogFrequency = () => ({
  type: TEMPERATURE_SYNC_ACTIONS.COMPLETE_RESETTING_LOG_FREQUENCY,
});
const errorResettingLogFrequency = () => ({
  type: TEMPERATURE_SYNC_ACTIONS.ERROR_RESETTING_LOG_FREQUENCY,
});

const resetLogFrequency = sensor => async dispatch => {
  dispatch(startResettingLogFrequency());

  const resettingLogFrequencyResult = await sensor.resetLogFrequency();

  const { success } = resettingLogFrequencyResult;

  if (success) dispatch(completeResettingLogFrequency());
  else dispatch(errorResettingLogFrequency());

  return new Promise(resolver => resolver(success));
};

const startSavingTemperatureLogs = () => ({
  type: TEMPERATURE_SYNC_ACTIONS.START_SAVING_TEMPERATURE_LOGS,
});
const completeSavingTemperatureLogs = () => ({
  type: TEMPERATURE_SYNC_ACTIONS.COMPLETE_SAVING_TEMPERATURE_LOGS,
});

const createTemperatureLogs = sensor => dispatch => {
  const { sensorLogs, location } = sensor;

  // Only create TemperatureLogs for the greatest multiple of 6 SensorLogs,
  // as each SensorLog is a 5 minute log, and each Temperature log a 30 minute log.
  const iterateTo = sensorLogs.length - (sensorLogs.length % 6);
  const sensorLogsToGroup = sensorLogs.sorted('timestamp').slice(0, iterateTo);
  const groupedSensorLogs = chunk(sensorLogsToGroup, 6);

  dispatch(startSavingTemperatureLogs(groupedSensorLogs.length));

  UIDatabase.write(() => {
    groupedSensorLogs.forEach(sensorLogGroup => {
      const { hasBreached, mostRecentTemperatureBreach } = sensor;
      const newLogTemperature = Math.min(...sensorLogGroup.map(({ temperature }) => temperature));
      const newLogTimestamp = Math.min(...sensorLogGroup.map(({ timestamp }) => timestamp));

      const newLog = createRecord(
        UIDatabase,
        'TemperatureLog',
        newLogTemperature,
        new Date(newLogTimestamp),
        location
      );

      if (hasBreached) {
        if (mostRecentTemperatureBreach?.willContinueBreach(newLog)) {
          UIDatabase.update('TemperatureLog', { ...newLog, breach: mostRecentTemperatureBreach });
        } else {
          UIDatabase.update('TemperatureBreach', {
            ...mostRecentTemperatureBreach,
            endTimestamp: newLogTimestamp,
          });
        }
      } else {
        const breachConfigs = UIDatabase.objects('TemperatureBreachConfiguration');
        breachConfigs.some(breachConfig => breachConfig.createBreach(UIDatabase, location, newLog));
      }
    });

    UIDatabase.delete('SensorLog', sensorLogsToGroup);
  });

  dispatch(completeSavingTemperatureLogs());

  return Promise.resolve();
};

const errorNoSensors = () => ({ type: TEMPERATURE_SYNC_ACTIONS.ERROR_NO_SENSORS });
const startSync = () => ({ type: TEMPERATURE_SYNC_ACTIONS.START_SYNC });
const completeSync = () => ({ type: TEMPERATURE_SYNC_ACTIONS.COMPLETE_SYNC });
const updateSensorProgress = sensor => ({
  type: TEMPERATURE_SYNC_ACTIONS.UPDATE_SENSOR_PROGRESS,
  payload: { sensor },
});

const syncTemperatures = () => async (dispatch, getState) => {
  const { temperatureSync } = getState();
  const { isSyncing } = temperatureSync;

  const sensors = UIDatabase.objects('Sensor').filtered('location != null');
  const { length: numberOfSensors } = sensors;

  if (isSyncing) return null;
  if (!numberOfSensors) return dispatch(errorNoSensors());

  dispatch(startSync());

  for (let i = 0; i < numberOfSensors; i++) {
    const sensor = sensors[i];

    dispatch(updateSensorProgress(sensor));

    const downloadedLogsResult = await dispatch(downloadLogs(sensor));
    if (downloadedLogsResult) {
      const resetLogFrequencyResult = await dispatch(resetLogFrequency(sensor));
      if (resetLogFrequencyResult) {
        const resetAdvertisementFrequencyResult = await dispatch(
          resetAdvertisementFrequency(sensor)
        );
        if (resetAdvertisementFrequencyResult) {
          dispatch(createTemperatureLogs(sensor));
        }
      }
    }
  }

  return dispatch(completeSync());
};

export const TemperatureSyncActions = {
  syncTemperatures,
  openModal,
  closeModal,
  startSensorScan,
};
<commit_msg>Add creation of saveLogs action<commit_after>/* eslint-disable no-await-in-loop */
/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2020
 */

import { ToastAndroid } from 'react-native';
import { generateUUID } from 'react-native-database';

import { UIDatabase } from '../database';
import { Sensor } from '../database/DataTypes';
import { createRecord } from '../database/utilities';
import { MILLISECONDS } from '../utilities';
import { chunk } from '../utilities/chunk';

import { vaccineStrings } from '../localization';
import { PageActions } from '../pages/dataTableUtilities/actions';
import { ROUTES } from '../navigation';

export const TEMPERATURE_SYNC_ACTIONS = {
  OPEN_MODAL: 'TemperatureSync/openModal',
  CLOSE_MODAL: 'TemperatureSync/closeModal',
  ERROR_NO_SENSORS: 'TemperatureSync/errorNoSensors',

  START_SYNC: 'TemperatureSync/startSync',
  COMPLETE_SYNC: 'TemperatureSync/completeSync',

  SCAN_START: 'TemperatureSync/scanStart',
  SCAN_COMPLETE: 'TemperatureSync/scanComplete',
  SCAN_ERROR: 'TemperatureSync/scanError',

  DOWNLOAD_LOGS_START: 'TemperatureSync/downloadLogsStart',
  DOWNLOAD_LOGS_COMPLETE: 'TemperatureSync/downloadLogsComplete',
  DOWNLOAD_LOGS_ERROR: 'TemperatureSync/downloadLogsError',

  START_RESETTING_ADVERTISEMENT_FREQUENCY: 'TemperatureSync/startResettingAdvertisementFrequency',
  ERROR_RESETTING_ADVERTISEMENT_FREQUENCY: 'TemperatureSync/errorResettingAdvertisementFrequency',
  COMPLETE_RESETTING_ADVERTISEMENT_FREQUENCY:
    'TemperatureSync/completeResettingAdvertisementFrequency',
  START_RESETTING_LOG_FREQUENCY: 'TemperatureSync/startResettingLogFrequency',
  COMPLETE_RESETTING_LOG_FREQUENCY: 'TemperatureSync/completeResettingLogFrequency',
  ERROR_RESETTING_LOG_FREQUENCY: 'TemperatureSync/errorResettingLogFrequency',

  START_SAVING_TEMPERATURE_LOGS: 'TemperatureSync/startSavingTemperatureLogs',
  COMPLETE_SAVING_TEMPERATURE_LOGS: 'TemperatureSync/completeSavingTemperatureLogs',

  UPDATE_SENSOR_PROGRESS: 'TemperatureSync/updateSensorProgress',
};

const openModal = () => ({ type: TEMPERATURE_SYNC_ACTIONS.OPEN_MODAL });
const closeModal = () => ({ type: TEMPERATURE_SYNC_ACTIONS.CLOSE_MODAL });

const scanStart = () => ({ type: TEMPERATURE_SYNC_ACTIONS.SCAN_START });
const scanComplete = () => ({ type: TEMPERATURE_SYNC_ACTIONS.SCAN_COMPLETE });
const scanError = () => ({ type: TEMPERATURE_SYNC_ACTIONS.SCAN_ERROR });

const updateSensors = sensorAdvertisements => dispatch => {
  const isArray = Array.isArray(sensorAdvertisements);

  if (!isArray) dispatch(scanError());
  if (isArray && !sensorAdvertisements.length) dispatch(scanError());

  if (isArray && sensorAdvertisements.length) {
    sensorAdvertisements.forEach(({ macAddress, batteryLevel }) => {
      UIDatabase.write(() => {
        UIDatabase.update('Sensor', {
          id: generateUUID(),
          ...UIDatabase.get('Sensor', macAddress, 'macAddress'),
          macAddress,
          batteryLevel,
        });
      });
    });
  }
};

const startSensorScan = () => async dispatch => {
  await dispatch(scanForSensors());
  dispatch(PageActions.refreshData(ROUTES.VACCINE_ADMIN_PAGE));
};

const scanForSensors = () => async dispatch => {
  dispatch(scanStart());

  const sensorResult = await Sensor.startScan();
  const { success, data } = sensorResult;

  dispatch(updateSensors(data));

  if (success) {
    ToastAndroid.show(
      vaccineStrings.formatString(vaccineStrings.found_sensors, data.length),
      ToastAndroid.LONG
    );
    dispatch(scanComplete());
  } else {
    ToastAndroid.show(vaccineStrings.could_not_find_sensors, ToastAndroid.LONG);
  }
};

const downloadLogsError = () => ({ type: TEMPERATURE_SYNC_ACTIONS.DOWNLOAD_LOGS_ERROR });
const downloadLogsStart = () => ({ type: TEMPERATURE_SYNC_ACTIONS.DOWNLOAD_LOGS_START });
const downloadLogsComplete = () => ({
  type: TEMPERATURE_SYNC_ACTIONS.DOWNLOAD_LOGS_COMPLETE,
});

const saveLogs = (logData, sensor) => async dispatch => {
  dispatch(startSavingTemperatureLogs(logData?.length));
  const timeNow = new Date().getTime();

  UIDatabase.write(() =>
    logData.forEach(({ temperature }, i) => {
      const timestamp = timeNow - (i + 1) * MILLISECONDS.FIVE_MINUTES;
      createRecord(UIDatabase, 'SensorLog', temperature, new Date(timestamp), sensor);
    })
  );
};

const downloadLogs = sensor => async dispatch => {
  dispatch(downloadLogsStart());

  const downloadedLogsResult = (await sensor?.downloadLogs()) ?? {};
  const { success = false, data = [] } = downloadedLogsResult;

  if (success && data?.[0]?.logs) {
    dispatch(downloadLogsComplete());
    return data?.[0]?.logs;
  }
  dispatch(downloadLogsError());
  return null;
};

const startResettingAdvertisementFrequency = () => ({
  type: TEMPERATURE_SYNC_ACTIONS.START_RESETTING_ADVERTISEMENT_FREQUENCY,
});
const completeResettingAdvertisementFrequency = () => ({
  type: TEMPERATURE_SYNC_ACTIONS.COMPLETE_RESETTING_ADVERTISEMENT_FREQUENCY,
});
const errorResettingAdvertisementFrequency = () => ({
  type: TEMPERATURE_SYNC_ACTIONS.ERROR_RESETTING_ADVERTISEMENT_FREQUENCY,
});

const resetAdvertisementFrequency = sensor => async dispatch => {
  dispatch(startResettingAdvertisementFrequency());

  const resettingAdvertisementFrequencyResult = await sensor.resetAdvertisementFrequency();

  const { success } = resettingAdvertisementFrequencyResult;

  if (success) dispatch(completeResettingAdvertisementFrequency());
  else dispatch(errorResettingAdvertisementFrequency());

  return success;
};

const startResettingLogFrequency = () => ({
  type: TEMPERATURE_SYNC_ACTIONS.START_RESETTING_LOG_FREQUENCY,
});
const completeResettingLogFrequency = () => ({
  type: TEMPERATURE_SYNC_ACTIONS.COMPLETE_RESETTING_LOG_FREQUENCY,
});
const errorResettingLogFrequency = () => ({
  type: TEMPERATURE_SYNC_ACTIONS.ERROR_RESETTING_LOG_FREQUENCY,
});

const resetLogFrequency = sensor => async dispatch => {
  dispatch(startResettingLogFrequency());

  const resettingLogFrequencyResult = await sensor.resetLogFrequency();

  const { success } = resettingLogFrequencyResult;

  if (success) dispatch(completeResettingLogFrequency());
  else dispatch(errorResettingLogFrequency());

  return success;
};

const startSavingTemperatureLogs = () => ({
  type: TEMPERATURE_SYNC_ACTIONS.START_SAVING_TEMPERATURE_LOGS,
});
const completeSavingTemperatureLogs = () => ({
  type: TEMPERATURE_SYNC_ACTIONS.COMPLETE_SAVING_TEMPERATURE_LOGS,
});

const createTemperatureLogs = sensor => async dispatch => {
  const { sensorLogs, location } = sensor;

  // Only create TemperatureLogs for the greatest multiple of 6 SensorLogs,
  // as each SensorLog is a 5 minute log, and each Temperature log a 30 minute log.
  const iterateTo = sensorLogs.length - (sensorLogs.length % 6);
  const sensorLogsToGroup = sensorLogs.sorted('timestamp').slice(0, iterateTo);
  const groupedSensorLogs = chunk(sensorLogsToGroup, 6);

  UIDatabase.write(() => {
    groupedSensorLogs.forEach(sensorLogGroup => {
      const { hasBreached, mostRecentTemperatureBreach } = sensor;
      const newLogTemperature = Math.min(...sensorLogGroup.map(({ temperature }) => temperature));
      const newLogTimestamp = Math.min(...sensorLogGroup.map(({ timestamp }) => timestamp));

      const newLog = createRecord(
        UIDatabase,
        'TemperatureLog',
        newLogTemperature,
        new Date(newLogTimestamp),
        location
      );

      if (hasBreached) {
        if (mostRecentTemperatureBreach?.willContinueBreach(newLog)) {
          UIDatabase.update('TemperatureLog', { ...newLog, breach: mostRecentTemperatureBreach });
        } else {
          UIDatabase.update('TemperatureBreach', {
            ...mostRecentTemperatureBreach,
            endTimestamp: newLogTimestamp,
          });
        }
      } else {
        const breachConfigs = UIDatabase.objects('TemperatureBreachConfiguration');
        breachConfigs.some(breachConfig => breachConfig.createBreach(UIDatabase, location, newLog));
      }
    });

    UIDatabase.delete('SensorLog', sensorLogsToGroup);
  });

  dispatch(completeSavingTemperatureLogs());
};

const errorNoSensors = () => ({ type: TEMPERATURE_SYNC_ACTIONS.ERROR_NO_SENSORS });
const startSync = () => ({ type: TEMPERATURE_SYNC_ACTIONS.START_SYNC });
const completeSync = () => ({ type: TEMPERATURE_SYNC_ACTIONS.COMPLETE_SYNC });
const updateSensorProgress = sensor => ({
  type: TEMPERATURE_SYNC_ACTIONS.UPDATE_SENSOR_PROGRESS,
  payload: { sensor },
});

const syncTemperatures = () => async (dispatch, getState) => {
  const { temperatureSync } = getState();
  const { isSyncing } = temperatureSync;

  const sensors = UIDatabase.objects('Sensor').filtered('location != null');
  const { length: numberOfSensors } = sensors;

  if (isSyncing) return null;
  if (!numberOfSensors) return dispatch(errorNoSensors());

  dispatch(startSync());

  for (let i = 0; i < numberOfSensors; i++) {
    const sensor = sensors[i];

    dispatch(updateSensorProgress(sensor));
    const downloadedLogsResult = await dispatch(downloadLogs(sensor));

    if (downloadedLogsResult) {
      const resetLogFrequencyResult = await dispatch(resetLogFrequency(sensor));

      if (resetLogFrequencyResult) {
        const resetAdvertisementFrequencyResult = await dispatch(
          resetAdvertisementFrequency(sensor)
        );

        if (resetAdvertisementFrequencyResult) {
          await dispatch(saveLogs(downloadedLogsResult, sensor));
          await dispatch(createTemperatureLogs(sensor));
        }
      }
    }
  }
  return dispatch(completeSync());
};

export const TemperatureSyncActions = {
  syncTemperatures,
  openModal,
  closeModal,
  startSensorScan,
};
<|endoftext|>


<commit_before>// VERSION = '1.3';

objName = 'omnisidebar';
objPathString = 'omnisidebar';
addonUUID = '8f7da5c0-61c7-11e4-9803-0800200c9a66';

addonUris = {
	homepage: 'https://addons.mozilla.org/firefox/addon/omnisidebar/',
	support: 'https://github.com/Quicksaver/OmniSidebar/issues',
	fullchangelog: 'https://github.com/Quicksaver/OmniSidebar/commits/master',
	email: 'mailto:quicksaver@gmail.com',
	profile: 'https://addons.mozilla.org/firefox/user/quicksaver/',
	api: 'http://fasezero.com/addons/api/omnisidebar',
	development: 'http://fasezero.com/addons/'
};

prefList = {
	NoSync_firstEnabled: true,
	NoSync_lastStateMain: true,
	NoSync_lastStateTwin: true,

	minSidebarWidth: 30, // pixels
	minSpaceBetweenSidebars: 18, // pixels

	lastStateMain: '',
	lastStateTwin: '',

	moveSidebars: false,
	twinSidebar: false,

	renderabove: false,
	useSwitch: true,
	autoClose: false,
	autoHide: true,
	toolbar: true,
	showheadertitle: true,
	showheaderdock: true,
	showheaderclose: true,
	coloricons: 'default',
	titleButton: true,
	goButton: false,

	renderaboveTwin: false,
	useSwitchTwin: true,
	autoCloseTwin: false,
	autoHideTwin: true,
	toolbarTwin: true,
	showheadertitleTwin: true,
	showheaderdockTwin: true,
	showheadercloseTwin: true,
	coloriconsTwin: 'default',
	titleButtonTwin: true,
	goButtonTwin: false,

	glassStyle: false,
	transparency: 250,
	fx: true,
	forceOpenToolbars: false,
	forceOpenMenus: true,
	showDelay: 250,
	hideDelay: 250,
	switcherAdjust: 0,
	keepPrivate: false,
	keepLoaded: false,

	alwaysAddons: true,
	alwaysConsole: false,
	alwaysDMT: false,
	alwaysPageInfo: false,
	alwaysScratchpad: false,

	mainKeysetKeycode: 'VK_F8',
	mainKeysetAccel: false,
	mainKeysetShift: false,
	mainKeysetAlt: false,
	mainKeysetPanel: false,
	twinKeysetKeycode: 'VK_F8',
	twinKeysetAccel: false,
	twinKeysetShift: true,
	twinKeysetAlt: false,
	twinKeysetPanel: false,

	noInitialShow: false,
	aboveSquared: false,
	firstEnabled: true
};

paneList = [
	[ 'paneMain' ],
	[ 'paneTwin' ],
	[ 'paneGlobal' ]
];

function waitForSessionStore(window, delayed) {
	if(window.__SSi) {
		window[objName].Modules.load(objName, delayed);
		return;
	}

	aSync(function() {
		waitForSessionStore(window, false);
	}, 100);
}

function startAddon(window) {
	// don't load in popup windows set to hide extra chrome
	var chromeHidden = window.document.documentElement.getAttribute('chromehidden');
	if(chromeHidden && chromeHidden.contains('extrachrome')) { return; }

	prepareObject(window);

	// We use SessionStore pretty much everywhere, which might not be yet initialized in this window.
	waitForSessionStore(window, true);
}

function stopAddon(window) {
	// Make sure we are ready to disable the add-on
	dispatch(window, { type: objName+'-disabled', cancelable: false });

	removeObject(window);
}

function toggleMoveSidebars() {
	Modules.loadIf('moveSidebars', Prefs.moveSidebars);
}

function toggleGlass() {
	Modules.loadIf('glassStyle', Prefs.glassStyle);
}

function onStartup() {
	// try not to show the sidebar when starting up, so the browser doesn't jump around
	if(STARTED == APP_STARTUP) {
		Styles.load('startupFix', 'startupFix');
	}

	Modules.load('compatibilityFix/sandboxFixes');
	Modules.load('keysets');
	Modules.load('sandbox');

	Prefs.listen('moveSidebars', toggleMoveSidebars);
	Prefs.listen('glassStyle', toggleGlass);

	toggleMoveSidebars();
	toggleGlass();

	// Register the global css stylesheets
	Styles.load('global', 'global');

	// Apply the add-on to every window opened and to be opened
	Windows.callOnAll(startAddon, 'navigator:browser');
	Windows.register(startAddon, 'domwindowopened', 'navigator:browser');
}

function onShutdown() {
	// remove the add-on from all windows
	Windows.callOnAll(stopAddon, null, null, true);

	Modules.unload('glassStyle');
	Modules.unload('moveSidebars');

	// Unregister stylesheets
	Styles.unload('global');

	Prefs.unlisten('moveSidebars', toggleMoveSidebars);
	Prefs.unlisten('glassStyle', toggleGlass);

	Modules.unload('sandbox');
	Modules.unload('keysets');
	Modules.unload('compatibilityFix/sandboxFixes');

	Styles.unload('startupFix');
}
<commit_msg>change twin shortcut to Ctrl+Shift+F8<commit_after>// VERSION = '1.3.1';

objName = 'omnisidebar';
objPathString = 'omnisidebar';
addonUUID = '8f7da5c0-61c7-11e4-9803-0800200c9a66';

addonUris = {
	homepage: 'https://addons.mozilla.org/firefox/addon/omnisidebar/',
	support: 'https://github.com/Quicksaver/OmniSidebar/issues',
	fullchangelog: 'https://github.com/Quicksaver/OmniSidebar/commits/master',
	email: 'mailto:quicksaver@gmail.com',
	profile: 'https://addons.mozilla.org/firefox/user/quicksaver/',
	api: 'http://fasezero.com/addons/api/omnisidebar',
	development: 'http://fasezero.com/addons/'
};

prefList = {
	NoSync_firstEnabled: true,
	NoSync_lastStateMain: true,
	NoSync_lastStateTwin: true,

	minSidebarWidth: 30, // pixels
	minSpaceBetweenSidebars: 18, // pixels

	lastStateMain: '',
	lastStateTwin: '',

	moveSidebars: false,
	twinSidebar: false,

	renderabove: false,
	useSwitch: true,
	autoClose: false,
	autoHide: true,
	toolbar: true,
	showheadertitle: true,
	showheaderdock: true,
	showheaderclose: true,
	coloricons: 'default',
	titleButton: true,
	goButton: false,

	renderaboveTwin: false,
	useSwitchTwin: true,
	autoCloseTwin: false,
	autoHideTwin: true,
	toolbarTwin: true,
	showheadertitleTwin: true,
	showheaderdockTwin: true,
	showheadercloseTwin: true,
	coloriconsTwin: 'default',
	titleButtonTwin: true,
	goButtonTwin: false,

	glassStyle: false,
	transparency: 250,
	fx: true,
	forceOpenToolbars: false,
	forceOpenMenus: true,
	showDelay: 250,
	hideDelay: 250,
	switcherAdjust: 0,
	keepPrivate: false,
	keepLoaded: false,

	alwaysAddons: true,
	alwaysConsole: false,
	alwaysDMT: false,
	alwaysPageInfo: false,
	alwaysScratchpad: false,

	mainKeysetKeycode: 'VK_F8',
	mainKeysetAccel: false,
	mainKeysetShift: false,
	mainKeysetAlt: false,
	mainKeysetPanel: false,
	twinKeysetKeycode: 'VK_F8',
	twinKeysetAccel: true,
	twinKeysetShift: true,
	twinKeysetAlt: false,
	twinKeysetPanel: false,

	noInitialShow: false,
	aboveSquared: false,
	firstEnabled: true
};

paneList = [
	[ 'paneMain' ],
	[ 'paneTwin' ],
	[ 'paneGlobal' ]
];

function waitForSessionStore(window, delayed) {
	if(window.__SSi) {
		window[objName].Modules.load(objName, delayed);
		return;
	}

	aSync(function() {
		waitForSessionStore(window, false);
	}, 100);
}

function startAddon(window) {
	// don't load in popup windows set to hide extra chrome
	var chromeHidden = window.document.documentElement.getAttribute('chromehidden');
	if(chromeHidden && chromeHidden.contains('extrachrome')) { return; }

	prepareObject(window);

	// We use SessionStore pretty much everywhere, which might not be yet initialized in this window.
	waitForSessionStore(window, true);
}

function stopAddon(window) {
	// Make sure we are ready to disable the add-on
	dispatch(window, { type: objName+'-disabled', cancelable: false });

	removeObject(window);
}

function toggleMoveSidebars() {
	Modules.loadIf('moveSidebars', Prefs.moveSidebars);
}

function toggleGlass() {
	Modules.loadIf('glassStyle', Prefs.glassStyle);
}

function onStartup() {
	// try not to show the sidebar when starting up, so the browser doesn't jump around
	if(STARTED == APP_STARTUP) {
		Styles.load('startupFix', 'startupFix');
	}

	Modules.load('compatibilityFix/sandboxFixes');
	Modules.load('keysets');
	Modules.load('sandbox');

	Prefs.listen('moveSidebars', toggleMoveSidebars);
	Prefs.listen('glassStyle', toggleGlass);

	toggleMoveSidebars();
	toggleGlass();

	// Register the global css stylesheets
	Styles.load('global', 'global');

	// Apply the add-on to every window opened and to be opened
	Windows.callOnAll(startAddon, 'navigator:browser');
	Windows.register(startAddon, 'domwindowopened', 'navigator:browser');
}

function onShutdown() {
	// remove the add-on from all windows
	Windows.callOnAll(stopAddon, null, null, true);

	Modules.unload('glassStyle');
	Modules.unload('moveSidebars');

	// Unregister stylesheets
	Styles.unload('global');

	Prefs.unlisten('moveSidebars', toggleMoveSidebars);
	Prefs.unlisten('glassStyle', toggleGlass);

	Modules.unload('sandbox');
	Modules.unload('keysets');
	Modules.unload('compatibilityFix/sandboxFixes');

	Styles.unload('startupFix');
}
<|endoftext|>


<commit_before>(function(){

  var shell = require("shell");
  onload = function(){
      var webview = document.getElementById("discord-webview");
      webview.addEventListener("new-window", function(event){
          console.log(event.url);
          shell.openExternal(event.url);
      });
  };
})();
<commit_msg>Added ability to use Custom CSS.<commit_after>(function(){

  var fs = require("fs");
  var shell = require("shell");

  var datapath = process.env.HOME + "/.config/Discord/init.json";
  var data;
  try{
    data = JSON.parse(fs.readFileSync(datapath, 'utf-8'));
  } catch(e){
    alert("Error loading init.json." + e);
  }

  var toggleCSS;
  toggleCSS = data.useCSS;
  //alert("Using CSS?" + toggleCSS);

  onload = function(){
      //alert(csspath);
      var customcss = "";
      var webview = document.getElementById("discord-webview");
      if(toggleCSS == true){
        var csspath = process.env.HOME + "/.config/Discord/user.css";
	fs.readFile(csspath, 'utf-8', function(err,data){
	  if (err) {alert(err);}
	  customcss = data;
	});
      }
      webview.addEventListener("dom-ready", function(event){
	//webview.openDevTools();
	if(customcss != "" && toggleCSS == true){
	  webview.insertCSS(customcss);
	}
      });

      webview.addEventListener("new-window", function(event){
          console.log(event.url);
          shell.openExternal(event.url);
      });

  };
})();
<|endoftext|>


<commit_before>import { PropertyBinding } from './PropertyBinding.js';
import { _Math } from '../math/Math.js';

/**
 *
 * A group of objects that receives a shared animation state.
 *
 * Usage:
 *
 * 	-	Add objects you would otherwise pass as 'root' to the
 * 		constructor or the .clipAction method of AnimationMixer.
 *
 * 	-	Instead pass this object as 'root'.
 *
 * 	-	You can also add and remove objects later when the mixer
 * 		is running.
 *
 * Note:
 *
 *  	Objects of this class appear as one object to the mixer,
 *  	so cache control of the individual objects must be done
 *  	on the group.
 *
 * Limitation:
 *
 * 	- 	The animated properties must be compatible among the
 * 		all objects in the group.
 *
 *  -	A single property can either be controlled through a
 *  	target group or directly, but not both.
 *
 * @author tschw
 */

function AnimationObjectGroup() {

	this.uuid = _Math.generateUUID();

	// cached objects followed by the active ones
	this._objects = Array.prototype.slice.call( arguments );

	this.nCachedObjects_ = 0;			// threshold
	// note: read by PropertyBinding.Composite

	var indices = {};
	this._indicesByUUID = indices;		// for bookkeeping

	for ( var i = 0, n = arguments.length; i !== n; ++ i ) {

		indices[ arguments[ i ].uuid ] = i;

	}

	this._paths = [];					// inside: string
	this._parsedPaths = [];				// inside: { we don't care, here }
	this._bindings = []; 				// inside: Array< PropertyBinding >
	this._bindingsIndicesByPath = {}; 	// inside: indices in these arrays

	var scope = this;

	this.stats = {

		objects: {
			get total() {

				return scope._objects.length;

			},
			get inUse() {

				return this.total - scope.nCachedObjects_;

			}
		},
		get bindingsPerObject() {

			return scope._bindings.length;

		}

	};

}

Object.assign( AnimationObjectGroup.prototype, {

	isAnimationObjectGroup: true,

	add: function () {

		var objects = this._objects,
			nObjects = objects.length,
			nCachedObjects = this.nCachedObjects_,
			indicesByUUID = this._indicesByUUID,
			paths = this._paths,
			parsedPaths = this._parsedPaths,
			bindings = this._bindings,
			nBindings = bindings.length,
		    	knownObject = undefined;;

		for ( var i = 0, n = arguments.length; i !== n; ++ i ) {

			var object = arguments[ i ],
				uuid = object.uuid,
				index = indicesByUUID[ uuid ];

			if ( index === undefined ) {

				// unknown object -> add it to the ACTIVE region

				index = nObjects ++;
				indicesByUUID[ uuid ] = index;
				objects.push( object );

				// accounting is done, now do the same for all bindings

				for ( var j = 0, m = nBindings; j !== m; ++ j ) {

					bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) );

				}

			} else if ( index < nCachedObjects ) {

				knownObject = objects[ index ];

				// move existing object to the ACTIVE region

				var firstActiveIndex = -- nCachedObjects,
					lastCachedObject = objects[ firstActiveIndex ];

				indicesByUUID[ lastCachedObject.uuid ] = index;
				objects[ index ] = lastCachedObject;

				indicesByUUID[ uuid ] = firstActiveIndex;
				objects[ firstActiveIndex ] = object;

				// accounting is done, now do the same for all bindings

				for ( var j = 0, m = nBindings; j !== m; ++ j ) {

					var bindingsForPath = bindings[ j ],
						lastCached = bindingsForPath[ firstActiveIndex ],
						binding = bindingsForPath[ index ];

					bindingsForPath[ index ] = lastCached;

					if ( binding === undefined ) {

						// since we do not bother to create new bindings
						// for objects that are cached, the binding may
						// or may not exist

						binding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] );

					}

					bindingsForPath[ firstActiveIndex ] = binding;

				}

			} else if ( objects[ index ] !== knownObject ) {

				console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' +
						'detected. Clean the caches or recreate your infrastructure when reloading scenes.' );

			} // else the object is already where we want it to be

		} // for arguments

		this.nCachedObjects_ = nCachedObjects;

	},

	remove: function () {

		var objects = this._objects,
			nCachedObjects = this.nCachedObjects_,
			indicesByUUID = this._indicesByUUID,
			bindings = this._bindings,
			nBindings = bindings.length;

		for ( var i = 0, n = arguments.length; i !== n; ++ i ) {

			var object = arguments[ i ],
				uuid = object.uuid,
				index = indicesByUUID[ uuid ];

			if ( index !== undefined && index >= nCachedObjects ) {

				// move existing object into the CACHED region

				var lastCachedIndex = nCachedObjects ++,
					firstActiveObject = objects[ lastCachedIndex ];

				indicesByUUID[ firstActiveObject.uuid ] = index;
				objects[ index ] = firstActiveObject;

				indicesByUUID[ uuid ] = lastCachedIndex;
				objects[ lastCachedIndex ] = object;

				// accounting is done, now do the same for all bindings

				for ( var j = 0, m = nBindings; j !== m; ++ j ) {

					var bindingsForPath = bindings[ j ],
						firstActive = bindingsForPath[ lastCachedIndex ],
						binding = bindingsForPath[ index ];

					bindingsForPath[ index ] = firstActive;
					bindingsForPath[ lastCachedIndex ] = binding;

				}

			}

		} // for arguments

		this.nCachedObjects_ = nCachedObjects;

	},

	// remove & forget
	uncache: function () {

		var objects = this._objects,
			nObjects = objects.length,
			nCachedObjects = this.nCachedObjects_,
			indicesByUUID = this._indicesByUUID,
			bindings = this._bindings,
			nBindings = bindings.length;

		for ( var i = 0, n = arguments.length; i !== n; ++ i ) {

			var object = arguments[ i ],
				uuid = object.uuid,
				index = indicesByUUID[ uuid ];

			if ( index !== undefined ) {

				delete indicesByUUID[ uuid ];

				if ( index < nCachedObjects ) {

					// object is cached, shrink the CACHED region

					var firstActiveIndex = -- nCachedObjects,
						lastCachedObject = objects[ firstActiveIndex ],
						lastIndex = -- nObjects,
						lastObject = objects[ lastIndex ];

					// last cached object takes this object's place
					indicesByUUID[ lastCachedObject.uuid ] = index;
					objects[ index ] = lastCachedObject;

					// last object goes to the activated slot and pop
					indicesByUUID[ lastObject.uuid ] = firstActiveIndex;
					objects[ firstActiveIndex ] = lastObject;
					objects.pop();

					// accounting is done, now do the same for all bindings

					for ( var j = 0, m = nBindings; j !== m; ++ j ) {

						var bindingsForPath = bindings[ j ],
							lastCached = bindingsForPath[ firstActiveIndex ],
							last = bindingsForPath[ lastIndex ];

						bindingsForPath[ index ] = lastCached;
						bindingsForPath[ firstActiveIndex ] = last;
						bindingsForPath.pop();

					}

				} else {

					// object is active, just swap with the last and pop

					var lastIndex = -- nObjects,
						lastObject = objects[ lastIndex ];

					indicesByUUID[ lastObject.uuid ] = index;
					objects[ index ] = lastObject;
					objects.pop();

					// accounting is done, now do the same for all bindings

					for ( var j = 0, m = nBindings; j !== m; ++ j ) {

						var bindingsForPath = bindings[ j ];

						bindingsForPath[ index ] = bindingsForPath[ lastIndex ];
						bindingsForPath.pop();

					}

				} // cached or active

			} // if object is known

		} // for arguments

		this.nCachedObjects_ = nCachedObjects;

	},

	// Internal interface used by befriended PropertyBinding.Composite:

	subscribe_: function ( path, parsedPath ) {

		// returns an array of bindings for the given path that is changed
		// according to the contained objects in the group

		var indicesByPath = this._bindingsIndicesByPath,
			index = indicesByPath[ path ],
			bindings = this._bindings;

		if ( index !== undefined ) return bindings[ index ];

		var paths = this._paths,
			parsedPaths = this._parsedPaths,
			objects = this._objects,
			nObjects = objects.length,
			nCachedObjects = this.nCachedObjects_,
			bindingsForPath = new Array( nObjects );

		index = bindings.length;

		indicesByPath[ path ] = index;

		paths.push( path );
		parsedPaths.push( parsedPath );
		bindings.push( bindingsForPath );

		for ( var i = nCachedObjects, n = objects.length; i !== n; ++ i ) {

			var object = objects[ i ];
			bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath );

		}

		return bindingsForPath;

	},

	unsubscribe_: function ( path ) {

		// tells the group to forget about a property path and no longer
		// update the array previously obtained with 'subscribe_'

		var indicesByPath = this._bindingsIndicesByPath,
			index = indicesByPath[ path ];

		if ( index !== undefined ) {

			var paths = this._paths,
				parsedPaths = this._parsedPaths,
				bindings = this._bindings,
				lastBindingsIndex = bindings.length - 1,
				lastBindings = bindings[ lastBindingsIndex ],
				lastBindingsPath = path[ lastBindingsIndex ];

			indicesByPath[ lastBindingsPath ] = index;

			bindings[ index ] = lastBindings;
			bindings.pop();

			parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ];
			parsedPaths.pop();

			paths[ index ] = paths[ lastBindingsIndex ];
			paths.pop();

		}

	}

} );

export { AnimationObjectGroup };
<commit_msg>AnimationObjectGroup clean up.<commit_after>import { PropertyBinding } from './PropertyBinding.js';
import { _Math } from '../math/Math.js';

/**
 *
 * A group of objects that receives a shared animation state.
 *
 * Usage:
 *
 * 	-	Add objects you would otherwise pass as 'root' to the
 * 		constructor or the .clipAction method of AnimationMixer.
 *
 * 	-	Instead pass this object as 'root'.
 *
 * 	-	You can also add and remove objects later when the mixer
 * 		is running.
 *
 * Note:
 *
 *  	Objects of this class appear as one object to the mixer,
 *  	so cache control of the individual objects must be done
 *  	on the group.
 *
 * Limitation:
 *
 * 	- 	The animated properties must be compatible among the
 * 		all objects in the group.
 *
 *  -	A single property can either be controlled through a
 *  	target group or directly, but not both.
 *
 * @author tschw
 */

function AnimationObjectGroup() {

	this.uuid = _Math.generateUUID();

	// cached objects followed by the active ones
	this._objects = Array.prototype.slice.call( arguments );

	this.nCachedObjects_ = 0;			// threshold
	// note: read by PropertyBinding.Composite

	var indices = {};
	this._indicesByUUID = indices;		// for bookkeeping

	for ( var i = 0, n = arguments.length; i !== n; ++ i ) {

		indices[ arguments[ i ].uuid ] = i;

	}

	this._paths = [];					// inside: string
	this._parsedPaths = [];				// inside: { we don't care, here }
	this._bindings = []; 				// inside: Array< PropertyBinding >
	this._bindingsIndicesByPath = {}; 	// inside: indices in these arrays

	var scope = this;

	this.stats = {

		objects: {
			get total() {

				return scope._objects.length;

			},
			get inUse() {

				return this.total - scope.nCachedObjects_;

			}
		},
		get bindingsPerObject() {

			return scope._bindings.length;

		}

	};

}

Object.assign( AnimationObjectGroup.prototype, {

	isAnimationObjectGroup: true,

	add: function () {

		var objects = this._objects,
			nObjects = objects.length,
			nCachedObjects = this.nCachedObjects_,
			indicesByUUID = this._indicesByUUID,
			paths = this._paths,
			parsedPaths = this._parsedPaths,
			bindings = this._bindings,
			nBindings = bindings.length,
		    	knownObject = undefined;

		for ( var i = 0, n = arguments.length; i !== n; ++ i ) {

			var object = arguments[ i ],
				uuid = object.uuid,
				index = indicesByUUID[ uuid ];

			if ( index === undefined ) {

				// unknown object -> add it to the ACTIVE region

				index = nObjects ++;
				indicesByUUID[ uuid ] = index;
				objects.push( object );

				// accounting is done, now do the same for all bindings

				for ( var j = 0, m = nBindings; j !== m; ++ j ) {

					bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) );

				}

			} else if ( index < nCachedObjects ) {

				knownObject = objects[ index ];

				// move existing object to the ACTIVE region

				var firstActiveIndex = -- nCachedObjects,
					lastCachedObject = objects[ firstActiveIndex ];

				indicesByUUID[ lastCachedObject.uuid ] = index;
				objects[ index ] = lastCachedObject;

				indicesByUUID[ uuid ] = firstActiveIndex;
				objects[ firstActiveIndex ] = object;

				// accounting is done, now do the same for all bindings

				for ( var j = 0, m = nBindings; j !== m; ++ j ) {

					var bindingsForPath = bindings[ j ],
						lastCached = bindingsForPath[ firstActiveIndex ],
						binding = bindingsForPath[ index ];

					bindingsForPath[ index ] = lastCached;

					if ( binding === undefined ) {

						// since we do not bother to create new bindings
						// for objects that are cached, the binding may
						// or may not exist

						binding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] );

					}

					bindingsForPath[ firstActiveIndex ] = binding;

				}

			} else if ( objects[ index ] !== knownObject ) {

				console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' +
						'detected. Clean the caches or recreate your infrastructure when reloading scenes.' );

			} // else the object is already where we want it to be

		} // for arguments

		this.nCachedObjects_ = nCachedObjects;

	},

	remove: function () {

		var objects = this._objects,
			nCachedObjects = this.nCachedObjects_,
			indicesByUUID = this._indicesByUUID,
			bindings = this._bindings,
			nBindings = bindings.length;

		for ( var i = 0, n = arguments.length; i !== n; ++ i ) {

			var object = arguments[ i ],
				uuid = object.uuid,
				index = indicesByUUID[ uuid ];

			if ( index !== undefined && index >= nCachedObjects ) {

				// move existing object into the CACHED region

				var lastCachedIndex = nCachedObjects ++,
					firstActiveObject = objects[ lastCachedIndex ];

				indicesByUUID[ firstActiveObject.uuid ] = index;
				objects[ index ] = firstActiveObject;

				indicesByUUID[ uuid ] = lastCachedIndex;
				objects[ lastCachedIndex ] = object;

				// accounting is done, now do the same for all bindings

				for ( var j = 0, m = nBindings; j !== m; ++ j ) {

					var bindingsForPath = bindings[ j ],
						firstActive = bindingsForPath[ lastCachedIndex ],
						binding = bindingsForPath[ index ];

					bindingsForPath[ index ] = firstActive;
					bindingsForPath[ lastCachedIndex ] = binding;

				}

			}

		} // for arguments

		this.nCachedObjects_ = nCachedObjects;

	},

	// remove & forget
	uncache: function () {

		var objects = this._objects,
			nObjects = objects.length,
			nCachedObjects = this.nCachedObjects_,
			indicesByUUID = this._indicesByUUID,
			bindings = this._bindings,
			nBindings = bindings.length;

		for ( var i = 0, n = arguments.length; i !== n; ++ i ) {

			var object = arguments[ i ],
				uuid = object.uuid,
				index = indicesByUUID[ uuid ];

			if ( index !== undefined ) {

				delete indicesByUUID[ uuid ];

				if ( index < nCachedObjects ) {

					// object is cached, shrink the CACHED region

					var firstActiveIndex = -- nCachedObjects,
						lastCachedObject = objects[ firstActiveIndex ],
						lastIndex = -- nObjects,
						lastObject = objects[ lastIndex ];

					// last cached object takes this object's place
					indicesByUUID[ lastCachedObject.uuid ] = index;
					objects[ index ] = lastCachedObject;

					// last object goes to the activated slot and pop
					indicesByUUID[ lastObject.uuid ] = firstActiveIndex;
					objects[ firstActiveIndex ] = lastObject;
					objects.pop();

					// accounting is done, now do the same for all bindings

					for ( var j = 0, m = nBindings; j !== m; ++ j ) {

						var bindingsForPath = bindings[ j ],
							lastCached = bindingsForPath[ firstActiveIndex ],
							last = bindingsForPath[ lastIndex ];

						bindingsForPath[ index ] = lastCached;
						bindingsForPath[ firstActiveIndex ] = last;
						bindingsForPath.pop();

					}

				} else {

					// object is active, just swap with the last and pop

					var lastIndex = -- nObjects,
						lastObject = objects[ lastIndex ];

					indicesByUUID[ lastObject.uuid ] = index;
					objects[ index ] = lastObject;
					objects.pop();

					// accounting is done, now do the same for all bindings

					for ( var j = 0, m = nBindings; j !== m; ++ j ) {

						var bindingsForPath = bindings[ j ];

						bindingsForPath[ index ] = bindingsForPath[ lastIndex ];
						bindingsForPath.pop();

					}

				} // cached or active

			} // if object is known

		} // for arguments

		this.nCachedObjects_ = nCachedObjects;

	},

	// Internal interface used by befriended PropertyBinding.Composite:

	subscribe_: function ( path, parsedPath ) {

		// returns an array of bindings for the given path that is changed
		// according to the contained objects in the group

		var indicesByPath = this._bindingsIndicesByPath,
			index = indicesByPath[ path ],
			bindings = this._bindings;

		if ( index !== undefined ) return bindings[ index ];

		var paths = this._paths,
			parsedPaths = this._parsedPaths,
			objects = this._objects,
			nObjects = objects.length,
			nCachedObjects = this.nCachedObjects_,
			bindingsForPath = new Array( nObjects );

		index = bindings.length;

		indicesByPath[ path ] = index;

		paths.push( path );
		parsedPaths.push( parsedPath );
		bindings.push( bindingsForPath );

		for ( var i = nCachedObjects, n = objects.length; i !== n; ++ i ) {

			var object = objects[ i ];
			bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath );

		}

		return bindingsForPath;

	},

	unsubscribe_: function ( path ) {

		// tells the group to forget about a property path and no longer
		// update the array previously obtained with 'subscribe_'

		var indicesByPath = this._bindingsIndicesByPath,
			index = indicesByPath[ path ];

		if ( index !== undefined ) {

			var paths = this._paths,
				parsedPaths = this._parsedPaths,
				bindings = this._bindings,
				lastBindingsIndex = bindings.length - 1,
				lastBindings = bindings[ lastBindingsIndex ],
				lastBindingsPath = path[ lastBindingsIndex ];

			indicesByPath[ lastBindingsPath ] = index;

			bindings[ index ] = lastBindings;
			bindings.pop();

			parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ];
			parsedPaths.pop();

			paths[ index ] = paths[ lastBindingsIndex ];
			paths.pop();

		}

	}

} );

export { AnimationObjectGroup };
<|endoftext|>


<commit_before>'use strict';

var typeRegEx =  /^\s*(?:\{([\w-_]+)\})?\s*(?:\$([\w-_]+))?\s*(?:\((.*)\))?\s*(?:-?\s*(.*))?/m;

module.exports = function( text ){
  var parsed = typeRegEx.exec(text);
  var obj = {};

  if (parsed[1]) {
    obj.type = parsed[1];
  }

  if (parsed[2]) {
    obj.variable = {
      name: parsed[2],
      default: parsed[3]
    };
  }

  if (parsed[4]) {
    obj.description = parsed[4];
  }

  return obj;
};

module.exports.alias = ['return'];<commit_msg>Revert returns<commit_after>'use strict';

var typeRegEx =  /^\s*(?:\{(.*?)\})?\s*(?:\$(\w+))?\s*(?:\((.*?)\))?\s*(?:-?\s*(.*))?$/m;

module.exports = function( text ){
  var parsed = typeRegEx.exec(text);
  var obj = {};

  if (parsed[1]) {
    obj.type = parsed[1];
  }

  if (parsed[2]) {
    obj.variable = {
      name: parsed[2],
      default: parsed[3]
    };
  }

  if (parsed[4]) {
    obj.description = parsed[4];
  }

  return obj;
};

module.exports.alias = ['return'];<|endoftext|>


<commit_before>'use strict';

const express = require('express');
const bodyParser = require('body-parser');
const request = require('request');
// Variables
const variables = require('./variables');
const slackUrl = 'https://slack.com/api/chat.postMessage';

const app = express();
app.use(bodyParser.json());

function sendMessage(channel, message, pullRequestUrl, color) {
    request.post({
        proxy: variables.proxy,
        url: slackUrl,
        form: {
            token: variables.botToken,
            channel: '@' + channel,
            text: message,
            as_user: true,
            attachments: JSON.stringify([
                {
                    color: color,
                    text: pullRequestUrl,
                    // footer: 'Yes I'm a bot (c) :robot_face:'
                }
            ])
        }
    }, function (error, response, body) {
        console.log(body);
    });
}

app.post('/' + variables.urlPath, function (req, res) {
    console.log(req.body);
    if (req.body) {
        // Notify on opened PR or button click
        if (req.body.pullRequestAction == 'OPENED' || req.body.pullRequestAction == 'BUTTON_TRIGGER') {
            const reviewers = req.body.pullRequestReviewers.split(',');
            reviewers.forEach(function (reviewer) {
                let cause = 'created a new';
                // Change text if button clicked
                if (req.body.pullRequestAction == 'BUTTON_TRIGGER')
                    cause = '*reminds* you to review his';
                const message = `*${req.body.pullRequestAuthorDisplayName}* ${cause} Pull Request: _${req.body.pullRequestTitle}_ \nPlease review at:`;
                sendMessage(reviewer, message, req.body.pullRequestUrl, '#3AA3E3');
            });
        } else if (req.body.pullRequestAction == 'APPROVED') {
            // Notify if required approvals are reached
            if (req.body.pullRequestApprovedCount >= variables.requiredApprovals) {
                const successMessage = `*Hurray*!!! Your Pull Request _${req.body.pullRequestTitle}_ reached required approval count and ready to be merged! \nCome on click *Merge* at:`;
                sendMessage(req.body.pullRequestAuthor, successMessage, req.body.pullRequestUrl, '#3DB014');
            }
        } else if (req.body.pullRequestAction == 'COMMENTED') {
            // Notify on new comment if it's not own comment
            if (req.body.triggerUser == variables.ciUserName && req.body.comment.indexOf('BUILD FAILED') >= 0) {
                // Notify if ci commented that build failed
                const buildFailedMessage = `*Warning*! Your Pull Request _${req.body.pullRequestTitle}_ just failed to build on ${variables.ciUserName} \nSee at:`;
                sendMessage(req.body.pullRequestAuthor, buildFailedMessage, req.body.pullRequestUrl, '#D21111');
            } else if (req.body.triggerUser != req.body.pullRequestAuthor) {
                const commentMessage = `*${req.body.triggerDisplayName}* commented on your Pull Request _${req.body.pullRequestTitle}_:\n ${req.body.comment} \nReply at:`;
                sendMessage(req.body.pullRequestAuthor, commentMessage, req.body.pullRequestUrl, '#EFC058');
            }
        }
    }
    res.send(req.body);
});

app.listen(variables.port);
console.log('Notifier server started at port ' + variables.port);<commit_msg>Minor fix<commit_after>'use strict';

const express = require('express');
const bodyParser = require('body-parser');
const request = require('request');
// Variables
const variables = require('./variables');
const slackUrl = 'https://slack.com/api/chat.postMessage';

const app = express();
app.use(bodyParser.json());

function sendMessage(channel, message, pullRequestUrl, color) {
    request.post({
        proxy: variables.proxy,
        url: slackUrl,
        form: {
            token: variables.botToken,
            channel: '@' + channel,
            text: message,
            as_user: true,
            attachments: JSON.stringify([
                {
                    color: color,
                    text: pullRequestUrl,
                    // footer: 'Yes I'm a bot (c) :robot_face:'
                }
            ])
        }
    }, function (error, response, body) {
        console.log(body);
    });
}

app.post('/' + variables.urlPath, function (req, res) {
    console.log(req.body);
    if (req.body) {
        // Notify on opened PR or button click
        if (req.body.pullRequestAction == 'OPENED' || req.body.pullRequestAction == 'BUTTON_TRIGGER') {
            const reviewers = req.body.pullRequestReviewers.split(',');
            reviewers.forEach(function (reviewer) {
                let cause = 'created a new';
                // Change text if button clicked
                if (req.body.pullRequestAction == 'BUTTON_TRIGGER')
                    cause = '*reminds* you to review his';
                const message = `*${req.body.pullRequestAuthorDisplayName}* ${cause} Pull Request: _${req.body.pullRequestTitle}_ \nPlease review at:`;
                sendMessage(reviewer, message, req.body.pullRequestUrl, '#3AA3E3');
            });
        } else if (req.body.pullRequestAction == 'APPROVED') {
            // Notify if required approvals are reached
            if (req.body.pullRequestApprovedCount >= variables.requiredApprovals) {
                const successMessage = `*Hurray*!!! Your Pull Request _${req.body.pullRequestTitle}_ reached required approval count and ready to be merged! \nCome on click *Merge* at:`;
                sendMessage(req.body.pullRequestAuthor, successMessage, req.body.pullRequestUrl, '#3DB014');
            }
        } else if (req.body.pullRequestAction == 'COMMENTED') {
            // Notify on new comment if it's not own comment
            if (req.body.triggerUser == variables.ciUserName && req.body.comment.indexOf('BUILD FAILED') >= 0) {
                // Notify if ci commented that build failed
                const buildFailedMessage = `*Warning*! Your Pull Request _${req.body.pullRequestTitle}_ just failed to build on ${variables.ciUserName} \nSee at:`;
                sendMessage(req.body.pullRequestAuthor, buildFailedMessage, req.body.pullRequestUrl, '#D21111');
            } else if (req.body.triggerUser != req.body.pullRequestAuthor && req.body.triggerUser != variables.ciUserName) {
                const commentMessage = `*${req.body.triggerDisplayName}* commented on your Pull Request _${req.body.pullRequestTitle}_:\n ${req.body.comment} \nReply at:`;
                sendMessage(req.body.pullRequestAuthor, commentMessage, req.body.pullRequestUrl, '#EFC058');
            }
        }
    }
    res.send(req.body);
});

app.listen(variables.port);
console.log('Notifier server started at port ' + variables.port);<|endoftext|>


<commit_before>(function($) {
  var mapInstance
  var defaults = {
    element: null,
    center: {
      lat: 59.3293358,
      lng: 18.0686101
    },
    zoom: 4,
    google: {
      map: null,
      markers: [],
      cluster: null
    },
    autorun: true
  }

  $.fn.googleMap = function(options) {
    var settings = $.extend(defaults, options)

    google.maps.InfoWindow.prototype.isOpen = function(){
        var map = this.map
        return (map !== null && typeof map !== "undefined")
    }

    fn = {
      init: function() {
        try {
          settings.google.map = new google.maps.Map(settings.element, {
            zoom: settings.zoom,
            center: settings.center
          })
          return true
        } catch (err) {
          throw err
        }
      },
      setMarker: function(options) {
        settings.google.markers.push(new google.maps.Marker({
          position: options.position,
          map: settings.google.map,
          title: options.title,
          icon: options.icon
        }))

        var index = settings.google.markers.length -1

        settings.google.markers[index].infowindow = new google.maps.InfoWindow({
          content: options.content,
          maxWidth: 200,
          minWidth: 200
        })

        settings.google.markers[index].addListener('click', function() {
          if( settings.google.markers[index].infowindow.isOpen() ) {
            settings.google.markers[index].infowindow.close()
          } else {
            for (var i = settings.google.markers.length - 1; i >= 0; i--) {
              settings.google.markers[i].infowindow.close()
            }
            settings.google.markers[index].infowindow.open(settings.google.map, settings.google.markers[index])
          }
        })
      },
      clusterMarkers: function() {
        settings.google.cluster = new MarkerClusterer(settings.google.map, settings.google.markers, {
          minimumClusterSize: 2,
          maxZoom: 13,
          gridSize: 20,
          styles: [
            {
              textColor: 'white',
              url: '/assets/images/map/cluster.png',
              height: 28,
              width: 31
            },

          ]
        })
      },
      setCenter: function(position) {
        try {
          settings.google.map.setCenter(position)
        } catch(err) {
          throw err
        }
      },
      setZoom: function(zoom) {
          try {
              settings.google.map.setZoom( parseInt(zoom) )
          } catch(err) {
              throw err
          }
      },
      setBounds: function(bounds) {
        try {
          settings.google.map.fitBounds(bounds);
        } catch(err) {
          throw err
        }
      },
      getSettings: function() {
        return settings
      },
      getBounds: function() {
        return settings.google.map.getBounds()
      },
      getCenter: function() {
        return settings.google.map.getCenter()
      },
      triggerResize: function() {
        google.maps.event.trigger(settings.google.map, 'resize');
      }
    }

    if (settings.autorun === true && ($(this).length)) {
      settings.element = $(this)[0]
      fn.init()
    }

    return fn
  }
}(jQuery))

//Place markers on map
function setMarkers(data, settings) {
  for (var i = 0; i < data.length; i++) {
    entry = data[i]
    if(typeof(entry.post.coordinates) !== 'undefined') {
      var iconUrl = '/assets/images/'

      switch(entry.type) {
        case '3':
          iconUrl += 'pin-restaurant.png'
          break
        case '5':
          iconUrl += 'pin-store.png'
          break
        default:
          iconUrl = false //use default google marker
          break
      }

      var infoWindowContent = function(entry) {
        var content = (entry.post.content.length > 90) ? entry.post.content.substr(0, 90) + '...' : entry.post.content
        return $('<div>', {
          class: 'infowindow-content'
        })
        .html(content)
      }

      var entryContent = $('<div>', {
        class: 'infowindow-container'
      })
      .append(
        $('<div>', {
          class: 'infowindow-header'
        })
        .append(
          $('<div>', {
            class: 'infowindow-image'
          })
          .append(
            $('<img>', {
              src: '/uploads/' + entry.post.cover.filename + '.jpg'
            })
          ),
          $('<div>', {
            class: 'infowindow-title'
          })
          .append(
            $('<a>', {
              href: entry.url
            })
            .html(entry.title)
          ),
          $('<div>', {
            class: 'infowindow-stars-container'
          })
          .append(
            $('<div>', {
              class: 'star'
            })
            .append(
              $('<span>', {
                class: 'glyphicon glyphicon-star'
              })
            )
          )
        ),
        infoWindowContent(entry)
      )

      mapInstance.setMarker({
        position: {
          lat: parseFloat(entry.post.coordinates.latitude),
          lng: parseFloat(entry.post.coordinates.longitude)
        },
        title: entry.title,
        content: entryContent.html(),
        icon: {
          url: iconUrl,
          size: new google.maps.Size(32, 32)
        }
      })
    } else {
      console.log(entry.title + ' has no coordinates!')
    }
  }
  if(typeof(settings) !== 'undefined' && settings.hasOwnProperty('cluster')) {
    if(settings.cluster === true) {
      mapInstance.clusterMarkers()
    }
  }
}

function zoomToUserLocation() {
  $.fn.geoLocation(function(result) {
    if (result.success === true) {
      mapInstance.setMarker({
        position: {
          lat: parseFloat(result.position.latitude),
          lng: parseFloat(result.position.longitude)
        },
        title: 'Din plats',
        content: 'Du är här!',
        icon: '/assets/images/pin-my-position.png'
      })
      mapInstance.setCenter({
        lat: parseFloat(result.position.latitude),
        lng: parseFloat(result.position.longitude)
      })
      mapInstance.setZoom(11)
    } else {
      //TODO display error
    }
  })
}

function getMarkerData(options, callback) {
  var settings = $.extend({
    url: '/ajax/map'
  }, options)

  $.ajax(settings)
  .done(function(data) {
    callback(data)
  })
}

function getMapOptions(element) {
  var options = {}
  var mapData = $('#map').data()

  //Check if map is configured to auto initialize
  if(mapData.hasOwnProperty('mapInit')) {
    options.init = mapData.mapInit
  }

  if(mapData.hasOwnProperty('mapCluster')) {
    options.cluster = mapData.mapCluster
  }

  if(mapData.hasOwnProperty('mapFilter')) {
    var filters = {
      single: function() {
        return {
          id: $('.content')[0].id
        }
      },
      restaurant: function() {
        return {
          type: '3'
        }
      },
      butik: function() {
        return {
          type: '5'
        }
      }
    }

    if(mapData.mapFilter in filters) {
      options.data = {
        filter: filters[mapData.mapFilter](),
        filterName: mapData.mapFilter
      }
    }
  }

  if(mapData.hasOwnProperty('markerLatitude')) {
    options.markerLatitude = mapData.markerLatitude
  }

  if(mapData.hasOwnProperty('markerLongitude')) {
    options.markerLongitude = mapData.markerLongitude
  }

  if(mapData.hasOwnProperty('markerTitle')) {
    options.markerTitle = mapData.markerTitle
  }

  return options
}

function applyMarkerData(data, options) {
  if(options.hasOwnProperty('data')) {
    if(options.data.filterName === 'single') {
      if(data.length > 0 && data[0].post.hasOwnProperty('coordinates')) {
        mapInstance.setCenter({
          lat: parseFloat(data[0].post.coordinates.latitude),
          lng: parseFloat(data[0].post.coordinates.longitude)
        })

        mapInstance.setZoom(11)
      } else {
        return
      }
    }
  }

  setMarkers(data, options)
}

function setSingleOpenMarker(obj) {
  mapInstance.setMarker({
    position: {
      lat: parseFloat(obj.coordinates.latitude),
      lng: parseFloat(obj.coordinates.longitude)
    },
    content: obj.content
  })

  mapInstance.setZoom(11)

  mapInstance.setCenter({
    lat: parseFloat(obj.coordinates.latitude),
    lng: parseFloat(obj.coordinates.longitude)
  })

  settings = mapInstance.getSettings()
  marker = settings.google.markers[0]
  marker.infowindow.open(settings.google.map, marker)
}

function fullscreenSupported() {
  return (document.fullscreenEnabled ||
    document.webkitFullscreenEnabled ||
    document.mozFullScreenEnabled ||
    document.msFullscreenEnabled
  )
}

function isFullscreen() {
  return ( document.fullscreenElement ||
    document.webkitFullscreenElement ||
    document.mozFullScreenElement ||
    document.msFullscreenElement ) ? true : false
}

function enterFullscreen(element) {
  if (element.requestFullscreen) {
    element.requestFullscreen()
  } else if (element.webkitRequestFullscreen) {
    element.webkitRequestFullscreen()
  } else if (element.mozRequestFullScreen) {
    element.mozRequestFullScreen()
  } else if (element.msRequestFullscreen) {
    element.msRequestFullscreen()
  }
}

function exitFullscreen() {
  if (document.exitFullscreen) {
    document.exitFullscreen();
  } else if (document.webkitExitFullscreen) {
    document.webkitExitFullscreen();
  } else if (document.mozCancelFullScreen) {
    document.mozCancelFullScreen();
  } else if (document.msExitFullscreen) {
    document.msExitFullscreen();
  }
}

$(document).bind('mapready', function(e) {
  //Initialize map
  mapInstance = $('#map').googleMap()

  $('#show-map').on('click', function(e) {
    e.preventDefault()

    $('.filter').addClass('hidden') //Remove overlay filter

    //Get map options
    var options = getMapOptions()

    //Get marker data
    getMarkerData(options, function(data) {
      applyMarkerData(data, options)
    })
  })

  $('.showMyLocation').on('click', function(e) {
    e.preventDefault()
    zoomToUserLocation()
  })

  $('.showFullscreen').on('click', function(e) {
    e.preventDefault()
    if( fullscreenSupported() ) {
      var element = document.getElementById('mapContainer')

      if( isFullscreen() ) {
        exitFullscreen()
        $(element).css({
          margin: '',
          width: '',
          height: '',
          position: '',
          top: ''
        })
        return
      }

      var data = $('#map').data()
      data.center = mapInstance.getCenter()

      enterFullscreen( element )

      $(document).on('webkitfullscreenchange mozfullscreenchange fullscreenchange', function(e) {
        if( isFullscreen() ) {
          $(element).css({
            margin: '0',
            width: '100%',
            height: '100%',
            position: 'absolute',
            top: '0'
          })
        } else {
          $(element).css({
            margin: '',
            width: '',
            height: '',
            position: '',
            top: ''
          })
        }

        mapInstance.triggerResize()
        mapInstance.setCenter( data.center )
      })
    } else {
      console.log('no fullscreen support')
      //TODO notify user
    }
  })

  if($('#map').length > 0) {
    var options = getMapOptions()

    if('init' in options && options.init === true) {
      if('markerLatitude' in options && 'markerLongitude' in options) {
        //Map provides it's own coordinates

        setSingleOpenMarker({
          coordinates: {
            latitude: options.markerLatitude,
            longitude: options.markerLongitude
          },
          content: options.markerTitle
        })

      } else {
        getMarkerData(options, function(data) {
          applyMarkerData(data, options)
        })
      }

      $('.filter').addClass('visible-xs') //Remove overlay filter
    }
  }
})
<commit_msg>Fix missing container element and add stars<commit_after>(function($) {
  var mapInstance
  var defaults = {
    element: null,
    center: {
      lat: 59.3293358,
      lng: 18.0686101
    },
    zoom: 4,
    google: {
      map: null,
      markers: [],
      cluster: null
    },
    autorun: true
  }

  $.fn.googleMap = function(options) {
    var settings = $.extend(defaults, options)

    google.maps.InfoWindow.prototype.isOpen = function(){
        var map = this.map
        return (map !== null && typeof map !== "undefined")
    }

    fn = {
      init: function() {
        try {
          settings.google.map = new google.maps.Map(settings.element, {
            zoom: settings.zoom,
            center: settings.center
          })
          return true
        } catch (err) {
          throw err
        }
      },
      setMarker: function(options) {
        settings.google.markers.push(new google.maps.Marker({
          position: options.position,
          map: settings.google.map,
          title: options.title,
          icon: options.icon
        }))

        var index = settings.google.markers.length -1

        settings.google.markers[index].infowindow = new google.maps.InfoWindow({
          content: options.content,
          maxWidth: 200,
          minWidth: 200
        })

        settings.google.markers[index].addListener('click', function() {
          if( settings.google.markers[index].infowindow.isOpen() ) {
            settings.google.markers[index].infowindow.close()
          } else {
            for (var i = settings.google.markers.length - 1; i >= 0; i--) {
              settings.google.markers[i].infowindow.close()
            }
            settings.google.markers[index].infowindow.open(settings.google.map, settings.google.markers[index])
          }
        })
      },
      clusterMarkers: function() {
        settings.google.cluster = new MarkerClusterer(settings.google.map, settings.google.markers, {
          minimumClusterSize: 2,
          maxZoom: 13,
          gridSize: 20,
          styles: [
            {
              textColor: 'white',
              url: '/assets/images/map/cluster.png',
              height: 28,
              width: 31
            },

          ]
        })
      },
      setCenter: function(position) {
        try {
          settings.google.map.setCenter(position)
        } catch(err) {
          throw err
        }
      },
      setZoom: function(zoom) {
          try {
              settings.google.map.setZoom( parseInt(zoom) )
          } catch(err) {
              throw err
          }
      },
      setBounds: function(bounds) {
        try {
          settings.google.map.fitBounds(bounds);
        } catch(err) {
          throw err
        }
      },
      getSettings: function() {
        return settings
      },
      getBounds: function() {
        return settings.google.map.getBounds()
      },
      getCenter: function() {
        return settings.google.map.getCenter()
      },
      triggerResize: function() {
        google.maps.event.trigger(settings.google.map, 'resize');
      }
    }

    if (settings.autorun === true && ($(this).length)) {
      settings.element = $(this)[0]
      fn.init()
    }

    return fn
  }
}(jQuery))

//Place markers on map
function setMarkers(data, settings) {
  for (var i = 0; i < data.length; i++) {
    entry = data[i]
    if(typeof(entry.post.coordinates) !== 'undefined') {
      var iconUrl = '/assets/images/'

      switch(entry.type) {
        case '3':
          iconUrl += 'pin-restaurant.png'
          break
        case '5':
          iconUrl += 'pin-store.png'
          break
        default:
          iconUrl = false //use default google marker
          break
      }

      var infoWindowContent = function(entry) {
        var content = (entry.post.content.length > 90) ? entry.post.content.substr(0, 90) + '...' : entry.post.content
        return $('<div>', {
          class: 'infowindow-content'
        })
        .html(content)
      }

      var entryContent = $('<div>')
      .append(
        $('<div>', {
          id: 'infowindow-' + entry._id,
          class: 'infowindow-container'
        })
        .append(
          $('<div>', {
            class: 'infowindow-header'
          })
          .append(
            $('<div>', {
              class: 'infowindow-image'
            })
            .append(
              $('<img>', {
                src: '/uploads/' + entry.post.cover.filename + '.jpg'
              })
            ),
            $('<div>', {
              class: 'infowindow-title'
            })
            .append(
              $('<a>', {
                href: entry.url
              })
              .html(entry.title)
            ),
            $('<div>', {
              class: 'infowindow-stars-container'
            })
            .append(
              $('<div>', {
                class: 'stars'
              })
              .append(
                $.map(new Array(5), function(value, i) {
                  return $('<div>', {
                    class: ('rating' in entry && 'votes_sum' in entry.rating && (i + 1) <= entry.rating.votes_sum) ? 'star active' : 'star'
                  }).append(
                    $('<span>', {
                      class: 'glyphicon glyphicon-star'
                    })
                  )
                })
              )
            )
          ),
          infoWindowContent(entry)
        )
      )

      mapInstance.setMarker({
        position: {
          lat: parseFloat(entry.post.coordinates.latitude),
          lng: parseFloat(entry.post.coordinates.longitude)
        },
        title: entry.title,
        content: entryContent.html(),
        icon: {
          url: iconUrl,
          size: new google.maps.Size(32, 32)
        }
      })
    } else {
      console.log(entry.title + ' has no coordinates!')
    }
  }
  if(typeof(settings) !== 'undefined' && settings.hasOwnProperty('cluster')) {
    if(settings.cluster === true) {
      mapInstance.clusterMarkers()
    }
  }
}

function zoomToUserLocation() {
  $.fn.geoLocation(function(result) {
    if (result.success === true) {
      mapInstance.setMarker({
        position: {
          lat: parseFloat(result.position.latitude),
          lng: parseFloat(result.position.longitude)
        },
        title: 'Din plats',
        content: 'Du är här!',
        icon: '/assets/images/pin-my-position.png'
      })
      mapInstance.setCenter({
        lat: parseFloat(result.position.latitude),
        lng: parseFloat(result.position.longitude)
      })
      mapInstance.setZoom(11)
    } else {
      //TODO display error
    }
  })
}

function getMarkerData(options, callback) {
  var settings = $.extend({
    url: '/ajax/map'
  }, options)

  $.ajax(settings)
  .done(function(data) {
    callback(data)
  })
}

function getMapOptions(element) {
  var options = {}
  var mapData = $('#map').data()

  //Check if map is configured to auto initialize
  if(mapData.hasOwnProperty('mapInit')) {
    options.init = mapData.mapInit
  }

  if(mapData.hasOwnProperty('mapCluster')) {
    options.cluster = mapData.mapCluster
  }

  if(mapData.hasOwnProperty('mapFilter')) {
    var filters = {
      single: function() {
        return {
          id: $('.content')[0].id
        }
      },
      restaurant: function() {
        return {
          type: '3'
        }
      },
      butik: function() {
        return {
          type: '5'
        }
      }
    }

    if(mapData.mapFilter in filters) {
      options.data = {
        filter: filters[mapData.mapFilter](),
        filterName: mapData.mapFilter
      }
    }
  }

  if(mapData.hasOwnProperty('markerLatitude')) {
    options.markerLatitude = mapData.markerLatitude
  }

  if(mapData.hasOwnProperty('markerLongitude')) {
    options.markerLongitude = mapData.markerLongitude
  }

  if(mapData.hasOwnProperty('markerTitle')) {
    options.markerTitle = mapData.markerTitle
  }

  return options
}

function applyMarkerData(data, options) {
  if(options.hasOwnProperty('data')) {
    if(options.data.filterName === 'single') {
      if(data.length > 0 && data[0].post.hasOwnProperty('coordinates')) {
        mapInstance.setCenter({
          lat: parseFloat(data[0].post.coordinates.latitude),
          lng: parseFloat(data[0].post.coordinates.longitude)
        })

        mapInstance.setZoom(11)
      } else {
        return
      }
    }
  }

  setMarkers(data, options)
}

function setSingleOpenMarker(obj) {
  mapInstance.setMarker({
    position: {
      lat: parseFloat(obj.coordinates.latitude),
      lng: parseFloat(obj.coordinates.longitude)
    },
    content: obj.content
  })

  mapInstance.setZoom(11)

  mapInstance.setCenter({
    lat: parseFloat(obj.coordinates.latitude),
    lng: parseFloat(obj.coordinates.longitude)
  })

  settings = mapInstance.getSettings()
  marker = settings.google.markers[0]
  marker.infowindow.open(settings.google.map, marker)
}

function fullscreenSupported() {
  return (document.fullscreenEnabled ||
    document.webkitFullscreenEnabled ||
    document.mozFullScreenEnabled ||
    document.msFullscreenEnabled
  )
}

function isFullscreen() {
  return ( document.fullscreenElement ||
    document.webkitFullscreenElement ||
    document.mozFullScreenElement ||
    document.msFullscreenElement ) ? true : false
}

function enterFullscreen(element) {
  if (element.requestFullscreen) {
    element.requestFullscreen()
  } else if (element.webkitRequestFullscreen) {
    element.webkitRequestFullscreen()
  } else if (element.mozRequestFullScreen) {
    element.mozRequestFullScreen()
  } else if (element.msRequestFullscreen) {
    element.msRequestFullscreen()
  }
}

function exitFullscreen() {
  if (document.exitFullscreen) {
    document.exitFullscreen();
  } else if (document.webkitExitFullscreen) {
    document.webkitExitFullscreen();
  } else if (document.mozCancelFullScreen) {
    document.mozCancelFullScreen();
  } else if (document.msExitFullscreen) {
    document.msExitFullscreen();
  }
}

$(document).bind('mapready', function(e) {
  //Initialize map
  mapInstance = $('#map').googleMap()

  $('#show-map').on('click', function(e) {
    e.preventDefault()

    $('.filter').addClass('hidden') //Remove overlay filter

    //Get map options
    var options = getMapOptions()

    //Get marker data
    getMarkerData(options, function(data) {
      applyMarkerData(data, options)
    })
  })

  $('.showMyLocation').on('click', function(e) {
    e.preventDefault()
    zoomToUserLocation()
  })

  $('.showFullscreen').on('click', function(e) {
    e.preventDefault()
    if( fullscreenSupported() ) {
      var element = document.getElementById('mapContainer')

      if( isFullscreen() ) {
        exitFullscreen()
        $(element).css({
          margin: '',
          width: '',
          height: '',
          position: '',
          top: ''
        })
        return
      }

      var data = $('#map').data()
      data.center = mapInstance.getCenter()

      enterFullscreen( element )

      $(document).on('webkitfullscreenchange mozfullscreenchange fullscreenchange', function(e) {
        if( isFullscreen() ) {
          $(element).css({
            margin: '0',
            width: '100%',
            height: '100%',
            position: 'absolute',
            top: '0'
          })
        } else {
          $(element).css({
            margin: '',
            width: '',
            height: '',
            position: '',
            top: ''
          })
        }

        mapInstance.triggerResize()
        mapInstance.setCenter( data.center )
      })
    } else {
      console.log('no fullscreen support')
      //TODO notify user
    }
  })

  if($('#map').length > 0) {
    var options = getMapOptions()

    if('init' in options && options.init === true) {
      if('markerLatitude' in options && 'markerLongitude' in options) {
        //Map provides it's own coordinates

        setSingleOpenMarker({
          coordinates: {
            latitude: options.markerLatitude,
            longitude: options.markerLongitude
          },
          content: options.markerTitle
        })

      } else {
        getMarkerData(options, function(data) {
          applyMarkerData(data, options)
        })
      }

      $('.filter').addClass('visible-xs') //Remove overlay filter
    }
  }
})
<|endoftext|>


<commit_before>'use strict';

/* global Connector, Util */

Connector.playerSelector = '.tradiio-music-player';

Connector.artistSelector = '.tradiio-music-player a.artist';

Connector.playButtonSelector = '.tradiio-music-player .section-controls .btn-play';

Connector.currentTimeSelector = '.tradiio-music-player .s-progress';

Connector.durationSelector = '.tradiio-music-player .s-total';

Connector.trackArtImageSelector = 'div.bgimge';

Connector.getTrack = function() {
	var songInfo = getSongInfo();
	return songInfo[INFO_TRACK];
};

Connector.getAlbum = function() {
	var songInfo = getSongInfo();
	return songInfo[INFO_ALBUM];
};

var INFO_ALBUM = 'album';
var INFO_TRACK = 'track';

var getSongInfo = function() {
	var album_track = $('.tradiio-music-player .musicname').text();
	if (album_track === null) {
		return null;
	}

	var separator = Util.findSeparator(album_track);

	var album = null;
	var track = null;

	if (separator !== null) {
		album = album_track.substr(0, separator.index);
		track = album_track.substr(separator.index + separator.length);
	} else {
		track = album_track;
	}

	return {album: album, track: track};
};
<commit_msg>Tradiio: Don't use function expression<commit_after>'use strict';

/* global Connector, Util */

Connector.playerSelector = '.tradiio-music-player';

Connector.artistSelector = '.tradiio-music-player a.artist';

Connector.playButtonSelector = '.tradiio-music-player .section-controls .btn-play';

Connector.currentTimeSelector = '.tradiio-music-player .s-progress';

Connector.durationSelector = '.tradiio-music-player .s-total';

Connector.trackArtImageSelector = 'div.bgimge';

Connector.getTrack = function() {
	var songInfo = getSongInfo();
	return songInfo[INFO_TRACK];
};

Connector.getAlbum = function() {
	var songInfo = getSongInfo();
	return songInfo[INFO_ALBUM];
};

var INFO_ALBUM = 'album';
var INFO_TRACK = 'track';

function getSongInfo() {
	var albumTrack = $('.tradiio-music-player .musicname').text();
	if (albumTrack === null) {
		return null;
	}

	var separator = Util.findSeparator(albumTrack);

	var album = null;
	var track = null;

	if (separator !== null) {
		album = albumTrack.substr(0, separator.index);
		track = albumTrack.substr(separator.index + separator.length);
	} else {
		track = albumTrack;
	}

	return { album, track };
}
<|endoftext|>


<commit_before>module.exports = {
  parserOptions: {
    ecmaVersion: 6,
    sourceType: 'module'
  },
  env: {
    'browser': true
  },
  plugins: [
    'ember-bpr-lint'
  ],
  rules: {
    // Custom rules
    'ember-bpr-lint/no-side-effect-cp': 2,
    'ember-bpr-lint/no-attrs': 2,
    'ember-bpr-lint/no-observers': 2
  }
};
<commit_msg>Fixing broken recommended.js<commit_after>module.exports = {
  parserOptions: {
    ecmaVersion: 6,
    sourceType: 'module'
  },
  env: {
    'browser': true
  },
  plugins: [
    'ember-bpr-lint'
  ],
  rules: {
    // Custom rules
    'ember-bpr-lint/no-timers': 2,
    'ember-bpr-lint/no-unguarded-document': 2,
    'ember-bpr-lint/no-unguarded-window': 2
  }
};
<|endoftext|>