<commit_before>import { List, Map, OrderedSet, Record, Set } from 'immutable'
import cuid from 'cuid'
import keyedReducer from '../reducers/keyed-reducer'
import * as SortedList from '../../shared/sorted-list'
import {
  CHAT_CHANNEL_ACTIVATE,
  CHAT_CHANNEL_DEACTIVATE,
  CHAT_INIT_CHANNEL,
  CHAT_LOAD_CHANNEL_HISTORY_BEGIN,
  CHAT_LOAD_CHANNEL_HISTORY,
  CHAT_LOAD_USER_LIST_BEGIN,
  CHAT_LOAD_USER_LIST,
  CHAT_UPDATE_MESSAGE,
  CHAT_UPDATE_USER_ACTIVE,
  CHAT_UPDATE_USER_IDLE,
  CHAT_UPDATE_USER_OFFLINE,
} from '../actions'
import {
  ChatMessage,
  UserOnlineMessage,
  UserOfflineMessage,
} from '../messaging/message-records'

// How many messages should be kept for inactive channels
const INACTIVE_CHANNEL_MAX_HISTORY = 150

const sortUsers = (a, b) => a.localeCompare(b)

// Create partial evaluations all the SortedList functions with our sort function pre-applied
const SortedUsers =
    Object.keys(SortedList)
      .map(fnName => [fnName, (...args) => SortedList[fnName](sortUsers, ...args)])
      .reduce((prev, cur) => {
        prev[cur[0]] = cur[1]
        return prev
      }, {})

export const Users = new Record({
  active: new List(),
  idle: new List(),
  offline: new List(),
})

const ChannelBase = new Record({
  name: null,
  messages: new List(),
  users: new Users(),

  loadingHistory: false,
  hasHistory: true,

  hasLoadedUserList: false,
  loadingUserList: false,

  activated: false,
  hasUnread: false,
})

export class Channel extends ChannelBase {
  get hasLoadedHistory() {
    return (this.loadingHistory ||
      this.messages.size > 0 ||
      (this.messages.size === 0 && !this.hasHistory)
    )
  }
}

export const ChatState = new Record({
  channels: new OrderedSet(),
  byName: new Map(),
})

function updateUserState(user, addTo, removeFirst, removeSecond) {
  const addToUpdated = SortedUsers.insert(addTo, user)

  const firstIndex = SortedUsers.findIndex(removeFirst, user)
  const removeFirstUpdated = firstIndex > -1 ? removeFirst.remove(firstIndex) : removeFirst

  const secondIndex = SortedUsers.findIndex(removeSecond, user)
  const removeSecondUpdated = secondIndex !== -1 ? removeSecond.remove(secondIndex) : removeSecond

  return [ addToUpdated, removeFirstUpdated, removeSecondUpdated ]
}

// Update the messages field for a channel, keeping the hasUnread flag in proper sync.
// updateFn is m => messages, and should perform the update operation on the messages field
function updateMessages(state, channelName, updateFn) {
  return state.updateIn(['byName', channelName], c => {
    let updated = updateFn(c.messages)
    if (updated === c.messages) {
      return c
    }

    let sliced = false
    if (!c.activated && updated.length > INACTIVE_CHANNEL_MAX_HISTORY) {
      updated = updated.slice(-INACTIVE_CHANNEL_MAX_HISTORY)
      sliced = true
    }

    return (c.set('messages', updated)
      .set('hasUnread', c.hasUnread || !c.activated)
      .set('hasHistory', c.hasHistory || sliced))
  })
}

export default keyedReducer(new ChatState(), {
  [CHAT_INIT_CHANNEL](state, action) {
    const { channel, activeUsers } = action.payload
    const sortedActiveUsers = SortedUsers.create(activeUsers)
    const record = new Channel({
      name: channel,
      users: new Users({
        active: sortedActiveUsers,
      })
    })
    return (state.update('channels', c => c.add(channel))
      .setIn(['byName', channel], record))
  },

  [CHAT_UPDATE_MESSAGE](state, action) {
    const { id, channel, time, user, message } = action.payload
    return updateMessages(state, channel, m => {
      return m.push(new ChatMessage({
        id,
        time,
        from: user,
        text: message,
      }))
    })
  },

  [CHAT_UPDATE_USER_ACTIVE](state, action) {
    const { channel, user } = action.payload
    let wasIdle = false
    let updated = state.updateIn(['byName', channel, 'users'], users => {
      const [ active, idle, offline ] =
          updateUserState(user, users.active, users.idle, users.offline)
      wasIdle = idle !== users.idle

      return users.set('active', active).set('idle', idle).set('offline', offline)
    })

    if (!updated.byName.get(channel).hasLoadedHistory) {
      // TODO(tec27): remove this check once #139 is fixed
      return updated
    }

    if (!wasIdle) {
      updated = updateMessages(updated, channel, m => {
        return m.push(new UserOnlineMessage({
          id: cuid(),
          time: Date.now(),
          user,
        }))
      })
    }

    return updated
  },

  [CHAT_UPDATE_USER_IDLE](state, action) {
    const { channel, user } = action.payload
    return state.updateIn(['byName', channel, 'users'], users => {
      const [ idle, active, offline ] =
          updateUserState(user, users.idle, users.active, users.offline)

      return users.set('active', active).set('idle', idle).set('offline', offline)
    })
  },

  [CHAT_UPDATE_USER_OFFLINE](state, action) {
    const { channel, user } = action.payload
    const updated = state.updateIn(['byName', channel, 'users'], users => {
      const [ offline, active, idle ] =
          updateUserState(user, users.offline, users.active, users.idle)

      return users.set('active', active).set('idle', idle).set('offline', offline)
    })

    if (!updated.byName.get(channel).hasLoadedHistory) {
      // TODO(tec27): remove this check once #139 is fixed
      return updated
    }

    return updateMessages(updated, channel, m => {
      return m.push(new UserOfflineMessage({
        id: cuid(),
        time: Date.now(),
        user,
      }))
    })
  },

  [CHAT_LOAD_CHANNEL_HISTORY_BEGIN](state, action) {
    const { channel } = action.payload
    return state.setIn(['byName', channel, 'loadingHistory'], true)
  },

  [CHAT_LOAD_CHANNEL_HISTORY](state, action) {
    const { channel } = action.meta
    const newMessages = action.payload
    const updated = state.setIn(['byName', channel, 'loadingHistory'], false)
    if (!newMessages.length) {
      return updated.setIn(['byName', channel, 'hasHistory'], false)
    }

    return updateMessages(updated, channel, messages => {
      return new List(newMessages.map(msg => new ChatMessage({
        id: msg.id,
        time: msg.sent,
        from: msg.user,
        text: msg.data.text,
      }))).concat(messages)
    })
  },

  [CHAT_LOAD_USER_LIST_BEGIN](state, action) {
    const { channel } = action.payload
    return (state.setIn(['byName', channel, 'hasLoadedUserList'], true)
      .setIn(['byName', channel, 'loadingUserList'], true))
  },

  [CHAT_LOAD_USER_LIST](state, action) {
    const { channel } = action.meta
    const userList = action.payload
    return (state.setIn(['byName', channel, 'loadingUserList'], false)
      .updateIn(['byName', channel, 'users'], users => {
        const offline =
            SortedUsers.create(new Set(userList).subtract(users.active).subtract(users.idle))
        return users.set('offline', offline)
      }))
  },

  [CHAT_CHANNEL_ACTIVATE](state, action) {
    const { channel } = action.payload
    return state.updateIn(['byName', channel], c => {
      return c.set('hasUnread', false).set('activated', true)
    })
  },

  [CHAT_CHANNEL_DEACTIVATE](state, action) {
    const { channel } = action.payload
    const hasHistory = state.byName.get(channel).messages.size > INACTIVE_CHANNEL_MAX_HISTORY

    return state.updateIn(['byName', channel], c => {
      return (c.set('messages', c.messages.slice(-INACTIVE_CHANNEL_MAX_HISTORY))
        .set('hasHistory', c.hasHistory || hasHistory)
        .set('activated', false))
    })
  },
})
<commit_msg>Make the chat reducer not care about deactivate event for channels it doesn't have the state for. (#159)<commit_after>import { List, Map, OrderedSet, Record, Set } from 'immutable'
import cuid from 'cuid'
import keyedReducer from '../reducers/keyed-reducer'
import * as SortedList from '../../shared/sorted-list'
import {
  CHAT_CHANNEL_ACTIVATE,
  CHAT_CHANNEL_DEACTIVATE,
  CHAT_INIT_CHANNEL,
  CHAT_LOAD_CHANNEL_HISTORY_BEGIN,
  CHAT_LOAD_CHANNEL_HISTORY,
  CHAT_LOAD_USER_LIST_BEGIN,
  CHAT_LOAD_USER_LIST,
  CHAT_UPDATE_MESSAGE,
  CHAT_UPDATE_USER_ACTIVE,
  CHAT_UPDATE_USER_IDLE,
  CHAT_UPDATE_USER_OFFLINE,
} from '../actions'
import {
  ChatMessage,
  UserOnlineMessage,
  UserOfflineMessage,
} from '../messaging/message-records'

// How many messages should be kept for inactive channels
const INACTIVE_CHANNEL_MAX_HISTORY = 150

const sortUsers = (a, b) => a.localeCompare(b)

// Create partial evaluations all the SortedList functions with our sort function pre-applied
const SortedUsers =
    Object.keys(SortedList)
      .map(fnName => [fnName, (...args) => SortedList[fnName](sortUsers, ...args)])
      .reduce((prev, cur) => {
        prev[cur[0]] = cur[1]
        return prev
      }, {})

export const Users = new Record({
  active: new List(),
  idle: new List(),
  offline: new List(),
})

const ChannelBase = new Record({
  name: null,
  messages: new List(),
  users: new Users(),

  loadingHistory: false,
  hasHistory: true,

  hasLoadedUserList: false,
  loadingUserList: false,

  activated: false,
  hasUnread: false,
})

export class Channel extends ChannelBase {
  get hasLoadedHistory() {
    return (this.loadingHistory ||
      this.messages.size > 0 ||
      (this.messages.size === 0 && !this.hasHistory)
    )
  }
}

export const ChatState = new Record({
  channels: new OrderedSet(),
  byName: new Map(),
})

function updateUserState(user, addTo, removeFirst, removeSecond) {
  const addToUpdated = SortedUsers.insert(addTo, user)

  const firstIndex = SortedUsers.findIndex(removeFirst, user)
  const removeFirstUpdated = firstIndex > -1 ? removeFirst.remove(firstIndex) : removeFirst

  const secondIndex = SortedUsers.findIndex(removeSecond, user)
  const removeSecondUpdated = secondIndex !== -1 ? removeSecond.remove(secondIndex) : removeSecond

  return [ addToUpdated, removeFirstUpdated, removeSecondUpdated ]
}

// Update the messages field for a channel, keeping the hasUnread flag in proper sync.
// updateFn is m => messages, and should perform the update operation on the messages field
function updateMessages(state, channelName, updateFn) {
  return state.updateIn(['byName', channelName], c => {
    let updated = updateFn(c.messages)
    if (updated === c.messages) {
      return c
    }

    let sliced = false
    if (!c.activated && updated.length > INACTIVE_CHANNEL_MAX_HISTORY) {
      updated = updated.slice(-INACTIVE_CHANNEL_MAX_HISTORY)
      sliced = true
    }

    return (c.set('messages', updated)
      .set('hasUnread', c.hasUnread || !c.activated)
      .set('hasHistory', c.hasHistory || sliced))
  })
}

