<commit_before>"use strict";

var CityTour = CityTour || {};

CityTour.HydraulicErosionGenerator = (function() {
  var RAINDROP_COUNT = 10000;
  var WATER_HEIGHT_PER_RAINDROP = 1.0;
  var EVAPORATION_WATER_HEIGHT = 2.5;

  var addRainfall = function(terrainCoordinates) {
    var i;
    var maxColumnIndex = terrainCoordinates.length - 1;
    var maxRowIndex = terrainCoordinates[0].length - 1;
    var column, row;

    for (i = 0; i < RAINDROP_COUNT; i++) {
      column = Math.round(Math.random() * maxColumnIndex);
      row = Math.round(Math.random() * maxRowIndex);

      terrainCoordinates[column][row].waterHeight += WATER_HEIGHT_PER_RAINDROP;
    }
  };

  var emptyWaterFlowCoordinates = function(terrainCoordinates) {
    var x, z;
    var waterFlowCoordinates = [];

    for (x = 0; x < terrainCoordinates.length; x++) {
      waterFlowCoordinates[x] = [];

      for (z = 0; z < terrainCoordinates[0].length; z++) {
        waterFlowCoordinates[x][z] = { landDelta: 0.0, waterDelta: 0.0 };
      }
    }

    return waterFlowCoordinates;
  };

  var erode = function(terrainCoordinates, iterationCount) {
    var waterFlowCoordinates;
    var northHeight, southHeight, westHeight, eastHeight, southWestHeight, northEastHeight;
    var currentLandHeight, currentHeight, minTargetHeight;
    var maxLandDelta, maxWaterDelta;
    var i, x, z;

    var columnCount = terrainCoordinates.length;
    var rowCount = terrainCoordinates[0].length;

    for (i = 0; i < iterationCount; i++) {
      waterFlowCoordinates = emptyWaterFlowCoordinates(terrainCoordinates);

      for (x = 0; x < columnCount; x++) {
        for (z = 0; z < rowCount; z++) {
          currentLandHeight = terrainCoordinates[x][z].height;
          currentHeight = currentLandHeight + terrainCoordinates[x][z].waterHeight;

          // North
          if (z > 0) {
            northHeight = terrainCoordinates[x][z - 1].height + terrainCoordinates[x][z - 1].waterHeight;
          }
          else {
            northHeight = Number.POSITIVE_INFINITY;
          }

          // South
          if (z < terrainCoordinates[0].length - 1) {
            southHeight = terrainCoordinates[x][z + 1].height + terrainCoordinates[x][z + 1].waterHeight;
          }
          else {
            southHeight = Number.POSITIVE_INFINITY;
          }

          // West
          if (x > 0) {
            westHeight = terrainCoordinates[x - 1][z].height + terrainCoordinates[x - 1][z].waterHeight;
          }
          else {
            westHeight = Number.POSITIVE_INFINITY;
          }

          // East
          if (x < terrainCoordinates.length - 1) {
            eastHeight = terrainCoordinates[x + 1][z].height + terrainCoordinates[x + 1][z].waterHeight;
          }
          else {
            eastHeight = Number.POSITIVE_INFINITY;
          }

          // Southwest
          if (x > 0 && z < (terrainCoordinates[0].length - 1)) {
            southWestHeight = terrainCoordinates[x - 1][z + 1].height + terrainCoordinates[x - 1][z + 1].waterHeight;
          }
          else {
            southWestHeight = Number.POSITIVE_INFINITY;
          }

          // Northeast
          if (x < (terrainCoordinates.length - 1) && z > 0) {
            northEastHeight = terrainCoordinates[x + 1][z - 1].height + terrainCoordinates[x + 1][z - 1].waterHeight;
          }
          else {
            northEastHeight = Number.POSITIVE_INFINITY;
          }

          minTargetHeight = Math.min(northHeight, southHeight, westHeight, eastHeight, southWestHeight, northEastHeight);

          if (currentHeight > minTargetHeight && terrainCoordinates[x][z].waterHeight > 0.0) {
            maxWaterDelta = (currentHeight - minTargetHeight) / 2;

            if (northHeight === minTargetHeight) {
              maxLandDelta = (currentLandHeight - terrainCoordinates[x][z - 1].height) / 2;
              if (maxLandDelta > 0.0) {
                waterFlowCoordinates[x][z - 1].landDelta += Math.min(1.0, maxLandDelta);
              }
              waterFlowCoordinates[x][z - 1].waterDelta += Math.min(maxWaterDelta, terrainCoordinates[x][z].waterHeight);
            }
            else if (southHeight === minTargetHeight) {
              maxLandDelta = (currentLandHeight - terrainCoordinates[x][z + 1].height) / 2;
              if (maxLandDelta > 0.0) {
                waterFlowCoordinates[x][z + 1].landDelta += Math.min(1.0, maxLandDelta);
              }
              waterFlowCoordinates[x][z + 1].waterDelta += Math.min(maxWaterDelta, terrainCoordinates[x][z].waterHeight);
            }
            else if (westHeight === minTargetHeight) {
              maxLandDelta = (currentLandHeight - terrainCoordinates[x - 1][z].height) / 2;
              if (maxLandDelta > 0.0) {
                waterFlowCoordinates[x - 1][z].landDelta += Math.min(1.0, maxLandDelta);
              }
              waterFlowCoordinates[x - 1][z].waterDelta += Math.min(maxWaterDelta, terrainCoordinates[x][z].waterHeight);
            }
            else if (eastHeight === minTargetHeight) {
              maxLandDelta = (currentLandHeight - terrainCoordinates[x + 1][z].height) / 2;
              if (maxLandDelta > 0.0) {
                waterFlowCoordinates[x + 1][z].landDelta += Math.min(1.0, maxLandDelta);
              }
              waterFlowCoordinates[x + 1][z].waterDelta += Math.min(maxWaterDelta, terrainCoordinates[x][z].waterHeight);
            }
            else if (southWestHeight === minTargetHeight) {
              maxLandDelta = (currentLandHeight - terrainCoordinates[x - 1][z + 1].height) / 2;
              if (maxLandDelta > 0.0) {
                waterFlowCoordinates[x - 1][z + 1].landDelta += Math.min(1.0, maxLandDelta);
              }
              waterFlowCoordinates[x - 1][z + 1].waterDelta += Math.min(maxWaterDelta, terrainCoordinates[x][z].waterHeight);
            }
            else if (northEastHeight === minTargetHeight) {
              maxLandDelta = (currentLandHeight - terrainCoordinates[x + 1][z - 1].height) / 2;
              if (maxLandDelta > 0.0) {
                waterFlowCoordinates[x + 1][z - 1].landDelta += Math.min(1.0, maxLandDelta);
              }
              waterFlowCoordinates[x + 1][z - 1].waterDelta += Math.min(maxWaterDelta, terrainCoordinates[x][z].waterHeight);
            }

            if (maxLandDelta > 0.0) {
              waterFlowCoordinates[x][z].landDelta -= Math.min(1.0, maxLandDelta);
            }
            waterFlowCoordinates[x][z].waterDelta -= Math.min(maxWaterDelta, terrainCoordinates[x][z].waterHeight);
          }
        }
      }

      for (x = 0; x < columnCount; x++) {
        for (z = 0; z < rowCount; z++) {
          terrainCoordinates[x][z].height += waterFlowCoordinates[x][z].landDelta;
          terrainCoordinates[x][z].waterHeight += waterFlowCoordinates[x][z].waterDelta;
        }
      }
    }
  };

  var evaporate = function(terrainCoordinates) {
    var x, z;

    for (x = 0; x < terrainCoordinates.length; x++) {
      for (z = 0; z < terrainCoordinates[0].length; z++) {
        terrainCoordinates[x][z].waterHeight = Math.max(terrainCoordinates[x][z].waterHeight - EVAPORATION_WATER_HEIGHT, 0.0);
      }
    }
  };

  return {
    addRainfall: addRainfall,
    evaporate: evaporate,
    erode: erode,
  };
})();
<commit_msg>Improving implementation of hydraulic erosion core code<commit_after>"use strict";

var CityTour = CityTour || {};

