<commit_before>import get from 'lodash/get';
import find from 'lodash/find';
import filter from 'lodash/filter';
import values from 'lodash/values';
import map from 'lodash/map';
import FirebasePersistor from '../persistors/FirebasePersistor';
import Gists from '../services/Gists';
import appFirebase from '../services/appFirebase';
import validations from '../validations';

import {createProject, changeCurrentProject} from './projects';
import {
  userTyped,
  userRequestedFocusedLine,
  editorFocusedRequestedLine,
  applicationErrorTriggered,
  userDismissedApplicationError,
} from './ui';
import {exportingGist} from './clients';
import {isPristineProject} from '../util/projectUtils';

function generateProjectKey() {
  const date = new Date();
  return (date.getTime() * 1000 + date.getMilliseconds()).toString();
}

function getCurrentPersistor(state) {
  const currentUser = state.user.toJS();
  if (currentUser.authenticated) {
    return new FirebasePersistor(currentUser);
  }
  return null;
}

export function getCurrentProject(state) {
  const projectKey = state.currentProject.get('projectKey');
  if (projectKey) {
    return state.projects.get(projectKey);
  }

  return null;
}

export function saveCurrentProject(state) {
  const currentProject = getCurrentProject(state);
  const persistor = getCurrentPersistor(state);

  if (persistor && currentProject && !isPristineProject(currentProject)) {
    persistor.saveCurrentProject(currentProject.toJS());
    return true;
  }

  return false;
}

function validateSource(language, source, enabledLibraries) {
  return (dispatch, getState) => {
    const validate = validations[language];
    validate(source, enabledLibraries.toJS()).then((errors) => {
      const currentSource = getCurrentProject(getState()).
        get('sources').get(language);

      if (currentSource !== source) {
        return;
      }

      dispatch({
        type: 'VALIDATED_SOURCE',
        payload: {
          language,
          errors,
        },
      });
    });
  };
}

export function validateAllSources(project) {
  return (dispatch) => {
    const enabledLibraries = project.get('enabledLibraries');
    project.get('sources').forEach((source, language) => {
      dispatch(validateSource(language, source, enabledLibraries));
    });
  };
}

function ensureProject() {
  return (dispatch, getState) => {
    if (getCurrentProject(getState()) === null) {
      dispatch(createProject());
    }
  };
}

function loadCurrentProjectFromStorage() {
  return (dispatch, getState) => {
    const persistor = getCurrentPersistor(getState());
    if (persistor === null) {
      dispatch(createProject());
      return;
    }

    persistor.getCurrentProjectKey().then((projectKey) => {
      if (projectKey) {
        persistor.load(projectKey).then((project) => {
          dispatch({
            type: 'CURRENT_PROJECT_LOADED_FROM_STORAGE',
            payload: {project},
          });

          dispatch(validateAllSources(getCurrentProject(getState())));
        });
      } else {
        dispatch(ensureProject());
      }
    });
  };
}

function updateProjectSource(projectKey, language, newValue) {
  return (dispatch, getState) => {
    dispatch({
      type: 'PROJECT_SOURCE_EDITED',
      meta: {timestamp: Date.now()},
      payload: {
        projectKey,
        language,
        newValue,
      },
    });

    const state = getState();
    saveCurrentProject(state);

    const currentProject = getCurrentProject(state);
    dispatch(validateSource(
      language,
      newValue,
      currentProject.get('enabledLibraries')
    ));
  };
}

function toggleLibrary(projectKey, libraryKey) {
  return (dispatch, getState) => {
    dispatch({
      type: 'PROJECT_LIBRARY_TOGGLED',
      meta: {timestamp: Date.now()},
      payload: {
        projectKey,
        libraryKey,
      },
    });

    const state = getState();
    dispatch(validateAllSources(getCurrentProject(state)));
    saveCurrentProject(state);
  };
}

function loadAllProjects() {
  return (dispatch, getState) => {
    const persistor = getCurrentPersistor(getState());
    if (persistor === null) {
      return;
    }

    persistor.all().then((projects) => {
      projects.forEach((project) => {
        dispatch({
          type: 'PROJECT_LOADED_FROM_STORAGE',
          payload: {project},
        });
      });
    });
  };
}

function addRuntimeError(error) {
  return {
    type: 'RUNTIME_ERROR_ADDED',
    payload: {error},
  };
}

function clearRuntimeErrors() {
  return {
    type: 'RUNTIME_ERRORS_CLEARED',
  };
}

function resetWorkspace() {
  return {type: 'RESET_WORKSPACE'};
}

function userAuthenticated(authData) {
  return {type: 'USER_AUTHENTICATED', payload: authData};
}

function logIn(authData) {
  return (dispatch, getState) => {
    dispatch(userAuthenticated(authData));

    if (!saveCurrentProject(getState())) {
      dispatch(resetWorkspace());
      dispatch(loadCurrentProjectFromStorage());
    }

    dispatch(loadAllProjects());
  };
}

function userLoggedOut() {
  return {type: 'USER_LOGGED_OUT'};
}

function logOut() {
  return (dispatch) => {
    dispatch(userLoggedOut());
    dispatch(resetWorkspace());
    dispatch(createProject());
  };
}

function initializeCurrentProjectFromGist(gistData) {
  return (dispatch) => {
    const projectKey = generateProjectKey();
    dispatch(importProjectFromGist(projectKey, gistData));
    dispatch(changeCurrentProject(projectKey));
  };
}

function importProjectFromGist(projectKey, gistData) {
  const files = values(gistData.files);
  const popcodeJson = parsePopcodeJson(files);
  const project = {
    projectKey,
    sources: {
      html: get(find(files, {language: 'HTML'}), 'content', ''),
      css: map(filter(files, {language: 'CSS'}), 'content').join('\n\n'),
      javascript: map(filter(files, {language: 'JavaScript'}), 'content').
        join('\n\n'),
    },
    enabledLibraries: popcodeJson.enabledLibraries || [],
    updatedAt: Date.now(),
  };

  return {
    type: 'PROJECT_IMPORTED',
    payload: {project},
  };
}

function parsePopcodeJson(files) {
  const popcodeJsonFile = find(files, {filename: 'popcode.json'});
  if (!popcodeJsonFile) {
    return {};
  }
  return JSON.parse(get(popcodeJsonFile, 'content', '{}'));
}

function minimizeComponent(componentName) {
  return {
    type: 'COMPONENT_MINIMIZED',
    payload: {componentName},
  };
}

function maximizeComponent(componentName) {
  return {
    type: 'COMPONENT_MAXIMIZED',
    payload: {componentName},
  };
}

function toggleDashboard() {
  return {type: 'DASHBOARD_TOGGLED'};
}

function toggleDashboardSubmenu(submenu) {
  return {type: 'DASHBOARD_SUBMENU_TOGGLED', payload: {submenu}};
}

function bootstrap({gistId} = {gistId: null}) {
  return (dispatch, getState) => {
    const initialAuth = new Promise((resolve) => {
      appFirebase.onAuth((authData) => {
        if (authData === null) {
          dispatch(logOut());
        } else {
          dispatch(logIn(authData));
        }
        resolve();
      });
    });

    let gistLoaded;
    if (gistId) {
      gistLoaded =
        Gists.loadFromId(gistId, getState().user.toJS()).catch((error) => {
          if (get(error, 'response.status') === 404) {
            dispatch(applicationErrorTriggered('gist-import-not-found'));
            return Promise.resolve();
          }
          return Promise.reject(error);
        });
    } else {
      gistLoaded = Promise.resolve();
    }

    Promise.all([gistLoaded, initialAuth]).then(([gistData]) => {
      if (gistData) {
        dispatch(initializeCurrentProjectFromGist(gistData));
      }
    });
  };
}

export {
  createProject,
  changeCurrentProject,
  loadCurrentProjectFromStorage,
  loadAllProjects,
  updateProjectSource,
  toggleLibrary,
  addRuntimeError,
  clearRuntimeErrors,
  minimizeComponent,
  maximizeComponent,
  toggleDashboard,
  toggleDashboardSubmenu,
  userTyped,
  userRequestedFocusedLine,
  editorFocusedRequestedLine,
  applicationErrorTriggered,
  userDismissedApplicationError,
  exportingGist,
  bootstrap,
  importProjectFromGist,
};
<commit_msg>Temporarily log the user ID on login<commit_after>import get from 'lodash/get';
import find from 'lodash/find';
import filter from 'lodash/filter';
import values from 'lodash/values';
import map from 'lodash/map';
import isFunction from 'lodash/isFunction';
import FirebasePersistor from '../persistors/FirebasePersistor';
import Gists from '../services/Gists';
import appFirebase from '../services/appFirebase';
import validations from '../validations';

import {createProject, changeCurrentProject} from './projects';
import {
  userTyped,
  userRequestedFocusedLine,
  editorFocusedRequestedLine,
  applicationErrorTriggered,
  userDismissedApplicationError,
} from './ui';
import {exportingGist} from './clients';
import {isPristineProject} from '../util/projectUtils';

function generateProjectKey() {
  const date = new Date();
  return (date.getTime() * 1000 + date.getMilliseconds()).toString();
}

function getCurrentPersistor(state) {
  const currentUser = state.user.toJS();
  if (currentUser.authenticated) {
    return new FirebasePersistor(currentUser);
  }
  return null;
}

export function getCurrentProject(state) {
  const projectKey = state.currentProject.get('projectKey');
  if (projectKey) {
    return state.projects.get(projectKey);
  }

  return null;
}

export function saveCurrentProject(state) {
  const currentProject = getCurrentProject(state);
  const persistor = getCurrentPersistor(state);

  if (persistor && currentProject && !isPristineProject(currentProject)) {
    persistor.saveCurrentProject(currentProject.toJS());
    return true;
  }

  return false;
}

function validateSource(language, source, enabledLibraries) {
  return (dispatch, getState) => {
    const validate = validations[language];
    validate(source, enabledLibraries.toJS()).then((errors) => {
      const currentSource = getCurrentProject(getState()).
        get('sources').get(language);

      if (currentSource !== source) {
        return;
      }

      dispatch({
        type: 'VALIDATED_SOURCE',
        payload: {
          language,
          errors,
        },
      });
    });
  };
}

export function validateAllSources(project) {
  return (dispatch) => {
    const enabledLibraries = project.get('enabledLibraries');
    project.get('sources').forEach((source, language) => {
      dispatch(validateSource(language, source, enabledLibraries));
    });
  };
}

function ensureProject() {
  return (dispatch, getState) => {
    if (getCurrentProject(getState()) === null) {
      dispatch(createProject());
    }
  };
}

function loadCurrentProjectFromStorage() {
  return (dispatch, getState) => {
    const persistor = getCurrentPersistor(getState());
    if (persistor === null) {
      dispatch(createProject());
      return;
    }

    persistor.getCurrentProjectKey().then((projectKey) => {
      if (projectKey) {
        persistor.load(projectKey).then((project) => {
          dispatch({
            type: 'CURRENT_PROJECT_LOADED_FROM_STORAGE',
            payload: {project},
          });

          dispatch(validateAllSources(getCurrentProject(getState())));
        });
      } else {
        dispatch(ensureProject());
      }
    });
  };
}

function updateProjectSource(projectKey, language, newValue) {
  return (dispatch, getState) => {
    dispatch({
      type: 'PROJECT_SOURCE_EDITED',
      meta: {timestamp: Date.now()},
      payload: {
        projectKey,
        language,
        newValue,
      },
    });

    const state = getState();
    saveCurrentProject(state);

    const currentProject = getCurrentProject(state);
    dispatch(validateSource(
      language,
      newValue,
      currentProject.get('enabledLibraries')
    ));
  };
}