export default keyedReducer(new ChatState(), {
  [CHAT_INIT_CHANNEL](state, action) {
    const { channel, activeUsers } = action.payload
    const sortedActiveUsers = SortedUsers.create(activeUsers)
    const record = new Channel({
      name: channel,
      users: new Users({
        active: sortedActiveUsers,
      })
    })
    return (state.update('channels', c => c.add(channel))
      .setIn(['byName', channel], record))
  },

  [CHAT_UPDATE_MESSAGE](state, action) {
    const { id, channel, time, user, message } = action.payload
    return updateMessages(state, channel, m => {
      return m.push(new ChatMessage({
        id,
        time,
        from: user,
        text: message,
      }))
    })
  },

  [CHAT_UPDATE_USER_ACTIVE](state, action) {
    const { channel, user } = action.payload
    let wasIdle = false
    let updated = state.updateIn(['byName', channel, 'users'], users => {
      const [ active, idle, offline ] =
          updateUserState(user, users.active, users.idle, users.offline)
      wasIdle = idle !== users.idle

      return users.set('active', active).set('idle', idle).set('offline', offline)
    })

    if (!updated.byName.get(channel).hasLoadedHistory) {
      // TODO(tec27): remove this check once #139 is fixed
      return updated
    }

    if (!wasIdle) {
      updated = updateMessages(updated, channel, m => {
        return m.push(new UserOnlineMessage({
          id: cuid(),
          time: Date.now(),
          user,
        }))
      })
    }

    return updated
  },

  [CHAT_UPDATE_USER_IDLE](state, action) {
    const { channel, user } = action.payload
    return state.updateIn(['byName', channel, 'users'], users => {
      const [ idle, active, offline ] =
          updateUserState(user, users.idle, users.active, users.offline)

      return users.set('active', active).set('idle', idle).set('offline', offline)
    })
  },

  [CHAT_UPDATE_USER_OFFLINE](state, action) {
    const { channel, user } = action.payload
    const updated = state.updateIn(['byName', channel, 'users'], users => {
      const [ offline, active, idle ] =
          updateUserState(user, users.offline, users.active, users.idle)

      return users.set('active', active).set('idle', idle).set('offline', offline)
    })

    if (!updated.byName.get(channel).hasLoadedHistory) {
      // TODO(tec27): remove this check once #139 is fixed
      return updated
    }

    return updateMessages(updated, channel, m => {
      return m.push(new UserOfflineMessage({
        id: cuid(),
        time: Date.now(),
        user,
      }))
    })
  },

  [CHAT_LOAD_CHANNEL_HISTORY_BEGIN](state, action) {
    const { channel } = action.payload
    return state.setIn(['byName', channel, 'loadingHistory'], true)
  },

  [CHAT_LOAD_CHANNEL_HISTORY](state, action) {
    const { channel } = action.meta
    const newMessages = action.payload
    const updated = state.setIn(['byName', channel, 'loadingHistory'], false)
    if (!newMessages.length) {
      return updated.setIn(['byName', channel, 'hasHistory'], false)
    }

    return updateMessages(updated, channel, messages => {
      return new List(newMessages.map(msg => new ChatMessage({
        id: msg.id,
        time: msg.sent,
        from: msg.user,
        text: msg.data.text,
      }))).concat(messages)
    })
  },

  [CHAT_LOAD_USER_LIST_BEGIN](state, action) {
    const { channel } = action.payload
    return (state.setIn(['byName', channel, 'hasLoadedUserList'], true)
      .setIn(['byName', channel, 'loadingUserList'], true))
  },

  [CHAT_LOAD_USER_LIST](state, action) {
    const { channel } = action.meta
    const userList = action.payload
    return (state.setIn(['byName', channel, 'loadingUserList'], false)
      .updateIn(['byName', channel, 'users'], users => {
        const offline =
            SortedUsers.create(new Set(userList).subtract(users.active).subtract(users.idle))
        return users.set('offline', offline)
      }))
  },

  [CHAT_CHANNEL_ACTIVATE](state, action) {
    const { channel } = action.payload
    return state.updateIn(['byName', channel], c => {
      return c.set('hasUnread', false).set('activated', true)
    })
  },

  [CHAT_CHANNEL_DEACTIVATE](state, action) {
    const { channel } = action.payload
    if (!state.byName.has(channel)) {
      return state
    }
    const hasHistory = state.byName.get(channel).messages.size > INACTIVE_CHANNEL_MAX_HISTORY

    return state.updateIn(['byName', channel], c => {
      return (c.set('messages', c.messages.slice(-INACTIVE_CHANNEL_MAX_HISTORY))
        .set('hasHistory', c.hasHistory || hasHistory)
        .set('activated', false))
    })
  },
})
<|endoftext|>


<commit_before>// @flow
import {app, BrowserWindow, ipcMain} from 'electron';
import log from 'electron-log';
import {autoUpdater} from "electron-updater";
import MenuBuilder from './menu';
import configureStore from './store/configureStore';
import appPackage from './package.json';

autoUpdater.logger = log;
autoUpdater.logger.transports.file.level = process.env.NODE_ENV === 'development' ? ['error', 'warn', 'info', 'verbose', 'debug', 'silly'] : 'info';
log.info('App starting...');

const store = configureStore();
let mainWindow = null;

if (process.env.NODE_ENV === 'development') {
  app.setName(appPackage.name);
  app.setVersion(appPackage.version);
  autoUpdater.updateConfigPath = './dev-app-update.yml';
}

if (process.env.NODE_ENV === 'production') {
  const sourceMapSupport = require('source-map-support'); // eslint-disable-line
  sourceMapSupport.install();
}

// if (process.env.NODE_ENV === 'development') {
require('electron-debug')(); // eslint-disable-line global-require
const path = require('path'); // eslint-disable-line
const p = path.join(__dirname, '..', 'app', 'node_modules'); // eslint-disable-line
require('module').globalPaths.push(p); // eslint-disable-line
// }

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') app.quit();
});

const installExtensions = async () => {
  if (process.env.NODE_ENV === 'development') {
    const installer = require('electron-devtools-installer'); // eslint-disable-line global-require

    const extensions = [
      'REACT_DEVELOPER_TOOLS',
      'REDUX_DEVTOOLS'
    ];

    const forceDownload = !!process.env.UPGRADE_EXTENSIONS;

    // TODO: Use async interation statement.
    //       Waiting on https://github.com/tc39/proposal-async-iteration
    //       Promises will fail silently, which isn't what we want in development
    return Promise
      .all(extensions.map(name => installer.default(installer[name], forceDownload)))
      .catch(console.log);
  }
};

app.on('ready', async () => {
  await installExtensions();

  mainWindow = new BrowserWindow({
    show: false,
    width: 1450,
    height: 800,
    backgroundColor: '#222222',
    title: `${app.getName()} ${app.getVersion()}`,
    webPreferences: {
      devTools: true,
    }
  });
  mainWindow.loadURL(`file://${__dirname}/app.html`);

  mainWindow.webContents.on('did-finish-load', () => {
    if (!mainWindow) {
      throw new Error('"mainWindow" is not defined');
    }
    mainWindow.show();
    mainWindow.focus();
    mainWindow.maximize();

    autoUpdater.checkForUpdates();
  });

  mainWindow.on('closed', () => {
    mainWindow = null;
  });
  mainWindow.on('page-title-updated', (e) => {
    e.preventDefault();
  });

  const menuBuilder = new MenuBuilder(mainWindow, store);
  menuBuilder.buildMenu();
});

autoUpdater.on('download-progress', (progressObj) => {
  log.info('Downloaded ' + Math.round(progressObj.percent) + '% (' + progressObj.transferred + "/" + progressObj.total + ')');
});
autoUpdater.on('update-downloaded', (update) => mainWindow.send('dispatchFromMain', {update}));
ipcMain.on('installUpdate', () => {
  if (process.env.NODE_ENV === 'development') {
    console.log('autoUpdater.quitAndInstall()');
  } else {
    autoUpdater.quitAndInstall();
  }
});
<commit_msg>Updater debug level<commit_after>// @flow
import {app, BrowserWindow, ipcMain} from 'electron';
import log from 'electron-log';
import {autoUpdater} from "electron-updater";
import MenuBuilder from './menu';
import configureStore from './store/configureStore';
import appPackage from './package.json';

autoUpdater.logger = log;
autoUpdater.logger.transports.file.level = process.env.NODE_ENV === 'development' ? 'debug' : 'info';
log.info('App starting...');

const store = configureStore();
let mainWindow = null;

if (process.env.NODE_ENV === 'development') {
  app.setName(appPackage.name);
  app.setVersion(appPackage.version);
  autoUpdater.updateConfigPath = './dev-app-update.yml';
}

if (process.env.NODE_ENV === 'production') {
  const sourceMapSupport = require('source-map-support'); // eslint-disable-line
  sourceMapSupport.install();
}

// if (process.env.NODE_ENV === 'development') {
require('electron-debug')(); // eslint-disable-line global-require
const path = require('path'); // eslint-disable-line
const p = path.join(__dirname, '..', 'app', 'node_modules'); // eslint-disable-line
require('module').globalPaths.push(p); // eslint-disable-line
// }

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') app.quit();
});

const installExtensions = async () => {
  if (process.env.NODE_ENV === 'development') {
    const installer = require('electron-devtools-installer'); // eslint-disable-line global-require

    const extensions = [
      'REACT_DEVELOPER_TOOLS',
      'REDUX_DEVTOOLS'
    ];

    const forceDownload = !!process.env.UPGRADE_EXTENSIONS;

    // TODO: Use async interation statement.
    //       Waiting on https://github.com/tc39/proposal-async-iteration
    //       Promises will fail silently, which isn't what we want in development
    return Promise
      .all(extensions.map(name => installer.default(installer[name], forceDownload)))
      .catch(console.log);
  }
};

app.on('ready', async () => {
  await installExtensions();

  mainWindow = new BrowserWindow({
    show: false,
    width: 1450,
    height: 800,
    backgroundColor: '#222222',
    title: `${app.getName()} ${app.getVersion()}`,
    webPreferences: {
      devTools: true,
    }
  });
  mainWindow.loadURL(`file://${__dirname}/app.html`);

  mainWindow.webContents.on('did-finish-load', () => {
    if (!mainWindow) {
      throw new Error('"mainWindow" is not defined');
    }
    mainWindow.show();
    mainWindow.focus();
    mainWindow.maximize();

    autoUpdater.checkForUpdates();
  });

  mainWindow.on('closed', () => {
    mainWindow = null;
  });
  mainWindow.on('page-title-updated', (e) => {
    e.preventDefault();
  });

  const menuBuilder = new MenuBuilder(mainWindow, store);
  menuBuilder.buildMenu();
});

autoUpdater.on('download-progress', (progressObj) => {
  log.info('Downloaded ' + Math.round(progressObj.percent) + '% (' + progressObj.transferred + "/" + progressObj.total + ')');
});
autoUpdater.on('update-downloaded', (update) => mainWindow.send('dispatchFromMain', {update}));
ipcMain.on('installUpdate', () => {
  if (process.env.NODE_ENV === 'development') {
    console.log('autoUpdater.quitAndInstall()');
  } else {
    autoUpdater.quitAndInstall();
  }
});
<|endoftext|>