CityTour.HydraulicErosionGenerator = (function() {
  var RAINDROP_COUNT = 10000;
  var WATER_HEIGHT_PER_RAINDROP = 1.0;
  var EVAPORATION_WATER_HEIGHT = 2.5;

  var addRainfall = function(terrainCoordinates) {
    var i;
    var maxColumnIndex = terrainCoordinates.length - 1;
    var maxRowIndex = terrainCoordinates[0].length - 1;
    var column, row;

    for (i = 0; i < RAINDROP_COUNT; i++) {
      column = Math.round(Math.random() * maxColumnIndex);
      row = Math.round(Math.random() * maxRowIndex);

      terrainCoordinates[column][row].waterHeight += WATER_HEIGHT_PER_RAINDROP;
    }
  };

  var emptyWaterFlowCoordinates = function(terrainCoordinates) {
    var x, z;
    var waterFlowCoordinates = [];

    for (x = 0; x < terrainCoordinates.length; x++) {
      waterFlowCoordinates[x] = [];

      for (z = 0; z < terrainCoordinates[0].length; z++) {
        waterFlowCoordinates[x][z] = { landDelta: 0.0, waterDelta: 0.0 };
      }
    }

    return waterFlowCoordinates;
  };

  var erode = function(terrainCoordinates, iterationCount) {
    var waterFlowCoordinates;
    var northHeight, southHeight, westHeight, eastHeight, southWestHeight, northEastHeight;
    var currentLandHeight, currentHeight, minTargetHeight;
    var minTargetX, minTargetZ;
    var landDelta, waterDelta, maxLandDelta, maxWaterDelta;
    var i, x, z;

    var columnCount = terrainCoordinates.length;
    var rowCount = terrainCoordinates[0].length;

    for (i = 0; i < iterationCount; i++) {
      waterFlowCoordinates = emptyWaterFlowCoordinates(terrainCoordinates);

      for (x = 0; x < columnCount; x++) {
        for (z = 0; z < rowCount; z++) {
          currentLandHeight = terrainCoordinates[x][z].height;
          currentHeight = currentLandHeight + terrainCoordinates[x][z].waterHeight;
          minTargetHeight = Number.POSITIVE_INFINITY;

          // North
          if (z > 0) {
            northHeight = terrainCoordinates[x][z - 1].height + terrainCoordinates[x][z - 1].waterHeight;
            if (northHeight < minTargetHeight) {
              minTargetHeight = northHeight;
              minTargetX = x;
              minTargetZ = z - 1;
            }
          }

          // South
          if (z < terrainCoordinates[0].length - 1) {
            southHeight = terrainCoordinates[x][z + 1].height + terrainCoordinates[x][z + 1].waterHeight;
            if (southHeight < minTargetHeight) {
              minTargetHeight = southHeight;
              minTargetX = x;
              minTargetZ = z + 1;
            }
          }

          // West
          if (x > 0) {
            westHeight = terrainCoordinates[x - 1][z].height + terrainCoordinates[x - 1][z].waterHeight;
            if (westHeight < minTargetHeight) {
              minTargetHeight = westHeight;
              minTargetX = x - 1;
              minTargetZ = z;
            }
          }

          // East
          if (x < terrainCoordinates.length - 1) {
            eastHeight = terrainCoordinates[x + 1][z].height + terrainCoordinates[x + 1][z].waterHeight;
            if (eastHeight < minTargetHeight) {
              minTargetHeight = eastHeight;
              minTargetX = x + 1;
              minTargetZ = z;
            }
          }

          // Southwest
          if (x > 0 && z < (terrainCoordinates[0].length - 1)) {
            southWestHeight = terrainCoordinates[x - 1][z + 1].height + terrainCoordinates[x - 1][z + 1].waterHeight;
            if (southWestHeight < minTargetHeight) {
              minTargetHeight = southWestHeight;
              minTargetX = x - 1;
              minTargetZ = z + 1;
            }
          }

          // Northeast
          if (x < (terrainCoordinates.length - 1) && z > 0) {
            northEastHeight = terrainCoordinates[x + 1][z - 1].height + terrainCoordinates[x + 1][z - 1].waterHeight;
            if (northEastHeight < minTargetHeight) {
              minTargetHeight = northEastHeight;
              minTargetX = x + 1;
              minTargetZ = z - 1;
            }
          }

          if (currentHeight > minTargetHeight && terrainCoordinates[x][z].waterHeight > 0.0) {
            maxLandDelta = (currentLandHeight - terrainCoordinates[minTargetX][minTargetZ].height) / 2;
            landDelta = (maxLandDelta > 0.0) ? Math.min(1.0, maxLandDelta) : 0.0;

            maxWaterDelta = (currentHeight - minTargetHeight) / 2;
            waterDelta = Math.min(maxWaterDelta, terrainCoordinates[x][z].waterHeight);

            waterFlowCoordinates[x][z].landDelta -= landDelta;
            waterFlowCoordinates[x][z].waterDelta -= waterDelta;

            waterFlowCoordinates[minTargetX][minTargetZ].landDelta += landDelta;
            waterFlowCoordinates[minTargetX][minTargetZ].waterDelta += waterDelta;
          }
        }
      }

      for (x = 0; x < columnCount; x++) {
        for (z = 0; z < rowCount; z++) {
          terrainCoordinates[x][z].height += waterFlowCoordinates[x][z].landDelta;
          terrainCoordinates[x][z].waterHeight += waterFlowCoordinates[x][z].waterDelta;
        }
      }
    }
  };

  var evaporate = function(terrainCoordinates) {
    var x, z;

    for (x = 0; x < terrainCoordinates.length; x++) {
      for (z = 0; z < terrainCoordinates[0].length; z++) {
        terrainCoordinates[x][z].waterHeight = Math.max(terrainCoordinates[x][z].waterHeight - EVAPORATION_WATER_HEIGHT, 0.0);
      }
    }
  };

  return {
    addRainfall: addRainfall,
    evaporate: evaporate,
    erode: erode,
  };
})();
<|endoftext|>


<commit_before>/**
 * @author Kuitos
 * @homepage https://github.com/kuitos/
 * @since 2016-09-09
 */
import { getRequestCredential, removeRequestCredential, setRequestCredential } from '../credentials';
import { CREDENTIAL_KEY_MAPPER, Date, REQUEST_TOKEN_HEADER, REQUEST_WHITE_LIST, USER_SESSION_AVAILABLE_TIME } from './metadata';

let needToRefreshToken = false;

export let execAuthFailure = function() {};
export function setAuthFailedBehavior(fn = execAuthFailure) {

	execAuthFailure = rejection => {

		try {
			fn();
		} finally {
			removeRequestCredential();
		}

		const ex = new TypeError('Unauthorized! Credential was expired or had been removed, pls set it before the get action!');
		console.error(ex);

		if (typeof rejection.abort === 'function') {
			rejection.abort(ex);
		} else {
			rejection.status = rejection.status || 401;
			rejection.statusText = rejection.statusText || 'Unauthorized!';
			const injector = require('angular-es-utils/injector').default;
			return injector.get('$q').reject(rejection);
		}

	};
}

export let refreshTokenUrl = '';
export function setRefreshTokenUrl(url) {
	refreshTokenUrl = url;
	REQUEST_WHITE_LIST.push(url);
}

export default {

	request(config) {

		const credential = getRequestCredential();
		const { accessToken, refreshToken, expireTime } = CREDENTIAL_KEY_MAPPER;
		// storage 里的状态有可能已经失效
		if (!credential) {
			return execAuthFailure({config});
		}

		config.headers[REQUEST_TOKEN_HEADER] = credential[accessToken];

		// 白名单之外的url做校验
		// TODO 兼容处理,如果拿不到refreshToken说明系统还未升级,则不做刷新token逻辑
		if (credential[refreshToken] && REQUEST_WHITE_LIST.indexOf(config.url) === -1) {

			const expireDateTime = Date.parse(credential[expireTime]);
			const now = Date.now();

			// token失效则直接跳转登录页面
			// token未失效但是可用时长已低于用户会话最短保留时间,则需要刷新token
			if (USER_SESSION_AVAILABLE_TIME >= expireDateTime - now && expireDateTime - now >= 0) {
				needToRefreshToken = true;
			} else if (expireDateTime - now < 0) { // token失效
				return execAuthFailure({config});
			}
		}

		return config;
	},

	response(response) {

		// 如果请求能正常响应,说明 storage 里的状态是存在的,所以这里不做判断
		const credential = getRequestCredential();
		const { accessToken, refreshToken } = CREDENTIAL_KEY_MAPPER;

		const injector = require('angular-es-utils/injector').default;
		const $http = injector.get('$http');
		// 所有请求结束了才做refreshToken的操作,避免后端因为token被刷新而导致前一请求失败
		if (needToRefreshToken && $http.pendingRequests.length === 0) {

			needToRefreshToken = false;
			// refresh token
			$http.put(refreshTokenUrl, credential[refreshToken], { headers: { [REQUEST_TOKEN_HEADER]: credential[accessToken] } })
				.then(response => {
					// 更新localStorage中token信息
					setRequestCredential(response.data);
				}, execAuthFailure);
		}

		return response;
	}

};
<commit_msg>catch unhandled exception<commit_after>/**
 * @author Kuitos
 * @homepage https://github.com/kuitos/
 * @since 2016-09-09
 */
import { getRequestCredential, removeRequestCredential, setRequestCredential } from '../credentials';
import { CREDENTIAL_KEY_MAPPER, Date, REQUEST_TOKEN_HEADER, REQUEST_WHITE_LIST, USER_SESSION_AVAILABLE_TIME } from './metadata';

let needToRefreshToken = false;

export let execAuthFailure = function() {};
export function setAuthFailedBehavior(fn = execAuthFailure) {

	execAuthFailure = rejection => {

		try {
			fn();
		} finally {
			removeRequestCredential();
		}

		const ex = new TypeError('Unauthorized! Credential was expired or had been removed, pls set it before the get action!');
		console.error(ex);

		// 兼容 jquery 处理
		if (typeof rejection.abort === 'function') {
			rejection.abort(ex);
		} else {
			rejection.status = rejection.status || 401;
			rejection.statusText = rejection.statusText || 'Unauthorized!';
			const injector = require('angular-es-utils/injector').default;
			return injector.get('$q').reject(rejection);
		}

	};
}

export let refreshTokenUrl = '';
export function setRefreshTokenUrl(url) {
	refreshTokenUrl = url;
	REQUEST_WHITE_LIST.push(url);
}

export default {

	request(config) {

		const credential = getRequestCredential();
		const { accessToken, refreshToken, expireTime } = CREDENTIAL_KEY_MAPPER;
		// storage 里的状态有可能已经失效
		if (!credential) {
			return execAuthFailure({config});
		}

		config.headers[REQUEST_TOKEN_HEADER] = credential[accessToken];

		// 白名单之外的url做校验
		// TODO 兼容处理,如果拿不到refreshToken说明系统还未升级,则不做刷新token逻辑
		if (credential[refreshToken] && REQUEST_WHITE_LIST.indexOf(config.url) === -1) {

			const expireDateTime = Date.parse(credential[expireTime]);
			const now = Date.now();

			// token失效则直接跳转登录页面
			// token未失效但是可用时长已低于用户会话最短保留时间,则需要刷新token
			if (USER_SESSION_AVAILABLE_TIME >= expireDateTime - now && expireDateTime - now >= 0) {
				needToRefreshToken = true;
			} else if (expireDateTime - now < 0) { // token失效
				return execAuthFailure({config});
			}
		}

		return config;
	},

	response(response) {

		// 如果请求能正常响应,说明 storage 里的状态是存在的,所以这里不做判断
		const credential = getRequestCredential();
		const { accessToken, refreshToken } = CREDENTIAL_KEY_MAPPER;

		const injector = require('angular-es-utils/injector').default;
		const $http = injector.get('$http');
		// 所有请求结束了才做refreshToken的操作,避免后端因为token被刷新而导致前一请求失败
		if (needToRefreshToken && $http.pendingRequests.length === 0) {

			needToRefreshToken = false;
			// refresh token
			$http.put(refreshTokenUrl, credential[refreshToken], { headers: { [REQUEST_TOKEN_HEADER]: credential[accessToken] } })
				.then(response => {
					// 更新localStorage中token信息
					setRequestCredential(response.data);
				}, execAuthFailure).catch(rejection => console.error(rejection));
		}

		return response;
	}

};
<|endoftext|>