function toggleLibrary(projectKey, libraryKey) {
  return (dispatch, getState) => {
    dispatch({
      type: 'PROJECT_LIBRARY_TOGGLED',
      meta: {timestamp: Date.now()},
      payload: {
        projectKey,
        libraryKey,
      },
    });

    const state = getState();
    dispatch(validateAllSources(getCurrentProject(state)));
    saveCurrentProject(state);
  };
}

function loadAllProjects() {
  return (dispatch, getState) => {
    const persistor = getCurrentPersistor(getState());
    if (persistor === null) {
      return;
    }

    persistor.all().then((projects) => {
      projects.forEach((project) => {
        dispatch({
          type: 'PROJECT_LOADED_FROM_STORAGE',
          payload: {project},
        });
      });
    });
  };
}

function addRuntimeError(error) {
  return {
    type: 'RUNTIME_ERROR_ADDED',
    payload: {error},
  };
}

function clearRuntimeErrors() {
  return {
    type: 'RUNTIME_ERRORS_CLEARED',
  };
}

function resetWorkspace() {
  return {type: 'RESET_WORKSPACE'};
}

function userAuthenticated(authData) {
  return {type: 'USER_AUTHENTICATED', payload: authData};
}

function logIn(authData) {
  return (dispatch, getState) => {
    dispatch(userAuthenticated(authData));

    if (!saveCurrentProject(getState())) {
      dispatch(resetWorkspace());
      dispatch(loadCurrentProjectFromStorage());
    }

    dispatch(loadAllProjects());
  };
}

function userLoggedOut() {
  return {type: 'USER_LOGGED_OUT'};
}

function logOut() {
  return (dispatch) => {
    dispatch(userLoggedOut());
    dispatch(resetWorkspace());
    dispatch(createProject());
  };
}

function initializeCurrentProjectFromGist(gistData) {
  return (dispatch) => {
    const projectKey = generateProjectKey();
    dispatch(importProjectFromGist(projectKey, gistData));
    dispatch(changeCurrentProject(projectKey));
  };
}

function importProjectFromGist(projectKey, gistData) {
  const files = values(gistData.files);
  const popcodeJson = parsePopcodeJson(files);
  const project = {
    projectKey,
    sources: {
      html: get(find(files, {language: 'HTML'}), 'content', ''),
      css: map(filter(files, {language: 'CSS'}), 'content').join('\n\n'),
      javascript: map(filter(files, {language: 'JavaScript'}), 'content').
        join('\n\n'),
    },
    enabledLibraries: popcodeJson.enabledLibraries || [],
    updatedAt: Date.now(),
  };

  return {
    type: 'PROJECT_IMPORTED',
    payload: {project},
  };
}

function parsePopcodeJson(files) {
  const popcodeJsonFile = find(files, {filename: 'popcode.json'});
  if (!popcodeJsonFile) {
    return {};
  }
  return JSON.parse(get(popcodeJsonFile, 'content', '{}'));
}

function minimizeComponent(componentName) {
  return {
    type: 'COMPONENT_MINIMIZED',
    payload: {componentName},
  };
}

function maximizeComponent(componentName) {
  return {
    type: 'COMPONENT_MAXIMIZED',
    payload: {componentName},
  };
}

function toggleDashboard() {
  return {type: 'DASHBOARD_TOGGLED'};
}

function toggleDashboardSubmenu(submenu) {
  return {type: 'DASHBOARD_SUBMENU_TOGGLED', payload: {submenu}};
}

function bootstrap({gistId} = {gistId: null}) {
  return (dispatch, getState) => {
    const initialAuth = new Promise((resolve) => {
      appFirebase.onAuth((authData) => {
        if (authData === null) {
          dispatch(logOut());
        } else {
          if (isFunction(get(window, 'console.log'))) {
            // eslint-disable-next-line no-console
            console.log('logged in with user ID', authData.uid);
          }
          dispatch(logIn(authData));
        }
        resolve();
      });
    });

    let gistLoaded;
    if (gistId) {
      gistLoaded =
        Gists.loadFromId(gistId, getState().user.toJS()).catch((error) => {
          if (get(error, 'response.status') === 404) {
            dispatch(applicationErrorTriggered('gist-import-not-found'));
            return Promise.resolve();
          }
          return Promise.reject(error);
        });
    } else {
      gistLoaded = Promise.resolve();
    }

    Promise.all([gistLoaded, initialAuth]).then(([gistData]) => {
      if (gistData) {
        dispatch(initializeCurrentProjectFromGist(gistData));
      }
    });
  };
}

export {
  createProject,
  changeCurrentProject,
  loadCurrentProjectFromStorage,
  loadAllProjects,
  updateProjectSource,
  toggleLibrary,
  addRuntimeError,
  clearRuntimeErrors,
  minimizeComponent,
  maximizeComponent,
  toggleDashboard,
  toggleDashboardSubmenu,
  userTyped,
  userRequestedFocusedLine,
  editorFocusedRequestedLine,
  applicationErrorTriggered,
  userDismissedApplicationError,
  exportingGist,
  bootstrap,
  importProjectFromGist,
};
<|endoftext|>


<commit_before>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
"use strict";

class ModuleDependencyTemplateAsId {

	apply(dep, source, outputOptions, requestShortener) {
		if(!dep.range) return;
		let comment = "";
		if(outputOptions.pathinfo) comment = "/*! " + requestShortener.shorten(dep.request) + " */ ";
		let content;
		if(dep.module)
			content = comment + JSON.stringify(dep.module.id);
		else
			content = require("./WebpackMissingModule").module(dep.request);
		source.replace(dep.range[0], dep.range[1] - 1, content);
	}
}
module.exports = ModuleDependencyTemplateAsId;
<commit_msg>use template string<commit_after>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
"use strict";

class ModuleDependencyTemplateAsId {

	apply(dep, source, outputOptions, requestShortener) {
		if(!dep.range) return;
		let comment = "";
		if(outputOptions.pathinfo) comment = `/*! ${requestShortener.shorten(dep.request)} */ `;
		let content;
		if(dep.module)
			content = comment + JSON.stringify(dep.module.id);
		else
			content = require("./WebpackMissingModule").module(dep.request);
		source.replace(dep.range[0], dep.range[1] - 1, content);
	}
}
module.exports = ModuleDependencyTemplateAsId;
<|endoftext|>


<commit_before>// Adapted from https://github.com/Lighthouse-io/react-visjs-timeline

import vis from 'vis';
import React, { Component, PropTypes } from 'react';
import ReplayControls from '../containers/ReplayControls';
import Link from './Link';
import FontAwesome from 'react-fontawesome';

const eventPropTypes = {};

export default class Timeline extends Component {
  static propTypes = {
    removeItem: PropTypes.func.isRequired,
    moveItem: PropTypes.func.isRequired,
  };

  componentWillMount() {
    this.state = {};
  }

  componentDidMount() {
    this.init();
  }

  shouldComponentUpdate(nextProps) {
    const {
      items,
      options,
      start,
      end,
    } = this.props;

    const timeChange = (start !== nextProps.start || end !== nextProps.end);
    const itemsChange = items !== nextProps.items;
    const optionsChange = options !== nextProps.options;

    return itemsChange || optionsChange || timeChange;
  }

  componentDidUpdate() {
    this.init();
  }

  componentWillUnmount() {
    this.TimelineElement.destroy();
  }

  init() {
    const { container } = this.refs;
    let $el = this.TimelineElement;

    const {
      items,
      options,
      start,
      end,
      removeItem,
      moveItem,
    } = this.props;

    let timelineItems;

    if (start && end) {
      const replayItem = {
        id: -1,
        type: 'range',
        content: 'Replay',
        start,
        end,
      };
      timelineItems = new vis.DataSet([replayItem, ...items]);
    } else {
      timelineItems = new vis.DataSet(items);
    }

    const fullOptions = Object.assign({
      editable: {
        add: false,
        updateTime: true,
        updateGroup: false,
        remove: true
      },
      onRemove: (item, callback) => {
        removeItem(item.id);
        callback(null);
      },
      onMove: (item, callback) => {
        moveItem(item.id, item.start, item.end);
        callback(null);
      }
    }, options);

    if (!!$el) {
      $el.setOptions(fullOptions);
      $el.setItems(timelineItems);
    } else {
      $el = this.TimelineElement = new vis.Timeline(container, timelineItems, options);
    }
  }

  render() {
    return (

          <ReplayControls />

            <Link onClick={() => { this.TimelineElement.fit(); }}>
              <FontAwesome name="arrows-h" /> Focus recorded events
            </Link>

    );
  }
}

Timeline.propTypes = Object.assign({
  items: PropTypes.array.isRequired,
  options: PropTypes.object.isRequired,
  start: PropTypes.object,
  end: PropTypes.object,
}, eventPropTypes);
<commit_msg>Hide vertical bar at the current time<commit_after>// Adapted from https://github.com/Lighthouse-io/react-visjs-timeline

import vis from 'vis';
import React, { Component, PropTypes } from 'react';
import ReplayControls from '../containers/ReplayControls';
import Link from './Link';
import FontAwesome from 'react-fontawesome';

const eventPropTypes = {};

export default class Timeline extends Component {
  static propTypes = {
    removeItem: PropTypes.func.isRequired,
    moveItem: PropTypes.func.isRequired,
  };

  componentWillMount() {
    this.state = {};
  }

  componentDidMount() {
    this.init();
  }

  shouldComponentUpdate(nextProps) {
    const {
      items,
      options,
      start,
      end,
    } = this.props;

    const timeChange = (start !== nextProps.start || end !== nextProps.end);
    const itemsChange = items !== nextProps.items;
    const optionsChange = options !== nextProps.options;

    return itemsChange || optionsChange || timeChange;
  }

  componentDidUpdate() {
    this.init();
  }

  componentWillUnmount() {
    this.TimelineElement.destroy();
  }

  init() {
    const { container } = this.refs;
    let $el = this.TimelineElement;

    const {
      items,
      options,
      start,
      end,
      removeItem,
      moveItem,
    } = this.props;

    let timelineItems;

    if (start && end) {
      const replayItem = {
        id: -1,
        type: 'range',
        content: 'Replay',
        start,
        end,
      };
      timelineItems = new vis.DataSet([replayItem, ...items]);
    } else {
      timelineItems = new vis.DataSet(items);
    }

    const fullOptions = Object.assign({
      editable: {
        add: false,
        updateTime: true,
        updateGroup: false,
        remove: true
      },
      onRemove: (item, callback) => {
        removeItem(item.id);
        callback(null);
      },
      onMove: (item, callback) => {
        moveItem(item.id, item.start, item.end);
        callback(null);
      },
      showCurrentTime: false
    }, options);

    if (!!$el) {
      $el.setOptions(fullOptions);
      $el.setItems(timelineItems);
    } else {
      $el = this.TimelineElement = new vis.Timeline(container, timelineItems, options);
    }
  }

  render() {
    return (

          <ReplayControls />

            <Link onClick={() => { this.TimelineElement.fit(); }}>
              <FontAwesome name="arrows-h" /> Focus recorded events
            </Link>

    );
  }
}

Timeline.propTypes = Object.assign({
  items: PropTypes.array.isRequired,
  options: PropTypes.object.isRequired,
  start: PropTypes.object,
  end: PropTypes.object,
}, eventPropTypes);
<|endoftext|>


<commit_before>var AWS = require('aws-sdk'),
    cloudwatchlogs,
    _ = require('lodash'),
    logEvents = [],
    logGroupName = '',
    logStreamName = '',
    messageAsJSON,
    intervalId;