<commit_before>export default function() {
  if (typeof arguments[0].signal !== 'object') {
    throw new TypeError();
  }

  var zcr = 0;
  for (var i = 0; i < arguments[0].signal.length; i++) {
    if ((arguments[0].signal[i] >= 0 && arguments[0].signal[i + 1] < 0) ||
         (arguments[0].signal[i] < 0 && arguments[0].signal[i + 1] >= 0)) {
      zcr++;
    }
  }

  return zcr;
}
<commit_msg>Fix bug in ZCR<commit_after>export default function() {
  if (typeof arguments[0].signal !== 'object') {
    throw new TypeError();
  }

  var zcr = 0;
  for (var i = 1; i < arguments[0].signal.length; i++) {
    if ((arguments[0].signal[i-1] >= 0 && arguments[0].signal[i] < 0) ||
         (arguments[0].signal[i-1] < 0 && arguments[0].signal[i] >= 0)) {
      zcr++;
    }
  }

  return zcr;
}
<|endoftext|>


<commit_before>import THREE from 'three';

class AnimationManager {

  constructor(root, animationDefs) {
    this.clips = [];
    this.activeActions = {};

    this.mixer = new THREE.AnimationMixer(root);
    this.mixer.timeScale = 1000.0;

    this.registerClips(animationDefs);

    this.length = this.clips.length;
  }

  update(delta) {
    this.mixer.update(delta);
  }

  play(animationIndex) {
    // The animation is already playing.
    if (typeof this.activeActions[animationIndex] !== 'undefined') {
      return;
    }

    const clip = this.clips[animationIndex];

    const action = new THREE.AnimationAction(clip);

    this.mixer.play(action);
    this.activeActions[animationIndex] = action;
  }

  stop(animationIndex) {
    // The animation isn't currently playing.
    if (typeof this.activeActions[animationIndex] === 'undefined') {
      return;
    }

    this.mixer.removeAction(this.activeActions[animationIndex]);
    delete this.activeActions[animationIndex];
  }

  registerClips(animationDefs) {
    animationDefs.forEach((animationDef, index) => {
      const clip = new THREE.AnimationClip('animation-' + index, animationDef.length, []);
      this.clips[index] = clip;
    });
  }

  registerTrack(opts) {
    const trackName = opts.target.uuid + '.' + opts.property;
    const animationBlock = opts.animationBlock;

    animationBlock.tracks.forEach((trackDef, animationIndex) => {
      // Avoid attempting to create empty tracks.
      if (trackDef.keyframes.length === 0) {
        return;
      }

      const keyframes = [];

      trackDef.keyframes.forEach((keyframeDef) => {
        const keyframe = {
          time: keyframeDef.time,
          value: opts.valueTransform(keyframeDef.value)
        };

        keyframes.push(keyframe);
      });

      const clip = this.clips[animationIndex];
      const track = new THREE[opts.trackType](trackName, keyframes);

      clip.tracks.push(track);

      clip.trim();
      clip.optimize();
    });
  }

  registerAnimations() {
    this.animationClips.forEach((clip) => {
      const animationMixer = new THREE.AnimationMixer(this);

      // M2 animations are keyframed in milliseconds.
      animationMixer.timeScale = 1000.0;

      clip.trim();
      clip.optimize();

      const action = new THREE.AnimationAction(clip);

      animationMixer.addAction(action);

      this.animations.push(animationMixer);
    });
  }

}

export default AnimationManager;
<commit_msg>Removed used function<commit_after>import THREE from 'three';

class AnimationManager {

  constructor(root, animationDefs) {
    this.clips = [];
    this.activeActions = {};

    this.mixer = new THREE.AnimationMixer(root);

    // M2 animations are keyframed in milliseconds.
    this.mixer.timeScale = 1000.0;

    this.registerClips(animationDefs);

    this.length = this.clips.length;
  }

  update(delta) {
    this.mixer.update(delta);
  }

  play(animationIndex) {
    // The animation is already playing.
    if (typeof this.activeActions[animationIndex] !== 'undefined') {
      return;
    }

    const clip = this.clips[animationIndex];

    const action = new THREE.AnimationAction(clip);

    this.mixer.play(action);
    this.activeActions[animationIndex] = action;
  }

  stop(animationIndex) {
    // The animation isn't currently playing.
    if (typeof this.activeActions[animationIndex] === 'undefined') {
      return;
    }

    this.mixer.removeAction(this.activeActions[animationIndex]);
    delete this.activeActions[animationIndex];
  }

  registerClips(animationDefs) {
    animationDefs.forEach((animationDef, index) => {
      const clip = new THREE.AnimationClip('animation-' + index, animationDef.length, []);
      this.clips[index] = clip;
    });
  }

  registerTrack(opts) {
    const trackName = opts.target.uuid + '.' + opts.property;
    const animationBlock = opts.animationBlock;

    animationBlock.tracks.forEach((trackDef, animationIndex) => {
      // Avoid attempting to create empty tracks.
      if (trackDef.keyframes.length === 0) {
        return;
      }

      const keyframes = [];

      trackDef.keyframes.forEach((keyframeDef) => {
        const keyframe = {
          time: keyframeDef.time,
          value: opts.valueTransform(keyframeDef.value)
        };

        keyframes.push(keyframe);
      });

      const clip = this.clips[animationIndex];
      const track = new THREE[opts.trackType](trackName, keyframes);

      clip.tracks.push(track);

      clip.trim();
      clip.optimize();
    });
  }

}

export default AnimationManager;
<|endoftext|>


<commit_before><commit_msg>delete backendSkillBarChart.js file<commit_after><|endoftext|>


<commit_before>"use strict";

/**
 * @ngdoc function
 * @name blogappApp.controller:SignupCtrl
 * @description
 * # SingupCtrl
 * Controller of the blogappApp
 */
angular.module("blogappApp")
	.controller("SignupCtrl", function ($scope, $http, $log) {
		$scope.signup = function() {
			$http.post("app/signup", )
		};
  	});
<commit_msg>Finish the sign up controller.<commit_after>"use strict";

/**
 * @ngdoc function
 * @name blogappApp.controller:SignupCtrl
 * @description
 * # SingupCtrl
 * Controller of the blogappApp
 */
angular.module("blogappApp")
	.controller("SignupCtrl", function ($scope, $http, $log) {
		$scope.signup = function() {
			$http.post("app/signup", {
				email: $scope.email,
				password: $scope.password
			})
			.success(function(data) {
				$log.debug(data);
			});
		};
  	});
<|endoftext|>


<commit_before>var _ = require('underscore');

var Controller = function (game, player, device) {
  this.game = game;
  this.device = device;
  this.buttonA = null;
  this.player = player;
  this.device.addCallbacks(this, { onConnect: _.bind(this.addButtons, this) });
}

Controller.prototype.addButtons = function () {
  var game = this.game;
<<<<<<< Updated upstream
=======
  if (this.device.index === 0) {
    console.log('creating device 1')
    this.imageA = game.add.image(200, 300, 'xbox360', '360_A');
  } else {
    console.log('creating device 2')
    this.imageA = game.add.image(500, 300, 'xbox360', '360_A');
  }
>>>>>>> Stashed changes

  //  We can't do this until we know that the gamepad has been connected and is started
  this.buttonA = this.device.getButton(Phaser.Gamepad.XBOX360_A);
  this.buttonA.onDown.add(onDown, this);
  this.buttonA.onUp.add(onUp, this);
}

function onDown (button, value) {
  if (button.buttonCode === Phaser.Gamepad.XBOX360_A) {
   this.player.choose();
  }
}

function onUp (button, value) {
  if (button.buttonCode === Phaser.Gamepad.XBOX360_A) {
    this.imageA.alpha = 1;
  }
}

module.exports = Controller;
<commit_msg>fix merge conflict<commit_after>var _ = require('underscore');

var Controller = function (game, player, device) {
  this.game = game;
  this.device = device;
  this.buttonA = null;
  this.player = player;
  this.device.addCallbacks(this, { onConnect: _.bind(this.addButtons, this) });
}

Controller.prototype.addButtons = function () {
  var game = this.game;
  //  We can't do this until we know that the gamepad has been connected and is started
  this.buttonA = this.device.getButton(Phaser.Gamepad.XBOX360_A);
  this.buttonA.onDown.add(onDown, this);
  this.buttonA.onUp.add(onUp, this);
}

function onDown (button, value) {
  if (button.buttonCode === Phaser.Gamepad.XBOX360_A) {
   this.player.choose();
  }
}

function onUp (button, value) {
  if (button.buttonCode === Phaser.Gamepad.XBOX360_A) {
    this.imageA.alpha = 1;
  }
}

module.exports = Controller;
<|endoftext|>


<commit_before>'use strict';

// Usage accumulator service.

const _ = require('underscore');
const cluster = require('abacus-cluster');
const dataflow = require('abacus-dataflow');
const mconfigcb = require('abacus-metering-config');
const oauth = require('abacus-oauth');
const router = require('abacus-router');
const rconfigcb = require('abacus-rating-config');
const seqid = require('abacus-seqid');
const timewindow = require('abacus-timewindow');
const urienv = require('abacus-urienv');
const yieldable = require('abacus-yieldable');
const webapp = require('abacus-webapp');

const map = _.map;
const extend = _.extend;
const omit = _.omit;
const filter = _.filter;
const find = _.find;
const indexOf = _.indexOf;

const mconfig = yieldable(mconfigcb);
const rconfig = yieldable(rconfigcb);

/* eslint camelcase: 1 */

const windowsSizes = process.env.TIME_WINDOWS_SIZES ? JSON.parse(process.env.TIME_WINDOWS_SIZES) : undefined;

const createTimeWindows = timewindow.timeWindowsSizes;

const dimension = timewindow.dimension;

// The scaling factor of each time window for creating the date string
// [Second, Minute, Hour, Day, Month]
const slack = () =>
  /^[0-9]+[MDhms]$/.test(process.env.SLACK)
    ? {
      scale: process.env.SLACK.charAt(process.env.SLACK.length - 1),
      width: process.env.SLACK.match(/[0-9]+/)[0]
    }
    : {
      scale: dimension.min,
      width: 10
    };

const timeWindows = createTimeWindows(slack(), windowsSizes);

// Setup debug log
const debug = require('abacus-debug')('abacus-usage-accumulator');
const edebug = require('abacus-debug')('e-abacus-usage-accumulator');

let systemToken;

// Secure the routes or not
const secured = () => process.env.SECURED === 'true';

// Resolve service URIs
const uris = urienv({
  auth_server: 9882,
  aggregator: 9300
});

// Return OAuth system scopes needed to write input docs
const iwscope = (udoc) =>
  secured()
    ? { system: ['abacus.usage.write'] }
    : undefined;

// Return OAuth system scopes needed to read input and output docs
const rscope = (udoc) =>
  secured()
    ? { system: ['abacus.usage.read'] }
    : undefined;

// Return the keys and times of our docs
const ikey = (udoc) =>
  [udoc.organization_id, udoc.resource_instance_id, udoc.consumer_id || 'UNKNOWN', udoc.plan_id].join('/');

const itime = (udoc) => seqid();

const igroups = (udoc) => [
  [
    udoc.organization_id,
    udoc.resource_instance_id,
    udoc.consumer_id || 'UNKNOWN',
    udoc.plan_id,
    udoc.metering_plan_id,
    udoc.rating_plan_id,
    udoc.pricing_plan_id
  ].join('/')
];