<commit_before>// Edit from https://github.com/zalmoxisus/remote-redux-devtools/blob/master/src/devTools.js

import instrument from 'redux-devtools-instrument';
import {
  evalAction,
  getActionsArray,
  generateId,
  stringify,
  getSeralizeParameter,
} from 'remotedev-utils';
import importState from 'remotedev-utils/lib/importState';
import {
  getLocalFilter,
  isFiltered,
  filterStagedActions,
  filterState,
} from 'remotedev-utils/lib/filters';

function configureStore(next, subscriber, options) {
  return instrument(subscriber, options)(next);
}

const instances = { /* [id]: { name, store, ... } */ };

let lastAction;
let isExcess;
let listenerAdded;
let locked;
let paused;

function getLiftedState(store, filters) {
  return filterStagedActions(store.liftedStore.getState(), filters);
}

function relay(type, state, instance, action, nextActionId) {
  const {
    filters, predicate,
    stateSanitizer, actionSanitizer,
    serializeState, serializeAction,
  } = instance;

  const message = {
    type,
    id: instance.id,
    name: instance.name,
  };
  if (state) {
    message.payload = type === 'ERROR' ?
      state :
      stringify(
        filterState(state, type, filters, stateSanitizer, actionSanitizer, nextActionId, predicate),
        serializeState
      );
  }
  if (type === 'ACTION') {
    message.action = stringify(
      !actionSanitizer ? action : actionSanitizer(action.action, nextActionId - 1),
      serializeAction
    );
    message.isExcess = isExcess;
    message.nextActionId = nextActionId;
  } else if (instance) {
    message.libConfig = {
      type: 'redux',
      actionCreators: stringify(instance.actionCreators),
      serialize: !!instance.serialize,
    };
  }
  postMessage({ __IS_REDUX_NATIVE_MESSAGE__: true, content: message });
}

function dispatchRemotely(action, instance) {
  try {
    const { store, actionCreators } = instance;
    const result = evalAction(action, actionCreators);
    store.dispatch(result);
  } catch (e) {
    relay('ERROR', e.message, instance);
  }
}

function importPayloadFrom(store, state, instance) {
  try {
    const nextLiftedState = importState(state, instance);
    if (!nextLiftedState) return;
    store.liftedStore.dispatch({ type: 'IMPORT_STATE', ...nextLiftedState });
    relay('STATE', getLiftedState(store, instance.filters), instance);
  } catch (e) {
    relay('ERROR', e.message, instance);
  }
}

function exportState({ id: instanceId, store, serializeState }) {
  const liftedState = store.liftedStore.getState();
  const actionsById = liftedState.actionsById;
  const payload = [];
  liftedState.stagedActionIds.slice(1).forEach(id => {
    payload.push(actionsById[id].action);
  });
  postMessage({
    __IS_REDUX_NATIVE_MESSAGE__: true,
    content: {
      type: 'EXPORT',
      payload: stringify(payload, serializeState),
      committedState:
        typeof liftedState.committedState !== 'undefined' ?
          stringify(liftedState.committedState, serializeState) :
          undefined,
      instanceId,
    },
  });
}

function handleMessages(message) {
  const { id, instanceId, type, action, state, toAll } = message;
  if (toAll) {
    Object.keys(instances).forEach(key => {
      handleMessages({ ...message, id: key, toAll: false });
    });
    return;
  }

  const instance = instances[id || instanceId];
  const { store, filters } = instance;
  if (!store) return;

  switch (type) {
    case 'DISPATCH':
      store.liftedStore.dispatch(action);
      return;
    case 'ACTION':
      dispatchRemotely(action, instance);
      return;
    case 'IMPORT':
      importPayloadFrom(store, state, instance);
      return;
    case 'EXPORT':
      exportState(instance);
      return;
    case 'UPDATE':
      relay('STATE', getLiftedState(store, filters), instance);
      return;
    default:
      return;
  }
}

function start(instance) {
  if (!listenerAdded) {
    self.addEventListener('message', message => {
      const { method, content } = message.data;
      if (method === 'emitReduxMessage') {
        handleMessages(content);
      }
    });
    listenerAdded = true;
  }
  const { store, actionCreators, filters } = instance;
  if (typeof actionCreators === 'function') {
    instance.actionCreators = actionCreators();
  }
  relay('STATE', getLiftedState(store, filters), instance);
}

function checkForReducerErrors(liftedState, instance) {
  if (liftedState.computedStates[liftedState.currentStateIndex].error) {
    relay('STATE', filterStagedActions(liftedState, instance.filters), instance);
    return true;
  }
  return false;
}

function monitorReducer(state = {}, action) {
  lastAction = action.type;
  return state;
}

function handleChange(state, liftedState, maxAge, instance) {
  if (checkForReducerErrors(liftedState, instance)) return;

  const { filters } = instance;
  if (lastAction === 'PERFORM_ACTION') {
    const nextActionId = liftedState.nextActionId;
    const liftedAction = liftedState.actionsById[nextActionId - 1];
    if (isFiltered(liftedAction.action, filters)) return;
    relay('ACTION', state, instance, liftedAction, nextActionId);
    if (!isExcess && maxAge) isExcess = liftedState.stagedActionIds.length >= maxAge;
  } else {
    if (lastAction === 'JUMP_TO_STATE') return;
    if (lastAction === 'PAUSE_RECORDING') {
      paused = liftedState.isPaused;
    } else if (lastAction === 'LOCK_CHANGES') {
      locked = liftedState.isLocked;
    }
    if (paused || locked) {
      if (lastAction) lastAction = undefined;
      else return;
    }
    relay('STATE', filterStagedActions(liftedState, filters), instance);
  }
}

export default function devToolsEnhancer(options = {}) {
  const {
    name,
    maxAge = 30,
    shouldCatchErrors = !!global.shouldCatchErrors,
    shouldHotReload,
    shouldRecordChanges,
    shouldStartLocked,
    pauseActionType = '@@PAUSED',
    actionCreators,
    filters,
    actionsBlacklist,
    actionsWhitelist,
    actionSanitizer,
    stateSanitizer,
    deserializeState,
    deserializeAction,
    serialize,
    predicate,
  } = options;
  const id = generateId(options.instanceId);

  const serializeState = getSeralizeParameter(options, 'serializeState');
  const serializeAction = getSeralizeParameter(options, 'serializeAction');

  return next => (reducer, initialState) => {
    const store = configureStore(
      next, monitorReducer, {
        maxAge,
        shouldCatchErrors,
        shouldHotReload,
        shouldRecordChanges,
        shouldStartLocked,
        pauseActionType,
      }
    )(reducer, initialState);

    instances[id] = {
      name: name || id,
      id,
      store,
      filters: getLocalFilter({
        actionsWhitelist: (filters && filters.whitelist) || actionsWhitelist,
        actionsBlacklist: (filters && filters.blacklist) || actionsBlacklist,
      }),
      actionCreators: actionCreators && (() => getActionsArray(actionCreators)),
      stateSanitizer,
      actionSanitizer,
      deserializeState,
      deserializeAction,
      serializeState,
      serializeAction,
      serialize,
      predicate,
    };

    start(instances[id]);
    store.subscribe(() => {
      handleChange(store.getState(), store.liftedStore.getState(), maxAge, instances[id]);
    });
    return store;
  };
}

const preEnhancer = instanceId => next =>
  (reducer, initialState, enhancer) => {
    const store = next(reducer, initialState, enhancer);

    if (instances[instanceId]) {
      instances[instanceId].store = store;
    }
    return {
      ...store,
      dispatch: (action) => (
        locked ? action : store.dispatch(action)
      ),
    };
  };

devToolsEnhancer.updateStore = (newStore, instanceId) => {
  console.warn(
    '[RNDebugger]',
    '`updateStore` is deprecated use `window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__` instead:',
    'https://github.com/jhen0409/react-native-debugger#redux-devtools-and-remotedev-on-local-even-mobx'
  );

  const keys = Object.keys(instances);
  if (!keys.length) return;

  if (keys.length > 1 && !instanceId) {
    console.warn(
      'You have multiple stores,',
      'please provide `instanceId` argument (`updateStore(store, instanceId)`)'
    );
  }
  if (instanceId) {
    const instance = instances[instanceId];
    if (!instance) return;
    instance.store = newStore;
  } else {
    instances[keys[0]].store = newStore;
  }
};

const compose = options => (...funcs) => (...args) => {
  const instanceId = generateId(options.instanceId);
  return [preEnhancer(instanceId), ...funcs].reduceRight(
    (composed, f) => f(composed), devToolsEnhancer({ ...options, instanceId })(...args)
  );
};

export function composeWithDevTools(...funcs) {
  if (funcs.length === 0) {
    return devToolsEnhancer();
  }
  if (funcs.length === 1 && typeof funcs[0] === 'object') {
    return compose(funcs[0]);
  }
  return compose({})(...funcs);
}
<commit_msg>Update link for warn of deprecated `updateStore` API<commit_after>// Edit from https://github.com/zalmoxisus/remote-redux-devtools/blob/master/src/devTools.js

import instrument from 'redux-devtools-instrument';
import {
  evalAction,
  getActionsArray,
  generateId,
  stringify,
  getSeralizeParameter,
} from 'remotedev-utils';
import importState from 'remotedev-utils/lib/importState';
import {
  getLocalFilter,
  isFiltered,
  filterStagedActions,
  filterState,
} from 'remotedev-utils/lib/filters';

function configureStore(next, subscriber, options) {
  return instrument(subscriber, options)(next);
}

const instances = { /* [id]: { name, store, ... } */ };

let lastAction;
let isExcess;
let listenerAdded;
let locked;
let paused;

function getLiftedState(store, filters) {
  return filterStagedActions(store.liftedStore.getState(), filters);
}

function relay(type, state, instance, action, nextActionId) {
  const {
    filters, predicate,
    stateSanitizer, actionSanitizer,
    serializeState, serializeAction,
  } = instance;

  const message = {
    type,
    id: instance.id,
    name: instance.name,
  };
  if (state) {
    message.payload = type === 'ERROR' ?
      state :
      stringify(
        filterState(state, type, filters, stateSanitizer, actionSanitizer, nextActionId, predicate),
        serializeState
      );
  }
  if (type === 'ACTION') {
    message.action = stringify(
      !actionSanitizer ? action : actionSanitizer(action.action, nextActionId - 1),
      serializeAction
    );
    message.isExcess = isExcess;
    message.nextActionId = nextActionId;
  } else if (instance) {
    message.libConfig = {
      type: 'redux',
      actionCreators: stringify(instance.actionCreators),
      serialize: !!instance.serialize,
    };
  }
  postMessage({ __IS_REDUX_NATIVE_MESSAGE__: true, content: message });
}