module.exports.init = function(awsLogGroupName, awsLogStreamName, awsAccessKeyId, awsSecretKey, awsRegion, jsonMessage) {
  if (awsAccessKeyId && awsSecretKey && awsRegion) {
    cloudwatchlogs = new AWS.CloudWatchLogs({accessKeyId: awsAccessKeyId, secretAccessKey: awsSecretKey, region: awsRegion});
  } else {
    cloudwatchlogs = new AWS.CloudWatchLogs();
  }
  logGroupName = awsLogGroupName;
  logStreamName = awsLogStreamName;
  messageAsJSON = jsonMessage;
};

module.exports.add = function(log) {
  logEvents.push({
    //message: [log.level, log.msg, JSON.stringify(log.meta, null, '  ')].join(' - '),
    message: messageAsJSON ? JSON.stringify(log, null, '  ') : [log.level, log.msg, JSON.stringify(log.meta, null, '  ')].join(' - '),
    timestamp: new Date().getTime()
  });

  var lastFree = new Date().getTime();
  function upload() {
    if (new Date().getTime() - 2000 > lastFree) {
      token(function(err, sequenceToken) {
        if (err) {
          return console.log(err, err.stack);
        }

        if (logEvents.length <= 0) {
          return;
        }

        var payload = {
          sequenceToken: sequenceToken,
          logGroupName: logGroupName,
          logStreamName: logStreamName,
          logEvents: logEvents.splice(0, 20)
        };

        cloudwatchlogs.putLogEvents(payload, function(err, data) {
          if (err) return console.log(err, err.stack);
          lastFree = new Date().getTime();
        });
      });
    }
  }
  if (!intervalId) {
    intervalId = setInterval(upload, 1000);
  }
};

function token(cb) {
  cloudwatchlogs.describeLogStreams({
    logGroupName: logGroupName
  }, function(err, data) {
    if (err) return cb(err);
    var logStream = _.find(data.logStreams, function(logStream) {
      return logStream.logStreamName === logStreamName;
    });
    cb(err, logStream.uploadSequenceToken);
  });
}
<commit_msg>removing comment (original line)<commit_after>var AWS = require('aws-sdk'),
    cloudwatchlogs,
    _ = require('lodash'),
    logEvents = [],
    logGroupName = '',
    logStreamName = '',
    messageAsJSON,
    intervalId;

module.exports.init = function(awsLogGroupName, awsLogStreamName, awsAccessKeyId, awsSecretKey, awsRegion, jsonMessage) {
  if (awsAccessKeyId && awsSecretKey && awsRegion) {
    cloudwatchlogs = new AWS.CloudWatchLogs({accessKeyId: awsAccessKeyId, secretAccessKey: awsSecretKey, region: awsRegion});
  } else {
    cloudwatchlogs = new AWS.CloudWatchLogs();
  }
  logGroupName = awsLogGroupName;
  logStreamName = awsLogStreamName;
  messageAsJSON = jsonMessage;
};

module.exports.add = function(log) {
  logEvents.push({
    message: messageAsJSON ? JSON.stringify(log, null, '  ') : [log.level, log.msg, JSON.stringify(log.meta, null, '  ')].join(' - '),
    timestamp: new Date().getTime()
  });

  var lastFree = new Date().getTime();
  function upload() {
    if (new Date().getTime() - 2000 > lastFree) {
      token(function(err, sequenceToken) {
        if (err) {
          return console.log(err, err.stack);
        }

        if (logEvents.length <= 0) {
          return;
        }

        var payload = {
          sequenceToken: sequenceToken,
          logGroupName: logGroupName,
          logStreamName: logStreamName,
          logEvents: logEvents.splice(0, 20)
        };

        cloudwatchlogs.putLogEvents(payload, function(err, data) {
          if (err) return console.log(err, err.stack);
          lastFree = new Date().getTime();
        });
      });
    }
  }
  if (!intervalId) {
    intervalId = setInterval(upload, 1000);
  }
};

function token(cb) {
  cloudwatchlogs.describeLogStreams({
    logGroupName: logGroupName
  }, function(err, data) {
    if (err) return cb(err);
    var logStream = _.find(data.logStreams, function(logStream) {
      return logStream.logStreamName === logStreamName;
    });
    cb(err, logStream.uploadSequenceToken);
  });
}
<|endoftext|>


<commit_before>angular.module('teamform-team-app', ['firebase'])
.controller('TeamCtrl', ['$scope', '$firebaseObject', '$firebaseArray', '$window',
    function($scope, $firebaseObject, $firebaseArray, $window) {

	// Call Firebase initialization code defined in site.js
	initalizeFirebase();

	var refPath = "";
	var eventName = getURLParameter("q");
	var teamName = getURLParameter("tn");

	refPath = "/event/" + eventName + "/team/" + teamName;
	ref = firebase.database().ref(refPath);
	$scope.teaminfo = $firebaseObject(ref);

	var userid,username,userPath,userref,userObj;

	$scope.jointeam = function()
	{
		/*
		 firebase.auth().onAuthStateChanged(function(user) {
		 	console.log(user);
    	if (user) {
    		console.log(user);
        	userPath = "/user/" + user.uid;
        	userref = firebase.database().ref(userPath);

        	var eventPath ="/event/" + eventName +"/members/"+ userid;
        	var eventref = firebase.database().ref(eventPath);

        	eventref.set({ joined : true })
    	} else {

    // No user is signed in.
    }
    });
*/
	    var user = firebase.auth().currentUser;
	    console.log(user);

		if (user != null) {
	        var userPath ="/user/" + user.uid;
	        var userref = firebase.database().ref(userPath);
	        var name;
	        var position;
	        var isPositionEmpty = true;

	        userref.once("value", function(data) {
	        	console.log(data.val());
	        	name = data.val().name;
	        	position = data.val().position;

	        	if(position=="Forward")
	        	{
	        		if($scope.teaminfo.Forward=="")
	        		{
	        			//Forward position is emtpy
	        		}
	        		else
	        		{
	        			isPositionEmpty = false;
	        		}
	        	}
	        	if(position=="Midfield")
	        	{
	        		if($scope.teaminfo.Midfield=="")
	        		{
	        			//Forward position is emtpy
	        		}
	        		else
	        		{
	        			isPositionEmpty = false;
	        		}
	        	}
	        	if(position=="LeftBack")
	        	{
	        		if($scope.teaminfo.LeftBack=="")
	        		{
	        			//Forward position is emtpy
	        		}
	        		else
	        		{
	        			isPositionEmpty = false;
	        		}
	        	}
	        	if(position=="RightBack")
	        	{
	        		if($scope.teaminfo.RightBack=="")
	        		{
	        			//Forward position is emtpy
	        		}
	        		else
	        		{
	        			isPositionEmpty = false;
	        		}
	        	}
	        	if(position=="GoalKeeper")
	        	{
	        		if($scope.teaminfo.GoalKeeper=="")
	        		{
	        			//Forward position is emtpy
	        		}
	        		else
	        		{
	        			isPositionEmpty = false;
	        		}
	        	}

	        	if(isPositionEmpty==true)
	        	{
		        	var eventPath ="/event/" + eventName + "/team/"+teamName+"/members/"+ user.uid;
		        	var eventref = firebase.database().ref(eventPath);

		        	eventref.update({
		        		'joined' : true,
		        		'username' : name,
		        		'position' : position
		        	})

		        	if(position!=null)
		        	{
		        		position = position.toString();
		        	}
		        	var positionPath = "/event/"+eventName+"/team/"+teamName;
		        	var positionRef = firebase.database().ref(positionPath);
		        	if(position=="Forward")
		        	{
		        		positionRef.update({
		        			'Forward' : name
		        		})
		        	}
		        	if(position=="Midfield")
		        	{
		        		positionRef.update({
		        			'Midfield' : name
		        		})
		        	}
		        	if(position=="LeftBack")
		        	{
		        		positionRef.update({
		        			'LeftBack' : name
		        		})
		        	}
		        	if(position=="RightBack")
		        	{
		        		positionRef.update({
		        			'RightBack' : name
		        		})
		        	}
		        	if(position=="GoalKeeper")
		        	{
		        		positionRef.update({
		        			'GoalKeeper' : name
		        		})
		        	}
				}
				else
				{
					//Failure of joining team
					$window.alert("Your position is occupied by other player!!!");
          		    console.log('Your position is occupied by other player!!!');
				}

			});
		} else
		{
	  			// No user is signed in.
		}

	}

	refPath = "/event/" + eventName + "/team/"+teamName+"/members";
	$scope.members = [];
	$scope.members = $firebaseArray(firebase.database().ref(refPath));

	refPath =  eventName + "/admin";
	retrieveOnceFirebase(firebase, refPath, function(data) {

		if ( data.child("param").val() != null ) {
			$scope.range = data.child("param").val();
			$scope.param.currentTeamSize = parseInt(($scope.range.minTeamSize + $scope.range.maxTeamSize)/2);
			$scope.$apply(); // force to refresh
			$('#team_page_controller').show(); // show UI

		}
	});

	$scope.input = {
			title: "",
			comment: "",
			date: "",
			likes: 0
		}

	// sync with firebaseArray
		var commentref = firebase.database().ref("comment");
		$scope.comment = $firebaseArray(commentref);

		$scope.addComment = function() {

			// update the date
			if ( /*$scope.input.title != "" && */$scope.input.comment != "" ) {
				$scope.input.date = new Date().toString();
				$scope.input.likes = 0;
				// add a comment
				$scope.comment.$add($scope.input);
			}
		}

}]);<commit_msg>Update team.js<commit_after>angular.module('teamform-team-app', ['firebase'])
.controller('TeamCtrl', ['$scope', '$firebaseObject', '$firebaseArray', '$window',
    function($scope, $firebaseObject, $firebaseArray, $window) {

	// Call Firebase initialization code defined in site.js
	initalizeFirebase();

	var refPath = "";
	var eventName = getURLParameter("q");
	var teamName = getURLParameter("tn");

	refPath = "/event/" + eventName + "/team/" + teamName;
	ref = firebase.database().ref(refPath);
	$scope.teaminfo = $firebaseObject(ref);

	var userid,username,userPath,userref,userObj;

	$scope.jointeam = function()
	{
		/*
		 firebase.auth().onAuthStateChanged(function(user) {
		 	console.log(user);
    	if (user) {
    		console.log(user);
        	userPath = "/user/" + user.uid;
        	userref = firebase.database().ref(userPath);

        	var eventPath ="/event/" + eventName +"/members/"+ userid;
        	var eventref = firebase.database().ref(eventPath);

        	eventref.set({ joined : true })
    	} else {

    // No user is signed in.
    }
    });
*/
	    var user = firebase.auth().currentUser;
	    console.log(user);

		if (user != null) {
	        var userPath ="/user/" + user.uid;
	        var userref = firebase.database().ref(userPath);
	        var name;
	        var position;
	        var isPositionEmpty = true;

	        userref.once("value", function(data) {
	        	console.log(data.val());
	        	name = data.val().name;
	        	position = data.val().position;

	        	if(position=="Forward")
	        	{
	        		if($scope.teaminfo.Forward=="")
	        		{
	        			//Forward position is emtpy
	        		}
	        		else
	        		{
	        			isPositionEmpty = false;
	        		}
	        	}
	        	if(position=="Midfield")
	        	{
	        		if($scope.teaminfo.Midfield=="")
	        		{
	        			//Forward position is emtpy
	        		}
	        		else
	        		{
	        			isPositionEmpty = false;
	        		}
	        	}
	        	if(position=="LeftBack")
	        	{
	        		if($scope.teaminfo.LeftBack=="")
	        		{
	        			//Forward position is emtpy
	        		}
	        		else
	        		{
	        			isPositionEmpty = false;
	        		}
	        	}
	        	if(position=="RightBack")
	        	{
	        		if($scope.teaminfo.RightBack=="")
	        		{
	        			//Forward position is emtpy
	        		}
	        		else
	        		{
	        			isPositionEmpty = false;
	        		}
	        	}
	        	if(position=="GoalKeeper")
	        	{
	        		if($scope.teaminfo.GoalKeeper=="")
	        		{
	        			//Forward position is emtpy
	        		}
	        		else
	        		{
	        			isPositionEmpty = false;
	        		}
	        	}

	        	if(isPositionEmpty==true)
	        	{
		        	var eventPath ="/event/" + eventName + "/team/"+teamName+"/members/"+ user.uid;
		        	var eventref = firebase.database().ref(eventPath);

		        	eventref.update({
		        		'joined' : true,
		        		'username' : name,
		        		'position' : position
		        	})

		        	if(position!=null)
		        	{
		        		position = position.toString();
		        	}
		        	var positionPath = "/event/"+eventName+"/team/"+teamName;
		        	var positionRef = firebase.database().ref(positionPath);
		        	if(position=="Forward")
		        	{
		        		positionRef.update({
		        			'Forward' : name
		        		})
		        	}
		        	if(position=="Midfield")
		        	{
		        		positionRef.update({
		        			'Midfield' : name
		        		})
		        	}
		        	if(position=="LeftBack")
		        	{
		        		positionRef.update({
		        			'LeftBack' : name
		        		})
		        	}
		        	if(position=="RightBack")
		        	{
		        		positionRef.update({
		        			'RightBack' : name
		        		})
		        	}
		        	if(position=="GoalKeeper")
		        	{
		        		positionRef.update({
		        			'GoalKeeper' : name
		        		})
		        	}
				}
				else
				{
					//Failure of joining team
					$window.alert("Your position is occupied by other player!!!");
          		    console.log('Your position is occupied by other player!!!');
				}

			});
		} else
		{
	  			// No user is signed in.
		}

	}

	refPath = "/event/" + eventName + "/team/"+teamName+"/members";
	$scope.members = [];
	$scope.members = $firebaseArray(firebase.database().ref(refPath));

	refPath =  eventName + "/admin";
	retrieveOnceFirebase(firebase, refPath, function(data) {

		if ( data.child("param").val() != null ) {
			$scope.range = data.child("param").val();
			$scope.param.currentTeamSize = parseInt(($scope.range.minTeamSize + $scope.range.maxTeamSize)/2);
			$scope.$apply(); // force to refresh
			$('#team_page_controller').show(); // show UI

		}
	});

	$scope.input = {
			title: "",
			comment: "",
			date: "",
			likes: 0
		}

	// sync with firebaseArray
		var commentref = firebase.database().ref("comment");
		$scope.comment = $firebaseArray(commentref);

		$scope.addComment = function() {

			// update the date
			if ( /*$scope.input.title != "" && */$scope.input.comment != "" ) {
				$scope.input.date = new Date().toString();
				$scope.input.likes = 0;
				// add a comment
				$scope.comment.$add($scope.input);
			}
		}

}]);
function functionName()
{
    $("#output").val("");
};
<|endoftext|>