const okeys = (udoc) => [
  [
    udoc.organization_id,
    udoc.resource_instance_id,
    udoc.consumer_id || 'UNKNOWN',
    udoc.plan_id,
    udoc.metering_plan_id,
    udoc.rating_plan_id,
    udoc.pricing_plan_id
  ].join('/'),
  [udoc.organization_id, udoc.resource_instance_id, udoc.consumer_id || 'UNKNOWN', udoc.plan_id].join('/')
];

const skeys = (udoc) => [udoc.organization_id, undefined];

// Configure reduction result doc sampling, to store reduction results
// in a single doc per min, hour or day for example instead of creating
// a new doc for each new result
const sampling = process.env.SAMPLING;

const otimes = (udoc, itime) => [seqid.sample(itime, sampling), map([udoc.end, udoc.start], seqid.pad16).join('/')];

const stimes = (udoc, itime) => [seqid.sample(itime, sampling), undefined];

// Time dimension keys corresponding to their respective window positions
const dimensions = [dimension.sec, dimension.min, dimension.hour, dimension.day, dimension.month];

// Millisecond representation of the time dimensions
const msDimensions = {
  M: 2678400000,
  D: 86400000,
  h: 3600000,
  m: 60000,
  s: 1000
};

// Return the configured price for the metrics that is attached in the
// usage document
const price = (pricings, metric) => filter(pricings, (m) => m.name === metric)[0].price;

// Return the accumulate function for a given metric
const accumfn = (metrics, metric) => {
  return filter(metrics, (m) => m.name === metric)[0].accumulatefn;
};

// Return the rate function for a given metric
const ratefn = (metrics, metric) => {
  return filter(metrics, (m) => m.name === metric)[0].ratefn;
};

// Return the accumulated usage windows for a given metric
const accum = (au, metric) => {
  const a = filter(au, (a) => a.metric === metric);
  return a.length
    ? a[0].windows
    : [
      timeWindows.getWindows(dimension.sec),
      timeWindows.getWindows(dimension.min),
      timeWindows.getWindows(dimension.hour),
      timeWindows.getWindows(dimension.day),
      timeWindows.getWindows(dimension.month)
    ];
};

// find info with error and reason to redirect
// usage to error db and stop processing it to the next pipeline.
const findError = (info) => find(info, (i) => i.error);

// Accumulate usage and return new accumulated value
const accumulate = function*(accums, u) {
  debug('Accumulating usage %o from %d and new usage %o from %d', accums[0], accums[0] ? accums[0].end : 0, u, u.end);

  // Accumulate new usage into the first of the set of output docs
  // produced at each reduction iteration
  const a = accums[0];

  // Even a millisecond difference could have the usage misplaced in the windows
  // Use time from processed_id
  const now = parseInt(u.processed_id);
  const slackLimit = msDimensions[slack().scale] * slack().width;
  if (u.end < now - slackLimit)
    throw extend(new Error('The usage submitted is older than ' + slackLimit + ' milliseconds'), {
      status: 409,
      error: 'slack',
      reason: 'The usage submitted is older than ' + slackLimit + ' milliseconds',
      noretry: true,
      nobreaker: true
    });

  // Retrieve the metering plan and rating plan
  const [mplan, rplan] = yield [
    mconfig(u.metering_plan_id, systemToken && systemToken()),
    rconfig(u.rating_plan_id, systemToken && systemToken())
  ];

  const e = findError([mplan, rplan]);

  if (e) {
    debug('The usage submitted has business errors %o', e);
    return [extend({}, u, e)];
  }

  // Compute the accumulated usage time and new usage time
  const processed = a ? a.processed : 0;

  // Use previous accumulated value if any
  const umerge = omit(u, 'id', 'metrics', 'metered_usage', 'measured_usage');
  const amerge = a
    ? extend({}, a, umerge)
    : extend({ accumulated_usage: [] }, umerge);

  // Calculate new accumulated usage
  const newa = extend({}, amerge, {
    accumulated_usage: map(u.metered_usage, (mu) => {
      debug('Accumulating metered usage quantity %o', mu);

      // Find the rate function for the given metric
      const rfn = ratefn(rplan.rating_plan.metrics, mu.metric);

      // Find the price for the metric
      const rp = price(u.prices.metrics, mu.metric);

      const aw = accum(amerge.accumulated_usage, mu.metric);

      // a function that gives the value of the submitted usage in the
      // dimension window.
      const getCell = timewindow.cellfn(aw, now, u.end);

      return {
        metric: mu.metric,
        windows: map(aw, (w, i) => {
          // Get the appropriate time window index
          const twi = timewindow.timeWindowIndex(w, now, u.end, dimensions[i], true);

          // Expand the timewindows if necessary
          if (i >= indexOf(dimensions, slack().scale) && w.length - 1 < twi)
            map(Array(twi - w.length + 1), () => w.push(null));

          // Shift the windows if now is part of a new time window
          if (a && now > processed) timewindow.shiftWindow(a.processed, now, w, dimensions[i]);

          /* eslint complexity: [1, 6] */
          const quantities = map(w, (tw, j) => {
            const bounds = timewindow.timeWindowBounds(now, dimensions[i], -j);
            const current = tw && tw.quantity && tw.quantity.current ? tw.quantity.current : 0;
            const accumulated = accumfn(mplan.metering_plan.metrics, mu.metric)(
              current,
              mu.quantity,
              u.start,
              u.end,
              bounds.from,
              bounds.to,
              getCell
            );

            // Do not accumulate if the function returns null
            if (accumulated === null) {
              debug('No accumulation in window %d index %d', i, j);
              return tw ? extend({}, tw) : null;
            }

            // Switch old current to previous in previously accumulated windows
            if (tw && tw.quantity && tw.quantity.current) {
              debug('Accumulating window %d index %d' + ' new quantity %o old quantity %o', i, j, tw, mu);
              return {
                quantity: {
                  previous: tw.quantity.current,
                  current: accumulated
                }
              };
            }

            // Create a new accumulated object at the window
            debug('New window %d index %d new quantity %o', i, j, tw);
            return {
              quantity: {
                current: accumulated
              }
            };
          });

          // Calculate cost for all accumulated quantities
          return map(
            quantities,
            (q) =>
              q
                ? extend(q, { cost: q.quantity.current ? rfn(rp, q.quantity.current) : 0 })
                : null
          );
        })
      };
    })
  });

  // Return new accumulated usage and an empty doc used for duplicate
  // usage detection
  debug('New accumulated usage %o', newa);
  return [newa, {}];
};

// Create an accumulator service app
const accumulator = (token) => {
  // Configure Node cluster to use a single process as we want to serialize
  // accumulation requests per db partition and app instance
  cluster.singleton();

  // Create the Webapp
  const app = webapp();

  // Secure metering and batch routes using an OAuth bearer access token
  if (secured()) app.use(/^\/v1\/metering|^\/batch$/, oauth.validator(process.env.JWTKEY, process.env.JWTALGO));

  const authFn = () => secured() ? token : () => {};

  const reducer = dataflow.reducer(accumulate, {
    input: {
      type: 'metered_usage',
      post: '/v1/metering/metered/usage',
      get:
        '/v1/metering/metered/usage' +
        '/t/:tseq/k/:korganization_id/:kresource_instance_id' +
        '/:kconsumer_id/:kplan_id',
      dbname: 'abacus-accumulator-metered-usage',
      wscope: iwscope,
      rscope: rscope,
      key: ikey,
      time: itime,
      groups: igroups
    },
    output: {
      type: 'accumulated_usage',
      get:
        '/v1/metering/accumulated/usage' +
        '/k/:korganization_id/:kresource_instance_id' +
        '/:kconsumer_id/:kplan_id' +
        '/t/:tend/:tstart',
      dbname: 'abacus-accumulator-accumulated-usage',
      rscope: rscope,
      keys: okeys,
      times: otimes
    },
    sink: {
      host: uris.aggregator,
      apps: process.env.AGGREGATOR_APPS,
      posts: ['/v1/metering/accumulated/usage', undefined],
      keys: skeys,
      times: stimes,
      authentication: authFn()
    }
  });

  app.use(reducer);
  app.use(router.batch(app));

  app.reducer = reducer;
  return app;
};

const startApp = (token) => {
  const app = accumulator(token);
  app.listen();

  if (!cluster.isWorker() || cluster.isDisabled()) {
    debug('Starting replay ...');
    dataflow.replay(app.reducer, 0, (err) => {
      if (err) edebug('Replay failed with error %o', err);
      else debug('Replay completed successfully');
    });
  }
};

const runCLI = () => {
  if (secured()) {
    systemToken = oauth.cache(
      uris.auth_server,
      process.env.CLIENT_ID,
      process.env.CLIENT_SECRET,
      'abacus.usage.write abacus.usage.read'
    );

    systemToken.start((err) => {
      if (err) edebug('Unable to obtain oAuth token due to %o', err);
      else startApp(systemToken);
    });
  } else startApp();
};