function dispatchRemotely(action, instance) {
  try {
    const { store, actionCreators } = instance;
    const result = evalAction(action, actionCreators);
    store.dispatch(result);
  } catch (e) {
    relay('ERROR', e.message, instance);
  }
}

function importPayloadFrom(store, state, instance) {
  try {
    const nextLiftedState = importState(state, instance);
    if (!nextLiftedState) return;
    store.liftedStore.dispatch({ type: 'IMPORT_STATE', ...nextLiftedState });
    relay('STATE', getLiftedState(store, instance.filters), instance);
  } catch (e) {
    relay('ERROR', e.message, instance);
  }
}

function exportState({ id: instanceId, store, serializeState }) {
  const liftedState = store.liftedStore.getState();
  const actionsById = liftedState.actionsById;
  const payload = [];
  liftedState.stagedActionIds.slice(1).forEach(id => {
    payload.push(actionsById[id].action);
  });
  postMessage({
    __IS_REDUX_NATIVE_MESSAGE__: true,
    content: {
      type: 'EXPORT',
      payload: stringify(payload, serializeState),
      committedState:
        typeof liftedState.committedState !== 'undefined' ?
          stringify(liftedState.committedState, serializeState) :
          undefined,
      instanceId,
    },
  });
}

function handleMessages(message) {
  const { id, instanceId, type, action, state, toAll } = message;
  if (toAll) {
    Object.keys(instances).forEach(key => {
      handleMessages({ ...message, id: key, toAll: false });
    });
    return;
  }

  const instance = instances[id || instanceId];
  const { store, filters } = instance;
  if (!store) return;

  switch (type) {
    case 'DISPATCH':
      store.liftedStore.dispatch(action);
      return;
    case 'ACTION':
      dispatchRemotely(action, instance);
      return;
    case 'IMPORT':
      importPayloadFrom(store, state, instance);
      return;
    case 'EXPORT':
      exportState(instance);
      return;
    case 'UPDATE':
      relay('STATE', getLiftedState(store, filters), instance);
      return;
    default:
      return;
  }
}

function start(instance) {
  if (!listenerAdded) {
    self.addEventListener('message', message => {
      const { method, content } = message.data;
      if (method === 'emitReduxMessage') {
        handleMessages(content);
      }
    });
    listenerAdded = true;
  }
  const { store, actionCreators, filters } = instance;
  if (typeof actionCreators === 'function') {
    instance.actionCreators = actionCreators();
  }
  relay('STATE', getLiftedState(store, filters), instance);
}

function checkForReducerErrors(liftedState, instance) {
  if (liftedState.computedStates[liftedState.currentStateIndex].error) {
    relay('STATE', filterStagedActions(liftedState, instance.filters), instance);
    return true;
  }
  return false;
}

function monitorReducer(state = {}, action) {
  lastAction = action.type;
  return state;
}

function handleChange(state, liftedState, maxAge, instance) {
  if (checkForReducerErrors(liftedState, instance)) return;

  const { filters } = instance;
  if (lastAction === 'PERFORM_ACTION') {
    const nextActionId = liftedState.nextActionId;
    const liftedAction = liftedState.actionsById[nextActionId - 1];
    if (isFiltered(liftedAction.action, filters)) return;
    relay('ACTION', state, instance, liftedAction, nextActionId);
    if (!isExcess && maxAge) isExcess = liftedState.stagedActionIds.length >= maxAge;
  } else {
    if (lastAction === 'JUMP_TO_STATE') return;
    if (lastAction === 'PAUSE_RECORDING') {
      paused = liftedState.isPaused;
    } else if (lastAction === 'LOCK_CHANGES') {
      locked = liftedState.isLocked;
    }
    if (paused || locked) {
      if (lastAction) lastAction = undefined;
      else return;
    }
    relay('STATE', filterStagedActions(liftedState, filters), instance);
  }
}

export default function devToolsEnhancer(options = {}) {
  const {
    name,
    maxAge = 30,
    shouldCatchErrors = !!global.shouldCatchErrors,
    shouldHotReload,
    shouldRecordChanges,
    shouldStartLocked,
    pauseActionType = '@@PAUSED',
    actionCreators,
    filters,
    actionsBlacklist,
    actionsWhitelist,
    actionSanitizer,
    stateSanitizer,
    deserializeState,
    deserializeAction,
    serialize,
    predicate,
  } = options;
  const id = generateId(options.instanceId);

  const serializeState = getSeralizeParameter(options, 'serializeState');
  const serializeAction = getSeralizeParameter(options, 'serializeAction');

  return next => (reducer, initialState) => {
    const store = configureStore(
      next, monitorReducer, {
        maxAge,
        shouldCatchErrors,
        shouldHotReload,
        shouldRecordChanges,
        shouldStartLocked,
        pauseActionType,
      }
    )(reducer, initialState);

    instances[id] = {
      name: name || id,
      id,
      store,
      filters: getLocalFilter({
        actionsWhitelist: (filters && filters.whitelist) || actionsWhitelist,
        actionsBlacklist: (filters && filters.blacklist) || actionsBlacklist,
      }),
      actionCreators: actionCreators && (() => getActionsArray(actionCreators)),
      stateSanitizer,
      actionSanitizer,
      deserializeState,
      deserializeAction,
      serializeState,
      serializeAction,
      serialize,
      predicate,
    };

    start(instances[id]);
    store.subscribe(() => {
      handleChange(store.getState(), store.liftedStore.getState(), maxAge, instances[id]);
    });
    return store;
  };
}

const preEnhancer = instanceId => next =>
  (reducer, initialState, enhancer) => {
    const store = next(reducer, initialState, enhancer);

    if (instances[instanceId]) {
      instances[instanceId].store = store;
    }
    return {
      ...store,
      dispatch: (action) => (
        locked ? action : store.dispatch(action)
      ),
    };
  };

devToolsEnhancer.updateStore = (newStore, instanceId) => {
  console.warn(
    '[RNDebugger]',
    '`updateStore` is deprecated use `window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__` instead:',
    'https://github.com/jhen0409/react-native-debugger/blob/master/docs/redux-devtools-integration.md'
  );

  const keys = Object.keys(instances);
  if (!keys.length) return;

  if (keys.length > 1 && !instanceId) {
    console.warn(
      'You have multiple stores,',
      'please provide `instanceId` argument (`updateStore(store, instanceId)`)'
    );
  }
  if (instanceId) {
    const instance = instances[instanceId];
    if (!instance) return;
    instance.store = newStore;
  } else {
    instances[keys[0]].store = newStore;
  }
};

const compose = options => (...funcs) => (...args) => {
  const instanceId = generateId(options.instanceId);
  return [preEnhancer(instanceId), ...funcs].reduceRight(
    (composed, f) => f(composed), devToolsEnhancer({ ...options, instanceId })(...args)
  );
};

export function composeWithDevTools(...funcs) {
  if (funcs.length === 0) {
    return devToolsEnhancer();
  }
  if (funcs.length === 1 && typeof funcs[0] === 'object') {
    return compose(funcs[0]);
  }
  return compose({})(...funcs);
}
<|endoftext|>


<commit_before>/* jshint node: true */
/* jshint esversion: 6 */

//************************************************************
//  socketEvents.js                                         //
//  Active Learning 2110                                    //
//                                                          //
//  Created by Odell Mizrahi on 9/18/16.                    //
//  Copyright © 2016 Odell Mizrahi. All rights reserved.    //
//                                                          //
//  Date        Name        Description                     //
//  -------     ---------   --------------                  //
//  01Apr17     O. Mizrahi  Initial Design                  //
//                                                          //
//************************************************************
"use strict";

var config = require('./../config'),
    mongoose = require('mongoose'),
    Lecture = require('./../app_api_v2/models/lectureModel'),
    LiveLecture = require('./../app_api_v2/models/liveLectureModel'),
    Question = require('./../app_api_v2/models/questionModel'),
    Result = require('./../app_api_v2/models/resultModel');