<commit_before>// Opt-in repos (case sensitive)
// - These are all children of Shopify and visible at https://github.com/Shopify
var optInRepos = [
  'dashing',
  'active_merchant',
  'liquid',
  'superdb',
  'active_shipping',
  'shopify_app',
  'identity_cache',
  'skeleton-theme',
  'statsd-instrument',
  'shopify_theme',
  'shopify_api',
  'sarama',
  'Timber',
  'shopify-css-import',
  'active_fulfillment',
  'shopify_python_api',
  'wolverine',
  'verdict',
  'shopify_django_app',
  'browser_sniffer',
  'active_utils',
  'embedded-app-example',
  'connect-googleapps',
  'omniauth-shopify-oauth2',
  'shipping-fulfillment-app',
  'sysv_mq',
  'money',
  'sync_app_demo',
  'rails_parallel',
  'dukpt',
  'splunk-auth-proxy',
  'magnet',
  'googleTrustedShopifyStores',
  'goreferrer',
  'asset_cloud'
]

// Add custom repos by full_name. Take the org/user and repo name
// - e.g. batmanjs/batman from https://github.com/batmanjs/batman
var customRepos = [
  'batmanjs/batman'
]

// Custom repo language, different than that defined by GitHub
var customRepoLanguage = {
  'liquid': 'Liquid',
  'Timber': 'Liquid',
  'skeleton-theme': 'Liquid',
  'dashing': 'Ruby',
  'shopify_theme': 'Ruby',
  'Shopify-Developer-Book': 'Ruby',
  'offsite-gateway-sim': 'Ruby',
  'shopify.github.com': 'JavaScript',
  'batman': 'JavaScript'
}

// Custom repo avatars. Dimensions should be 40x40
// - Be sure a custom repo doesn't have the same name as a Shopify one, or a one will be overridden
var customRepoAvatar = {
  'Timber': '/images/repo-avatars/timber.gif',
  'dashing': '/images/repo-avatars/dashing.gif',
  'superdb': '/images/repo-avatars/super-debugger.gif',
  'batman': '/images/repo-avatars/batmanjs.gif'
}
<commit_msg>Added shopify-fulfillment-integration<commit_after>// Opt-in repos (case sensitive)
// - These are all children of Shopify and visible at https://github.com/Shopify
var optInRepos = [
  'dashing',
  'active_merchant',
  'liquid',
  'superdb',
  'active_shipping',
  'shopify_app',
  'identity_cache',
  'skeleton-theme',
  'statsd-instrument',
  'shopify_theme',
  'shopify_api',
  'sarama',
  'Timber',
  'shopify-css-import',
  'active_fulfillment',
  'shopify_python_api',
  'wolverine',
  'verdict',
  'shopify_django_app',
  'browser_sniffer',
  'active_utils',
  'embedded-app-example',
  'connect-googleapps',
  'omniauth-shopify-oauth2',
  'shopify-fulfillment-integration',
  'sysv_mq',
  'money',
  'sync_app_demo',
  'rails_parallel',
  'dukpt',
  'splunk-auth-proxy',
  'magnet',
  'googleTrustedShopifyStores',
  'goreferrer',
  'asset_cloud'
]

// Add custom repos by full_name. Take the org/user and repo name
// - e.g. batmanjs/batman from https://github.com/batmanjs/batman
var customRepos = [
  'batmanjs/batman'
]

// Custom repo language, different than that defined by GitHub
var customRepoLanguage = {
  'liquid': 'Liquid',
  'Timber': 'Liquid',
  'skeleton-theme': 'Liquid',
  'dashing': 'Ruby',
  'shopify_theme': 'Ruby',
  'Shopify-Developer-Book': 'Ruby',
  'offsite-gateway-sim': 'Ruby',
  'shopify.github.com': 'JavaScript',
  'batman': 'JavaScript'
}

// Custom repo avatars. Dimensions should be 40x40
// - Be sure a custom repo doesn't have the same name as a Shopify one, or a one will be overridden
var customRepoAvatar = {
  'Timber': '/images/repo-avatars/timber.gif',
  'dashing': '/images/repo-avatars/dashing.gif',
  'superdb': '/images/repo-avatars/super-debugger.gif',
  'batman': '/images/repo-avatars/batmanjs.gif'
}
<|endoftext|>


<commit_before>"use strict";

// Layout.
var kAurasIconPosX = 150;
var kAurasIconPosY = 0;
var kAurasIconSizeW = 40;
var kAurasIconSizeH = 40;
var kAurasIconBorderWidth = 1;
var kAurasIconTextW = 100;

class Auras {
  constructor() {
    this.init = false;
    this.icon = null;
    this.iconText = null;
    this.infoText = null;
    this.alertText = null;
    this.alarmText = null;
    this.data = {};
    this.triggers = [];
  }

  OnPlayerChange(e) {
    if (this.init)
      return;
    this.init = true;
    this.me = e.detail.name;

    this.icon = document.getElementById('auras-icon');
    this.iconText = document.getElementById('auras-text-bottom');
    this.infoText = document.getElementById('auras-text-info');
    this.alertText = document.getElementById('auras-text-alert');
    this.alarmText = document.getElementById('auras-text-alarm');
  }

  OnZoneChange(e) {
    this.triggers = [];
    for (var zone in kAurasTriggers) {
      if (e.detail.zoneName.search(zone) >= 0)
        this.triggers = this.triggers.concat(kAurasTriggers[zone]);
    }
  }

  OnBossFightEnd(e) {
    this.data = {};
  }

  OnLog(e) {
    if (!this.init)
      return;
    for (var i = 0; i < e.detail.logs.length; i++) {
      var log = e.detail.logs[i];

      for (var j = 0; j < this.triggers.length; ++j) {
        var trigger = this.triggers[j];
        var r = log.match(trigger.regex);
        if (r != null)
          this.OnTrigger(trigger, r);
      }
    }
  }

  OnTrigger(trigger, matches) {
    if ('condition' in trigger) {
      if (!trigger.condition(this.data, matches))
        return;
    }

    var delay = 'delaySeconds' in trigger ? trigger.delaySeconds : 0;
    var duration = 0;
    if ('durationSeconds' in trigger)
      duration = trigger.durationSeconds;
    else if ('durationPosition' in trigger)
      duration = matches[trigger.durationPosition];
    else
      duration = 3;

    var that = this;

    var TextOrFunction = function(f) {
      return (typeof(f) == "function") ? f(that.data, matches) : f;
    }

    var f = function() {
      if ('icon' in trigger) {
        that.icon.classList.remove('hide');
        that.iconText.classList.remove('hide');
        var url = trigger.icon in gAurasIcons ? gAurasIcons[trigger.icon] : trigger.icon;
        that.icon.style.backgroundImage = 'url("' + url + '")';
        if ('iconBorderColor' in trigger)
          that.icon.style.borderColor = trigger.iconBorderColor;
        else
          that.icon.style.borderColor = 'rgb(0, 0, 0)';
        if ('iconText' in trigger) {
          that.iconText.innerText = TextOrFunction(trigger.iconText);
        } else {
          that.iconText.innerText = '';
        }
        if ('iconTextColor' in trigger)
          that.iconText.style.color = trigger.iconTextColor;
        else
          that.iconText.style.color = 'rba(255, 255, 255)';

        window.clearTimeout(that.iconTimer);
        that.iconTimer = window.setTimeout(function() {
          that.icon.classList.add('hide');
          that.iconText.classList.add('hide');
        }, duration * 1000);
      }

      var textSound = '';

      if ('infoText' in trigger) {
        var text = TextOrFunction(trigger.infoText);
        if (text) {
          that.infoText.classList.remove('hide');
          that.infoText.innerText = text;
          textSound = 'sound' in trigger ? '' : gAurasSounds.Info;

          window.clearTimeout(that.infoTextTimer);
          that.infoTextTimer = window.setTimeout(function() {
            that.infoText.classList.add('hide');
          }, duration * 1000);
        }
      }
      if ('alertText' in trigger) {
        var text = TextOrFunction(trigger.alertText);
        if (text) {
          that.alertText.classList.remove('hide');
          that.alertText.innerText = text;
          textSound = 'sound' in trigger ? '' : gAurasSounds.Info;

          window.clearTimeout(that.alertTextTimer);
          that.alertTextTimer = window.setTimeout(function() {
            that.alertText.classList.add('hide');
          }, duration * 1000);
        }
      }
      if ('alarmText' in trigger) {
        var text = TextOrFunction(trigger.alarmText);
        if (text) {
          that.alarmText.classList.remove('hide');
          that.alarmText.innerText = text;
          textSound = 'sound' in trigger ? '' : gAurasSounds.Info;

          window.clearTimeout(that.alarmTextTimer);
          that.alarmTextTimer = window.setTimeout(function() {
            that.alarmText.classList.add('hide');
          }, duration * 1000);
        }
      }

      if (textSound)
        new Audio(textSound).play();

      if ('sound' in trigger && trigger.sound) {
        var url = trigger.sound in gAurasSounds ? gAurasSounds[trigger.sound] : trigger.sound;
        var audio = new Audio(url);
        if ('soundVolume' in trigger)
          audio.volume = trigger.soundVolume;
        audio.play();
      }

      if ('run' in trigger)
        trigger.run(that.data, matches);
    };
    if (!delay)
      f();
    else
      window.setTimeout(f, delay * 1000);
  }