// Export our public functions
module.exports = accumulator;
module.exports.accumulate = accumulate;
module.exports.runCLI = runCLI;
<commit_msg>Use _.times instead of map for iterations (#848)<commit_after>'use strict';

// Usage accumulator service.

const _ = require('underscore');
const cluster = require('abacus-cluster');
const dataflow = require('abacus-dataflow');
const mconfigcb = require('abacus-metering-config');
const oauth = require('abacus-oauth');
const router = require('abacus-router');
const rconfigcb = require('abacus-rating-config');
const seqid = require('abacus-seqid');
const timewindow = require('abacus-timewindow');
const urienv = require('abacus-urienv');
const yieldable = require('abacus-yieldable');
const webapp = require('abacus-webapp');

const map = _.map;
const extend = _.extend;
const omit = _.omit;
const filter = _.filter;
const find = _.find;
const indexOf = _.indexOf;
const times = _.times;

const mconfig = yieldable(mconfigcb);
const rconfig = yieldable(rconfigcb);

/* eslint camelcase: 1 */

const windowsSizes = process.env.TIME_WINDOWS_SIZES ? JSON.parse(process.env.TIME_WINDOWS_SIZES) : undefined;

const createTimeWindows = timewindow.timeWindowsSizes;

const dimension = timewindow.dimension;

// The scaling factor of each time window for creating the date string
// [Second, Minute, Hour, Day, Month]
const slack = () =>
  /^[0-9]+[MDhms]$/.test(process.env.SLACK)
    ? {
      scale: process.env.SLACK.charAt(process.env.SLACK.length - 1),
      width: process.env.SLACK.match(/[0-9]+/)[0]
    }
    : {
      scale: dimension.min,
      width: 10
    };

const timeWindows = createTimeWindows(slack(), windowsSizes);

// Setup debug log
const debug = require('abacus-debug')('abacus-usage-accumulator');
const edebug = require('abacus-debug')('e-abacus-usage-accumulator');

let systemToken;

// Secure the routes or not
const secured = () => process.env.SECURED === 'true';

// Resolve service URIs
const uris = urienv({
  auth_server: 9882,
  aggregator: 9300
});

// Return OAuth system scopes needed to write input docs
const iwscope = (udoc) =>
  secured()
    ? { system: ['abacus.usage.write'] }
    : undefined;

// Return OAuth system scopes needed to read input and output docs
const rscope = (udoc) =>
  secured()
    ? { system: ['abacus.usage.read'] }
    : undefined;

// Return the keys and times of our docs
const ikey = (udoc) =>
  [udoc.organization_id, udoc.resource_instance_id, udoc.consumer_id || 'UNKNOWN', udoc.plan_id].join('/');

const itime = (udoc) => seqid();

const igroups = (udoc) => [
  [
    udoc.organization_id,
    udoc.resource_instance_id,
    udoc.consumer_id || 'UNKNOWN',
    udoc.plan_id,
    udoc.metering_plan_id,
    udoc.rating_plan_id,
    udoc.pricing_plan_id
  ].join('/')
];

const okeys = (udoc) => [
  [
    udoc.organization_id,
    udoc.resource_instance_id,
    udoc.consumer_id || 'UNKNOWN',
    udoc.plan_id,
    udoc.metering_plan_id,
    udoc.rating_plan_id,
    udoc.pricing_plan_id
  ].join('/'),
  [udoc.organization_id, udoc.resource_instance_id, udoc.consumer_id || 'UNKNOWN', udoc.plan_id].join('/')
];

const skeys = (udoc) => [udoc.organization_id, undefined];

// Configure reduction result doc sampling, to store reduction results
// in a single doc per min, hour or day for example instead of creating
// a new doc for each new result
const sampling = process.env.SAMPLING;

const otimes = (udoc, itime) => [seqid.sample(itime, sampling), map([udoc.end, udoc.start], seqid.pad16).join('/')];

const stimes = (udoc, itime) => [seqid.sample(itime, sampling), undefined];

// Time dimension keys corresponding to their respective window positions
const dimensions = [dimension.sec, dimension.min, dimension.hour, dimension.day, dimension.month];

// Millisecond representation of the time dimensions
const msDimensions = {
  M: 2678400000,
  D: 86400000,
  h: 3600000,
  m: 60000,
  s: 1000
};

// Return the configured price for the metrics that is attached in the
// usage document
const price = (pricings, metric) => filter(pricings, (m) => m.name === metric)[0].price;

// Return the accumulate function for a given metric
const accumfn = (metrics, metric) => {
  return filter(metrics, (m) => m.name === metric)[0].accumulatefn;
};

// Return the rate function for a given metric
const ratefn = (metrics, metric) => {
  return filter(metrics, (m) => m.name === metric)[0].ratefn;
};

// Return the accumulated usage windows for a given metric
const accum = (au, metric) => {
  const a = filter(au, (a) => a.metric === metric);
  return a.length
    ? a[0].windows
    : [
      timeWindows.getWindows(dimension.sec),
      timeWindows.getWindows(dimension.min),
      timeWindows.getWindows(dimension.hour),
      timeWindows.getWindows(dimension.day),
      timeWindows.getWindows(dimension.month)
    ];
};

// find info with error and reason to redirect
// usage to error db and stop processing it to the next pipeline.
const findError = (info) => find(info, (i) => i.error);

// Accumulate usage and return new accumulated value
const accumulate = function*(accums, u) {
  debug('Accumulating usage %o from %d and new usage %o from %d', accums[0], accums[0] ? accums[0].end : 0, u, u.end);

  // Accumulate new usage into the first of the set of output docs
  // produced at each reduction iteration
  const a = accums[0];

  // Even a millisecond difference could have the usage misplaced in the windows
  // Use time from processed_id
  const now = parseInt(u.processed_id);
  const slackLimit = msDimensions[slack().scale] * slack().width;
  if (u.end < now - slackLimit)
    throw extend(new Error('The usage submitted is older than ' + slackLimit + ' milliseconds'), {
      status: 409,
      error: 'slack',
      reason: 'The usage submitted is older than ' + slackLimit + ' milliseconds',
      noretry: true,
      nobreaker: true
    });

  // Retrieve the metering plan and rating plan
  const [mplan, rplan] = yield [
    mconfig(u.metering_plan_id, systemToken && systemToken()),
    rconfig(u.rating_plan_id, systemToken && systemToken())
  ];

  const e = findError([mplan, rplan]);

  if (e) {
    debug('The usage submitted has business errors %o', e);
    return [extend({}, u, e)];
  }

  // Compute the accumulated usage time and new usage time
  const processed = a ? a.processed : 0;

  // Use previous accumulated value if any
  const umerge = omit(u, 'id', 'metrics', 'metered_usage', 'measured_usage');
  const amerge = a
    ? extend({}, a, umerge)
    : extend({ accumulated_usage: [] }, umerge);

  // Calculate new accumulated usage
  const newa = extend({}, amerge, {
    accumulated_usage: map(u.metered_usage, (mu) => {
      debug('Accumulating metered usage quantity %o', mu);

      // Find the rate function for the given metric
      const rfn = ratefn(rplan.rating_plan.metrics, mu.metric);

      // Find the price for the metric
      const rp = price(u.prices.metrics, mu.metric);

      const aw = accum(amerge.accumulated_usage, mu.metric);

      // a function that gives the value of the submitted usage in the
      // dimension window.
      const getCell = timewindow.cellfn(aw, now, u.end);

      return {
        metric: mu.metric,
        windows: map(aw, (w, i) => {
          // Get the appropriate time window index
          const twi = timewindow.timeWindowIndex(w, now, u.end, dimensions[i], true);

          // Expand the timewindows if necessary
          if (i >= indexOf(dimensions, slack().scale) && w.length - 1 < twi)
            times(twi - w.length + 1, () => w.push(null));

          // Shift the windows if now is part of a new time window
          if (a && now > processed) timewindow.shiftWindow(a.processed, now, w, dimensions[i]);

          /* eslint complexity: [1, 6] */
          const quantities = map(w, (tw, j) => {
            const bounds = timewindow.timeWindowBounds(now, dimensions[i], -j);
            const current = tw && tw.quantity && tw.quantity.current ? tw.quantity.current : 0;
            const accumulated = accumfn(mplan.metering_plan.metrics, mu.metric)(
              current,
              mu.quantity,
              u.start,
              u.end,
              bounds.from,
              bounds.to,
              getCell
            );

            // Do not accumulate if the function returns null
            if (accumulated === null) {
              debug('No accumulation in window %d index %d', i, j);
              return tw ? extend({}, tw) : null;
            }

            // Switch old current to previous in previously accumulated windows
            if (tw && tw.quantity && tw.quantity.current) {
              debug('Accumulating window %d index %d' + ' new quantity %o old quantity %o', i, j, tw, mu);
              return {
                quantity: {
                  previous: tw.quantity.current,
                  current: accumulated
                }
              };
            }

            // Create a new accumulated object at the window
            debug('New window %d index %d new quantity %o', i, j, tw);
            return {
              quantity: {
                current: accumulated
              }
            };
          });

          // Calculate cost for all accumulated quantities
          return map(
            quantities,
            (q) =>
              q
                ? extend(q, { cost: q.quantity.current ? rfn(rp, q.quantity.current) : 0 })
                : null
          );
        })
      };
    })
  });

  // Return new accumulated usage and an empty doc used for duplicate
  // usage detection
  debug('New accumulated usage %o', newa);
  return [newa, {}];
};

// Create an accumulator service app
const accumulator = (token) => {
  // Configure Node cluster to use a single process as we want to serialize
  // accumulation requests per db partition and app instance
  cluster.singleton();

  // Create the Webapp
  const app = webapp();

  // Secure metering and batch routes using an OAuth bearer access token
  if (secured()) app.use(/^\/v1\/metering|^\/batch$/, oauth.validator(process.env.JWTKEY, process.env.JWTALGO));

  const authFn = () => secured() ? token : () => {};

  const reducer = dataflow.reducer(accumulate, {
    input: {
      type: 'metered_usage',
      post: '/v1/metering/metered/usage',
      get:
        '/v1/metering/metered/usage' +
        '/t/:tseq/k/:korganization_id/:kresource_instance_id' +
        '/:kconsumer_id/:kplan_id',
      dbname: 'abacus-accumulator-metered-usage',
      wscope: iwscope,
      rscope: rscope,
      key: ikey,
      time: itime,
      groups: igroups
    },
    output: {
      type: 'accumulated_usage',
      get:
        '/v1/metering/accumulated/usage' +
        '/k/:korganization_id/:kresource_instance_id' +
        '/:kconsumer_id/:kplan_id' +
        '/t/:tend/:tstart',
      dbname: 'abacus-accumulator-accumulated-usage',
      rscope: rscope,
      keys: okeys,
      times: otimes
    },
    sink: {
      host: uris.aggregator,
      apps: process.env.AGGREGATOR_APPS,
      posts: ['/v1/metering/accumulated/usage', undefined],
      keys: skeys,
      times: stimes,
      authentication: authFn()
    }
  });

  app.use(reducer);
  app.use(router.batch(app));

  app.reducer = reducer;
  return app;
};

const startApp = (token) => {
  const app = accumulator(token);
  app.listen();

  if (!cluster.isWorker() || cluster.isDisabled()) {
    debug('Starting replay ...');
    dataflow.replay(app.reducer, 0, (err) => {
      if (err) edebug('Replay failed with error %o', err);
      else debug('Replay completed successfully');
    });
  }
};

const runCLI = () => {
  if (secured()) {
    systemToken = oauth.cache(
      uris.auth_server,
      process.env.CLIENT_ID,
      process.env.CLIENT_SECRET,
      'abacus.usage.write abacus.usage.read'
    );

    systemToken.start((err) => {
      if (err) edebug('Unable to obtain oAuth token due to %o', err);
      else startApp(systemToken);
    });
  } else startApp();
};

// Export our public functions
module.exports = accumulator;
module.exports.accumulate = accumulate;
module.exports.runCLI = runCLI;
<|endoftext|>


<commit_before>/*
    globals define console
*/
define([
    '/api/config?cb=' + Math.random().toString(16).substring(2),
    '/common/messages.js',
    '/common/crypto.js',
    '/common/realtime-input.js',
    '/common/convert.js',
    '/common/toolbar.js',
    '/common/cursor.js',
    '/bower_components/diff-dom/diffDOM.js',

    '/bower_components/jquery/dist/jquery.min.js',
    '/customize/pad.js'
], function (Config, Messages, Crypto, realtimeInput, Convert, Toolbar, Cursor) {
    var $ = window.jQuery;
    var ifrw = $('#pad-iframe')[0].contentWindow;
    var Ckeditor; // to be initialized later...
    //window.Ckeditor = ifrw.CKEDITOR;
    var DiffDom = window.diffDOM;
    var ChainPad = window.ChainPad;

    var userName = Crypto.rand64(8),
        toolbar;

    var Vdom = Convert.core.vdom,
        Hyperjson = Convert.core.hyperjson;

    window.Hyperjson = Hyperjson;

    var andThen = function () {
        $(window).on('hashchange', function() {
            window.location.reload();
        });
        if (window.location.href.indexOf('#') === -1) {
            window.location.href = window.location.href + '#' + Crypto.genKey();
            return;
        }

        var fixThings = false;
        var key = Crypto.parseKey(window.location.hash.substring(1));
        var editor = window.editor = Ckeditor.replace('editor1', {
            // https://dev.ckeditor.com/ticket/10907
            needsBrFiller: fixThings,
            needsNbspFiller: fixThings,
            removeButtons: 'Source,Maximize',
            // magicline plugin inserts html crap into the document which is not part of the
            // document itself and causes problems when it's sent across the wire and reflected back
            removePlugins: 'magicline,resize'
        });

        editor.on('instanceReady', function (Ckeditor) {
            editor.execCommand('maximize');
            var documentBody = ifrw.$('iframe')[0].contentDocument.body;

            documentBody.innerHTML = Messages.initialState;

            var inner = documentBody;
            window.inner = inner;
            var cursor = window.cursor = Cursor(Ckeditor, editor, inner);

            var $textarea = $('#feedback');

            var vdom1 = Convert.dom.to.vdom(inner);

            var applyHjson = function (shjson) {
                console.log("Applying HJSON");
                var userDocStateDom = Convert.hjson.to.dom(JSON.parse(shjson));
                //var userDocStateDom = Vdom.create(Convert.hjson.to.vdom(JSON.parse(shjson)));

                userDocStateDom.setAttribute("contentEditable", "true"); // lol wtf
                var patch = (new DiffDom()).diff(inner, userDocStateDom);
                (new DiffDom()).apply(inner, patch);
            };

            var onRemote = function (shjson) {
                // remember where the cursor is
                //cursor.update()

                applyHjson(shjson);

                cursor.find();

                // put the cursor back where you left it
                // FIXME put this back in
                //cursor.replace();
            };

            var onInit = function (info) {
                // TODO initialize the toolbar
            };

            var rti = realtimeInput.start($textarea[0], // synced element
                                    Config.websocketURL, // websocketURL, ofc
                                    userName, // userName
                                    key.channel, // channelName
                                    key.cryptKey, // key
                                    { // configuration :D
                                        doc: inner,

                                        onReady: function (info) {
                                            applyHjson($textarea.val());
                                            $textarea.trigger('keyup');
                                        },

                                        onRemote: onRemote,
                                        onInit: onInit,

                                        transformFunction : function (text, toTransform, transformBy) {
                                            /* FIXME
                                                operational transform on json shouldn't be in all editors
                                                just those transmitting/expecting JSON
                                            console.log({
                                                text: text,
                                                toTransform: toTransform,
                                                transformBy: transformBy
                                            });
                                            */

                                            var resultOp = ChainPad.Operation.transform0(text, toTransform, transformBy);
                                            var text2 = ChainPad.Operation.apply(transformBy, text);
                                            var text3 = ChainPad.Operation.apply(resultOp, text2);
                                            try { JSON.parse(text3); return resultOp; } catch (e) { console.log(e); }

                                            // returning **null** breaks out of the loop
                                            // which transforms conflicting operations
                                            // in theory this should prevent us from producing bad JSON
                                            return null;
                                        }
                                        /*
                                            FIXME NOT A REAL FUNCTION WONT WORK
                                            transformFunction: function (state0str, toTransform, transformBy) {
                                                var state1A = JSON.parse(Operation.apply(state0str, transformBy));
                                                var state1B = JSON.parse(Operation.apply(state0str, toTransform));
                                                var state0  = JSON.parse(state0str);
                                            }
                                        */
                                    });

            $textarea.val(JSON.stringify(Convert.dom.to.hjson(inner)));

            editor.on('change', function () {
                var hjson = Hyperjson.fromDOM(inner);

                $textarea.val(JSON.stringify(hjson));
                rti.bumpSharejs();
                cursor.update();
            });

            ['mouseup', 'keyup'].forEach(function (type) {
                editor.document.on(type, function (e) {
                    cursor.update();
                });
            });
        });
    };

    var interval = 100;
    var first = function () {
        Ckeditor = ifrw.CKEDITOR;
        if (Ckeditor) {
            andThen(Ckeditor);
        } else {
            console.log("Ckeditor was not defined. Trying again in %sms",interval);
            setTimeout(first, interval);
        }
    };

    $(first);
});
<commit_msg>main.js : clean up and commit before making big-ish changes for cursor fixing<commit_after>define([
    '/api/config?cb=' + Math.random().toString(16).substring(2),
    '/common/messages.js',
    '/common/crypto.js',
    '/common/realtime-input.js',
    '/common/convert.js',
    '/common/toolbar.js',
    '/common/cursor.js',
    '/bower_components/diff-dom/diffDOM.js',
    '/bower_components/jquery/dist/jquery.min.js',
    '/customize/pad.js'
], function (Config, Messages, Crypto, realtimeInput, Convert, Toolbar, Cursor) {
    var $ = window.jQuery;
    var ifrw = $('#pad-iframe')[0].contentWindow;
    var Ckeditor; // to be initialized later...
    //window.Ckeditor = ifrw.CKEDITOR;
    var DiffDom = window.diffDOM;
    var ChainPad = window.ChainPad;

    var userName = Crypto.rand64(8),
        toolbar;

    var andThen = function (Ckeditor) {
        $(window).on('hashchange', function() {
            window.location.reload();
        });
        if (window.location.href.indexOf('#') === -1) {
            window.location.href = window.location.href + '#' + Crypto.genKey();
            return;
        }

        var fixThings = false;
        var key = Crypto.parseKey(window.location.hash.substring(1));
        var editor = window.editor = Ckeditor.replace('editor1', {
            // https://dev.ckeditor.com/ticket/10907
            needsBrFiller: fixThings,
            needsNbspFiller: fixThings,
            removeButtons: 'Source,Maximize',
            // magicline plugin inserts html crap into the document which is not part of the
            // document itself and causes problems when it's sent across the wire and reflected back
            removePlugins: 'magicline,resize'
        });

        var CKE = Ckeditor;

        editor.on('instanceReady', function (Ckeditor) {
            editor.execCommand('maximize');
            var documentBody = ifrw.$('iframe')[0].contentDocument.body;

            documentBody.innerHTML = Messages.initialState;

            var inner = documentBody;
            window.inner = inner;
            var cursor = window.cursor = Cursor(CKE, editor, inner);

            var $textarea = $('#feedback');

            var vdom1 = Convert.dom.to.vdom(inner);

            var applyHjson = function (shjson) {
                console.log("Applying HJSON");
                var userDocStateDom = Convert.hjson.to.dom(JSON.parse(shjson));

                userDocStateDom.setAttribute("contentEditable", "true"); // lol wtf
                var patch = (new DiffDom()).diff(inner, userDocStateDom);
                (new DiffDom()).apply(inner, patch);
            };

            var onRemote = function (shjson) {
                // remember where the cursor is
                //cursor.update()

                applyHjson(shjson);

                //cursor.find();

                // put the cursor back where you left it
                // FIXME put this back in
                //cursor.replace();
            };

            var onInit = function (info) {
                // TODO initialize the toolbar
            };

            var rejectIfNotValidJson = function (text, toTransform, transformBy) {
                var resultOp = ChainPad.Operation.transform0(text, toTransform, transformBy);
                var text2 = ChainPad.Operation.apply(transformBy, text);
                var text3 = ChainPad.Operation.apply(resultOp, text2);
                try {
                    JSON.parse(text3);
                    return resultOp;
                } catch (e) {
                    console.log(e);
                }

                // returning **null** breaks out of the loop
                // which transforms conflicting operations
                // in theory this should prevent us from producing bad JSON
                return null;
            };

            var rti = realtimeInput.start($textarea[0], // synced element
                                    Config.websocketURL, // websocketURL, ofc
                                    userName, // userName
                                    key.channel, // channelName
                                    key.cryptKey, // key
                                    { // configuration :D
                                        doc: inner,

                                        // first thing called
                                        onInit: onInit,

                                        onReady: function (info) {
                                            applyHjson($textarea.val());
                                            $textarea.trigger('keyup');
                                        },

                                        // when remote changes occur
                                        onRemote: onRemote,

                                        transformFunction : rejectIfNotValidJson,

                                        // pass in websocket/netflux object
                                    });

            $textarea.val(JSON.stringify(Convert.dom.to.hjson(inner)));

            editor.on('change', function () {
                var hjson = Convert.core.hyperjson.fromDOM(inner);

                $textarea.val(JSON.stringify(hjson));
                rti.bumpSharejs();
                cursor.update();
            });

            ['mouseup', 'keyup'].forEach(function (type) {
                editor.document.on(type, function (e) {
                    cursor.update();
                });
            });
        });
    };

    var interval = 100;
    var first = function () {
        Ckeditor = ifrw.CKEDITOR;
        if (Ckeditor) {
            andThen(Ckeditor);
        } else {
            console.log("Ckeditor was not defined. Trying again in %sms",interval);
            setTimeout(first, interval);
        }
    };

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


<commit_before>/** @ngInject */
export function LogoutState (routerHelper) {
  routerHelper.configureStates(getStates())
}

function getStates () {
  return {
    'logout': {
      url: '/logout',
      controller: StateController,
      controllerAs: 'vm',
      title: N_('Logout')
    }
  }
}

/** @ngInject */
function StateController (Session, $window) {
  activate()

  function activate () {
    Session.destroy()
    $window.location.href = $window.location.href
  }
}
<commit_msg>If in production route to /ui/service/ if in dev route to /<commit_after>/** @ngInject */
export function LogoutState (routerHelper) {
  routerHelper.configureStates(getStates())
}

function getStates () {
  return {
    'logout': {
      url: '/logout',
      controller: StateController,
      controllerAs: 'vm',
      title: N_('Logout')
    }
  }
}

/** @ngInject */
function StateController (Session, $window) {
  activate()

  function activate () {
    Session.destroy()
    const location = $window.location.href
    if (location.includes(`/ui/service`)) {
      $window.location.href = `/ui/service/`
    } else {
      $window.location.href = `/`
    }
  }
}
<|endoftext|>


<commit_before>'use strict';

angular.module('umm3601ursamajorApp')

  .controller('SubformCtrl', function ($scope, $http, Auth, $location, socket, $filter, $window) {

    if(Auth.isLoggedIn() === false) {
        $location.path('/');
    }

    $scope.isAdmin = Auth.isAdmin;
    $scope.isLoggedIn = Auth.isLoggedIn;
    $scope.timestamp = Date();

    $scope.submissions = [];
    $scope.flaggedSubmissions = [];
    $scope.resubmitParent = null;

    $scope.updateFlaggedSubmissions = function(subs){
        $scope.flaggedSubmissions = $filter('filter')(subs, function(sub){return (sub.resubmissionData.resubmitFlag && (Auth.getCurrentUser().email === sub.presenterInfo.email))});
    };

    $http.get('/api/submissions').success(function(submissions) {
        $scope.submissions = submissions;
        $scope.updateFlaggedSubmissions(submissions);
        socket.syncUpdates('submission', $scope.submissions);
    });

    $scope.hasResubmitFlags = function(){
        return $scope.flaggedSubmissions.length > 0;
    };

    $scope.isResubmitting = false;

    $scope.formatOptions =
        ['Artist Statement',
         'Humanities Proposal',
         'Science or Social Science Abstract'
        ];

    $scope.presentationTypes =
        ['Poster or visual display',
         'Oral presentation',
         'Performance'
        ];

    $scope.fundingSources = [
        'UROP',
        'MAP',
        'MMP',
        'LSAMP'
    ];

    $scope.numberOfSources = $scope.fundingSources.length;

    $scope.teeSizes = [
        'S',
        'M',
        'L',
        'XL',
        'XXL',
        'XXXL'
    ];

    $scope.submissionData = {
        title: "",
        format: "",
        abstract: "",
        presentationType: "",
        formatChange: Boolean,
        presenterInfo: {first: "", last: "", email: ""},
        copresenterOne: {first: "", last: "", email: ""},
        copresenterTwo: {first: "", last: "", email: ""},
        discipline: "",
        sponsors: [],
        sponsorsFinal: [],
        adviserInfo: {first: "", last: "", email: ""},
        featuredPresentation: Boolean,
        mediaServicesEquipment: "",
        specialRequirements: "",
        presenterTeeSize: "",
        otherInfo: "",
        resubmitComment: "",
        resubmitParent: "",
        resubmitFlag: false
    };

    //Email for advisors
    var sendGmail = function(opts){
        var str = 'http://mail.google.com/mail/?view=cm&fs=1'+
            '&to=' + opts.to +
            '&su=' + opts.subject +
            '&body=' + opts.message +
            '&ui=1';
        $window.open(str);
    };

    $scope.getResubmitData = function(submission){
        var tempSponsors = [];
        var addedToggle = false;

        //fixed now (probably)
        for(var x = 0; x <= $scope.fundingSources.length; x++){
            addedToggle = false;
//            console.log("Main for loop, sponsor: " + $scope.fundingSources[x]);
//            console.log("Length of sponsors from submission: " + submission.sponsors.length);
//            console.log("X: " + x);
            for(var y = 0; y < submission.sponsors.length; y++){
//                console.log("final case? " + (x == $scope.fundingSources.length));
                if(x == $scope.fundingSources.length){
                    if(submission.sponsors[submission.sponsors.length - 1] != $scope.fundingSources[x -1]){
                        tempSponsors.push(submission.sponsors[submission.sponsors.length - 1]);
                    }
                    break;
                } else if(submission.sponsors[y] === $scope.fundingSources[x]){
                    tempSponsors.push(submission.sponsors[y]);
                    addedToggle = true;
                }
            }
            if(!addedToggle){
//                console.log("Added toggle false!");
                if(x == $scope.fundingSources.length){
                    addedToggle = !addedToggle;
                } else {
                    tempSponsors.push("");
                    addedToggle = !addedToggle;
                }
            }
//            console.log(tempSponsors);
        }
        console.log("~~~~~~~~~~~~~~sponsors from parent submission~~~~~~~~~~~~~~~~~~");
        console.log(tempSponsors);

        $scope.submissionData = {
            title: submission.title,
            format: submission.format,
            abstract: submission.abstract,
            presentationType: submission.presentationType,
            formatChange: submission.formatChange,
            presenterInfo: {first: submission.presenterInfo.first, last: submission.presenterInfo.last, email: submission.presenterInfo.email},
            copresenterOne: {first: submission.copresenterOneInfo.first, last: submission.copresenterOneInfo.last, email: submission.copresenterOneInfo.email},
            copresenterTwo: {first: submission.copresenterTwoInfo.first, last: submission.copresenterTwoInfo.last, email: submission.copresenterTwoInfo.email},
            discipline: submission.discipline,
            sponsors: tempSponsors,
            sponsorsFinal: [],
            adviserInfo: {first: submission.adviserInfo.first, last: submission.adviserInfo.last, email: submission.adviserInfo.email},
            featuredPresentation: submission.featured,
            mediaServicesEquipment: submission.mediaServicesEquipment,
            specialRequirements: submission.specialRequirements,
            presenterTeeSize: submission.presenterTeeSize,
            otherInfo: submission.otherInfo,
            resubmitComment: "",
            resubmitParent: submission._id,
            resubmitFlag: false
        };

        $scope.isResubmitting = true;
        $scope.resubmitParent = submission;
    };

    $scope.submissionTextArray = [];

    $scope.submissionText = {};

    $http.get('/api/subformtexts').success(function(submissionTextArray) {
        $scope.submissionTextArray = submissionTextArray;
        $scope.submissionText = $scope.submissionTextArray[0];
    });

    $scope.checkEmailsAreMorris = function (){
        var presenterEmail = $scope.submissionData.presenterInfo.email;
        var copresenterOneEmail = $scope.submissionData.copresenterOne.email;
        var copresenterTwoEmail = $scope.submissionData.copresenterTwo.email;

        var presenterCheck = (presenterEmail.indexOf("morris.umn.edu") != -1);

        if(copresenterOneEmail != ""){
            var copresenterOneCheck = (copresenterOneEmail.indexOf("morris.umn.edu") != -1);
        } else{
            var copresenterOneCheck = true;
        }

        if(copresenterTwoEmail != ""){
            var copresenterTwoCheck = (copresenterTwoEmail.indexOf("morris.umn.edu") != -1);
        } else{
            var copresenterTwoCheck = true;
        }

        return presenterCheck && copresenterOneCheck && copresenterTwoCheck;
    };

    $scope.submitSubmission = function(){
        if($scope.checkEmailsAreMorris() === true) {
            var r = confirm("Are you sure you want to submit?");
            if (r) {
                for (var i = 0; i < $scope.submissionData.sponsors.length; i++) {
                    if ($scope.submissionData.sponsors[i] != "" && $scope.submissionData.sponsors[i] != null) {
                        $scope.submissionData.sponsorsFinal.push($scope.submissionData.sponsors[i]);
                    }
                }
                console.log('posting Data!');
                $http.post('/api/submissions/',
                    {   title: $scope.submissionData.title,
                        format: $scope.submissionData.format,
                        abstract: $scope.submissionData.abstract,
                        presentationType: $scope.submissionData.presentationType,
                        formatChange: $scope.submissionData.formatChange,
                        presenterInfo: {first: $scope.submissionData.presenterInfo.first, last: $scope.submissionData.presenterInfo.last, email: $scope.submissionData.presenterInfo.email},
                        copresenterOneInfo: {first: $scope.submissionData.copresenterOne.first, last: $scope.submissionData.copresenterOne.last, email: $scope.submissionData.copresenterOne.email},
                        copresenterTwoInfo: {first: $scope.submissionData.copresenterTwo.first, last: $scope.submissionData.copresenterTwo.last, email: $scope.submissionData.copresenterTwo.email},
                        discipline: $scope.submissionData.discipline,
                        sponsors: $scope.submissionData.sponsorsFinal,
                        adviserInfo: {first: $scope.submissionData.adviserInfo.first, last: $scope.submissionData.adviserInfo.last, email: $scope.submissionData.adviserInfo.email},
                        featured: $scope.submissionData.featuredPresentation,
                        mediaServicesEquipment: $scope.submissionData.mediaServicesEquipment,
                        specialRequirements: $scope.submissionData.specialRequirements,
                        presenterTeeSize: $scope.submissionData.presenterTeeSize,
                        otherInfo: $scope.submissionData.otherInfo,
                        approval: false,
                        status: {strict: "Awaiting Adviser Approval", text: "Adviser has not been notified"},
                        timestamp: $scope.timestamp,
                        group: 0,
                        resubmissionData: {comment: $scope.submissionData.resubmitComment, parentSubmission: $scope.submissionData.resubmitParent, isPrimary: false, resubmitFlag: $scope.submissionData.resubmitFlag }
                    });
            }
            ;

            if (r) {
                alert("Please send the email that is about to be generated.");
                sendGmail({
                    to: $scope.submissionData.adviserInfo.email,
                    subject: 'URS Submission requires approval',
                    message: $scope.submissionData.presenterInfo.first + " " + $scope.submissionData.presenterInfo.last +
                        ' has submitted a URS submission that requires your approval. Please go to https://ursa-major.herokuapp.com/ to log in and approve the submission.'
                });
            }
            if ($scope.isResubmitting && r) {
                $http.patch('api/submissions/' + $scope.submissionData.resubmitParent,
                    // This is only setting false right now. comment and submission donot get stored.
                    {resubmissionData: {comment: $scope.resubmitParent.resubmissionData.comment, parentSubmission: $scope.resubmitParent.resubmissionData.parentSubmission, resubmitFlag: false}}
                ).success(function () {
                        console.log("Successfully unflagged the original submission for resbumission.");
                    });
            }
            if (r) {
                $scope.resetData();
                $location.path('/submissionpage');
            }
        } else{
            $window.alert("One of the emails you entered is not a UMN Morris email.");
        }
    };

    $scope.charsRemaining = function() {
        return 1000 - $scope.submissionData.abstract.length;
    };

    $scope.resetData = function(){
        $scope.submissionData = {
            title: "",
            format: "",
            abstract: "",
            presentationType: "",
            formatChange: Boolean,
            presenterInfo: {first: "", last: "", email: ""},
            copresenterOne: {first: "", last: "", email: ""},
            copresenterTwo: {first: "", last: "", email: ""},
            discipline: "",
            sponsors: ["","","","",""], //Might need to worry about if this is static for the DB later.
            adviserInfo: {first: "", last: "", email: ""},
            featuredPresentation: Boolean,
            mediaServicesEquipment: "",
            specialRequirements: "",
            presenterTeeSize: "",
            otherInfo: ""
        };
    };

  });
<commit_msg>THe new field for comments in the model for submissions was not having anything initially pushed to the database for it from the original submission form. Added in an empty comments array that gets added to a submission when it is first created by the submission form. -JPO<commit_after>'use strict';

angular.module('umm3601ursamajorApp')

  .controller('SubformCtrl', function ($scope, $http, Auth, $location, socket, $filter, $window) {

    if(Auth.isLoggedIn() === false) {
        $location.path('/');
    }

    $scope.isAdmin = Auth.isAdmin;
    $scope.isLoggedIn = Auth.isLoggedIn;
    $scope.timestamp = Date();

    $scope.submissions = [];
    $scope.flaggedSubmissions = [];
    $scope.resubmitParent = null;

    $scope.updateFlaggedSubmissions = function(subs){
        $scope.flaggedSubmissions = $filter('filter')(subs, function(sub){return (sub.resubmissionData.resubmitFlag && (Auth.getCurrentUser().email === sub.presenterInfo.email))});
    };

    $http.get('/api/submissions').success(function(submissions) {
        $scope.submissions = submissions;
        $scope.updateFlaggedSubmissions(submissions);
        socket.syncUpdates('submission', $scope.submissions);
    });

    $scope.hasResubmitFlags = function(){
        return $scope.flaggedSubmissions.length > 0;
    };

    $scope.isResubmitting = false;

    $scope.formatOptions =
        ['Artist Statement',
         'Humanities Proposal',
         'Science or Social Science Abstract'
        ];

    $scope.presentationTypes =
        ['Poster or visual display',
         'Oral presentation',
         'Performance'
        ];

    $scope.fundingSources = [
        'UROP',
        'MAP',
        'MMP',
        'LSAMP'
    ];

    $scope.numberOfSources = $scope.fundingSources.length;

    $scope.teeSizes = [
        'S',
        'M',
        'L',
        'XL',
        'XXL',
        'XXXL'
    ];

    $scope.submissionData = {
        title: "",
        format: "",
        abstract: "",
        presentationType: "",
        formatChange: Boolean,
        presenterInfo: {first: "", last: "", email: ""},
        copresenterOne: {first: "", last: "", email: ""},
        copresenterTwo: {first: "", last: "", email: ""},
        discipline: "",
        sponsors: [],
        sponsorsFinal: [],
        adviserInfo: {first: "", last: "", email: ""},
        featuredPresentation: Boolean,
        mediaServicesEquipment: "",
        specialRequirements: "",
        presenterTeeSize: "",
        otherInfo: "",
        resubmitComment: "",
        resubmitParent: "",
        resubmitFlag: false
    };

    //Email for advisors
    var sendGmail = function(opts){
        var str = 'http://mail.google.com/mail/?view=cm&fs=1'+
            '&to=' + opts.to +
            '&su=' + opts.subject +
            '&body=' + opts.message +
            '&ui=1';
        $window.open(str);
    };

    $scope.getResubmitData = function(submission){
        var tempSponsors = [];
        var addedToggle = false;

        //fixed now (probably)
        for(var x = 0; x <= $scope.fundingSources.length; x++){
            addedToggle = false;
//            console.log("Main for loop, sponsor: " + $scope.fundingSources[x]);
//            console.log("Length of sponsors from submission: " + submission.sponsors.length);
//            console.log("X: " + x);
            for(var y = 0; y < submission.sponsors.length; y++){
//                console.log("final case? " + (x == $scope.fundingSources.length));
                if(x == $scope.fundingSources.length){
                    if(submission.sponsors[submission.sponsors.length - 1] != $scope.fundingSources[x -1]){
                        tempSponsors.push(submission.sponsors[submission.sponsors.length - 1]);
                    }
                    break;
                } else if(submission.sponsors[y] === $scope.fundingSources[x]){
                    tempSponsors.push(submission.sponsors[y]);
                    addedToggle = true;
                }
            }
            if(!addedToggle){
//                console.log("Added toggle false!");
                if(x == $scope.fundingSources.length){
                    addedToggle = !addedToggle;
                } else {
                    tempSponsors.push("");
                    addedToggle = !addedToggle;
                }
            }
//            console.log(tempSponsors);
        }
        console.log("~~~~~~~~~~~~~~sponsors from parent submission~~~~~~~~~~~~~~~~~~");
        console.log(tempSponsors);

        $scope.submissionData = {
            title: submission.title,
            format: submission.format,
            abstract: submission.abstract,
            presentationType: submission.presentationType,
            formatChange: submission.formatChange,
            presenterInfo: {first: submission.presenterInfo.first, last: submission.presenterInfo.last, email: submission.presenterInfo.email},
            copresenterOne: {first: submission.copresenterOneInfo.first, last: submission.copresenterOneInfo.last, email: submission.copresenterOneInfo.email},
            copresenterTwo: {first: submission.copresenterTwoInfo.first, last: submission.copresenterTwoInfo.last, email: submission.copresenterTwoInfo.email},
            discipline: submission.discipline,
            sponsors: tempSponsors,
            sponsorsFinal: [],
            adviserInfo: {first: submission.adviserInfo.first, last: submission.adviserInfo.last, email: submission.adviserInfo.email},
            featuredPresentation: submission.featured,
            mediaServicesEquipment: submission.mediaServicesEquipment,
            specialRequirements: submission.specialRequirements,
            presenterTeeSize: submission.presenterTeeSize,
            otherInfo: submission.otherInfo,
            resubmitComment: "",
            resubmitParent: submission._id,
            resubmitFlag: false
        };

        $scope.isResubmitting = true;
        $scope.resubmitParent = submission;
    };

    $scope.submissionTextArray = [];

    $scope.submissionText = {};

    $http.get('/api/subformtexts').success(function(submissionTextArray) {
        $scope.submissionTextArray = submissionTextArray;
        $scope.submissionText = $scope.submissionTextArray[0];
    });

    $scope.checkEmailsAreMorris = function (){
        var presenterEmail = $scope.submissionData.presenterInfo.email;
        var copresenterOneEmail = $scope.submissionData.copresenterOne.email;
        var copresenterTwoEmail = $scope.submissionData.copresenterTwo.email;

        var presenterCheck = (presenterEmail.indexOf("morris.umn.edu") != -1);

        if(copresenterOneEmail != ""){
            var copresenterOneCheck = (copresenterOneEmail.indexOf("morris.umn.edu") != -1);
        } else{
            var copresenterOneCheck = true;
        }

        if(copresenterTwoEmail != ""){
            var copresenterTwoCheck = (copresenterTwoEmail.indexOf("morris.umn.edu") != -1);
        } else{
            var copresenterTwoCheck = true;
        }

        return presenterCheck && copresenterOneCheck && copresenterTwoCheck;
    };

    $scope.submitSubmission = function(){
        if($scope.checkEmailsAreMorris() === true) {
            var r = confirm("Are you sure you want to submit?");
            if (r) {
                for (var i = 0; i < $scope.submissionData.sponsors.length; i++) {
                    if ($scope.submissionData.sponsors[i] != "" && $scope.submissionData.sponsors[i] != null) {
                        $scope.submissionData.sponsorsFinal.push($scope.submissionData.sponsors[i]);
                    }
                }
                console.log('posting Data!');
                $http.post('/api/submissions/',
                    {   title: $scope.submissionData.title,
                        format: $scope.submissionData.format,
                        abstract: $scope.submissionData.abstract,
                        presentationType: $scope.submissionData.presentationType,
                        formatChange: $scope.submissionData.formatChange,
                        presenterInfo: {first: $scope.submissionData.presenterInfo.first, last: $scope.submissionData.presenterInfo.last, email: $scope.submissionData.presenterInfo.email},
                        copresenterOneInfo: {first: $scope.submissionData.copresenterOne.first, last: $scope.submissionData.copresenterOne.last, email: $scope.submissionData.copresenterOne.email},
                        copresenterTwoInfo: {first: $scope.submissionData.copresenterTwo.first, last: $scope.submissionData.copresenterTwo.last, email: $scope.submissionData.copresenterTwo.email},
                        discipline: $scope.submissionData.discipline,
                        sponsors: $scope.submissionData.sponsorsFinal,
                        adviserInfo: {first: $scope.submissionData.adviserInfo.first, last: $scope.submissionData.adviserInfo.last, email: $scope.submissionData.adviserInfo.email},
                        featured: $scope.submissionData.featuredPresentation,
                        mediaServicesEquipment: $scope.submissionData.mediaServicesEquipment,
                        specialRequirements: $scope.submissionData.specialRequirements,
                        presenterTeeSize: $scope.submissionData.presenterTeeSize,
                        otherInfo: $scope.submissionData.otherInfo,
                        approval: false,
                        status: {strict: "Awaiting Adviser Approval", text: "Adviser has not been notified"},
                        timestamp: $scope.timestamp,
                        group: 0,
                        resubmissionData: {comment: $scope.submissionData.resubmitComment, parentSubmission: $scope.submissionData.resubmitParent, isPrimary: false, resubmitFlag: $scope.submissionData.resubmitFlag },
                        comments: []
                    });
            }
            ;

            if (r) {
                alert("Please send the email that is about to be generated.");
                sendGmail({
                    to: $scope.submissionData.adviserInfo.email,
                    subject: 'URS Submission requires approval',
                    message: $scope.submissionData.presenterInfo.first + " " + $scope.submissionData.presenterInfo.last +
                        ' has submitted a URS submission that requires your approval. Please go to https://ursa-major.herokuapp.com/ to log in and approve the submission.'
                });
            }
            if ($scope.isResubmitting && r) {
                $http.patch('api/submissions/' + $scope.submissionData.resubmitParent,
                    // This is only setting false right now. comment and submission donot get stored.
                    {resubmissionData: {comment: $scope.resubmitParent.resubmissionData.comment, parentSubmission: $scope.resubmitParent.resubmissionData.parentSubmission, resubmitFlag: false}}
                ).success(function () {
                        console.log("Successfully unflagged the original submission for resbumission.");
                    });
            }
            if (r) {
                $scope.resetData();
                $location.path('/submissionpage');
            }
        } else{
            $window.alert("One of the emails you entered is not a UMN Morris email.");
        }
    };

    $scope.charsRemaining = function() {
        return 1000 - $scope.submissionData.abstract.length;
    };

    $scope.resetData = function(){
        $scope.submissionData = {
            title: "",
            format: "",
            abstract: "",
            presentationType: "",
            formatChange: Boolean,
            presenterInfo: {first: "", last: "", email: ""},
            copresenterOne: {first: "", last: "", email: ""},
            copresenterTwo: {first: "", last: "", email: ""},
            discipline: "",
            sponsors: ["","","","",""], //Might need to worry about if this is static for the DB later.
            adviserInfo: {first: "", last: "", email: ""},
            featuredPresentation: Boolean,
            mediaServicesEquipment: "",
            specialRequirements: "",
            presenterTeeSize: "",
            otherInfo: ""
        };
    };

  });
<|endoftext|>


<commit_before>window.common = (function(global) {
  const {
    Rx: { Observable },
    common = { init: [] }
  } = global;

  var libraryIncludes = `
<link
  rel='stylesheet'
  href='//cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.0/animate.min.css'
  />
<link
  rel='stylesheet'
  href='//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css'
  />

<link
  rel='stylesheet'
  href='//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css'
  />
<script src='https://cdn.jsdelivr.net/jquery/1.9.0/jquery.js'></script>
<style>
  body { padding: 0px 3px 0px 3px; }
</style>
  `;

  const iFrameScript$ =
    common.getScriptContent$('/js/iFrameScripts.js').shareReplay();

  // runPreviewTests$ should be set up in the preview window
  common.runPreviewTests$ =
    () => Observable.throw({ err: new Error('run preview not enabled') });

  common.updatePreview$ = function updatePreview$(code = '') {
    const previewFrame = document.getElementById('preview');
    const preview = previewFrame.contentDocument ||
      previewFrame.contentWindow.document;
    if (!preview) {
      return Observable.just(code);
    }

    return iFrameScript$
      .map(script => `<script>${script}</script>`)
      .flatMap(script => {
        preview.open();
        preview.write(libraryIncludes + code + '<!-- -->' + script);
        preview.close();
        return Observable.fromCallback($(preview).ready, $(preview))()
          .first()
          // delay is need here for first initial run
          .delay(50);
      })
      .map(() => code);
  };

  return common;
}(window));
<commit_msg>Increase updatePreview delay<commit_after>window.common = (function(global) {
  const {
    Rx: { Observable },
    common = { init: [] }
  } = global;

  var libraryIncludes = `
<link
  rel='stylesheet'
  href='//cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.0/animate.min.css'
  />
<link
  rel='stylesheet'
  href='//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css'
  />

<link
  rel='stylesheet'
  href='//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css'
  />
<script src='https://cdn.jsdelivr.net/jquery/1.9.0/jquery.js'></script>
<style>
  body { padding: 0px 3px 0px 3px; }
</style>
  `;

  const iFrameScript$ =
    common.getScriptContent$('/js/iFrameScripts.js').shareReplay();

  // runPreviewTests$ should be set up in the preview window
  common.runPreviewTests$ =
    () => Observable.throw({ err: new Error('run preview not enabled') });

  common.updatePreview$ = function updatePreview$(code = '') {
    const previewFrame = document.getElementById('preview');
    const preview = previewFrame.contentDocument ||
      previewFrame.contentWindow.document;
    if (!preview) {
      return Observable.just(code);
    }

    return iFrameScript$
      .map(script => `<script>${script}</script>`)
      .flatMap(script => {
        preview.open();
        preview.write(libraryIncludes + code + '<!-- -->' + script);
        preview.close();
        return Observable.fromCallback($(preview).ready, $(preview))()
          .first()
          // delay is need here for first initial run
          .delay(100);
      })
      .map(() => code);
  };

  return common;
}(window));
<|endoftext|>