exports = module.exports = function(io, winston) {
    var lectures = io.of('/lectures').on('connection', function(socket) {
        winston.info('Socket.io: Connection from: %s', socket.handshake.address);

        socket.on('lookup_lectures', function() {
            LiveLecture.find({}, {
                    lecture_id: 1
                })
                .exec()
                .then(getCurrentLiveLectures)
                .catch(function(err) {
                    return socket.emit('lectures_update', 'there seems to be a problem');
                });
        });

        socket.on('start_lecture', function(lecture_id) {
            winston.info('Socket.io: Starting Live Lecture: %s', lecture_id);

            var newLiveLecture = new LiveLecture({
                lecture_id: lecture_id,
                instructor_socket: socket.id,
            });

            Lecture.findById(lecture_id, {"course_oid": 1})
            .exec()
            .then(function(lecture) {
                var newLiveLecture = new LiveLecture({
                    lecture_id: lecture_id,
                    instructor_socket: socket.id,
                    course_oid: lecture.course_oid
                });
                return newLiveLecture.save();
            })
            .then(function(){
                return Lecture.update({_id: lecture_id}, {$set: {live: true}});
            })
            .then(function() {
                return LiveLecture.find({}, {
                    lecture_id: 1,
                    _id: 0
                });
            })
            .then(getCurrentLiveLectures)
            .catch(function(err) {
                winston.error('Socket.io: Live Lecture Error: %s, %s', lecture_id, err);
                return lectures.emit('lectures_update', 'could not add lecture');
            });

            // newLiveLecture.save()
            //     .then(function() {
            //         return Lecture.update({
            //             _id: lecture_id
            //         }, {
            //             $set: {
            //                 live: true
            //             }
            //         });
            //     })
            //     .then(function() {
            //         return LiveLecture.find({}, {
            //             lecture_id: 1,
            //             _id: 0
            //         });
            //     })
            //     .then(getCurrentLiveLectures)
            //     .catch(function(err) {
            //         winston.error('Socket.io: Live Lecture Error: %s, %s', lecture_id, err);
            //         return lectures.emit('lectures_update', 'could not add lecture');
            //     });
        });

        socket.on('stop_lecture', function() {
            clearRoom(socket.lecture_id);
        });

        socket.on('retire_lecture', function() {
            clearRoom(socket.lecture_id);
            retireLecture(socket.lecture_id);
        });

        socket.on('join_lecture', function(data) {
            LiveLecture.findOne({
                    lecture_id: data.lecture_id
                }, {
                    instructor_socket: 1,
                    current_question: 1,
                    course_oid: 1
                })
                .exec()
                .then(function(live_lecture) {
                    socket.instructor_socket = live_lecture.instructor_socket;
                    socket.course_oid = live_lecture.course_oid;
                    socket.username = data.username;
                    socket.user_id = data.user_id;
                    socket.role = data.user_role;
                    socket.lecture_id = data.lecture_id;
                    socket.join(data.lecture_id);
                    winston.info('Socket.io: Joining Live Lecture: %s, %s', socket.username, socket.lecture_id);
                    if (live_lecture.current_question) {
                        winston.info('Socket.io: Emitting Question that started to: %s', socket.username);
                        socket.emit('question_feed', live_lecture.current_question);
                    }
                    return emitUserNumer(data.lecture_id);
                }).catch(function(err) {
                    winston.error('Socket.io: join lecture error %s', err);
                });
        });

        socket.on('leave_lecture', function() {
            socket.leave(socket.lecture_id);
            emitUserNumer(socket.lecture_id);
        });

        socket.on('new_question', function(data) {
            winston.info('Socket.io: new question recieved: %j', data);
            Question.findById(data.question_id, {
                    "__v": 0,
                    "answer_choices.answer": 0
                })
                .exec()
                .then(function(question) {
                    data.question = question;
                    return LiveLecture.update({
                        lecture_id: socket.lecture_id
                    }, {
                        $set: {
                            current_question: data
                        }
                    });
                })
                .then(function(results) {
                    winston.info('Socket.io: emitting question to %s', socket.lecture_id);
                    return socket.broadcast.to(socket.lecture_id).emit('question_feed', data);
                })
                .catch(function(err) {
                    winston.error('Socket.io: Question Feed Error: %s', err);
                    return socket.emit('question_feed', 'error');
                });
        });

        socket.on('end_question', function() {
            LiveLecture.update({
                    lecture_id: socket.lecture_id
                }, {
                    $set: {
                        current_question: undefined
                    }
                })
                .exec()
                .then(function(results) {
                    winston.info('Socket.io: ending current question for %s', socket.lecture_id);
                    return socket.broadcast.to(socket.lecture_id).emit('end_question');
                });
        });

        socket.on('new_time', function(data) {
            winston.info('Socket.io: new time recieved from professor %j', data);
            LiveLecture.findOne({
                    lecture_id: socket.lecture_id
                }, {
                    current_question: 1
                })
                .exec()
                .then(function(liveLecture) {
                    var updatedQuestion = liveLecture.current_question;
                    updatedQuestion.end_time = data.time;
                    updatedQuestion.max_time = data.timeMax;
                    return LiveLecture.update({
                        lecture_id: socket.lecture_id
                    }, {
                        $set: {
                            current_question: updatedQuestion
                        }
                    });
                })
                .then(function(results) {
                    winston.info('Socket.io: new end time emiited to %s', socket.lecture_id);
                    return socket.broadcast.to(socket.lecture_id).emit('new_end', data);
                })
                .catch(function(err) {
                    winston.info('Socket.io: new end time error %s', err);
                    return socket.broadcast.to(socket.lecture_id).emit('new_end', 'error');
                });
        });

        socket.on('answer_question', function(data) {
            winston.info('Socket.io: answer recieved from %s: %j', socket.username, data.answer);
            var correct = Boolean(false);
            Question.findOne({
                    _id: data.question_id
                }, {
                    answer_choices: {
                        $elemMatch: {
                            text: data.answer
                        }
                    },
                    title: 0,
                    html_title: 0,
                    html_body: 0,
                    copied: 0,
                    tags: 0,
                    __v: 0
                })
                .exec()
                .then(function(question) {
                    if (question.answer_choices[0].answer === true) {
                        correct = Boolean(true);
                    }
                    var newResult = new Result({
                        student_id: socket.user_id,
                        course_oid: socket.course_oid,
                        lecture_id: socket.lecture_id,
                        lecture_oid: mongoose.Types.ObjectId(socket.lecture_id),
                        question_id: data.question_id,
                        question_oid: question._id,
                        answer: data.answer,
                        correct: correct
                    });
                    return newResult.save();
                })
                .then(function(result) {
                    winston.info('Socket.io: answer result for %s: %s', socket.username, result.correct);
                    socket.emit('answer_result', result.correct);
                    return socket.broadcast.to(socket.instructor_socket).emit('new_answer', result.answer);
                })
                .catch(function(err) {
                    winston.error('Socket.io: answer result error: %s', err);
                    return socket.emit('answer_result', 'error');
                });
        });

        socket.on('disconnect', function() {
            if (socket.username) {
                winston.info('Socket.io: user disconnected: %s', socket.username);
                if (socket.role === 'instructor') {
                    winston.info('Socket.io: clearing live lecture %s', socket.lecture_id);
                    clearRoom(socket.lecture_id);
                } else {
                    emitUserNumer(socket.lecture_id);
                }
            }
        });

        function emitUserNumer(lecture) {
            var users = io.nsps['/lectures'].adapter.rooms[lecture];
            if (users) {
                winston.info('Socket.io: emitting live lecture: %s, updated user total: %d', lecture, users.length);
                socket.broadcast.to(socket.instructor_socket).emit('updated_user_total', users.length);
            }
        }

        function clearRoom(lecture) {
            var roomObj = io.nsps['/lectures'].adapter.rooms[lecture];
            if (roomObj) {
                Object.keys(roomObj.sockets).forEach(function(id) {
                    lectures.sockets[id].leave(lecture);
                });
            }
            stopLecture(lecture);
        }

        function stopLecture(lecture_id) {
            winston.info('Socket.io: ending live lecture: %s', lecture_id);

            LiveLecture.remove({
                    lecture_id: lecture_id
                })
                .then(function(data) {
                    return Lecture.update({
                        _id: lecture_id
                    }, {
                        $set: {
                            live: false
                        }
                    });
                })
                .then(function(lecture) {
                    return LiveLecture.find({}, {
                        lecture_id: 1
                    });
                })
                .then(getCurrentLiveLectures)
                .catch(function(err) {
                    winston.error('Socket.io: ending live lecture error: %s', err);
                    return lectures.emit('lectures_update', 'could not add lecture');
                });
        }

        function retireLecture(lecture_id) {
            winston.info('Socket.io: retiring live lecture: %s', lecture_id);

            Lecture.update({
                    _id: lecture_id
                }, {
                    $set: {
                        live: false,
                        post_lecture: true
                    }
                })
                .then(function(lecture) {
                    socket.emit('lecture_retired');
                })
                .catch(function(err) {
                    winston.error('Socket.io: retiring live lecture error: %s', err);
                    return lectures.emit('lectures_update', 'could not add lecture');
                });
        }

        function getCurrentLiveLectures(live_lectures) {
            var current_lectures = live_lectures.map(function(lecture) {
                return lecture.lecture_id;
            });
            return lectures.emit('lectures_update', JSON.stringify(current_lectures));
        }
    });
};
<commit_msg>update<commit_after>/* jshint node: true */
/* jshint esversion: 6 */

//************************************************************
//  socketEvents.js                                         //
//  Active Learning 2110                                    //
//                                                          //
//  Created by Odell Mizrahi on 9/18/16.                    //
//  Copyright © 2016 Odell Mizrahi. All rights reserved.    //
//                                                          //
//  Date        Name        Description                     //
//  -------     ---------   --------------                  //
//  01Apr17     O. Mizrahi  Initial Design                  //
//                                                          //
//************************************************************
"use strict";

var config = require('./../config'),
    mongoose = require('mongoose'),
    Lecture = require('./../app_api_v2/models/lectureModel'),
    LiveLecture = require('./../app_api_v2/models/liveLectureModel'),
    Question = require('./../app_api_v2/models/questionModel'),
    Result = require('./../app_api_v2/models/resultModel');