  Test(zone, log) {
    this.OnPlayerChange({ detail: { name : 'ME' } });
    this.OnZoneChange({ detail: { zoneName: zone } });
    this.OnLog({ detail: { logs : ['abcdefgh', log, 'hgfedcba']}});
  }
};

var gAuras = new Auras();

document.addEventListener("onPlayerChangedEvent", function(e) {
  gAuras.OnPlayerChange(e);
});
document.addEventListener("onZoneChangedEvent", function(e) {
  gAuras.OnZoneChange(e);
});
document.addEventListener("onBossFightEnd", function(e) {
  gAuras.OnBossFightEnd(e);
});
document.addEventListener("onLogEvent", function(e) {
  gAuras.OnLog(e);
});

// Testing...
/*
window.onload = function() {
  window.setTimeout(function() { gAuras.Test('Unknown Zone (2Ba)', ':Neo Exdeath:2401:Unknown_2401:328AD123:Asada Fireclaw:') }, 0);
  window.setTimeout(function() { gAuras.Test('Unknown Zone (2Ba)', ':Neo Exdeath:2401:Unknown_2401:328AD123:Ryythe Larke:') }, 0);
  window.setTimeout(function() { gAuras.Test('Unknown Zone (2Ba)', ':Neo Exdeath:2401:Unknown_2401:328AD123:Test Name:') }, 0);
};
*/<commit_msg>Fix the alert and alarm triggers to have their appropriate sounds<commit_after>"use strict";

// Layout.
var kAurasIconPosX = 150;
var kAurasIconPosY = 0;
var kAurasIconSizeW = 40;
var kAurasIconSizeH = 40;
var kAurasIconBorderWidth = 1;
var kAurasIconTextW = 100;

class Auras {
  constructor() {
    this.init = false;
    this.icon = null;
    this.iconText = null;
    this.infoText = null;
    this.alertText = null;
    this.alarmText = null;
    this.data = {};
    this.triggers = [];
  }

  OnPlayerChange(e) {
    if (this.init)
      return;
    this.init = true;
    this.me = e.detail.name;

    this.icon = document.getElementById('auras-icon');
    this.iconText = document.getElementById('auras-text-bottom');
    this.infoText = document.getElementById('auras-text-info');
    this.alertText = document.getElementById('auras-text-alert');
    this.alarmText = document.getElementById('auras-text-alarm');
  }

  OnZoneChange(e) {
    this.triggers = [];
    for (var zone in kAurasTriggers) {
      if (e.detail.zoneName.search(zone) >= 0)
        this.triggers = this.triggers.concat(kAurasTriggers[zone]);
    }
  }

  OnBossFightEnd(e) {
    this.data = {};
  }

  OnLog(e) {
    if (!this.init)
      return;
    for (var i = 0; i < e.detail.logs.length; i++) {
      var log = e.detail.logs[i];

      for (var j = 0; j < this.triggers.length; ++j) {
        var trigger = this.triggers[j];
        var r = log.match(trigger.regex);
        if (r != null)
          this.OnTrigger(trigger, r);
      }
    }
  }

  OnTrigger(trigger, matches) {
    if ('condition' in trigger) {
      if (!trigger.condition(this.data, matches))
        return;
    }

    var delay = 'delaySeconds' in trigger ? trigger.delaySeconds : 0;
    var duration = 0;
    if ('durationSeconds' in trigger)
      duration = trigger.durationSeconds;
    else if ('durationPosition' in trigger)
      duration = matches[trigger.durationPosition];
    else
      duration = 3;

    var that = this;

    var TextOrFunction = function(f) {
      return (typeof(f) == "function") ? f(that.data, matches) : f;
    }

    var f = function() {
      if ('icon' in trigger) {
        that.icon.classList.remove('hide');
        that.iconText.classList.remove('hide');
        var url = trigger.icon in gAurasIcons ? gAurasIcons[trigger.icon] : trigger.icon;
        that.icon.style.backgroundImage = 'url("' + url + '")';
        if ('iconBorderColor' in trigger)
          that.icon.style.borderColor = trigger.iconBorderColor;
        else
          that.icon.style.borderColor = 'rgb(0, 0, 0)';
        if ('iconText' in trigger) {
          that.iconText.innerText = TextOrFunction(trigger.iconText);
        } else {
          that.iconText.innerText = '';
        }
        if ('iconTextColor' in trigger)
          that.iconText.style.color = trigger.iconTextColor;
        else
          that.iconText.style.color = 'rba(255, 255, 255)';

        window.clearTimeout(that.iconTimer);
        that.iconTimer = window.setTimeout(function() {
          that.icon.classList.add('hide');
          that.iconText.classList.add('hide');
        }, duration * 1000);
      }

      var textSound = '';

      if ('infoText' in trigger) {
        var text = TextOrFunction(trigger.infoText);
        if (text) {
          that.infoText.classList.remove('hide');
          that.infoText.innerText = text;
          textSound = 'sound' in trigger ? '' : gAurasSounds.Info;

          window.clearTimeout(that.infoTextTimer);
          that.infoTextTimer = window.setTimeout(function() {
            that.infoText.classList.add('hide');
          }, duration * 1000);
        }
      }
      if ('alertText' in trigger) {
        var text = TextOrFunction(trigger.alertText);
        if (text) {
          that.alertText.classList.remove('hide');
          that.alertText.innerText = text;
          textSound = 'sound' in trigger ? '' : gAurasSounds.Alert;

          window.clearTimeout(that.alertTextTimer);
          that.alertTextTimer = window.setTimeout(function() {
            that.alertText.classList.add('hide');
          }, duration * 1000);
        }
      }
      if ('alarmText' in trigger) {
        var text = TextOrFunction(trigger.alarmText);
        if (text) {
          that.alarmText.classList.remove('hide');
          that.alarmText.innerText = text;
          textSound = 'sound' in trigger ? '' : gAurasSounds.Alarm;

          window.clearTimeout(that.alarmTextTimer);
          that.alarmTextTimer = window.setTimeout(function() {
            that.alarmText.classList.add('hide');
          }, duration * 1000);
        }
      }

      if (textSound)
        new Audio(textSound).play();

      if ('sound' in trigger && trigger.sound) {
        var url = trigger.sound in gAurasSounds ? gAurasSounds[trigger.sound] : trigger.sound;
        var audio = new Audio(url);
        if ('soundVolume' in trigger)
          audio.volume = trigger.soundVolume;
        audio.play();
      }

      if ('run' in trigger)
        trigger.run(that.data, matches);
    };
    if (!delay)
      f();
    else
      window.setTimeout(f, delay * 1000);
  }

  Test(zone, log) {
    this.OnPlayerChange({ detail: { name : 'ME' } });
    this.OnZoneChange({ detail: { zoneName: zone } });
    this.OnLog({ detail: { logs : ['abcdefgh', log, 'hgfedcba']}});
  }
};

var gAuras = new Auras();

document.addEventListener("onPlayerChangedEvent", function(e) {
  gAuras.OnPlayerChange(e);
});
document.addEventListener("onZoneChangedEvent", function(e) {
  gAuras.OnZoneChange(e);
});
document.addEventListener("onBossFightEnd", function(e) {
  gAuras.OnBossFightEnd(e);
});
document.addEventListener("onLogEvent", function(e) {
  gAuras.OnLog(e);
});

// Testing...
window.onload = function() {
  //window.setTimeout(function() { gAuras.Test('Unknown Zone (2Ba)', ':Exdeath uses The Decisive Battle.') }, 0);
  //window.setTimeout(function() { gAuras.Test('Unknown Zone (2Ba)', ':Exdeath begins casting Fire III.') }, 0);
};
<|endoftext|>


<commit_before>const _ = require('lodash');
module.exports = class MemberRepository {
    /**
     * @param {object} deps
     * @param {any} deps.Member
     * @param {any} deps.StripeCustomer
     * @param {any} deps.StripeCustomerSubscription
     * @param {import('../../services/stripe-api')} deps.stripeAPIService
     * @param {import('../../services/stripe-plans')} deps.stripePlansService
     * @param {any} deps.logger
     */
    constructor({
        Member,
        StripeCustomer,
        StripeCustomerSubscription,
        stripeAPIService,
        stripePlansService,
        logger
    }) {
        this._Member = Member;
        this._StripeCustomer = StripeCustomer;
        this._StripeCustomerSubscription = StripeCustomerSubscription;
        this._stripeAPIService = stripeAPIService;
        this._stripePlansService = stripePlansService;
        this._logging = logger;
    }

    isActiveSubscriptionStatus(status) {
        return ['active', 'trialing', 'unpaid', 'past_due'].includes(status);
    }

    async get(data, options) {
        if (data.customer_id) {
            const customer = await this._StripeCustomer.findOne({
                customer_id: data.customer_id
            }, {
                withRelated: ['member']
            });
            if (customer) {
                return customer.related('member');
            }
            return null;
        }
        return this._Member.findOne(data, options);
    }

    async create(data, options) {
        const {labels} = data;

        if (labels) {
            labels.forEach((label, index) => {
                if (typeof label === 'string') {
                    labels[index] = {name: label};
                }
            });
        }

        const memberData = _.pick(data, ['email', 'name', 'note', 'subscribed', 'geolocation', 'created_at']);

        return this._Member.add({
            ...memberData,
            labels
        }, options);
    }

    async update(data, options) {
        const member = await this._Member.edit(_.pick(data, [
            'email',
            'name',
            'note',
            'subscribed',
            'labels',
            'geolocation'
        ]), options);

        if (this._stripeAPIService && member._changed.email) {
            await member.related('stripeCustomers').fetch();
            const customers = member.related('stripeCustomers');
            for (const customer of customers.models) {
                await this._stripeAPIService.updateCustomerEmail(
                    customer.get('customer_id'),
                    member.get('email')
                );
            }
        }

        return member;
    }

    async list(options) {
        return this._Member.findPage(options);
    }

    async destroy(data, options) {
        const member = await this._Member.findOne(data, options);

        if (!member) {
            // throw error?
            return;
        }

        if (this._stripeAPIService && options.cancelStripeSubscriptions) {
            await member.related('stripeSubscriptions');
            const subscriptions = member.related('stripeSubscriptions');
            for (const subscription of subscriptions.models) {
                if (subscription.get('status') !== 'canceled') {
                    const updatedSubscription = await this._stripeAPIService.cancelSubscription(
                        subscription.get('subscription_id')
                    );
                    await this._StripeCustomerSubscription.update({
                        status: updatedSubscription.status
                    });
                }
            }
        }

        return this._Member.destroy({
            id: data.id
        }, options);
    }

    async linkStripeCustomer(data, options) {
        if (!this._stripeAPIService.configured) {
            throw new Error('Cannot link Stripe Customer with no Stripe Connection');
        }
        const customer = await this._stripeAPIService.getCustomer(data.customer_id);

        if (!customer) {
            return;
        }

        // Add instead of upsert ensures that we do not link existing customer
        await this._StripeCustomer.add({
            customer_id: data.customer_id,
            member_id: data.member_id,
            name: customer.name,
            email: customer.email
        }, options);

        for (const subscription of customer.subscriptions.data) {
            await this.linkSubscription({
                id: data.member_id,
                subscription
            }, options);
        }
    }

    async linkSubscription(data, options) {
        if (!this._stripeAPIService.configured) {
            throw new Error('Cannot link Stripe Subscription with no Stripe Connection');
        }
        const member = await this._Member.findOne({
            id: data.id
        }, options);

        const customer = await member.related('stripeCustomers').query({
            where: {
                customer_id: data.subscription.customer
            }
        }).fetchOne(options);

        if (!customer) {
            // Maybe just link the customer?
            throw new Error('Subscription is not associated with a customer for the member');
        }

        const subscription = await this._stripeAPIService.getSubscription(data.subscription.id);
        let paymentMethodId;
        if (!subscription.default_payment_method) {
            paymentMethodId = null;
        } else if (typeof subscription.default_payment_method === 'string') {
            paymentMethodId = subscription.default_payment_method;
        } else {
            paymentMethodId = subscription.default_payment_method.id;
        }
        const paymentMethod = paymentMethodId ? await this._stripeAPIService.getCardPaymentMethod(paymentMethodId) : null;
        await this._StripeCustomerSubscription.upsert({
            customer_id: subscription.customer,
            subscription_id: subscription.id,
            status: subscription.status,
            cancel_at_period_end: subscription.cancel_at_period_end,
            cancellation_reason: subscription.metadata && subscription.metadata.cancellation_reason || null,
            current_period_end: new Date(subscription.current_period_end * 1000),
            start_date: new Date(subscription.start_date * 1000),
            default_payment_card_last4: paymentMethod && paymentMethod.card && paymentMethod.card.last4 || null,

            plan_id: subscription.plan.id,
            // NOTE: Defaulting to interval as migration to nullable field
            // turned out to be much bigger problem.
            // Ideally, would need nickname field to be nullable on the DB level
            // condition can be simplified once this is done
            plan_nickname: subscription.plan.nickname || subscription.plan.interval,
            plan_interval: subscription.plan.interval,
            plan_amount: subscription.plan.amount,
            plan_currency: subscription.plan.currency
        }, {
            ...options,
            subscription_id: subscription.id
        });

        if (this.isActiveSubscriptionStatus(subscription.status)) {
            await this._Member.edit({status: 'paid'}, {...options, id: data.id});
        } else {
            const subscriptions = await member.related('stripeSubscriptions').fetch(options);
            let status = 'free';
            for (const subscription of subscriptions.models) {
                if (this.isActiveSubscriptionStatus(subscription.get('status'))) {
                    status = 'paid';
                    break;
                }
            }
            await this._Member.edit({status: status}, {...options, id: data.id});
        }
    }

    async updateSubscription(data, options) {
        if (!this._stripeAPIService.configured) {
            throw new Error('Cannot update Stripe Subscription with no Stripe Connection');
        }
        const member = await this._Member.findOne({
            id: data.id
        });

        const subscription = await member.related('stripeSubscriptions').query({
            where: {
                subscription_id: data.subscription.subscription_id
            }
        }).fetchOne(options);

        if (!subscription) {
            throw new Error('Subscription not found');
        }

        if (data.subscription.cancel_at_period_end === undefined) {
            throw new Error('Incorrect usage');
        }

        if (data.subscription.cancel_at_period_end) {
            await this._stripeAPIService.cancelSubscriptionAtPeriodEnd(data.subscription.subscription_id);
        } else {
            await this._stripeAPIService.continueSubscriptionAtPeriodEnd(data.subscription.subscription_id);
        }

        await this._StripeCustomerSubscription.edit({
            subscription_id: data.subscription.subscription_id,
            cancel_at_period_end: data.subscription.cancel_at_period_end
        }, {
            id: subscription.id
        });
    }

    async setComplimentarySubscription(data, options) {
        if (!this._stripeAPIService.configured) {
            throw new Error('Cannot update Stripe Subscription with no Stripe Connection');
        }
        const member = await this._Member.findOne({
            id: data.id
        }, options);

        const subscriptions = await member.related('stripeSubscriptions').fetch(options);

        const activeSubscriptions = subscriptions.models.filter((subscription) => {
            return this.isActiveSubscriptionStatus(subscription.get('status'));
        });

        // NOTE: Because we allow for multiple Complimentary plans, need to take into account currently availalbe
        //       plan currencies so that we don't end up giving a member complimentary subscription in wrong currency.
        //       Giving member a subscription in different currency would prevent them from resubscribing with a regular
        //       plan if Complimentary is cancelled (ref. https://stripe.com/docs/billing/customer#currency)
        let complimentaryCurrency = this._stripePlansService.getPlans().find(plan => plan.interval === 'month').currency.toLowerCase();

        if (activeSubscriptions.length) {
            complimentaryCurrency = activeSubscriptions[0].get('plan_currency').toLowerCase();
        }

        const complimentaryPlan = this._stripePlansService.getComplimentaryPlan(complimentaryCurrency);

        if (!complimentaryPlan) {
            throw new Error('Could not find Complimentary plan');
        }

        let stripeCustomer;

        await member.related('stripeCustomers').fetch(options);

        for (const customer of member.related('stripeCustomers').models) {
            try {
                const fetchedCustomer = await this._stripeAPIService.getCustomer(customer.get('customer_id'));
                if (!fetchedCustomer.deleted) {
                    stripeCustomer = fetchedCustomer;
                    break;
                }
            } catch (err) {
                console.log('Ignoring error for fetching customer for checkout');
            }
        }

        if (!stripeCustomer) {
            stripeCustomer = await this._stripeAPIService.createCustomer({
                email: member.get('email')
            });

            await this._StripeCustomer.upsert({
                customer_id: stripeCustomer.id,
                member_id: data.id,
                email: stripeCustomer.email,
                name: stripeCustomer.name
            }, options);
        }

        if (!activeSubscriptions.length) {
            const subscription = await this._stripeAPIService.createSubscription(stripeCustomer.id, complimentaryPlan.id);

            await this.linkSubscription({
                id: member.id,
                subscription
            }, options);
        } else {
            // NOTE: we should only ever have 1 active subscription, but just in case there is more update is done on all of them
            for (const subscription of activeSubscriptions) {
                const updatedSubscription = await this._stripeAPIService.changeSubscriptionPlan(
                    subscription.get('subscription_id'),
                    complimentaryPlan.id
                );

                await this.linkSubscription({
                    id: member.id,
                    subscription: updatedSubscription
                }, options);
            }
        }
    }

    async cancelComplimentarySubscription(data) {
        if (!this._stripeAPIService.configured) {
            throw new Error('Cannot cancel Complimentary Subscription with no Stripe Connection');
        }

        const member = await this._Member.findOne({
            id: data.id
        });

        const subscriptions = await member.related('stripeSubscriptions').fetch();

        for (const subscription of subscriptions.models) {
            if (subscription.get('status') !== 'canceled') {
                try {
                    const updatedSubscription = await this._stripeAPIService.cancelSubscription(
                        subscription.get('subscription_id')
                    );
                    // Only needs to update `status`
                    await this.linkSubscription({
                        id: data.id,
                        subscription: updatedSubscription
                    });
                } catch (err) {
                    this._logging.error(`There was an error cancelling subscription ${subscription.get('subscription_id')}`);
                    this._logging.error(err);
                }
            }
        }
        return true;
    }
};
<commit_msg>Revert "Removed unused upsertCustomer method"<commit_after>const _ = require('lodash');
module.exports = class MemberRepository {
    /**
     * @param {object} deps
     * @param {any} deps.Member
     * @param {any} deps.StripeCustomer
     * @param {any} deps.StripeCustomerSubscription
     * @param {import('../../services/stripe-api')} deps.stripeAPIService
     * @param {import('../../services/stripe-plans')} deps.stripePlansService
     * @param {any} deps.logger
     */
    constructor({
        Member,
        StripeCustomer,
        StripeCustomerSubscription,
        stripeAPIService,
        stripePlansService,
        logger
    }) {
        this._Member = Member;
        this._StripeCustomer = StripeCustomer;
        this._StripeCustomerSubscription = StripeCustomerSubscription;
        this._stripeAPIService = stripeAPIService;
        this._stripePlansService = stripePlansService;
        this._logging = logger;
    }

    isActiveSubscriptionStatus(status) {
        return ['active', 'trialing', 'unpaid', 'past_due'].includes(status);
    }

    async get(data, options) {
        if (data.customer_id) {
            const customer = await this._StripeCustomer.findOne({
                customer_id: data.customer_id
            }, {
                withRelated: ['member']
            });
            if (customer) {
                return customer.related('member');
            }
            return null;
        }
        return this._Member.findOne(data, options);
    }

    async create(data, options) {
        const {labels} = data;

        if (labels) {
            labels.forEach((label, index) => {
                if (typeof label === 'string') {
                    labels[index] = {name: label};
                }
            });
        }

        const memberData = _.pick(data, ['email', 'name', 'note', 'subscribed', 'geolocation', 'created_at']);

        return this._Member.add({
            ...memberData,
            labels
        }, options);
    }

    async update(data, options) {
        const member = await this._Member.edit(_.pick(data, [
            'email',
            'name',
            'note',
            'subscribed',
            'labels',
            'geolocation'
        ]), options);

        if (this._stripeAPIService && member._changed.email) {
            await member.related('stripeCustomers').fetch();
            const customers = member.related('stripeCustomers');
            for (const customer of customers.models) {
                await this._stripeAPIService.updateCustomerEmail(
                    customer.get('customer_id'),
                    member.get('email')
                );
            }
        }

        return member;
    }

    async list(options) {
        return this._Member.findPage(options);
    }

    async destroy(data, options) {
        const member = await this._Member.findOne(data, options);

        if (!member) {
            // throw error?
            return;
        }

        if (this._stripeAPIService && options.cancelStripeSubscriptions) {
            await member.related('stripeSubscriptions');
            const subscriptions = member.related('stripeSubscriptions');
            for (const subscription of subscriptions.models) {
                if (subscription.get('status') !== 'canceled') {
                    const updatedSubscription = await this._stripeAPIService.cancelSubscription(
                        subscription.get('subscription_id')
                    );
                    await this._StripeCustomerSubscription.update({
                        status: updatedSubscription.status
                    });
                }
            }
        }

        return this._Member.destroy({
            id: data.id
        }, options);
    }

    async upsertCustomer(data) {
        return await this._StripeCustomer.upsert({
            customer_id: data.customer_id,
            member_id: data.member_id,
            name: data.name,
            email: data.email
        });
    }

    async linkStripeCustomer(data, options) {
        if (!this._stripeAPIService.configured) {
            throw new Error('Cannot link Stripe Customer with no Stripe Connection');
        }
        const customer = await this._stripeAPIService.getCustomer(data.customer_id);

        if (!customer) {
            return;
        }

        // Add instead of upsert ensures that we do not link existing customer
        await this._StripeCustomer.add({
            customer_id: data.customer_id,
            member_id: data.member_id,
            name: customer.name,
            email: customer.email
        }, options);

        for (const subscription of customer.subscriptions.data) {
            await this.linkSubscription({
                id: data.member_id,
                subscription
            }, options);
        }
    }

    async linkSubscription(data, options) {
        if (!this._stripeAPIService.configured) {
            throw new Error('Cannot link Stripe Subscription with no Stripe Connection');
        }
        const member = await this._Member.findOne({
            id: data.id
        }, options);

        const customer = await member.related('stripeCustomers').query({
            where: {
                customer_id: data.subscription.customer
            }
        }).fetchOne(options);

        if (!customer) {
            // Maybe just link the customer?
            throw new Error('Subscription is not associated with a customer for the member');
        }

        const subscription = await this._stripeAPIService.getSubscription(data.subscription.id);
        let paymentMethodId;
        if (!subscription.default_payment_method) {
            paymentMethodId = null;
        } else if (typeof subscription.default_payment_method === 'string') {
            paymentMethodId = subscription.default_payment_method;
        } else {
            paymentMethodId = subscription.default_payment_method.id;
        }
        const paymentMethod = paymentMethodId ? await this._stripeAPIService.getCardPaymentMethod(paymentMethodId) : null;
        await this._StripeCustomerSubscription.upsert({
            customer_id: subscription.customer,
            subscription_id: subscription.id,
            status: subscription.status,
            cancel_at_period_end: subscription.cancel_at_period_end,
            cancellation_reason: subscription.metadata && subscription.metadata.cancellation_reason || null,
            current_period_end: new Date(subscription.current_period_end * 1000),
            start_date: new Date(subscription.start_date * 1000),
            default_payment_card_last4: paymentMethod && paymentMethod.card && paymentMethod.card.last4 || null,

            plan_id: subscription.plan.id,
            // NOTE: Defaulting to interval as migration to nullable field
            // turned out to be much bigger problem.
            // Ideally, would need nickname field to be nullable on the DB level
            // condition can be simplified once this is done
            plan_nickname: subscription.plan.nickname || subscription.plan.interval,
            plan_interval: subscription.plan.interval,
            plan_amount: subscription.plan.amount,
            plan_currency: subscription.plan.currency
        }, {
            ...options,
            subscription_id: subscription.id
        });

        if (this.isActiveSubscriptionStatus(subscription.status)) {
            await this._Member.edit({status: 'paid'}, {...options, id: data.id});
        } else {
            const subscriptions = await member.related('stripeSubscriptions').fetch(options);
            let status = 'free';
            for (const subscription of subscriptions.models) {
                if (this.isActiveSubscriptionStatus(subscription.get('status'))) {
                    status = 'paid';
                    break;
                }
            }
            await this._Member.edit({status: status}, {...options, id: data.id});
        }
    }

    async updateSubscription(data, options) {
        if (!this._stripeAPIService.configured) {
            throw new Error('Cannot update Stripe Subscription with no Stripe Connection');
        }
        const member = await this._Member.findOne({
            id: data.id
        });

        const subscription = await member.related('stripeSubscriptions').query({
            where: {
                subscription_id: data.subscription.subscription_id
            }
        }).fetchOne(options);

        if (!subscription) {
            throw new Error('Subscription not found');
        }

        if (data.subscription.cancel_at_period_end === undefined) {
            throw new Error('Incorrect usage');
        }

        if (data.subscription.cancel_at_period_end) {
            await this._stripeAPIService.cancelSubscriptionAtPeriodEnd(data.subscription.subscription_id);
        } else {
            await this._stripeAPIService.continueSubscriptionAtPeriodEnd(data.subscription.subscription_id);
        }

        await this._StripeCustomerSubscription.edit({
            subscription_id: data.subscription.subscription_id,
            cancel_at_period_end: data.subscription.cancel_at_period_end
        }, {
            id: subscription.id
        });
    }

    async setComplimentarySubscription(data, options) {
        if (!this._stripeAPIService.configured) {
            throw new Error('Cannot update Stripe Subscription with no Stripe Connection');
        }
        const member = await this._Member.findOne({
            id: data.id
        }, options);

        const subscriptions = await member.related('stripeSubscriptions').fetch(options);

        const activeSubscriptions = subscriptions.models.filter((subscription) => {
            return this.isActiveSubscriptionStatus(subscription.get('status'));
        });

        // NOTE: Because we allow for multiple Complimentary plans, need to take into account currently availalbe
        //       plan currencies so that we don't end up giving a member complimentary subscription in wrong currency.
        //       Giving member a subscription in different currency would prevent them from resubscribing with a regular
        //       plan if Complimentary is cancelled (ref. https://stripe.com/docs/billing/customer#currency)
        let complimentaryCurrency = this._stripePlansService.getPlans().find(plan => plan.interval === 'month').currency.toLowerCase();

        if (activeSubscriptions.length) {
            complimentaryCurrency = activeSubscriptions[0].get('plan_currency').toLowerCase();
        }

        const complimentaryPlan = this._stripePlansService.getComplimentaryPlan(complimentaryCurrency);

        if (!complimentaryPlan) {
            throw new Error('Could not find Complimentary plan');
        }

        let stripeCustomer;

        await member.related('stripeCustomers').fetch(options);

        for (const customer of member.related('stripeCustomers').models) {
            try {
                const fetchedCustomer = await this._stripeAPIService.getCustomer(customer.get('customer_id'));
                if (!fetchedCustomer.deleted) {
                    stripeCustomer = fetchedCustomer;
                    break;
                }
            } catch (err) {
                console.log('Ignoring error for fetching customer for checkout');
            }
        }

        if (!stripeCustomer) {
            stripeCustomer = await this._stripeAPIService.createCustomer({
                email: member.get('email')
            });

            await this._StripeCustomer.upsert({
                customer_id: stripeCustomer.id,
                member_id: data.id,
                email: stripeCustomer.email,
                name: stripeCustomer.name
            }, options);
        }

        if (!activeSubscriptions.length) {
            const subscription = await this._stripeAPIService.createSubscription(stripeCustomer.id, complimentaryPlan.id);

            await this.linkSubscription({
                id: member.id,
                subscription
            }, options);
        } else {
            // NOTE: we should only ever have 1 active subscription, but just in case there is more update is done on all of them
            for (const subscription of activeSubscriptions) {
                const updatedSubscription = await this._stripeAPIService.changeSubscriptionPlan(
                    subscription.get('subscription_id'),
                    complimentaryPlan.id
                );

                await this.linkSubscription({
                    id: member.id,
                    subscription: updatedSubscription
                }, options);
            }
        }
    }

    async cancelComplimentarySubscription(data) {
        if (!this._stripeAPIService.configured) {
            throw new Error('Cannot cancel Complimentary Subscription with no Stripe Connection');
        }

        const member = await this._Member.findOne({
            id: data.id
        });

        const subscriptions = await member.related('stripeSubscriptions').fetch();

        for (const subscription of subscriptions.models) {
            if (subscription.get('status') !== 'canceled') {
                try {
                    const updatedSubscription = await this._stripeAPIService.cancelSubscription(
                        subscription.get('subscription_id')
                    );
                    // Only needs to update `status`
                    await this.linkSubscription({
                        id: data.id,
                        subscription: updatedSubscription
                    });
                } catch (err) {
                    this._logging.error(`There was an error cancelling subscription ${subscription.get('subscription_id')}`);
                    this._logging.error(err);
                }
            }
        }
        return true;
    }
};
<|endoftext|>