exports = module.exports = function(io, winston) {
    var lectures = io.of('/lectures').on('connection', function(socket) {
        winston.info('Socket.io: Connection from: %s', socket.handshake.address);

        socket.on('lookup_lectures', function() {
            LiveLecture.find({}, {
                    lecture_id: 1
                })
                .exec()
                .then(getCurrentLiveLectures)
                .catch(function(err) {
                    return socket.emit('lectures_update', 'there seems to be a problem');
                });
        });

        socket.on('start_lecture', function(data) {
            winston.info('Socket.io: Starting Live Lecture: %s', data.lecture_id);

            console.log(data);

            // var newLiveLecture = new LiveLecture({
            //     lecture_id: lecture_id,
            //     instructor_socket: socket.id,
            // });

            // Lecture.findById(lecture_id, {"course_oid": 1})
            // .exec()
            // .then(function(lecture) {
            //     var newLiveLecture = new LiveLecture({
            //         lecture_id: lecture_id,
            //         instructor_socket: socket.id,
            //         course_oid: lecture.course_oid
            //     });
            //     return newLiveLecture.save();
            // })
            // .then(function(){
            //     return Lecture.update({_id: lecture_id}, {$set: {live: true}});
            // })
            // .then(function() {
            //     return LiveLecture.find({}, {
            //         lecture_id: 1,
            //         _id: 0
            //     });
            // })
            // .then(getCurrentLiveLectures)
            // .catch(function(err) {
            //     winston.error('Socket.io: Live Lecture Error: %s, %s', lecture_id, err);
            //     return lectures.emit('lectures_update', 'could not add lecture');
            // });

            var newLiveLecture = new LiveLecture({
                    lecture_id: data.lecture_id,
                    instructor_socket: socket.id,
                    course_oid: mongoose.Types.ObjectId(data.course_id),
              });

            newLiveLecture.save()
                .then(function() {
                    return Lecture.update(
                      {_id: data.lecture_id},
                      {$set: {live: true}});
                })
                .then(function() {
                    return LiveLecture.find({},
                      {lecture_id: 1,_id: 0}
                    );
                })
                .then(getCurrentLiveLectures)
                .catch(function(err) {
                    winston.error('Socket.io: Live Lecture Error: %s, %s', data.lecture_id, err);
                    return lectures.emit('lectures_update', 'could not add lecture');
                });
        });

        socket.on('stop_lecture', function() {
            clearRoom(socket.lecture_id);
        });

        socket.on('retire_lecture', function() {
            clearRoom(socket.lecture_id);
            retireLecture(socket.lecture_id);
        });

        socket.on('join_lecture', function(data) {
            LiveLecture.findOne({
                    lecture_id: data.lecture_id
                }, {
                    instructor_socket: 1,
                    current_question: 1,
                    course_oid: 1
                })
                .exec()
                .then(function(live_lecture) {
                    socket.instructor_socket = live_lecture.instructor_socket;
                    socket.course_oid = live_lecture.course_oid;
                    socket.username = data.username;
                    socket.user_id = data.user_id;
                    socket.role = data.user_role;
                    socket.lecture_id = data.lecture_id;
                    socket.join(data.lecture_id);
                    winston.info('Socket.io: Joining Live Lecture: %s, %s', socket.username, socket.lecture_id);
                    if (live_lecture.current_question) {
                        winston.info('Socket.io: Emitting Question that started to: %s', socket.username);
                        socket.emit('question_feed', live_lecture.current_question);
                    }
                    return emitUserNumer(data.lecture_id);
                }).catch(function(err) {
                    winston.error('Socket.io: join lecture error %s', err);
                });
        });

        socket.on('leave_lecture', function() {
            socket.leave(socket.lecture_id);
            emitUserNumer(socket.lecture_id);
        });

        socket.on('new_question', function(data) {
            winston.info('Socket.io: new question recieved: %j', data);
            Question.findById(data.question_id, {
                    "__v": 0,
                    "answer_choices.answer": 0
                })
                .exec()
                .then(function(question) {
                    data.question = question;
                    return LiveLecture.update({
                        lecture_id: socket.lecture_id
                    }, {
                        $set: {
                            current_question: data
                        }
                    });
                })
                .then(function(results) {
                    winston.info('Socket.io: emitting question to %s', socket.lecture_id);
                    return socket.broadcast.to(socket.lecture_id).emit('question_feed', data);
                })
                .catch(function(err) {
                    winston.error('Socket.io: Question Feed Error: %s', err);
                    return socket.emit('question_feed', 'error');
                });
        });

        socket.on('end_question', function() {
            LiveLecture.update({
                    lecture_id: socket.lecture_id
                }, {
                    $set: {
                        current_question: undefined
                    }
                })
                .exec()
                .then(function(results) {
                    winston.info('Socket.io: ending current question for %s', socket.lecture_id);
                    return socket.broadcast.to(socket.lecture_id).emit('end_question');
                });
        });

        socket.on('new_time', function(data) {
            winston.info('Socket.io: new time recieved from professor %j', data);
            LiveLecture.findOne({
                    lecture_id: socket.lecture_id
                }, {
                    current_question: 1
                })
                .exec()
                .then(function(liveLecture) {
                    var updatedQuestion = liveLecture.current_question;
                    updatedQuestion.end_time = data.time;
                    updatedQuestion.max_time = data.timeMax;
                    return LiveLecture.update({
                        lecture_id: socket.lecture_id
                    }, {
                        $set: {
                            current_question: updatedQuestion
                        }
                    });
                })
                .then(function(results) {
                    winston.info('Socket.io: new end time emiited to %s', socket.lecture_id);
                    return socket.broadcast.to(socket.lecture_id).emit('new_end', data);
                })
                .catch(function(err) {
                    winston.info('Socket.io: new end time error %s', err);
                    return socket.broadcast.to(socket.lecture_id).emit('new_end', 'error');
                });
        });

        socket.on('answer_question', function(data) {
            winston.info('Socket.io: answer recieved from %s: %j', socket.username, data.answer);
            var correct = Boolean(false);
            Question.findOne({
                    _id: data.question_id
                }, {
                    answer_choices: {
                        $elemMatch: {
                            text: data.answer
                        }
                    },
                    title: 0,
                    html_title: 0,
                    html_body: 0,
                    copied: 0,
                    tags: 0,
                    __v: 0
                })
                .exec()
                .then(function(question) {
                    if (question.answer_choices[0].answer === true) {
                        correct = Boolean(true);
                    }
                    var newResult = new Result({
                        student_id: socket.user_id,
                        course_oid: socket.course_oid,
                        lecture_id: socket.lecture_id,
                        lecture_oid: mongoose.Types.ObjectId(socket.lecture_id),
                        question_id: data.question_id,
                        question_oid: question._id,
                        answer: data.answer,
                        correct: correct
                    });
                    return newResult.save();
                })
                .then(function(result) {
                    winston.info('Socket.io: answer result for %s: %s', socket.username, result.correct);
                    socket.emit('answer_result', result.correct);
                    return socket.broadcast.to(socket.instructor_socket).emit('new_answer', result.answer);
                })
                .catch(function(err) {
                    winston.error('Socket.io: answer result error: %s', err);
                    return socket.emit('answer_result', 'error');
                });
        });

        socket.on('disconnect', function() {
            if (socket.username) {
                winston.info('Socket.io: user disconnected: %s', socket.username);
                if (socket.role === 'instructor') {
                    winston.info('Socket.io: clearing live lecture %s', socket.lecture_id);
                    clearRoom(socket.lecture_id);
                } else {
                    emitUserNumer(socket.lecture_id);
                }
            }
        });

        function emitUserNumer(lecture) {
            var users = io.nsps['/lectures'].adapter.rooms[lecture];
            if (users) {
                winston.info('Socket.io: emitting live lecture: %s, updated user total: %d', lecture, users.length);
                socket.broadcast.to(socket.instructor_socket).emit('updated_user_total', users.length);
            }
        }

        function clearRoom(lecture) {
            var roomObj = io.nsps['/lectures'].adapter.rooms[lecture];
            if (roomObj) {
                Object.keys(roomObj.sockets).forEach(function(id) {
                    lectures.sockets[id].leave(lecture);
                });
            }
            stopLecture(lecture);
        }

        function stopLecture(lecture_id) {
            winston.info('Socket.io: ending live lecture: %s', lecture_id);

            LiveLecture.remove({
                    lecture_id: lecture_id
                })
                .then(function(data) {
                    return Lecture.update({
                        _id: lecture_id
                    }, {
                        $set: {
                            live: false
                        }
                    });
                })
                .then(function(lecture) {
                    return LiveLecture.find({}, {
                        lecture_id: 1
                    });
                })
                .then(getCurrentLiveLectures)
                .catch(function(err) {
                    winston.error('Socket.io: ending live lecture error: %s', err);
                    return lectures.emit('lectures_update', 'could not add lecture');
                });
        }

        function retireLecture(lecture_id) {
            winston.info('Socket.io: retiring live lecture: %s', lecture_id);

            Lecture.update({
                    _id: lecture_id
                }, {
                    $set: {
                        live: false,
                        post_lecture: true
                    }
                })
                .then(function(lecture) {
                    socket.emit('lecture_retired');
                })
                .catch(function(err) {
                    winston.error('Socket.io: retiring live lecture error: %s', err);
                    return lectures.emit('lectures_update', 'could not add lecture');
                });
        }

        function getCurrentLiveLectures(live_lectures) {
            var current_lectures = live_lectures.map(function(lecture) {
                return lecture.lecture_id;
            });
            return lectures.emit('lectures_update', JSON.stringify(current_lectures));
        }
    });
};
<|endoftext|>


<commit_before>var Promise = require("bluebird")
var request = require('request');
var progress = require('progress');
var fs = require('fs-extra');
var path = require('path');
var gunzip = require("gunzip-maybe");
var tar = require('tar-fs');
var temp = require('temp');
var DecompressZip = require('decompress-zip');

// Automatically track and cleanup files at exit
temp.track();
var isWin = /^win/.test(process.platform);

// one progressbar for all downloads
var bar;