<commit_before>var metaMarked =    require("meta-marked"),
    fs =            require("fs-extra"),
    yamljs =        require("yamljs"),
    fswf =          require("safe-write-file");

var SOURCE_PATH = "src/",
    SOURCE_INFO_FILE = "info.yml",
    SOURCE_EXTENSION = "md",
    SOURCE_COVER_FILE = "cover.png",
    DIST_PATH = "dist/",
    DIST_INFO_FILE = "info.json",
    DIST_COVER_FILE = "cover.png",
    DIST_EXTENSION = "html",
    DIST_S3 = "https://s3-us-west-2.amazonaws.com/com.cryart.sabbathschool";

var processLang = function(path){
  var quarterlies = fs.readdirSync(path).reverse(),
      lang_info = [];

  for (var i = 0; i < quarterlies.length; i++){
    var quarterly_path = path + "/" + quarterlies[i];
    if (!fs.lstatSync(quarterly_path).isDirectory()) continue;
    if (!fs.lstatSync(quarterly_path + "/" + SOURCE_INFO_FILE).isFile()) continue;
    if (!fs.lstatSync(quarterly_path + "/" + SOURCE_COVER_FILE).isFile()) continue;

    var quarterly = fs.readdirSync(quarterly_path);

    var quarterly_info = yamljs.load(quarterly_path + "/" + SOURCE_INFO_FILE);
    quarterly_info.lessons = [];

    fs.copySync(quarterly_path + "/" + SOURCE_COVER_FILE, quarterly_path.replace(SOURCE_PATH, DIST_PATH) + "/" + DIST_COVER_FILE);
    quarterly_info.cover = DIST_S3 + "/" + quarterly_path.replace(SOURCE_PATH, "") + "/" + DIST_COVER_FILE;

    for (var j = 0; j < quarterly.length; j++){
      var extension = quarterly[j].split(".").pop();
      if (extension != SOURCE_EXTENSION) continue;

      var day_path = quarterly_path.replace(SOURCE_PATH, DIST_PATH) + "/" + quarterly[j].replace(SOURCE_EXTENSION, DIST_EXTENSION),
          quarterly_md = metaMarked(fs.readFileSync(quarterly_path + "/" + quarterly[j], "utf-8"));

      fswf(day_path, quarterly_md.html);
      quarterly_md.meta.path = DIST_S3 + "/" + quarterly_path.replace(SOURCE_PATH, "") + "/" + quarterly[j].replace(SOURCE_EXTENSION, DIST_EXTENSION);
      quarterly_info.lessons.push(quarterly_md.meta);
    }
    fswf(quarterly_path.replace(SOURCE_PATH, DIST_PATH) + "/" + DIST_INFO_FILE, JSON.stringify(quarterly_info));
    lang_info.push(quarterly_info);

  }

  fswf(path.replace(SOURCE_PATH, DIST_PATH) + "/" + DIST_INFO_FILE, JSON.stringify(lang_info));
};

var languages = fs.readdirSync(SOURCE_PATH);

for (var i = 0; i < languages.length; i++){
  if (!fs.lstatSync(SOURCE_PATH + languages[i]).isDirectory()) continue;
  processLang(SOURCE_PATH + languages[i]);
}

<commit_msg>Do not save lessons in the language info<commit_after>var metaMarked =    require("meta-marked"),
    fs =            require("fs-extra"),
    yamljs =        require("yamljs"),
    fswf =          require("safe-write-file");

var SOURCE_PATH = "src/",
    SOURCE_INFO_FILE = "info.yml",
    SOURCE_EXTENSION = "md",
    SOURCE_COVER_FILE = "cover.png",
    DIST_PATH = "dist/",
    DIST_INFO_FILE = "info.json",
    DIST_COVER_FILE = "cover.png",
    DIST_EXTENSION = "html",
    DIST_S3 = "https://s3-us-west-2.amazonaws.com/com.cryart.sabbathschool";

var processLang = function(path){
  var quarterlies = fs.readdirSync(path).reverse(),
      lang_info = [];

  for (var i = 0; i < quarterlies.length; i++){
    var quarterly_path = path + "/" + quarterlies[i];
    if (!fs.lstatSync(quarterly_path).isDirectory()) continue;
    if (!fs.lstatSync(quarterly_path + "/" + SOURCE_INFO_FILE).isFile()) continue;
    if (!fs.lstatSync(quarterly_path + "/" + SOURCE_COVER_FILE).isFile()) continue;

    var quarterly = fs.readdirSync(quarterly_path);

    var quarterly_info = yamljs.load(quarterly_path + "/" + SOURCE_INFO_FILE);
    quarterly_info.lessons = [];

    fs.copySync(quarterly_path + "/" + SOURCE_COVER_FILE, quarterly_path.replace(SOURCE_PATH, DIST_PATH) + "/" + DIST_COVER_FILE);
    quarterly_info.cover = DIST_S3 + "/" + quarterly_path.replace(SOURCE_PATH, "") + "/" + DIST_COVER_FILE;

    for (var j = 0; j < quarterly.length; j++){
      var extension = quarterly[j].split(".").pop();
      if (extension != SOURCE_EXTENSION) continue;

      var day_path = quarterly_path.replace(SOURCE_PATH, DIST_PATH) + "/" + quarterly[j].replace(SOURCE_EXTENSION, DIST_EXTENSION),
          quarterly_md = metaMarked(fs.readFileSync(quarterly_path + "/" + quarterly[j], "utf-8"));

      fswf(day_path, quarterly_md.html);
      quarterly_md.meta.path = DIST_S3 + "/" + quarterly_path.replace(SOURCE_PATH, "") + "/" + quarterly[j].replace(SOURCE_EXTENSION, DIST_EXTENSION);
      quarterly_info.lessons.push(quarterly_md.meta);
    }
    fswf(quarterly_path.replace(SOURCE_PATH, DIST_PATH) + "/" + DIST_INFO_FILE, JSON.stringify(quarterly_info));
    delete quarterly_info.lessons;
    lang_info.push(quarterly_info);

  }

  fswf(path.replace(SOURCE_PATH, DIST_PATH) + "/" + DIST_INFO_FILE, JSON.stringify(lang_info));
};