module.exports = {
    clearProgressbar: function() {
        bar && bar.terminate();
        bar = null;
    },
    downloadAndUnpack: function(destination, name, url, token) {
        var cachepath = path.resolve(destination, './temp');
        fs.mkdirsSync(cachepath);
        var requestSettings = { url: url
                , 'method':'GET'
                , headers: {
                    'User-Agent': 'request',
                    'Accept': 'application/octet-stream'
                }
            }
        if(token)
            requestSettings.auth = {
                    'bearer': token,
                    'sendImmediately': true
                }
        var extention = path.extname(name),
            done = Promise.defer(),
            self = this,
            rq = request(requestSettings),
            len,
            stream;

        function format(statusCode) {
            return statusCode + ': ' + require('http').STATUS_CODES[statusCode];
        }

        rq.on('error', function(err) {
            bar && bar.terminate();
            done.reject(err);
        });
        rq.on('response', function(res) {
            //console.log(res.headers)
            len = parseInt(res.headers['content-length'], 10);
            if (res.statusCode !== 200) {
                done.reject({
                    statusCode: res.statusCode,
                    msg: 'Recieved status code ' + format(res.statusCode)
                });
            } else if (len) {
                if (!bar) {
                    bar = new progress('  downloading [:bar] :percent :etas', {
                        complete: '=',
                        incomplete: '-',
                        width: 20,
                        total: len
                    });
                } else {
                    bar.total += len;
                }
            }
        });
        rq.on('data', function(chunk) {
            len && bar && bar.tick(chunk.length);
        });

        if (extention === '.zip') {
            stream = temp.createWriteStream();

            stream.on('close', function() {
                if (done.promise.isRejected()) return;
                self.extractZip(stream.path, cachepath).then(self.stripRootFolder).then(function() {
                    self.moveExtractedFilesToDestination(cachepath, destination).then(function() {
                        done.resolve();
                    });
                });
            });

            rq.pipe(stream);
        }

        if (extention === '.gz') {
            rq.on('response', function(res) {
                if (res.statusCode !== 200) return;
                self.extractTar(res, cachepath).then(self.stripRootFolder).then(function() {
                    self.moveExtractedFilesToDestination(cachepath, destination).then(function() {
                        done.resolve();
                    });
                });
            });
        }

        return done.promise;
    },
    extractTar: function(tarstream, destination) {
        var done = Promise.defer(),
            files = [];

        tarstream
            .pipe(gunzip())
            .on('error', function(err) {
                done.reject(err);
            })
            .pipe(tar.extract(destination, {
                umask: (isWin ? false : 0),
                map: function(header) {
                    files.push({
                        path: path.basename(header.name)
                    });
                    return header;
                }
            }))
            .on('finish', function() {
                done.resolve({
                    files: files,
                    destination: destination
                });
            });

        return done.promise;
    },
    extractZip: function(zipfile, destination) {
        var files = [],
            done = Promise.defer();

        new DecompressZip(zipfile)
            .on('error', function(err) {
                done.reject(err);
            })
            .on('extract', function(log) {
                // Setup chmodSync to fix permissions
                files.forEach(function(file) {
                    fs.chmodSync(path.join(destination, file.path), file.mode);
                });

                done.resolve({
                    files: files,
                    destination: destination
                });
            })
            .extract({
                path: destination,
                filter: function(entry) {
                    files.push({
                        path: entry.path,
                        mode: entry.mode.toString(8)
                    });

                    return true;
                }
            });

        return done.promise;
    },
    stripRootFolder: function(extracted) {
        var done = Promise.defer(),
            extractionFolder = extracted.destination,
            rootFiles = fs.readdirSync(extractionFolder);

        // strip out root folder if it exists
        if (rootFiles.length === 1){
            var rootFolder = path.join(extractionFolder, rootFiles[0]);
            if(fs.statSync(rootFolder).isDirectory()) {
                // move stripped folder to destination
                fs.copy(rootFolder, extractionFolder, function(err) {
                    if (err) done.reject(err);
                    else fs.remove(rootFolder, function() {
                        done.resolve();
                    });
                });
            }
        }
        else {
            done.resolve();
        }

        return done.promise;
    },
    moveExtractedFilesToDestination: function(cachepath, destination) {
        var done = Promise.defer();

        fs.copy(cachepath, destination, function(err) {
            if (err) done.reject(err);
            else fs.remove(cachepath, function() {
                done.resolve();
            });
        });

        return done.promise;
    }
};<commit_msg>take care of .tgz as well<commit_after>var Promise = require("bluebird")
var request = require('request');
var progress = require('progress');
var fs = require('fs-extra');
var path = require('path');
var gunzip = require("gunzip-maybe");
var tar = require('tar-fs');
var temp = require('temp');
var DecompressZip = require('decompress-zip');

// Automatically track and cleanup files at exit
temp.track();
var isWin = /^win/.test(process.platform);

// one progressbar for all downloads
var bar;

module.exports = {
    clearProgressbar: function() {
        bar && bar.terminate();
        bar = null;
    },
    downloadAndUnpack: function(destination, name, url, token) {
        var cachepath = path.resolve(destination, './temp');
        fs.mkdirsSync(cachepath);
        var requestSettings = { url: url
                , 'method':'GET'
                , headers: {
                    'User-Agent': 'request',
                    'Accept': 'application/octet-stream'
                }
            }
        if(token)
            requestSettings.auth = {
                    'bearer': token,
                    'sendImmediately': true
                }
        var extention = path.extname(name),
            done = Promise.defer(),
            self = this,
            rq = request(requestSettings),
            len,
            stream;

        function format(statusCode) {
            return statusCode + ': ' + require('http').STATUS_CODES[statusCode];
        }

        rq.on('error', function(err) {
            bar && bar.terminate();
            done.reject(err);
        });
        rq.on('response', function(res) {
            //console.log(res.headers)
            len = parseInt(res.headers['content-length'], 10);
            if (res.statusCode !== 200) {
                done.reject({
                    statusCode: res.statusCode,
                    msg: 'Recieved status code ' + format(res.statusCode)
                });
            } else if (len) {
                if (!bar) {
                    bar = new progress('  downloading [:bar] :percent :etas', {
                        complete: '=',
                        incomplete: '-',
                        width: 20,
                        total: len
                    });
                } else {
                    bar.total += len;
                }
            }
        });
        rq.on('data', function(chunk) {
            len && bar && bar.tick(chunk.length);
        });

        if (extention === '.zip') {
            stream = temp.createWriteStream();

            stream.on('close', function() {
                if (done.promise.isRejected()) return;
                self.extractZip(stream.path, cachepath).then(self.stripRootFolder).then(function() {
                    self.moveExtractedFilesToDestination(cachepath, destination).then(function() {
                        done.resolve();
                    });
                });
            });

            rq.pipe(stream);
        }

        if (extention === '.gz' || extension === '.tgz' ) {
            rq.on('response', function(res) {
                if (res.statusCode !== 200) return;
                self.extractTar(res, cachepath).then(self.stripRootFolder).then(function() {
                    self.moveExtractedFilesToDestination(cachepath, destination).then(function() {
                        done.resolve();
                    });
                });
            });
        }

        return done.promise;
    },
    extractTar: function(tarstream, destination) {
        var done = Promise.defer(),
            files = [];

        tarstream
            .pipe(gunzip())
            .on('error', function(err) {
                done.reject(err);
            })
            .pipe(tar.extract(destination, {
                umask: (isWin ? false : 0),
                map: function(header) {
                    files.push({
                        path: path.basename(header.name)
                    });
                    return header;
                }
            }))
            .on('finish', function() {
                done.resolve({
                    files: files,
                    destination: destination
                });
            });

        return done.promise;
    },
    extractZip: function(zipfile, destination) {
        var files = [],
            done = Promise.defer();

        new DecompressZip(zipfile)
            .on('error', function(err) {
                done.reject(err);
            })
            .on('extract', function(log) {
                // Setup chmodSync to fix permissions
                files.forEach(function(file) {
                    fs.chmodSync(path.join(destination, file.path), file.mode);
                });

                done.resolve({
                    files: files,
                    destination: destination
                });
            })
            .extract({
                path: destination,
                filter: function(entry) {
                    files.push({
                        path: entry.path,
                        mode: entry.mode.toString(8)
                    });

                    return true;
                }
            });

        return done.promise;
    },
    stripRootFolder: function(extracted) {
        var done = Promise.defer(),
            extractionFolder = extracted.destination,
            rootFiles = fs.readdirSync(extractionFolder);

        // strip out root folder if it exists
        if (rootFiles.length === 1){
            var rootFolder = path.join(extractionFolder, rootFiles[0]);
            if(fs.statSync(rootFolder).isDirectory()) {
                // move stripped folder to destination
                fs.copy(rootFolder, extractionFolder, function(err) {
                    if (err) done.reject(err);
                    else fs.remove(rootFolder, function() {
                        done.resolve();
                    });
                });
            }
        }
        else {
            done.resolve();
        }

        return done.promise;
    },
    moveExtractedFilesToDestination: function(cachepath, destination) {
        var done = Promise.defer();

        fs.copy(cachepath, destination, function(err) {
            if (err) done.reject(err);
            else fs.remove(cachepath, function() {
                done.resolve();
            });
        });

        return done.promise;
    }
};
<|endoftext|>


<commit_before>(function() {
  var startup = {
    name: 'Startup',
    kind: 'Component',
    components: [
      { name: 'notices', kind: 'Notices' }
    ],
    create: function() {
      this.inherited(arguments);
      this.launch(enyo.windowParams);
    },

    launch: function(parameters) {
      if (!enyo.applicationRelaunchHandler)
        enyo.applicationRelaunchHandler = _.bind(this.launch, this);

      if (parameters.dockMode)
        return this.exhibition(parameters);
      else {
        switch (parameters.reason || "") {
          case 'alarm': return this.alert(parameters);
          case 'snooze': return this.notify(parameters);
          default: return this.application(parameters);
        }
      }
    },

    alert: function(parameters) {
      this.$.notices.hide();

      var path = resolve_path('alert');
      return enyo.windows.openPopup(path, 'Alert', parameters, {
        clickableWhenLocked: true
      }, 180, true);
    },

    notify: function(parameters) {
      this.$.notices.show(parameters.reason, parameters.alarm);
    },

    application: function(parameters) {
      if (!is_app_open()) {
        enyo.windows.activate(
          resolve_path('app'), 'App', parameters);
      }
    },

    exhibition: function() {
      enyo.windows.activate(resolve_path('dock'), 'Dock', {});
    }
  };

  function is_app_open() {
    return enyo.windows.fetchWindow('App') != null;
  }

  function resolve_path(type) {
    return enyo.fetchAppRootPath() + '/' + type + '/index.html';
  }

  enyo.kind(startup);
})();
<commit_msg>Exhibition mode launches correctly.<commit_after>(function() {
  var startup = {
    name: 'Startup',
    kind: 'Component',
    dock: null,
    components: [
      { name: 'notices', kind: 'Notices' }
    ],
    create: function() {
      this.inherited(arguments);
      this.launch(enyo.windowParams);
    },

    launch: function(parameters) {
      if (!enyo.applicationRelaunchHandler)
        enyo.applicationRelaunchHandler = _.bind(this.launch, this);

      if (parameters.dockMode)
        return this.exhibition(parameters);
      else {
        switch (parameters.reason || "") {
          case 'alarm': return this.alert(parameters);
          case 'snooze': return this.notify(parameters);
          default: return this.application(parameters);
        }
      }
    },

    alert: function(parameters) {
      this.$.notices.hide();

      var path = resolve_path('alert');
      return enyo.windows.openPopup(path, 'Alert', parameters, {
        clickableWhenLocked: true
      }, 180, true);
    },

    notify: function(parameters) {
      this.$.notices.show(parameters.reason, parameters.alarm);
    },

    application: function(parameters) {
      if (!is_app_open()) {
        enyo.windows.activate(
          resolve_path('app'), 'App', parameters);
      }
    },

    exhibition: function() {
      is_dock_open()
        ? enyo.windows.activateWindow(fetch_window('Dock'))
        : enyo.windows.openWindow(resolve_path('dock'), 'Dock', {}, {window:'dockMode'});
    }
  };

  function is_app_open() {
    return fetch_window('App') != null;
  }

  function is_dock_open() {
    return fetch_window('Dock') != null;
  }

  function fetch_window(name) {
    return enyo.windows.fetchWindow(name);
  }

  function resolve_path(type) {
    return enyo.fetchAppRootPath() + '/' + type + '/index.html';
  }

  enyo.kind(startup);
})();
<|endoftext|>


<commit_before>ngapp.service('automationService', function($rootScope, $timeout, progressService, timerService) {
    let keepOpen;

    let buildScriptFunction = function(scriptCode) {
        try {
            return new Function('zedit', 'fh', scriptCode);
        } catch (e) {
            logger.error(`Exception parsing script: ${e.message}`);
        }
    };

    let getSelectedNodes = function(targetScope) {
        return function() {
            if (!targetScope.selectedNodes) return [];
            return targetScope.selectedNodes.map(node => ({
                handle: node.handle,
                element_type: node.element_type,
                column_values: node.column_values.slice(),
                class: node.class
            }));
        };
    };

    let getSelectedRecords = function(targetScope) {
        return function(sig) {
            if (!targetScope.selectedNodes) return [];
            return targetScope.selectedNodes.filter(node => {
                if (node.element_type !== xelib.etMainRecord) return;
                return !sig || xelib.Signature(node.handle) === sig;
            }).map(node => node.handle);
        };
    };

    let navigateToElement = function(targetScope) {
        return function(element, open) {
            xelib.OutsideHandleGroup(() => {
                try {
                    targetScope.navigateToElement(element, open);
                } catch (x) {
                    logger.error(`Failed to navigate to element, ${x.message}`);
                }
            });
        }
    };

    let showProgress = function(progress) {
        keepOpen = progress.determinate;
        progressService.showProgress(progress);
    };

    // TODO: Prompt and ShowModal
    let buildZEditContext = function(targetScope) {
        // these functions are pascal case for clarity
        return {
            NavigateToElement: navigateToElement(targetScope),
            GetSelectedNodes: getSelectedNodes(targetScope),
            GetSelectedRecords: getSelectedRecords(targetScope),
            ShowProgress: showProgress,
            LogMessage: progressService.logMessage,
            ProgressMessage: progressService.progressMessage,
            AddProgress: progressService.addProgress,
            ProgressTitle: progressService.progressTitle
        }
    };

    let getScriptTime = function() {
        return `${timerService.getSeconds('scriptTime').toFixed(3)}s`;
    };

    let executeScriptFn = function(scriptFn, zedit) {
        try {
            scriptFn(zedit, fh);
            logger.info(`Script completed in ${getScriptTime()}`);
        } catch(e) {
            logger.error(`Exception running script: \n${e.stack}`);
        } finally {
            xelib.FreeHandleGroup();
            xelib.CleanStore();
            $rootScope.$broadcast('reloadGUI');
            let method = keepOpen ? 'allowClose' : 'hideProgress';
            progressService[method]();
        }
    };

    this.runScript = function(targetScope, scriptCode, scriptFilename) {
        let scriptFn = buildScriptFunction(scriptCode),
            zedit = buildZEditContext(targetScope);
        xelib.CreateHandleGroup();
        targetScope.$emit('executingScript', scriptFilename);
        timerService.start('scriptTime');
        showProgress({
            determinate: false,
            message: `Executing ${scriptFilename}...`
        });
        $timeout(() => executeScriptFn(scriptFn, zedit), 50);
    };
});
<commit_msg>exposed StartTimer and GetSeconds through zEdit context<commit_after>ngapp.service('automationService', function($rootScope, $timeout, progressService, timerService) {
    let keepOpen;

    let buildScriptFunction = function(scriptCode) {
        try {
            return new Function('zedit', 'fh', scriptCode);
        } catch (e) {
            logger.error(`Exception parsing script: ${e.message}`);
        }
    };

    let getSelectedNodes = function(targetScope) {
        return function() {
            if (!targetScope.selectedNodes) return [];
            return targetScope.selectedNodes.map(node => ({
                handle: node.handle,
                element_type: node.element_type,
                column_values: node.column_values.slice(),
                class: node.class
            }));
        };
    };

    let getSelectedRecords = function(targetScope) {
        return function(sig) {
            if (!targetScope.selectedNodes) return [];
            return targetScope.selectedNodes.filter(node => {
                if (node.element_type !== xelib.etMainRecord) return;
                return !sig || xelib.Signature(node.handle) === sig;
            }).map(node => node.handle);
        };
    };

    let navigateToElement = function(targetScope) {
        return function(element, open) {
            xelib.OutsideHandleGroup(() => {
                try {
                    targetScope.navigateToElement(element, open);
                } catch (x) {
                    logger.error(`Failed to navigate to element, ${x.message}`);
                }
            });
        }
    };

    let showProgress = function(progress) {
        keepOpen = progress.determinate;
        progressService.showProgress(progress);
    };

    // TODO: Prompt and ShowModal
    let buildZEditContext = function(targetScope) {
        // these functions are pascal case for clarity
        return {
            NavigateToElement: navigateToElement(targetScope),
            GetSelectedNodes: getSelectedNodes(targetScope),
            GetSelectedRecords: getSelectedRecords(targetScope),
            ShowProgress: showProgress,
            StartTimer: timerService.start,
            GetSeconds: timerService.getSeconds,
            LogMessage: progressService.logMessage,
            ProgressMessage: progressService.progressMessage,
            AddProgress: progressService.addProgress,
            ProgressTitle: progressService.progressTitle
        }
    };

    let getScriptTime = function() {
        return `${timerService.getSeconds('scriptTime').toFixed(3)}s`;
    };

    let executeScriptFn = function(scriptFn, zedit) {
        try {
            scriptFn(zedit, fh);
            logger.info(`Script completed in ${getScriptTime()}`);
        } catch(e) {
            logger.error(`Exception running script: \n${e.stack}`);
        } finally {
            xelib.FreeHandleGroup();
            xelib.CleanStore();
            $rootScope.$broadcast('reloadGUI');
            let method = keepOpen ? 'allowClose' : 'hideProgress';
            progressService[method]();
        }
    };

    this.runScript = function(targetScope, scriptCode, scriptFilename) {
        let scriptFn = buildScriptFunction(scriptCode),
            zedit = buildZEditContext(targetScope);
        xelib.CreateHandleGroup();
        targetScope.$emit('executingScript', scriptFilename);
        timerService.start('scriptTime');
        showProgress({
            determinate: false,
            message: `Executing ${scriptFilename}...`
        });
        $timeout(() => executeScriptFn(scriptFn, zedit), 50);
    };
});
<|endoftext|>


<commit_before>ngapp.service('treeColumnService', function(stylesheetService) {
    this.buildFunctions = function(scope, treeSelector, columnsEditable, allowOverflow) {
        scope.toggleSort = function(column) {
            if (!column.canSort) return;
            let oldReverse = scope.sort.reverse;
            if (scope.sort.column !== column.label) {
                scope.sort.column = column.label;
                scope.sort.reverse = false;
            } else {
                scope.sort.reverse = !scope.sort.reverse;
            }
            let reverseChanged = oldReverse != scope.sort.reverse;
            scope.reloadNodes(reverseChanged);
        };

        scope.setFirstSplitBarLeft = function(width) {
            let selector = `${treeSelector} .first-split-bar`,
                left = parseInt(width.slice(0, -2)) - 3;
            stylesheetService.setProperty(selector, 'left', `${left}px`)
        };

        scope.columnResized = function(index, width, skipWidth) {
            scope.columns[index].width = width;
            if (allowOverflow && !index) scope.setFirstSplitBarLeft(width);
            if (allowOverflow && !skipWidth) scope.updateWidths();
            let selector = `${treeSelector} .column-${index}`,
                property = allowOverflow ? 'min-width' : 'width';
            stylesheetService.setProperty(selector, property, width);
        };

        scope.updateWidths = function() {
            let width = scope.columns.reduce(function(total, column) {
                return total + parseInt(column.width.slice(0, -2));
            }, 0);
            let selector = `${treeSelector} .fix-width`;
            stylesheetService.setProperty(selector, 'min-width', `${width}px`);
        };

        scope.resizeColumns = function() {
            scope.columns.forEach(function(column, index) {
                if (column.width) scope.columnResized(index, column.width, true)
            });
            if (allowOverflow) scope.updateWidths();
        };

        if (columnsEditable) {
            scope.toggleColumnsModal = function(visible) {
                scope.showColumnsModal = visible;
            };
        }
    }
});<commit_msg>fixed issue with column cell overflow on the record view<commit_after>ngapp.service('treeColumnService', function(stylesheetService) {
    this.buildFunctions = function(scope, treeSelector, columnsEditable, allowOverflow) {
        scope.toggleSort = function(column) {
            if (!column.canSort) return;
            let oldReverse = scope.sort.reverse;
            if (scope.sort.column !== column.label) {
                scope.sort.column = column.label;
                scope.sort.reverse = false;
            } else {
                scope.sort.reverse = !scope.sort.reverse;
            }
            let reverseChanged = oldReverse != scope.sort.reverse;
            scope.reloadNodes(reverseChanged);
        };

        scope.setFirstSplitBarLeft = function(width) {
            let selector = `${treeSelector} .first-split-bar`,
                left = parseInt(width.slice(0, -2)) - 3;
            stylesheetService.setProperty(selector, 'left', `${left}px`)
        };

        scope.columnResized = function(index, width, skipWidth) {
            scope.columns[index].width = width;
            if (allowOverflow && !index) scope.setFirstSplitBarLeft(width);
            if (allowOverflow && !skipWidth) scope.updateWidths();
            let selector = `${treeSelector} .column-${index}`;
            stylesheetService.setProperty(selector, 'width', width);
            // this hack really shouldn't be necessary, but if it isn't set
            // the column widths don't get applied properly
            if (allowOverflow) {
                stylesheetService.setProperty(selector, 'min-width', width);
            }
        };

        scope.updateWidths = function() {
            let width = scope.columns.reduce(function(total, column) {
                return total + parseInt(column.width.slice(0, -2));
            }, 0);
            let selector = `${treeSelector} .fix-width`;
            stylesheetService.setProperty(selector, 'min-width', `${width}px`);
        };

        scope.resizeColumns = function() {
            scope.columns.forEach(function(column, index) {
                if (column.width) scope.columnResized(index, column.width, true)
            });
            if (allowOverflow) scope.updateWidths();
        };

        if (columnsEditable) {
            scope.toggleColumnsModal = function(visible) {
                scope.showColumnsModal = visible;
            };
        }
    }
});<|endoftext|>