var languages = fs.readdirSync(SOURCE_PATH);

for (var i = 0; i < languages.length; i++){
  if (!fs.lstatSync(SOURCE_PATH + languages[i]).isDirectory()) continue;
  processLang(SOURCE_PATH + languages[i]);
}

<|endoftext|>


<commit_before>distributions.push(
  [
    {
      "name": "example_core_emlynoregan_com",
      "language": "sUTL0",
      "transform-t": "Core: Example"
    },
    {
      "name": "example2_core_emlynoregan_com",
      "language": "sUTL0",
      "transform-t": [ "#*.example_core", "#*.example_core" ],
      "test-t": {
        "&": "if",
        "cond": {"'":
          {
            "&": "!=",
            "a": "#*.example_core",
            "b": "Core: Example"
          }
        },
        "true": "example_core behaves unexpectedly",
        "false": null
      },
      "requires": ["example_core"]
    },
    {
      "name": "example3fails_core_emlynoregan_com",
      "language": "sUTL0",
      "transform-t": "Core: Example 3",
      "test-t": [
        "Example 3 Fails"
      ]
    },
    {
      "name": "map_core_emlynoregan_com",
      "language": "sUTL0",
      "transform-t":
      {
        "&": "if",
        "cond": "#@.list",
        "true": {
          "'": [
            "&&",
            {
              "!": "#@.t",
              "item": {
                "!": "#*.head_core_emlynoregan_com",
                "list": "#@.list"
              }
            },
            {
              "!": "#*.map_core_emlynoregan_com",
              "list": {
                "!": "#*.tail_core_emlynoregan_com",
                "list": "#@.list"
              },
              "t": "#@.t"
            }
          ]
        },
        "false": {
          "'": []
        }
      },
      "requires": [
        "map_core_emlynoregan_com",
        "head_core_emlynoregan_com",
        "tail_core_emlynoregan_com"
      ]
    },
    {
      "name": "reduce_core_emlynoregan_com",
      "language": "sUTL0",
      "transform-t": {
        "&": "if",
        "cond": "#@.list",
        "true": { "'": {
          "!": "#*.reduce_core_emlynoregan_com",
          "list": {
            "!": "#*.tail_core_emlynoregan_com",
            "list": "#@.list"
          },
          "t": "#@.t",
          "accum": {
            "!": "#@.t",
            "item": {
              "!": "#*.head_core_emlynoregan_com",
              "list": "#@.list"
            },
            "accum": "#@.accum"
          }
        }},
        "false": {
          "'": "#@.accum"
        }
      },
      "requires": [
        "reduce_core_emlynoregan_com",
        "head_core_emlynoregan_com",
        "tail_core_emlynoregan_com"
      ]
    },
    {
      "name": "reverse_core_emlynoregan_com",
      "language": "sUTL0",
      "transform-t":
      {
        "&": "if",
        "cond": "#@.list",
        "true": {
          "'": [
            "&&",
            {
              "!": "#*.reverse_core_emlynoregan_com",
              "list": {
                "!": "#*.tail_core_emlynoregan_com",
                "list": "#@.list"
              }
            },
            {
              "!": "#*.head_core_emlynoregan_com",
              "list": "#@.list"
            }
          ]
        },
        "false": {
          "'": []
        }
      },
      "requires": [
        "reverse_core_emlynoregan_com",
        "head_core_emlynoregan_com",
        "tail_core_emlynoregan_com"
      ]
    },
    {
      "name": "head_core_emlynoregan_com",
      "language": "sUTL0",
      "transform-t": "#@.list[0]"
    },
    {
      "name": "last_core_emlynoregan_com",
      "language": "sUTL0",
      "transform-t": "#@.list[-1:]"
    },
    {
      "name": "tail_core_emlynoregan_com",
      "language": "sUTL0",
      "transform-t": "##@.list[1:]"
    },
    {
      "name": "front_core_emlynoregan_com",
      "language": "sUTL0",
      "transform-t": "##@.list[:-1]"
    },
    {
      "name": "concat_core_emlynoregan_com",
      "language": "sUTL0",
      "transform-t": [
        "&&",
        "#@.a",
        "#@.b"
      ]
    },
    {
      "name": "removenulls_core_emlynoregan_com",
      "language": "sUTL0",
      "transform-t": {
        "!": "#*.reduce_core_emlynoregan_com",
        "list": "#@.list",
        "t": {"'": {
         "&": "if",
         "cond": "#@.item",
         "true": {
             "&": "if",
             "cond": "#@.accum",
             "true": ["&&", "#@.accum", ["#@.item"]],
             "false": ["#@.item"]
         },
         "false": {
             "&": "if",
             "cond": "#@.accum",
             "true": ["&&", "#@.accum"],
             "false": []
         }
        }}
      },
      "requires": [
        "reduce_core_emlynoregan_com"
      ]
    },
    {
      "name": "count_core_emlynoregan_com",
      "language": "sUTL0",
      "transform-t":
      {
        "&": "if",
        "cond": {"'": {
          "&": "=",
          "a": "list",
          "b": {
            "&": "type",
            "value": "#@.obj"
          }
        }},
        "true": {"'": {
            "!": "#*.reduce_core_emlynoregan_com",
            "list": "#@.obj",
            "accum": 0,
            "t": {"'": {
              "&": "+",
              "a": {
                "!": "#*.count_core_emlynoregan_com",
                "obj": "#@.item"
              },
              "b": "#@.accum"
            }}
        }},
        "false": {"'": 1}
      },
      "requires": ["reduce_core_emlynoregan_com", "count_core_emlynoregan_com"]
    },
    {
      "name": "sum_core_emlynoregan_com",
      "language": "sUTL0",
      "transform-t":
      {
        "&": "if",
        "cond": {"'": {
          "&": "=",
          "a": "list",
          "b": {
            "&": "type",
            "value": "#@.obj"
          }
        }},
        "true": {"'": {
            "!": "#*.reduce_core_emlynoregan_com",
            "list": "#@.obj",
            "accum": 0,
            "t": {"'": {
              "&": "+",
              "a": {
                "!": "#*.sum_core_emlynoregan_com",
                "obj": "#@.item"
              },
              "b": "#@.accum"
            }}
        }},
        "false": {"'": {
          "&": "if",
          "cond": {"'": {
            "&": "=",
            "a": "number",
            "b": {
              "&": "type",
              "value": "#@.obj"
            }
          }},
          "true": {"'": "#@.obj"},
          "false": 0
        }}
      },
      "requires": ["reduce_core_emlynoregan_com", "sum_core_emlynoregan_com"]
    },
    {
      "name": "zip_core_emlynoregan_com",
      "language": "sUTL0",
      "transform-t": {
        "&": "if",
        "cond": {"'": {
          "&": "<",
          "a": 0,
          "b": {
            "!": "#*.count_core_emlynoregan_com",
            "obj": "#@.list"
          }
        }},
        "true": {"'": [
          "&&",
          [
            {
              "!": "#*.reduce_core_emlynoregan_com",
              "list": "#@.list",
              "accum": [],
              "t": {"'": [
                "&&",
                "#@.accum",
                {
                  "!": "#*.head_core_emlynoregan_com",
                  "list": "#@.item"
                }
              ]}
            }
          ],
          {
            "!": "#*.zip_core_emlynoregan_com",
            "list": {
              "!": "#*.reduce_core_emlynoregan_com",
              "list": "#@.list",
              "accum": [],
              "t": {"'": [
                "&&",
                "#@.accum",
                [
                  {
                    "!": "#*.tail_core_emlynoregan_com",
                    "list": "#@.item"
                  }
                ]
              ]}
            }
          }
        ]},
        "false": []
      },
      "requires": [
        "count_core_emlynoregan_com",
        "require_core_emlynoregan_com",
        "head_core_emlynoregan_com",
        "tail_core_emlynoregan_com",
        "zip_core_emlynoregan_com"
      ]
    },
    {
      "name": "addmaps_core_emlynoregan_com",
      "language": "sUTL0",
      "transform-t": {
        "&": "makemap",
        "value": {
          "!": "#*.zip_core_emlynoregan_com",
          "list": [
            [
              "&&",
              {
                "&": "keys",
                "map": "#@.map1"
              },
              {
                "&": "keys",
                "map": "#@.map2"
              }
            ],
            [
              "&&",
              {
                "&": "values",
                "map": "#@.map1"
              },
              {
                "&": "values",
                "map": "#@.map2"
              }
            ]
          ]
        }
      },
      "requires": ["zip_core_emlynoregan_com"]
    },
    {
      "name": "mapget_core_emlynoregan_com",
      "language": "sUTL0",
      "transform-t": {
        "!": "#*.head_core_emlynoregan_com",
        "list":
        {
          "&": "path",
          "path": {
            "&": "+",
            "a": {"'": "@.map"},
            "b": {
              "&": "+",
              "a": ".",
              "b": "#@.key"
            }
          }
        }
      },
      "requires": ["head_core_emlynoregan_com"]
    },
    {
      "name": "arrget_core_emlynoregan_com",
      "language": "sUTL0",
      "transform-t":
      {
        "!": "#*.head_core_emlynoregan_com",
        "list":
        {
          "&": "path",
          "path": {
            "&": "+",
            "a": {"'": "@.map"},
            "b": {
              "&": "+",
              "a": "[",
              "b": {
                "&": "+",
                "a": "#@.ix",
                "b": "]"
              }
            }
          }
        }
      },
      "requires": ["head_core_emlynoregan_com"]
    },
    {
      "name": "keys2map_core_emlynoregan_com",
      "language": "sUTL0",
      "transform-t":
      {
        "&": "makemap",
        "value":
        {
          "!": "#*.map_core_emlynoregan_com",
          "list": "#@.list",
          "t": {"'":
            [[ "#@.item", true]]
          }
        }
      },
      "requires": ["map_core_emlynoregan_com"]
    },
    {
      "name": "tests_tst_emlynoregan_com",
      "language": "sUTL0",
      "transform-t":
      {
        "!": "#*.removenulls_core_emlynoregan_com",
        "list":
        {
          "!": "#*.map_core_emlynoregan_com",
          "list": "#@.tests",
          "t": {"'":
            {
              "!": "#*.test_tst_emlynoregan_com",
              "test-t": "#@.item.test-t",
              "name": "#@.item.name"
            }
          }
        }
      },
      "requires": [
        "map_core_emlynoregan_com",
        "test_tst_emlynoregan_com",
        "removenulls_core_emlynoregan_com"
      ]
    },
    {
      "name": "test_tst_emlynoregan_com",
      "language": "sUTL0",
      "transform-t":
      {
        "&": "if",
        "cond": "#@.test-t",
        "true": null,
        "false": "#@.name"
      }
    },
    {
      "name": "asserttrue_tst_emlynoregan_com",
      "language": "sUTL0",
      "transform-t":
      {
        "&": "if",
        "cond": {"'":
        {
          "&": "=",
          "a": "#@.test-t",
          "b": true
        }},
        "true": null,
        "false": "fails"
      }
    }
  ]
)
<commit_msg>Delete sUTL_core.js<commit_after><|endoftext|>