<commit_before>((global) => {
  const TOKEN_TYPE_STRING = 'string';
  const TOKEN_TYPE_ARRAY = 'array';

  const validTokenKeys = [{
    key: 'author',
    type: 'string',
    param: 'username',
  },{
    key: 'assignee',
    type: 'string',
    param: 'username',
  },{
    key: 'milestone',
    type: 'string',
    param: 'title',
  },{
    key: 'label',
    type: 'array',
    param: 'name%5B%5D',
  },];

  class FilteredSearchManager {
    constructor() {
      this.bindEvents();
      this.loadSearchParamsFromURL();
      this.clearTokens();
    }

    bindEvents() {
      const input = document.querySelector('.filtered-search');
      const clearSearch = document.querySelector('.clear-search');

      input.addEventListener('input', this.tokenize.bind(this));
      input.addEventListener('keydown', this.checkForEnter.bind(this));

      clearSearch.addEventListener('click', this.clearSearch.bind(this));
    }

    clearSearch(event) {
      event.stopPropagation();
      event.preventDefault();

      this.clearTokens();
      const input = document.querySelector('.filtered-search');
      input.value = '';

      event.target.classList.add('hidden');
    }

    clearTokens() {
      this.tokens = [];
      this.searchToken = '';
    }

    loadSearchParamsFromURL() {
      const params = window.location.search.split('&');
      let inputValue = '';

      params.forEach((p) => {
        const split = p.split('=');
        const key = split[0];
        const value = split[1];

        const match = validTokenKeys.find((t) => {
          return key === `${t.key}_${t.param}`;
        });

        if (match) {
          const sanitizedKey = key.slice(0, key.indexOf('_'));
          let sanitizedValue = value;

          if (match && sanitizedKey === 'label') {
            sanitizedValue = sanitizedValue.replace(/%20/g, ' ');
          }

          inputValue += `${sanitizedKey}:${sanitizedValue} `;
        } else if (!match && key === 'search') {
          // Sanitize value as URL converts spaces into +
          const sanitizedValue = value.replace(/[+]/g, ' ');
          inputValue += `${sanitizedValue} `;
        }
      });

      // Trim the last space value
      document.querySelector('.filtered-search').value = inputValue.trim();

      if (inputValue.trim()) {
        document.querySelector('.clear-search').classList.remove('hidden');
      }
    }

    tokenize(event) {
      // Re-calculate tokens
      this.clearTokens();

      // Enable clear button
      document.querySelector('.clear-search').classList.remove('hidden');

      const input = event.target.value;
      const inputs = input.split(' ');
      let searchTerms = '';
      let lastQuotation = '';
      let incompleteToken = false;

      const addSearchTerm = function addSearchTerm(term) {
        searchTerms += term + ' ';
      }

      inputs.forEach((i) => {
        if (incompleteToken) {
          const prevToken = this.tokens[this.tokens.length - 1];
          prevToken.value += ` ${i}`;

          // Remove last quotation
          const lastQuotationRegex = new RegExp(lastQuotation, 'g');
          prevToken.value = prevToken.value.replace(lastQuotationRegex, '');
          this.tokens[this.tokens.length - 1] = prevToken;

          // Check to see if this quotation completes the token value
          if (i.indexOf(lastQuotation)) {
            incompleteToken = !incompleteToken;
          }

          return;
        }

        const colonIndex = i.indexOf(':');

        if (colonIndex !== -1) {
          const tokenKey = i.slice(0, colonIndex).toLowerCase();
          const tokenValue = i.slice(colonIndex + 1);

          const match = validTokenKeys.find((v) => {
            return v.key === tokenKey;
          });

          if (tokenValue.indexOf('"') !== -1) {
            lastQuotation = '"';
            incompleteToken = true;
          } else if (tokenValue.indexOf('\'') !== -1) {
            lastQuotation = '\'';
            incompleteToken = true;
          }

          if (match && tokenValue.length > 0) {
            this.tokens.push({
              key: match.key,
              value: tokenValue,
            });
          } else {
            addSearchTerm(i);
          }
        } else {
          addSearchTerm(i);
        }
      }, this);

      this.searchToken = searchTerms.trim();
      this.printTokens();
    }

    printTokens() {
      console.log('tokens:')
      this.tokens.forEach((token) => {
        console.log(token);
      })
      console.log('search: ' + this.searchToken);
    }

    checkForEnter(event) {
      if (event.key === 'Enter') {
        event.stopPropagation();
        event.preventDefault();
        this.search();
      }
    }

    search() {
      console.log('search');
      let path = '?scope=all&utf8=✓';

      // Check current state
      const currentPath = window.location.search;
      const stateIndex = currentPath.indexOf('state=');
      const defaultState = 'opened';
      let currentState = defaultState;

      if (stateIndex !== -1) {
        const remaining = currentPath.slice(stateIndex + 6);
        const separatorIndex = remaining.indexOf('&');

        currentState = separatorIndex === -1 ? remaining : remaining.slice(0, separatorIndex);
      }

      path += `&state=${currentState}`

      this.tokens.forEach((token) => {
        const param = validTokenKeys.find((t) => {
          return t.key === token.key;
        }).param;

        path += `&${token.key}_${param}=${token.value}`;
      });

      if (this.searchToken) {
        path += '&search=' + this.searchToken.replace(/ /g, '+');
      }

      window.location = path;
    }
  }

  global.FilteredSearchManager = FilteredSearchManager;
})(window.gl || (window.gl = {}));
<commit_msg>Add special character encoding<commit_after>((global) => {
  const TOKEN_TYPE_STRING = 'string';
  const TOKEN_TYPE_ARRAY = 'array';

  const validTokenKeys = [{
    key: 'author',
    type: 'string',
    param: 'username',
  },{
    key: 'assignee',
    type: 'string',
    param: 'username',
  },{
    key: 'milestone',
    type: 'string',
    param: 'title',
  },{
    key: 'label',
    type: 'array',
    param: 'name[]',
  },];

  class FilteredSearchManager {
    constructor() {
      this.bindEvents();
      this.loadSearchParamsFromURL();
      this.clearTokens();
    }

    bindEvents() {
      const input = document.querySelector('.filtered-search');
      const clearSearch = document.querySelector('.clear-search');

      input.addEventListener('input', this.tokenize.bind(this));
      input.addEventListener('keydown', this.checkForEnter.bind(this));

      clearSearch.addEventListener('click', this.clearSearch.bind(this));
    }

    clearSearch(event) {
      event.stopPropagation();
      event.preventDefault();

      this.clearTokens();
      const input = document.querySelector('.filtered-search');
      input.value = '';

      event.target.classList.add('hidden');
    }

    clearTokens() {
      this.tokens = [];
      this.searchToken = '';
    }

    loadSearchParamsFromURL() {
      // We can trust that each param has one & since values containing & will be encoded
      const params = window.location.search.split('&');
      let inputValue = '';

      params.forEach((p) => {
        const split = p.split('=');
        const key = split[0];
        const value = decodeURIComponent(split[1]);

        const match = validTokenKeys.find((t) => {
          return key === `${t.key}_${t.param}`;
        });

        if (match) {
          const sanitizedKey = key.slice(0, key.indexOf('_'));
          let sanitizedValue = value;

          if (match && sanitizedKey === 'label') {
            sanitizedValue = sanitizedValue.replace(/%20/g, ' ');
          }

          inputValue += `${sanitizedKey}:${sanitizedValue} `;
        } else if (!match && key === 'search') {
          // Sanitize value as URL converts spaces into +
          const sanitizedValue = value.replace(/[+]/g, ' ');
          inputValue += `${sanitizedValue} `;
        }
      });

      // Trim the last space value
      document.querySelector('.filtered-search').value = inputValue.trim();

      if (inputValue.trim()) {
        document.querySelector('.clear-search').classList.remove('hidden');
      }
    }

    tokenize(event) {
      // Re-calculate tokens
      this.clearTokens();

      // Enable clear button
      document.querySelector('.clear-search').classList.remove('hidden');

      const input = event.target.value;
      const inputs = input.split(' ');
      let searchTerms = '';
      let lastQuotation = '';
      let incompleteToken = false;

      const addSearchTerm = function addSearchTerm(term) {
        searchTerms += term + ' ';
      }

      inputs.forEach((i) => {
        if (incompleteToken) {
          const prevToken = this.tokens[this.tokens.length - 1];
          prevToken.value += ` ${i}`;

          // Remove last quotation
          const lastQuotationRegex = new RegExp(lastQuotation, 'g');
          prevToken.value = prevToken.value.replace(lastQuotationRegex, '');
          this.tokens[this.tokens.length - 1] = prevToken;

          // Check to see if this quotation completes the token value
          if (i.indexOf(lastQuotation)) {
            incompleteToken = !incompleteToken;
          }

          return;
        }

        const colonIndex = i.indexOf(':');

        if (colonIndex !== -1) {
          const tokenKey = i.slice(0, colonIndex).toLowerCase();
          const tokenValue = i.slice(colonIndex + 1);

          const match = validTokenKeys.find((v) => {
            return v.key === tokenKey;
          });

          if (tokenValue.indexOf('"') !== -1) {
            lastQuotation = '"';
            incompleteToken = true;
          } else if (tokenValue.indexOf('\'') !== -1) {
            lastQuotation = '\'';
            incompleteToken = true;
          }

          if (match && tokenValue.length > 0) {
            this.tokens.push({
              key: match.key,
              value: tokenValue,
            });
          } else {
            addSearchTerm(i);
          }
        } else {
          addSearchTerm(i);
        }
      }, this);

      this.searchToken = searchTerms.trim();
      this.printTokens();
    }

    printTokens() {
      console.log('tokens:')
      this.tokens.forEach((token) => {
        console.log(token);
      })
      console.log('search: ' + this.searchToken);
    }

    checkForEnter(event) {
      if (event.key === 'Enter') {
        event.stopPropagation();
        event.preventDefault();
        this.search();
      }
    }

    search() {
      console.log('search');
      let path = '?scope=all&utf8=✓';

      // Check current state
      const currentPath = window.location.search;
      const stateIndex = currentPath.indexOf('state=');
      const defaultState = 'opened';
      let currentState = defaultState;

      if (stateIndex !== -1) {
        const remaining = currentPath.slice(stateIndex + 6);
        const separatorIndex = remaining.indexOf('&');

        currentState = separatorIndex === -1 ? remaining : remaining.slice(0, separatorIndex);
      }

      path += `&state=${currentState}`

      this.tokens.forEach((token) => {
        const param = validTokenKeys.find((t) => {
          return t.key === token.key;
        }).param;

        path += `&${token.key}_${param}=${encodeURIComponent(token.value)}`;
      });

      if (this.searchToken) {
        path += '&search=' + encodeURIComponent(this.searchToken.replace(/ /g, '+'));
      }

      window.location = path;
    }
  }

  global.FilteredSearchManager = FilteredSearchManager;
})(window.gl || (window.gl = {}));
<|endoftext|>


<commit_before>'use strict';

module.exports = function(app) {
	var users = require('../../app/controllers/users.server.controller');
	var tasks = require('../../app/controllers/tasks.server.controller');

	// Tasks Routes

	app.post('/tasks/create', function(req, res) {
		tasks.create(req, res);
	});

	app.post('/tasks/updateMilestone', function(req, res) {
		tasks.updateMilestone(req, res);
	});

	app.get('/tasks', function(req, res) {
		tasks.list(req, res);
	});
	app.post('/task/update', function(req, res) {
		tasks.update(req, res);
	});
	app.get('/task/:id', function(req, res) {
		tasks.taskByID(req, res);
	});
    app.get('/tasks/myTask', function(req, res) {
		tasks.taskByUserId(req, res);
	});
	app.get('/task/deleteAssignee/:taskId/:assigneeId', function(req, res) {
		tasks.updateAssigneesList(req, res);
	});

	//app.route('/tasks')
	//	.get(tasks.list)
	//	.post(users.requiresLogin, tasks.create);
    //
	//app.route('/tasks/:taskId')
	//	.get(tasks.read)
	//	.put(users.requiresLogin, tasks.hasAuthorization, tasks.update)
	//	.delete(users.requiresLogin, tasks.hasAuthorization, tasks.delete);
    //
	//// Finish by binding the Task middleware
	//app.param('taskId', tasks.taskByID);
};
<commit_msg>Cleaning code before merge.<commit_after>'use strict';

module.exports = function(app) {
	var users = require('../../app/controllers/users.server.controller');
	var tasks = require('../../app/controllers/tasks.server.controller');

	// Tasks Routes

	app.post('/tasks/create', function(req, res) {
		tasks.create(req, res);
	});

	app.post('/tasks/updateMilestone', function(req, res) {
		tasks.updateMilestone(req, res);
	});

	app.get('/tasks', function(req, res) {
		tasks.list(req, res);
	});
	app.post('/task/update', function(req, res) {
		tasks.update(req, res);
	});
	app.get('/task/:id', function(req, res) {
		tasks.taskByID(req, res);
	});
    app.get('/tasks/myTask', function(req, res) {
		tasks.taskByUserId(req, res);
	});
	app.get('/task/deleteAssignee/:taskId/:assigneeId', function(req, res) {
		tasks.updateAssigneesList(req, res);
	});
};
<|endoftext|>


<commit_before>// @flow
import React, { PureComponent } from "react";
import Model from "oxalis/model";
import Store from "oxalis/store";
import { connect } from "react-redux";
import { Button, Dropdown, Menu, Icon, Modal } from "antd";
import Constants from "oxalis/constants";
import MergeModalView from "oxalis/view/action-bar/merge_modal_view";
import ShareModalView from "oxalis/view/action-bar/share_modal_view";
import UserScriptsModalView from "oxalis/view/action-bar/user_scripts_modal_view";
import SaveButton from "oxalis/view/action-bar/save_button";
import ButtonComponent from "oxalis/view/components/button_component";
import messages from "messages";
import api from "oxalis/api/internal_api";
import { undoAction, redoAction } from "oxalis/model/actions/save_actions";
import { copyAnnotationToUserAccount } from "admin/admin_rest_api";
import { location } from "libs/window";
import type { OxalisState, RestrictionsType, SettingsType, TaskType } from "oxalis/store";
import type { APIUserType } from "admin/api_flow_types";

type StateProps = {
  tracingType: string,
  annotationId: string,
  restrictions: RestrictionsType & SettingsType,
  task: ?TaskType,
  activeUser: ?APIUserType,
};

type State = {
  isShareModalOpen: boolean,
  isMergeModalOpen: boolean,
  isUserScriptsModalOpen: boolean,
};

class TracingActionsView extends PureComponent<StateProps, State> {
  state = {
    isShareModalOpen: false,
    isMergeModalOpen: false,
    isUserScriptsModalOpen: false,
  };

  modalWrapper: ?HTMLDivElement = null;

  handleSave = async (event?: SyntheticInputEvent<>) => {
    if (event != null) {
      event.target.blur();
    }
    await Model.save();
  };

  handleUndo = () => {
    Store.dispatch(undoAction());
  };

  handleRedo = () => {
    Store.dispatch(redoAction());
  };

  handleCopyToAccount = async (event: SyntheticInputEvent<>) => {
    event.target.blur();
    const newAnnotation = await copyAnnotationToUserAccount(
      this.props.annotationId,
      this.props.tracingType,
    );
    location.href = `/annotations/Explorational/${newAnnotation.id}`;
  };

  handleFinish = async (event: SyntheticInputEvent<>) => {
    event.target.blur();
    const url = `/annotations/${this.props.tracingType}/${
      this.props.annotationId
    }/finishAndRedirect`;
    await this.handleSave();

    Modal.confirm({
      title: messages["annotation.finish"],
      onOk: () => {
        location.href = url;
      },
    });
  };

  handleShareOpen = () => {
    this.setState({ isShareModalOpen: true });
  };

  handleShareClose = () => {
    this.setState({ isShareModalOpen: false });
  };

  handleDownload = async (event: SyntheticInputEvent<>) => {
    event.target.blur();
    const win = window.open("about:blank", "_blank");
    win.document.body.innerHTML = messages["download.wait"];
    await this.handleSave();

    const downloadUrl = `/annotations/${this.props.tracingType}/${
      this.props.annotationId
    }/download`;
    win.location.href = downloadUrl;
    win.document.body.innerHTML = messages["download.close_window"];
  };

  handleFinishAndGetNextTask = async (event: SyntheticInputEvent<>) => {
    event.target.blur();
    api.tracing.finishAndGetNextTask();
  };

  handleMergeOpen = () => {
    this.setState({ isMergeModalOpen: true });
  };

  handleMergeClose = () => {
    this.setState({ isMergeModalOpen: false });
  };

  handleUserScriptsOpen = () => {
    this.setState({ isUserScriptsModalOpen: true });
  };

  handleUserScriptsClose = () => {
    this.setState({ isUserScriptsModalOpen: false });
  };

  render() {
    const viewMode = Store.getState().temporaryConfiguration.viewMode;
    const isSkeletonMode = Constants.MODES_SKELETON.includes(viewMode);
    const hasAdvancedOptions = this.props.restrictions.advancedOptionsAllowed;
    const archiveButtonText = this.props.task ? "Finish" : "Archive";
    const restrictions = this.props.restrictions;

    const saveButton = restrictions.allowUpdate
      ? [
          isSkeletonMode
            ? [
                <ButtonComponent key="undo-button" title="Undo (Ctrl+Z)" onClick={this.handleUndo}>

                </ButtonComponent>,
                <ButtonComponent key="redo-button" title="Redo (Ctrl+Y)" onClick={this.handleRedo}>

                </ButtonComponent>,
              ]
            : null,
          <SaveButton key="save-button" onClick={this.handleSave} />,
        ]
      : [
          <ButtonComponent key="read-only-button" type="primary" disabled>
            Read only
          </ButtonComponent>,
          <ButtonComponent key="copy-button" icon="file-add" onClick={this.handleCopyToAccount}>
            Copy To My Account
          </ButtonComponent>,
        ];

    const finishAndNextTaskButton =
      hasAdvancedOptions && restrictions.allowFinish && this.props.task ? (
        <ButtonComponent
          key="next-button"
          icon="verticle-left"
          onClick={this.handleFinishAndGetNextTask}
        >
          Finish and Get Next Task
        </ButtonComponent>
      ) : null;

    const elements = [];
    const modals = [];
    if (hasAdvancedOptions) {
      if (restrictions.allowFinish) {
        elements.push(
          <Menu.Item key="finish-button">

              <Icon type="check-circle-o" />
              {archiveButtonText}

          </Menu.Item>,
        );
      }
      if (restrictions.allowDownload) {
        elements.push(
          <Menu.Item key="download-button">

              <Icon type="download" />
              Download

          </Menu.Item>,
        );
      }
      elements.push(
        <Menu.Item key="share-button">

            <Icon type="share-alt" />
            Share

        </Menu.Item>,
      );
      modals.push(
        <ShareModalView
          key="share-modal"
          isVisible={this.state.isShareModalOpen}
          onOk={this.handleShareClose}
        />,
      );
      elements.push(
        <Menu.Item key="user-scripts-button">

            <Icon type="setting" />
            Add Script

        </Menu.Item>,
      );
      modals.push(
        <UserScriptsModalView
          key="user-scripts-modal"
          isVisible={this.state.isUserScriptsModalOpen}
          onOK={this.handleUserScriptsClose}
        />,
      );
    }

    if (isSkeletonMode && this.props.activeUser != null) {
      elements.push(
        <Menu.Item key="merge-button">

            <Icon type="folder-open" />
            Merge Tracing

        </Menu.Item>,
      );
      modals.push(
        <MergeModalView
          key="merge-modal"
          isVisible={this.state.isMergeModalOpen}
          onOk={this.handleMergeClose}
        />,
      );
    }

    const menu = <Menu>{elements}</Menu>;

    return (

        <Button.Group size="large">
          {saveButton}
          {finishAndNextTaskButton}
          {modals}
          <Dropdown overlay={menu}>
            <ButtonComponent>
              <Icon type="down" />
            </ButtonComponent>
          </Dropdown>
        </Button.Group>

    );
  }
}

function mapStateToProps(state: OxalisState): StateProps {
  return {
    tracingType: state.tracing.tracingType,
    annotationId: state.tracing.annotationId,
    restrictions: state.tracing.restrictions,
    task: state.task,
    activeUser: state.activeUser,
  };
}

export default connect(mapStateToProps)(TracingActionsView);
<commit_msg>removed "copy to my account" button for volume tracing #2123<commit_after>// @flow
import React, { PureComponent } from "react";
import Model from "oxalis/model";
import Store from "oxalis/store";
import { connect } from "react-redux";
import { Button, Dropdown, Menu, Icon, Modal } from "antd";
import Constants from "oxalis/constants";
import MergeModalView from "oxalis/view/action-bar/merge_modal_view";
import ShareModalView from "oxalis/view/action-bar/share_modal_view";
import UserScriptsModalView from "oxalis/view/action-bar/user_scripts_modal_view";
import SaveButton from "oxalis/view/action-bar/save_button";
import ButtonComponent from "oxalis/view/components/button_component";
import messages from "messages";
import api from "oxalis/api/internal_api";
import { undoAction, redoAction } from "oxalis/model/actions/save_actions";
import { copyAnnotationToUserAccount } from "admin/admin_rest_api";
import { location } from "libs/window";
import type { OxalisState, RestrictionsType, SettingsType, TaskType } from "oxalis/store";
import type { APIUserType } from "admin/api_flow_types";

type StateProps = {
  tracingType: string,
  annotationId: string,
  restrictions: RestrictionsType & SettingsType,
  task: ?TaskType,
  activeUser: ?APIUserType,
};

type State = {
  isShareModalOpen: boolean,
  isMergeModalOpen: boolean,
  isUserScriptsModalOpen: boolean,
};

class TracingActionsView extends PureComponent<StateProps, State> {
  state = {
    isShareModalOpen: false,
    isMergeModalOpen: false,
    isUserScriptsModalOpen: false,
  };

  modalWrapper: ?HTMLDivElement = null;

  handleSave = async (event?: SyntheticInputEvent<>) => {
    if (event != null) {
      event.target.blur();
    }
    await Model.save();
  };

  handleUndo = () => {
    Store.dispatch(undoAction());
  };

  handleRedo = () => {
    Store.dispatch(redoAction());
  };

  handleCopyToAccount = async (event: SyntheticInputEvent<>) => {
    event.target.blur();
    const newAnnotation = await copyAnnotationToUserAccount(
      this.props.annotationId,
      this.props.tracingType,
    );
    location.href = `/annotations/Explorational/${newAnnotation.id}`;
  };

  handleFinish = async (event: SyntheticInputEvent<>) => {
    event.target.blur();
    const url = `/annotations/${this.props.tracingType}/${
      this.props.annotationId
    }/finishAndRedirect`;
    await this.handleSave();

    Modal.confirm({
      title: messages["annotation.finish"],
      onOk: () => {
        location.href = url;
      },
    });
  };

  handleShareOpen = () => {
    this.setState({ isShareModalOpen: true });
  };

  handleShareClose = () => {
    this.setState({ isShareModalOpen: false });
  };

  handleDownload = async (event: SyntheticInputEvent<>) => {
    event.target.blur();
    const win = window.open("about:blank", "_blank");
    win.document.body.innerHTML = messages["download.wait"];
    await this.handleSave();

    const downloadUrl = `/annotations/${this.props.tracingType}/${
      this.props.annotationId
    }/download`;
    win.location.href = downloadUrl;
    win.document.body.innerHTML = messages["download.close_window"];
  };

  handleFinishAndGetNextTask = async (event: SyntheticInputEvent<>) => {
    event.target.blur();
    api.tracing.finishAndGetNextTask();
  };

  handleMergeOpen = () => {
    this.setState({ isMergeModalOpen: true });
  };

  handleMergeClose = () => {
    this.setState({ isMergeModalOpen: false });
  };

  handleUserScriptsOpen = () => {
    this.setState({ isUserScriptsModalOpen: true });
  };

  handleUserScriptsClose = () => {
    this.setState({ isUserScriptsModalOpen: false });
  };

  render() {
    const viewMode = Store.getState().temporaryConfiguration.viewMode;
    const isSkeletonMode = Constants.MODES_SKELETON.includes(viewMode);
    const hasAdvancedOptions = this.props.restrictions.advancedOptionsAllowed;
    const archiveButtonText = this.props.task ? "Finish" : "Archive";
    const restrictions = this.props.restrictions;

    const saveButton = restrictions.allowUpdate
      ? [
          isSkeletonMode
            ? [
                <ButtonComponent key="undo-button" title="Undo (Ctrl+Z)" onClick={this.handleUndo}>

                </ButtonComponent>,
                <ButtonComponent key="redo-button" title="Redo (Ctrl+Y)" onClick={this.handleRedo}>

                </ButtonComponent>,
              ]
            : null,
          <SaveButton key="save-button" onClick={this.handleSave} />,
        ]
      : [
          <ButtonComponent key="read-only-button" type="primary" disabled>
            Read only
          </ButtonComponent>,
          isSkeletonMode ? (
            <ButtonComponent key="copy-button" icon="file-add" onClick={this.handleCopyToAccount}>
              Copy To My Account
            </ButtonComponent>
          ) : null,
        ];

    const finishAndNextTaskButton =
      hasAdvancedOptions && restrictions.allowFinish && this.props.task ? (
        <ButtonComponent
          key="next-button"
          icon="verticle-left"
          onClick={this.handleFinishAndGetNextTask}
        >
          Finish and Get Next Task
        </ButtonComponent>
      ) : null;

    const elements = [];
    const modals = [];
    if (hasAdvancedOptions) {
      if (restrictions.allowFinish) {
        elements.push(
          <Menu.Item key="finish-button">

              <Icon type="check-circle-o" />
              {archiveButtonText}

          </Menu.Item>,
        );
      }
      if (restrictions.allowDownload) {
        elements.push(
          <Menu.Item key="download-button">

              <Icon type="download" />
              Download

          </Menu.Item>,
        );
      }
      elements.push(
        <Menu.Item key="share-button">

            <Icon type="share-alt" />
            Share

        </Menu.Item>,
      );
      modals.push(
        <ShareModalView
          key="share-modal"
          isVisible={this.state.isShareModalOpen}
          onOk={this.handleShareClose}
        />,
      );
      elements.push(
        <Menu.Item key="user-scripts-button">

            <Icon type="setting" />
            Add Script

        </Menu.Item>,
      );
      modals.push(
        <UserScriptsModalView
          key="user-scripts-modal"
          isVisible={this.state.isUserScriptsModalOpen}
          onOK={this.handleUserScriptsClose}
        />,
      );
    }

    if (isSkeletonMode && this.props.activeUser != null) {
      elements.push(
        <Menu.Item key="merge-button">

            <Icon type="folder-open" />
            Merge Tracing

        </Menu.Item>,
      );
      modals.push(
        <MergeModalView
          key="merge-modal"
          isVisible={this.state.isMergeModalOpen}
          onOk={this.handleMergeClose}
        />,
      );
    }

    const menu = <Menu>{elements}</Menu>;

    return (

        <Button.Group size="large">
          {saveButton}
          {finishAndNextTaskButton}
          {modals}
          <Dropdown overlay={menu}>
            <ButtonComponent>
              <Icon type="down" />
            </ButtonComponent>
          </Dropdown>
        </Button.Group>

    );
  }
}

function mapStateToProps(state: OxalisState): StateProps {
  return {
    tracingType: state.tracing.tracingType,
    annotationId: state.tracing.annotationId,
    restrictions: state.tracing.restrictions,
    task: state.task,
    activeUser: state.activeUser,
  };
}

export default connect(mapStateToProps)(TracingActionsView);
<|endoftext|>


<commit_before>'use strict';

/**
 * Module dependencies.
 */
var passport = require('passport');

module.exports = function(app) {
	// User Routes
	var users = require('../../app/controllers/users');
	app.route('/users/me').get(users.me);
	app.route('/users').put(users.update);
	app.route('/users/password').post(users.changePassword);
	app.route('/users/accounts').delete(users.removeOAuthProvider);

	// Setting up the users api
	app.route('/auth/signup').post(users.signup);
	app.route('/auth/signin').post(users.signin);
	app.route('/auth/signout').get(users.signout);

	// Finish by binding the user middleware
	app.param('userId', users.userByID);
};<commit_msg>user route updated<commit_after>'use strict';

/**
 * Module dependencies.
 */
var passport = require('passport');

module.exports = function(app) {
	// User Routes
	var users = require('../../app/controllers/users');
	app.route('/users/me').get(users.me);
	app.route('/users').put(users.update);
	app.route('/users/password').post(users.changePassword);
	app.route('/users/accounts').delete(users.removeOAuthProvider);

	// Setting up the users api
	app.route('/auth/signup').post(users.signup);
	app.route('/auth/signin').post(users.signin);
	app.route('/auth/signout').get(users.signout);

	// Setting the facebook oauth routes
	app.route('/auth/facebook').get(passport.authenticate('facebook', {
		scope: ['email']
	}));
	app.route('/auth/facebook/callback').get(users.oauthCallback('facebook'));

	// Setting the twitter oauth routes
	app.route('/auth/twitter').get(passport.authenticate('twitter'));
	app.route('/auth/twitter/callback').get(users.oauthCallback('twitter'));

	// Setting the google oauth routes
	app.route('/auth/google').get(passport.authenticate('google', {
		scope: [
			'https://www.googleapis.com/auth/userinfo.profile',
			'https://www.googleapis.com/auth/userinfo.email'
		]
	}));
	app.route('/auth/google/callback').get(users.oauthCallback('google'));

	// Setting the linkedin oauth routes
	app.route('/auth/linkedin').get(passport.authenticate('linkedin'));
	app.route('/auth/linkedin/callback').get(users.oauthCallback('linkedin'));

	// Finish by binding the user middleware
	app.param('userId', users.userByID);
};<|endoftext|>


<commit_before>import mediator from '../mediator'

let checked = false

const update = status => {
	checked = status
	document.querySelector("#whether-to-unfollow").setAttribute("data-checked", checked)
	mediator.publish("whetherToUnfollow", checked)
}

document.addEventListener("click", e => {
	if(e.target.closest("#whether-to-unfollow")) {
		e.stopPropagation()
		update(!checked)
	}
})

mediator.subscribe("data-initialized", () => {
	update(checked)
})<commit_msg>whether to unfollow initial setting<commit_after>import mediator from '../mediator'

let checked = true

const update = status => {
	checked = status
	document.querySelector("#whether-to-unfollow").setAttribute("data-checked", checked)
	mediator.publish("whetherToUnfollow", checked)
}

document.addEventListener("click", e => {
	if(e.target.closest("#whether-to-unfollow")) {
		e.stopPropagation()
		update(!checked)
	}
})

mediator.subscribe("data-initialized", () => {
	update(checked)
})<|endoftext|>


<commit_before>/*globals jQuery,exports,require*/
/*exported createOfflineController*/

function createOfflineController(router) {
  'use strict';
  var AppConfig = AppConfig || require('config');
  var l = AppConfig.translate;
  return {
    template: '
' + '
' + 'OFFLINE' + '
' + '
' + '
' + l('offlineDetail') + '
' + '
' + '
',
    ready: function offlineReady() {
      jQuery('#splash').dimmer('hide').remove();
      var check = setInterval(function checkOnline() {
        if (navigator.onLine) {
          clearInterval(check);
          router.go('/online');
        }
      }, 1000);
    }
  };
}

if (typeof exports !== 'undefined') {
  exports.offline = {
    create: createOfflineController
  };
}
<commit_msg>clear offline check on offline descrtuctio<commit_after>/*globals jQuery,exports,require*/
/*exported createOfflineController*/

function createOfflineController(router) {
  'use strict';
  var AppConfig = AppConfig || require('config');
  var l = AppConfig.translate;
  var check;
  return {
    template: '
' + '
' + 'OFFLINE' + '
' + '
' + '
' + l('offlineDetail') + '
' + '
' + '
',
    destroyed: function destroydOffline() {
      if (check) {
        clearInterval(check);
        check = undefined;
      }
    },
    ready: function offlineReady() {
      jQuery('#splash').dimmer('hide').remove();
      check = setInterval(function checkOnline() {
        if (navigator.onLine) {
          clearInterval(check);
          check = undefined;
          router.go('/online');
        }
      }, 1000);
    }
  };
}

if (typeof exports !== 'undefined') {
  exports.offline = {
    create: createOfflineController
  };
}
<|endoftext|>


<commit_before>'use strict';

angular.module('BaubleApp')
    .controller('SearchCtrl', function ($scope, globals, Search, ViewMeta) {
        $scope.viewMeta = null;
        $scope.selected = null;
        $scope.results = null; // the results of the search

        // query the server for search results
        $scope.search = function(q) {
            $scope.results = [];
            if(!q) {
                $scope.alert = "Please enter a search query";
                return;
            } else {
                $scope.alert = null;
            }

            Search.query(q)
                .success(function(data, status, headers, config) {
                    console.log("data: ", data);
                    $scope.results = data.results;
                    if($scope.results.length==0) {
                        $scope.alert = "No results for your search query"
                    }
                })
                .error(function(data, status, headers, config) {
                    console.log("");
                });
        };

        $scope.itemSelected = function(selected) {
            $scope.viewMeta = ViewMeta.getView(selected.ref);
            console.log('selected: ', selected);
            $scope.selected = selected;
            globals.selected = selected;
        };

        $scope.itemExpanded = function() {
            console.log('itemExpanded(');
        };
    });
<commit_msg>- keep around the current search for when we reload the search results<commit_after>'use strict';

angular.module('BaubleApp')
    .controller('SearchCtrl', function ($scope, globals, Search, ViewMeta) {
        $scope.viewMeta = null;
        $scope.selected = null;
        $scope.results = null; // the results of the search

        // query the server for search results
        $scope.search = function(q) {
            $scope.results = [];
            if(!q) {
                $scope.alert = "Please enter a search query";
                return;
            } else {
                $scope.alert = null;
            }

            $scope.message = "Searching....";
            $scope.selected = $scope.viewMeta = $scope.results = null;
            console.log("q: ", q);
            localStorage.setItem('current_search', q);
            Search.query(q)
                .success(function(data, status, headers, config) {
                    $scope.results = data.results;
                    if($scope.results.length==0) {
                        $scope.alert = "No results for your search query"
                    }
                    $scope.message = "";
                })
                .error(function(data, status, headers, config) {
                    $scope.message = "";
                });
        };

        $scope.itemSelected = function(selected) {
            $scope.viewMeta = ViewMeta.getView(selected.ref);
            console.log('selected: ', selected);
            $scope.selected = selected;
            globals.selected = selected;
        };

        $scope.itemExpanded = function() {
            console.log('itemExpanded(');
        };

        var current_search = localStorage.getItem("current_search");
        if(current_search) {
            $scope.q = current_search;
            $scope.search(current_search);
        };
    });
<|endoftext|>


<commit_before>(function() {
	function seekBar($document) {
		var calculatePercent = function(seekBar, event) {
			var offsetX = event.pageX - seekBar.offset().left;
			var seekBarWidth = seekBar.width();
			var offsetXPercent = offsetX / seekBarWidth;
			offsetXPercent = Math.max(0, offsetXPercent);
			offsetXPercent = Math.min(1, offsetXPercent);
			return offsetXPercent;
		};

		return {
			templateUrl: '/templates/directives/seek_bar.html',
			replace: true,
			restrict: 'E',
			scope: {
				onChange: '&'
			},
			link: function(scope, element, attributes) {
				scope.value = 0;
				scope.max = 100;

				var seekBar = $(element);

				attributes.$observe('value', function(newValue) {
					scope.value = newValue;
				});

				attributes.$observe('max', function(newValue) {
					scope.max = newValue;
				});

				var percentString = function () {
					var value = scope.value;
					var max = scope.max;
					var percent = value / max * 100;
					return percent + "%";
				};

				scope.fillStyle = function() {
					return {width: percentString()};
				};

				scope.thumbStyle = function() {
					return {left: percentString()};
				};

				scope.onClickSeekBar = function(event) {
					var percent = calculatePercent(seekBar, event);
					scope.value = percent * scope.max;
					notifyOnChange(scope.value);
				};

				scope.trackThumb = function() {
					$document.bind('mousemove.thumb', function(event) {
						var percent = calculatePercent(seekBar, event);
						scope.$apply(function() {
							scope.value = percent * scope.max;
							notifyOnChange(scope.value);
						});
					});
				var notifyOnChange = function(newValue) {
					if (typeof scope.onChange === 'function') {
						scope.onChange({value: newValue});
					}
				};
					$document.bind('mouseup.thumb', function() {
						$document.unbind('mousemove.thumb');
						$document.unbind('mouseup.thumb');
					});
				};
			}
		};
	}

	angular
		.module('blocJams')
		.directive('seekBar', ['$document', seekBar]);
})();

/*
These are the error messages produced from the code in it's current state:

[Error] null is not an object (evaluating 'currentBuzzObject.isPaused')
http://localhost:3000/scripts/services/SongPlayer.js:83
	(anonymous function) (angular.min.js:95)
	$apply (angular.min.js:149:449)
	(anonymous function) (angular.min.js:285:469)
	dispatch (jquery-3.2.1.min.js:3:10322)
[Error] Can't find variable: notifyOnChange
http://localhost:3000/scripts/directives/seekBar.js:51
	(anonymous function) (angular.min.js:95)
	$apply (angular.min.js:149:449)
	(anonymous function) (angular.min.js:285:469)
	dispatch (jquery-3.2.1.min.js:3:10322)
*/

/*  git commit -m "angular-checkpoint-10-Directives-Part-2:  completed"  */<commit_msg>Created branch 'angular-assignment-10-Directives-Part-2'...<commit_after>(function() {
	function seekBar($document) {
		var calculatePercent = function(seekBar, event) {
			var offsetX = event.pageX - seekBar.offset().left;
			var seekBarWidth = seekBar.width();
			var offsetXPercent = offsetX / seekBarWidth;
			offsetXPercent = Math.max(0, offsetXPercent);
			offsetXPercent = Math.min(1, offsetXPercent);
			return offsetXPercent;
		};

		return {
			templateUrl: '/templates/directives/seek_bar.html',
			replace: true,
			restrict: 'E',
			scope: {
				onChange: '&'
			},
			link: function(scope, element, attributes) {
				scope.value = 0;
				scope.max = 100;

				var seekBar = $(element);

				attributes.$observe('value', function(newValue) {
					scope.value = newValue;
				});

				attributes.$observe('max', function(newValue) {
					scope.max = newValue;
				});

				var percentString = function () {
					var value = scope.value;
					var max = scope.max;
					var percent = value / max * 100;
					return percent + "%";
				};

				scope.fillStyle = function() {
					return {width: percentString()};
				};

				scope.thumbStyle = function() {
					return {left: percentString()};
				};

				scope.onClickSeekBar = function(event) {
					var percent = calculatePercent(seekBar, event);
					scope.value = percent * scope.max;
					notifyOnChange(scope.value);
				};

				scope.trackThumb = function() {
					$document.bind('mousemove.thumb', function(event) {
						var percent = calculatePercent(seekBar, event);
						scope.$apply(function() {
							scope.value = percent * scope.max;
							notifyOnChange(scope.value);
						});
					});
				var notifyOnChange = function(newValue) {
					if (typeof scope.onChange === 'function') {
						scope.onChange({value: newValue});
					}
				};
					$document.bind('mouseup.thumb', function() {
						$document.unbind('mousemove.thumb');
						$document.unbind('mouseup.thumb');
					});
				};
			}
		};
	}

	angular
		.module('blocJams')
		.directive('seekBar', ['$document', seekBar]);
})();

/*
These are the error messages produced from the code in it's current state:

[Error] null is not an object (evaluating 'currentBuzzObject.isPaused')
http://localhost:3000/scripts/services/SongPlayer.js:83
	(anonymous function) (angular.min.js:95)
	$apply (angular.min.js:149:449)
	(anonymous function) (angular.min.js:285:469)
	dispatch (jquery-3.2.1.min.js:3:10322)
[Error] Can't find variable: notifyOnChange
http://localhost:3000/scripts/directives/seekBar.js:51
	(anonymous function) (angular.min.js:95)
	$apply (angular.min.js:149:449)
	(anonymous function) (angular.min.js:285:469)
	dispatch (jquery-3.2.1.min.js:3:10322)
*/

/*  git checkout -b angular-assignment-10-Directives-Part-2  */<|endoftext|>


<commit_before>function path(fp) {
    if (fp[fp.length -1] == '/')
        return fp;
    var last = fp.lastIndexOf('/');
    if (last < 0)
        return '.';
    return fp.slice(0, last);
}

function fileName(fph) {
    var fp = fph.toString();
    if (fp[fp.length -1] == '/')
        return fp;
    var last = fp.lastIndexOf('/');
    if (last < 0)
        return '.';
    return fp.slice(last + 1);
}

function baseName(fph) {
    var fn = fileName(fph);
    return fn.split('.')[0];
}

function relativePath(base, rel)
{
    var basel = base.split('/');
    var rell  = rel.split('/');
    var i;
    for (i = basel.length; i-- >= 0;) {
        if (basel[i] === '.' || basel[i] === '')
            basel.splice(i, 1);
    }
    for (i = rell.length; i-- >= 0;) {
        if (rell[i] === '.' || rell[i] === '')
            rell.splice(i, 1);
    }

    i = 0;
    while (i < basel.length && i < rell.length && basel[i] === rell[i])
        i++;

    var j = i;
    var r = [];

    for (; i < basel.length; i++)
        r.push('..');

    for (; j < rell.length; j++)
        r.push(rell[j]);

    return r.join('/');
}

var windowsAbsolutePathPattern = new RegExp("^[a-z,A-Z]:[/,\\\\]")

function isAbsolutePath(path)
{
    if (!path)
        return false;
    return (path.charAt(0) == '/' || windowsAbsolutePathPattern.test(path));
}

function toWindowsSeparators(str)
{
    return str.toString().replace(/\//g, '\\');
}

function fromWindowsSeparators(str)
{
    return str.toString().replace(/\\/g, '/');
}

var removeDoubleSlashesPattern = new RegExp("/{2,}", "g")

function joinPaths()
{
    function pathFilter(path) {
        return path && typeof path === 'string';
    }

    var paths = Array.prototype.slice.call(arguments, 0).filter(pathFilter);
    var joinedPaths = paths.join('/');

    return joinedPaths.replace(removeDoubleSlashesPattern, "/")
}
<commit_msg>Synced behaviour of JS and C++ FileInfo object<commit_after>function path(fp) {
    if (fp[fp.length -1] == '/')
        return fp;
    var last = fp.lastIndexOf('/');
    if (last < 0)
        return '.';
    return fp.slice(0, last);
}

function fileName(fph) {
    var fp = fph.toString();
    var last = fp.lastIndexOf('/');
    if (last < 0)
        return fp;
    return fp.slice(last + 1);
}

function baseName(fph) {
    var fn = fileName(fph);
    return fn.split('.')[0];
}

function completeBaseName(fph) {
    var fn = fileName(fph);
    var last = fn.lastIndexOf(".");
    if (last < 0)
        return fn;
    else
        return fn.slice(0, last);
}

function relativePath(base, rel)
{
    var basel = base.split('/');
    var rell  = rel.split('/');
    var i;
    for (i = basel.length; i-- >= 0;) {
        if (basel[i] === '.' || basel[i] === '')
            basel.splice(i, 1);
    }
    for (i = rell.length; i-- >= 0;) {
        if (rell[i] === '.' || rell[i] === '')
            rell.splice(i, 1);
    }

    i = 0;
    while (i < basel.length && i < rell.length && basel[i] === rell[i])
        i++;

    var j = i;
    var r = [];

    for (; i < basel.length; i++)
        r.push('..');

    for (; j < rell.length; j++)
        r.push(rell[j]);

    return r.join('/');
}

var windowsAbsolutePathPattern = new RegExp("^[a-z,A-Z]:[/,\\\\]")

function isAbsolutePath(path)
{
    if (!path)
        return false;
    return (path.charAt(0) == '/' || windowsAbsolutePathPattern.test(path));
}

function toWindowsSeparators(str)
{
    return str.toString().replace(/\//g, '\\');
}

function fromWindowsSeparators(str)
{
    return str.toString().replace(/\\/g, '/');
}

var removeDoubleSlashesPattern = new RegExp("/{2,}", "g")

function joinPaths()
{
    function pathFilter(path) {
        return path && typeof path === 'string';
    }

    var paths = Array.prototype.slice.call(arguments, 0).filter(pathFilter);
    var joinedPaths = paths.join('/');

    return joinedPaths.replace(removeDoubleSlashesPattern, "/")
}
<|endoftext|>


<commit_before>'use strict';

angular.module('quakeStatsApp').service('FlagsService', ['Constants', function(Constants) {
    this.stats = null;
    var me = this;

    this.initMap = function(startIndex) {
        var map = {};
        map.timeline = [];
        map.startIndex = startIndex;
        map.fetches = {
            '1':0,
            '2':0
        };
        map.score = {
            '1':0,
            '2':0
        };
        map.returns = {
            '1':0,
            '2':0
        };
        map.carrierFrags = {
            '1':0,
            '2':0
        };
        map.players = {};
        map.topScorer = null;
        map.topReturner = null;
        map.topCarrierFragger = null;
        map.endReason = null;
        return map;
    };

    this.setGotFlag = function(record, map) {
        var playerName = me.getPlayerName(record);
        if (playerName) {
            if (record.indexOf('RED') !== -1) {
                map.fetches[Constants.BLUE] += 1;
            } else if (record.indexOf('BLUE') !== -1) {
                map.fetches[Constants.RED] += 1;
            }
            map.players[playerName].fetches += 1;
        }
    };

    this.setCapturedFlag = function(record, map) {
        var playerName = me.getPlayerName(record);
        if (playerName) {
            if (record.indexOf('RED') !== -1) {
                map.score[Constants.BLUE] += 1;
                me.stats.capturedFlags[Constants.BLUE] += 1;
            } else if (record.indexOf('BLUE') !== -1) {
                map.score[Constants.RED] += 1;
                me.stats.capturedFlags[Constants.RED] += 1;
            }
            map.players[playerName].scores += 1;
        }
    };

    this.setReturnedFlag = function(record, map) {
        var playerName = me.getPlayerName(record);
        if (playerName) {
            if (record.indexOf('BLUE') !== -1) {
                map.returns[Constants.BLUE] += 1;
            } else if (record.indexOf('RED') !== -1) {
                map.returns[Constants.RED] += 1;
            }
            map.players[playerName].returns += 1;
        }
    };

    this.setFraggedFlagCarrier = function(record, map) {
        var playerName = me.getPlayerName(record);
        if (playerName) {
            if (record.indexOf('BLUE') !== -1) {
                map.carrierFrags[Constants.BLUE] += 1;
            } else if (record.indexOf('RED') !== -1) {
                map.carrierFrags[Constants.RED] += 1;
            }
            map.players[playerName].carrierFrags += 1;
        }
    };

    this.getPlayerName = function(record) {
        if (record.indexOf('^7') !== -1) {
            return record.slice(0, record.indexOf('^7'));
        }
        return null;
    };

    this.getTopPlayer = function(prop, map) {
        var topPlayer = null,
            player = null;
        for (var playerName in map.players) {
            player = map.players[playerName];
            if (topPlayer) {
                if (player[prop] > topPlayer[prop]) {
                    topPlayer = player;
                }
            } else {
                topPlayer = player;
            }
        }
        return topPlayer;
    };

    this.getWins = function(maps) {
        var map,
            wins = {
                '1':0,
                '2':0
            };
        for (var i = 0; i < maps.length; i++) {
            map = maps[i];
            if (map.score[Constants.RED] > map.score[Constants.BLUE]) {
                wins[Constants.RED] += 1;
            } else if (map.score[Constants.RED] < map.score[Constants.BLUE]) {
                wins[Constants.BLUE] += 1;
            }
        }
        return wins;
    };

    this.getFlagsStats = function(log) {
        var i,
            record,
            map,
            playerName;
        me.stats = {};
        me.stats.capturedFlags = {
            '1':0,
            '2':0
        };
        me.stats.maps = [];

        for (i = 0; i < log.length; i++) {
            record = log[i];
            // Should be replaced with 'Game Initialization'
            if (record.indexOf('CL_InitCGame') !== -1) {
                map = me.initMap(i);
                me.stats.maps.push(map);
            }

            // Flag Records
            if (record.indexOf('RED') !== -1 || record.indexOf('BLUE') !== -1) {
                // Register the player to the map
                playerName = me.getPlayerName(record);
                if (map.players[playerName] === undefined) {
                    map.players[playerName] = {
                        name:playerName,
                        scores:0,
                        fetches:0,
                        carrierFrags:0,
                        returns:0,
                        rebounds:0
                    };
                }
                //
                if (record.indexOf('got') !== -1) {
                    me.setGotFlag(record, map);
                }

                if (record.indexOf('captured') !== -1) {
                    me.setCapturedFlag(record, map);
                }

                if (record.indexOf('returned') !== -1) {
                    me.setReturnedFlag(record, map);
                }

                if (record.indexOf('fragged') !== -1) {
                    me.setFraggedFlagCarrier(record, map);
                }
                //
                map.timeline.push(record);
            }

            // Map end
            if (record.indexOf('hit') !== -1) {
                map.topScorer = me.getTopPlayer('scores', map);
                map.topReturner = me.getTopPlayer('returns', map);
                map.topCarrierFragger = me.getTopPlayer('carrierFrags', map);
                map.topFetcher = me.getTopPlayer('fetches', map);
                map.endReason = record;
            }
        }

        me.stats.wins = me.getWins(me.stats.maps);
        return me.stats;
    };
}]);<commit_msg>Ongoing: Return cached stats from flags-srv if available<commit_after>'use strict';

angular.module('quakeStatsApp').service('FlagsService', ['Constants', function(Constants) {
    this.stats = null;
    var me = this;

    this.initMap = function(startIndex) {
        var map = {};
        map.timeline = [];
        map.startIndex = startIndex;
        map.fetches = {
            '1':0,
            '2':0
        };
        map.score = {
            '1':0,
            '2':0
        };
        map.returns = {
            '1':0,
            '2':0
        };
        map.carrierFrags = {
            '1':0,
            '2':0
        };
        map.players = {};
        map.topScorer = null;
        map.topReturner = null;
        map.topCarrierFragger = null;
        map.endReason = null;
        return map;
    };

    this.setGotFlag = function(record, map) {
        var playerName = me.getPlayerName(record);
        if (playerName) {
            if (record.indexOf('RED') !== -1) {
                map.fetches[Constants.BLUE] += 1;
            } else if (record.indexOf('BLUE') !== -1) {
                map.fetches[Constants.RED] += 1;
            }
            map.players[playerName].fetches += 1;
        }
    };

    this.setCapturedFlag = function(record, map) {
        var playerName = me.getPlayerName(record);
        if (playerName) {
            if (record.indexOf('RED') !== -1) {
                map.score[Constants.BLUE] += 1;
                me.stats.capturedFlags[Constants.BLUE] += 1;
            } else if (record.indexOf('BLUE') !== -1) {
                map.score[Constants.RED] += 1;
                me.stats.capturedFlags[Constants.RED] += 1;
            }
            map.players[playerName].scores += 1;
        }
    };

    this.setReturnedFlag = function(record, map) {
        var playerName = me.getPlayerName(record);
        if (playerName) {
            if (record.indexOf('BLUE') !== -1) {
                map.returns[Constants.BLUE] += 1;
            } else if (record.indexOf('RED') !== -1) {
                map.returns[Constants.RED] += 1;
            }
            map.players[playerName].returns += 1;
        }
    };

    this.setFraggedFlagCarrier = function(record, map) {
        var playerName = me.getPlayerName(record);
        if (playerName) {
            if (record.indexOf('BLUE') !== -1) {
                map.carrierFrags[Constants.BLUE] += 1;
            } else if (record.indexOf('RED') !== -1) {
                map.carrierFrags[Constants.RED] += 1;
            }
            map.players[playerName].carrierFrags += 1;
        }
    };

    this.getPlayerName = function(record) {
        if (record.indexOf('^7') !== -1) {
            return record.slice(0, record.indexOf('^7'));
        }
        return null;
    };

    this.getTopPlayer = function(prop, map) {
        var topPlayer = null,
            player = null;
        for (var playerName in map.players) {
            player = map.players[playerName];
            if (topPlayer) {
                if (player[prop] > topPlayer[prop]) {
                    topPlayer = player;
                }
            } else {
                topPlayer = player;
            }
        }
        return topPlayer;
    };

    this.getWins = function(maps) {
        var map,
            wins = {
                '1':0,
                '2':0
            };
        for (var i = 0; i < maps.length; i++) {
            map = maps[i];
            if (map.score[Constants.RED] > map.score[Constants.BLUE]) {
                wins[Constants.RED] += 1;
            } else if (map.score[Constants.RED] < map.score[Constants.BLUE]) {
                wins[Constants.BLUE] += 1;
            }
        }
        return wins;
    };

    this.getFlagsStats = function(log) {
        if (me.stats) {
            return me.stats;
        }
        var i,
            record,
            map,
            playerName;
        me.stats = {};
        me.stats.capturedFlags = {
            '1':0,
            '2':0
        };
        me.stats.maps = [];

        for (i = 0; i < log.length; i++) {
            record = log[i];
            // Should be replaced with 'Game Initialization'
            if (record.indexOf('CL_InitCGame') !== -1) {
                map = me.initMap(i);
                me.stats.maps.push(map);
            }

            // Flag Records
            if (record.indexOf('RED') !== -1 || record.indexOf('BLUE') !== -1) {
                // Register the player to the map
                playerName = me.getPlayerName(record);
                if (map.players[playerName] === undefined) {
                    map.players[playerName] = {
                        name:playerName,
                        scores:0,
                        fetches:0,
                        carrierFrags:0,
                        returns:0,
                        rebounds:0
                    };
                }
                //
                if (record.indexOf('got') !== -1) {
                    me.setGotFlag(record, map);
                }

                if (record.indexOf('captured') !== -1) {
                    me.setCapturedFlag(record, map);
                }

                if (record.indexOf('returned') !== -1) {
                    me.setReturnedFlag(record, map);
                }

                if (record.indexOf('fragged') !== -1) {
                    me.setFraggedFlagCarrier(record, map);
                }
                //
                map.timeline.push(record);
            }

            // Map end
            if (record.indexOf('hit') !== -1) {
                map.topScorer = me.getTopPlayer('scores', map);
                map.topReturner = me.getTopPlayer('returns', map);
                map.topCarrierFragger = me.getTopPlayer('carrierFrags', map);
                map.topFetcher = me.getTopPlayer('fetches', map);
                map.endReason = record;
            }
        }

        me.stats.wins = me.getWins(me.stats.maps);
        return me.stats;
    };
}]);<|endoftext|>


<commit_before>// ERPNext - web based ERP (http://erpnext.com)
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

wn.pages['general-ledger'].onload = function(wrapper) {
	wn.ui.make_app_page({
		parent: wrapper,
		title: 'General Ledger',
		single_column: true
	});

	erpnext.general_ledger = new erpnext.GeneralLedger(wrapper);

	wrapper.appframe.add_home_breadcrumb()
	wrapper.appframe.add_module_breadcrumb("Accounts")
	wrapper.appframe.add_breadcrumb("icon-bar-chart")

}

erpnext.GeneralLedger = wn.views.GridReport.extend({
	init: function(wrapper) {
		this._super({
			title: "General Ledger",
			page: wrapper,
			parent: $(wrapper).find('.layout-main'),
			appframe: wrapper.appframe,
			doctypes: ["Company", "Account", "GL Entry", "Cost Center"],
		});
	},
	setup_columns: function() {
		this.columns = [
			{id: "posting_date", name: "Posting Date", field: "posting_date", width: 100,
				formatter: this.date_formatter},
			{id: "account", name: "Account", field: "account", width: 240,
				link_formatter: {
					filter_input: "account",
					open_btn: true,
					doctype: "'Account'"
				}},
			{id: "against_account", name: "Against Account", field: "against_account",
				width: 240, hidden: !this.account},

			{id: "debit", name: "Debit", field: "debit", width: 100,
				formatter: this.currency_formatter},
			{id: "credit", name: "Credit", field: "credit", width: 100,
				formatter: this.currency_formatter},
			{id: "voucher_type", name: "Voucher Type", field: "voucher_type", width: 120},
			{id: "voucher_no", name: "Voucher No", field: "voucher_no", width: 160,
				link_formatter: {
					filter_input: "voucher_no",
					open_btn: true,
					doctype: "dataContext.voucher_type"
				}},
			{id: "remarks", name: "Remarks", field: "remarks", width: 200,
				formatter: this.text_formatter},

		];
	},
	filters: [
		{fieldtype:"Select", label: "Company", link:"Company", default_value: "Select Company...",
			filter: function(val, item, opts) {
				return item.company == val || val == opts.default_value;
			}},
		{fieldtype:"Link", label: "Account", link:"Account",
			filter: function(val, item, opts, me) {
				if(!val) {
					return true;
				} else {
					// true if GL Entry belongs to selected
					// account ledger or group
					return me.is_child_account(val, item.account);
				}
			}},
		{fieldtype:"Data", label: "Voucher No",
			filter: function(val, item, opts) {
				if(!val) return true;
				return (item.voucher_no && item.voucher_no.indexOf(val)!=-1);
			}},
		{fieldtype:"Date", label: "From Date", filter: function(val, item) {
			return dateutil.str_to_obj(val) <= dateutil.str_to_obj(item.posting_date);
		}},
		{fieldtype:"Label", label: "To"},
		{fieldtype:"Date", label: "To Date", filter: function(val, item) {
			return dateutil.str_to_obj(val) >= dateutil.str_to_obj(item.posting_date);
		}},
		{fieldtype:"Button", label: "Refresh", icon:"icon-refresh icon-white", cssClass:"btn-info"},
		{fieldtype:"Button", label: "Reset Filters"}
	],
	setup_filters: function() {
		this._super();
		var me = this;

		this.accounts_by_company = this.make_accounts_by_company();
		// filter accounts options by company
		this.filter_inputs.company && this.filter_inputs.company.change(function() {
			me.setup_account_filter(this);
			me.filter_inputs.refresh.click();
		});
	},
	setup_account_filter: function(company_filter) {
		var me = this;

		var $account = me.filter_inputs.account;
		var company = $(company_filter).val();
		var default_company = this.filter_inputs.company.get(0).opts.default_value;
		var opts = $account.get(0).opts;
		opts.list = $.map(wn.report_dump.data["Account"], function(ac) {
				return (company===default_company ||
					me.accounts_by_company[company].indexOf(ac.name)!=-1) ?
					ac.name : null;
			});

		this.set_autocomplete($account, opts.list);

	},
	init_filter_values: function() {
		this._super();
		this.filter_inputs.company.change();
	},
	apply_filters_from_route: function() {
		this._super();
		this.filter_inputs.company.change();
	},
	make_accounts_by_company: function() {
		var accounts_by_company = {};
		var me = this;
		$.each(wn.report_dump.data["Account"], function(i, ac) {
			if(!accounts_by_company[ac.company]) accounts_by_company[ac.company] = [];
			accounts_by_company[ac.company].push(ac.name);
		});
		return accounts_by_company;
	},
	is_child_account: function(account, item_account) {
		var opts = [account, item_account];
		account = this.account_by_name[account];
		item_account = this.account_by_name[item_account];

		return ((item_account.lft >= account.lft) && (item_account.rgt <= account.rgt));
	},
	prepare_data: function() {
		// add Opening, Closing, Totals rows
		// if filtered by account and / or voucher
		var data = wn.report_dump.data["GL Entry"];
		var out = [];

		if(!this.account_by_name) {
			this.account_by_name = this.make_name_map(wn.report_dump.data["Account"]);
			this.make_voucher_acconuts_map();
		}

		var me = this;

		var from_date = dateutil.str_to_obj(this.from_date);
		var to_date = dateutil.str_to_obj(this.to_date);

		if(to_date < from_date) {
			msgprint("From Date must be before To Date");
			return;
		}

		var opening = {
			account: "Opening", debit: 0.0, credit: 0.0,
				id:"_opening", _show: true, _style: "font-weight: bold"
		}
		var totals = {
			account: "Totals", debit: 0.0, credit: 0.0,
				id:"_totals", _show: true, _style: "font-weight: bold"
		}

		$.each(data, function(i, item) {
			if((me.is_default("company") ? true : me.apply_filter(item, "company")) &&
				(me.account ? me.is_child_account(me.account, item.account)
				: true) && (me.voucher_no ? item.voucher_no==me.voucher_no : true)) {
				var date = dateutil.str_to_obj(item.posting_date);

				if(date < from_date || item.is_opening=="Yes") {
					opening.debit += item.debit;
					opening.credit += item.credit;
				} else if(date <= to_date) {
					totals.debit += item.debit;
					totals.credit += item.credit;
				}

				if(me.account) {
					item.against_account = me.voucher_accounts[item.voucher_type + ":"
						+ item.voucher_no][(item.debit > 0 ? "credits" : "debits")].join(", ");
				}

				if(me.apply_filters(item) && item.is_opening=="No") {
					out.push(item);
				}
			}
		})

		var closing = {
			account: "Closing (Opening + Totals)", debit: opening.debit + totals.debit,
				credit: opening.credit + totals.credit,
				id:"_closing", _show: true, _style: "font-weight: bold"
		}

		if(me.account) {
			me.appframe.set_title("General Ledger: " + me.account);

			if(me.account_by_name[me.account].debit_or_credit == "Debit") {
				opening.debit -= opening.credit; opening.credit = 0;
				closing.debit -= closing.credit; closing.credit = 0;
			} else {
				opening.credit -= opening.debit; opening.debit = 0;
				closing.credit -= closing.debit; closing.debit = 0;
			}
			var out = [opening].concat(out).concat([totals, closing]);
		} else {
			me.appframe.set_title("General Ledger");
			var out = out.concat([totals]);
		}

		this.data = out;
	},

	make_voucher_acconuts_map: function() {
		this.voucher_accounts = {};
		var data = wn.report_dump.data["GL Entry"];
		for(var i=0, j=data.length; i<j; i++) {
			var gl = data[i];

			if(!this.voucher_accounts[gl.voucher_type + ":" + gl.voucher_no])
				this.voucher_accounts[gl.voucher_type + ":" + gl.voucher_no] = {
					debits: [],
					credits: []
				}

			var va = this.voucher_accounts[gl.voucher_type + ":" + gl.voucher_no];
			if(gl.debit > 0) {
				va.debits.push(gl.account);
			} else {
				va.credits.push(gl.account);
			}
		}
	},

	get_plot_data: function() {
		var data = [];
		var me = this;
		if(!me.account || me.voucher_no) return false;
		var debit_or_credit = me.account_by_name[me.account].debit_or_credit;
		var balance = debit_or_credit=="Debit" ? me.data[0].debit : me.data[0].credit;
		data.push({
			label: me.account,
			data: [[dateutil.str_to_obj(me.from_date).getTime(), balance]]
				.concat($.map(me.data, function(col, idx) {
					if (col.posting_date) {
						var diff = (debit_or_credit == "Debit" ? 1 : -1) * (flt(col.debit) - flt(col.credit));
						balance += diff;
						return [[dateutil.str_to_obj(col.posting_date).getTime(), balance - diff],
								[dateutil.str_to_obj(col.posting_date).getTime(), balance]]
					}
					return null;
				})).concat([
					// closing
					[dateutil.str_to_obj(me.to_date).getTime(), balance]
				]),
			points: {show: true},
			lines: {show: true, fill: true},
		});
		return data;
	},
	get_plot_options: function() {
		return {
			grid: { hoverable: true, clickable: true },
			xaxis: { mode: "time",
				min: dateutil.str_to_obj(this.from_date).getTime(),
				max: dateutil.str_to_obj(this.to_date).getTime() }
		}
	},
});<commit_msg>group gl entries by ledger<commit_after>// ERPNext - web based ERP (http://erpnext.com)
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

wn.pages['general-ledger'].onload = function(wrapper) {
	wn.ui.make_app_page({
		parent: wrapper,
		title: 'General Ledger',
		single_column: true
	});

	erpnext.general_ledger = new erpnext.GeneralLedger(wrapper);

	wrapper.appframe.add_home_breadcrumb()
	wrapper.appframe.add_module_breadcrumb("Accounts")
	wrapper.appframe.add_breadcrumb("icon-bar-chart")

}

erpnext.GeneralLedger = wn.views.GridReport.extend({
	init: function(wrapper) {
		this._super({
			title: "General Ledger",
			page: wrapper,
			parent: $(wrapper).find('.layout-main'),
			appframe: wrapper.appframe,
			doctypes: ["Company", "Account", "GL Entry", "Cost Center"],
		});
	},
	setup_columns: function() {
		this.columns = [
			{id: "posting_date", name: "Posting Date", field: "posting_date", width: 100,
				formatter: this.date_formatter},
			{id: "account", name: "Account", field: "account", width: 240,
				link_formatter: {
					filter_input: "account",
					open_btn: true,
					doctype: "'Account'"
				}},
			{id: "against_account", name: "Against Account", field: "against_account",
				width: 240, hidden: !this.account},

			{id: "debit", name: "Debit", field: "debit", width: 100,
				formatter: this.currency_formatter},
			{id: "credit", name: "Credit", field: "credit", width: 100,
				formatter: this.currency_formatter},
			{id: "voucher_type", name: "Voucher Type", field: "voucher_type", width: 120},
			{id: "voucher_no", name: "Voucher No", field: "voucher_no", width: 160,
				link_formatter: {
					filter_input: "voucher_no",
					open_btn: true,
					doctype: "dataContext.voucher_type"
				}},
			{id: "remarks", name: "Remarks", field: "remarks", width: 200,
				formatter: this.text_formatter},

		];
	},
	filters: [
		{fieldtype:"Select", label: "Company", link:"Company", default_value: "Select Company...",
			filter: function(val, item, opts) {
				return item.company == val || val == opts.default_value;
			}},
		{fieldtype:"Link", label: "Account", link:"Account",
			filter: function(val, item, opts, me) {
				if(!val) {
					return true;
				} else {
					// true if GL Entry belongs to selected
					// account ledger or group
					return me.is_child_account(val, item.account);
				}
			}},
		{fieldtype:"Data", label: "Voucher No",
			filter: function(val, item, opts) {
				if(!val) return true;
				return (item.voucher_no && item.voucher_no.indexOf(val)!=-1);
			}},
		{fieldtype:"Date", label: "From Date", filter: function(val, item) {
			return dateutil.str_to_obj(val) <= dateutil.str_to_obj(item.posting_date);
		}},
		{fieldtype:"Label", label: "To"},
		{fieldtype:"Date", label: "To Date", filter: function(val, item) {
			return dateutil.str_to_obj(val) >= dateutil.str_to_obj(item.posting_date);
		}},
		{fieldtype: "Check", label: "Group by Ledger"},
		{fieldtype:"Button", label: "Refresh", icon:"icon-refresh icon-white", cssClass:"btn-info"},
		{fieldtype:"Button", label: "Reset Filters"}
	],
	setup_filters: function() {
		this._super();
		var me = this;

		this.accounts_by_company = this.make_accounts_by_company();
		// filter accounts options by company
		this.filter_inputs.company && this.filter_inputs.company.change(function() {
			me.setup_account_filter(this);
			me.filter_inputs.refresh.click();
		});

		this.filter_inputs.account && this.filter_inputs.group_by_ledger
			&& this.filter_inputs.account.change(function() {
				me.make_account_by_name();
				me.filter_inputs.group_by_ledger.parent()
					.toggle(!!(me.account_by_name[$(this).val()] && me.account_by_name[$(this).val()].group_or_ledger==="Group"));
			});
	},
	setup_account_filter: function(company_filter) {
		var me = this;

		var $account = me.filter_inputs.account;
		var company = $(company_filter).val();
		var default_company = this.filter_inputs.company.get(0).opts.default_value;
		var opts = $account.get(0).opts;
		opts.list = $.map(wn.report_dump.data["Account"], function(ac) {
				return (company===default_company ||
					me.accounts_by_company[company].indexOf(ac.name)!=-1) ?
					ac.name : null;
			});

		this.set_autocomplete($account, opts.list);

	},
	init_filter_values: function() {
		this._super();
		this.filter_inputs.company.change();
		this.filter_inputs.account.change();
	},
	apply_filters_from_route: function() {
		this._super();
		this.filter_inputs.company.change();
		this.filter_inputs.account.change();
	},
	make_accounts_by_company: function() {
		var accounts_by_company = {};
		var me = this;
		$.each(wn.report_dump.data["Account"], function(i, ac) {
			if(!accounts_by_company[ac.company]) accounts_by_company[ac.company] = [];
			accounts_by_company[ac.company].push(ac.name);
		});
		return accounts_by_company;
	},
	is_child_account: function(account, item_account) {
		var opts = [account, item_account];
		account = this.account_by_name[account];
		item_account = this.account_by_name[item_account];

		return ((item_account.lft >= account.lft) && (item_account.rgt <= account.rgt));
	},
	prepare_data: function() {
		// add Opening, Closing, Totals rows
		// if filtered by account and / or voucher
		var data = wn.report_dump.data["GL Entry"];
		var out = [];

		this.make_account_by_name();

		var me = this;

		var from_date = dateutil.str_to_obj(this.from_date);
		var to_date = dateutil.str_to_obj(this.to_date);

		if(to_date < from_date) {
			msgprint("From Date must be before To Date");
			return;
		}

		var opening = this.make_summary_row("Opening", this.account);
		var totals = this.make_summary_row("Totals", this.account);

		var grouped_ledgers = {};

		$.each(data, function(i, item) {
			if((me.is_default("company") ? true : me.apply_filter(item, "company")) &&
				(me.account ? me.is_child_account(me.account, item.account)
				: true) && (me.voucher_no ? item.voucher_no==me.voucher_no : true)) {
				var date = dateutil.str_to_obj(item.posting_date);

				// create grouping by ledger
				if(!grouped_ledgers[item.account]) {
					grouped_ledgers[item.account] = {
						entries: [],
						opening: me.make_summary_row("Opening", item.account),
						totals: me.make_summary_row("Totals", item.account),
						closing: me.make_summary_row("Closing (Opening + Totals)",
							item.account)
					};
				}

				if(date < from_date || item.is_opening=="Yes") {
					opening.debit += item.debit;
					opening.credit += item.credit;

					grouped_ledgers[item.account].opening.debit += item.debit;
					grouped_ledgers[item.account].opening.credit += item.credit;
				} else if(date <= to_date) {
					totals.debit += item.debit;
					totals.credit += item.credit;

					grouped_ledgers[item.account].totals.debit += item.debit;
					grouped_ledgers[item.account].totals.credit += item.credit;
				}

				if(me.account) {
					item.against_account = me.voucher_accounts[item.voucher_type + ":"
						+ item.voucher_no][(item.debit > 0 ? "credits" : "debits")].join(", ");
				}

				if(me.apply_filters(item) && item.is_opening=="No") {
					out.push(item);
					grouped_ledgers[item.account].entries.push(item);
				}
			}
		});

		var closing = this.make_summary_row("Closing (Opening + Totals)", this.account);
		closing.debit = opening.debit + totals.debit;
		closing.credit = opening.credit + totals.credit;

		if(me.account) {
			me.appframe.set_title("General Ledger: " + me.account);

			// group by ledgers
			if(this.account_by_name[this.account].group_or_ledger==="Group"
				&& this.group_by_ledger) {
					out = this.group_data_by_ledger(grouped_ledgers);
			}

			if(me.account_by_name[me.account].debit_or_credit == "Debit") {
				opening.debit -= opening.credit; opening.credit = 0;
				closing.debit -= closing.credit; closing.credit = 0;
			} else {
				opening.credit -= opening.debit; opening.debit = 0;
				closing.credit -= closing.debit; closing.debit = 0;
			}
			out = [opening].concat(out).concat([totals, closing]);
		} else {
			me.appframe.set_title("General Ledger");
			out = out.concat([totals]);
		}

		this.data = out;
	},

	group_data_by_ledger: function(grouped_ledgers) {
		var out = []
		$.each(Object.keys(grouped_ledgers).sort(), function(i, account) {
			if(grouped_ledgers[account].entries.length) {
				grouped_ledgers[account].closing.debit =
					grouped_ledgers[account].opening.debit
					+ grouped_ledgers[account].totals.debit;

				grouped_ledgers[account].closing.credit =
					grouped_ledgers[account].opening.credit
					+ grouped_ledgers[account].totals.credit;

				out = out.concat([grouped_ledgers[account].opening])
					.concat(grouped_ledgers[account].entries)
					.concat([grouped_ledgers[account].totals,
						grouped_ledgers[account].closing]);
			}
		});
		return out;
	},

	make_summary_row: function(label, item_account) {
		return {
			account: label,
			debit: 0.0,
			credit: 0.0,
			id: ["", label, item_account].join("_").replace(" ", "_").toLowerCase(),
			_show: true,
			_style: "font-weight: bold"
		}
	},

	make_account_by_name: function() {
		if(!this.account_by_name) {
			this.account_by_name = this.make_name_map(wn.report_dump.data["Account"]);
			this.make_voucher_acconuts_map();
		}
	},

	make_voucher_acconuts_map: function() {
		this.voucher_accounts = {};
		var data = wn.report_dump.data["GL Entry"];
		for(var i=0, j=data.length; i<j; i++) {
			var gl = data[i];

			if(!this.voucher_accounts[gl.voucher_type + ":" + gl.voucher_no])
				this.voucher_accounts[gl.voucher_type + ":" + gl.voucher_no] = {
					debits: [],
					credits: []
				}

			var va = this.voucher_accounts[gl.voucher_type + ":" + gl.voucher_no];
			if(gl.debit > 0) {
				va.debits.push(gl.account);
			} else {
				va.credits.push(gl.account);
			}
		}
	},

	get_plot_data: function() {
		var data = [];
		var me = this;
		if(!me.account || me.voucher_no) return false;
		var debit_or_credit = me.account_by_name[me.account].debit_or_credit;
		var balance = debit_or_credit=="Debit" ? me.data[0].debit : me.data[0].credit;
		data.push({
			label: me.account,
			data: [[dateutil.str_to_obj(me.from_date).getTime(), balance]]
				.concat($.map(me.data, function(col, idx) {
					if (col.posting_date) {
						var diff = (debit_or_credit == "Debit" ? 1 : -1) * (flt(col.debit) - flt(col.credit));
						balance += diff;
						return [[dateutil.str_to_obj(col.posting_date).getTime(), balance - diff],
								[dateutil.str_to_obj(col.posting_date).getTime(), balance]]
					}
					return null;
				})).concat([
					// closing
					[dateutil.str_to_obj(me.to_date).getTime(), balance]
				]),
			points: {show: true},
			lines: {show: true, fill: true},
		});
		return data;
	},
	get_plot_options: function() {
		return {
			grid: { hoverable: true, clickable: true },
			xaxis: { mode: "time",
				min: dateutil.str_to_obj(this.from_date).getTime(),
				max: dateutil.str_to_obj(this.to_date).getTime() }
		}
	},
});<|endoftext|>


<commit_before>'use strict';

angular.module('quakeStatsApp').service('KillsService', ['GamesLogParserService', 'Constants', function(GamesLogParserService, Constants) {
	this.stats = null;
    this.alainKills = 0;
	var me = this;

    this.initMap = function(record, startIndex) {
        var map = {};
        map.name = me.getMapKey(record);
        map.startIndex = startIndex;
        map.players = {};
        return map;
    };

    this.getMapKey = function(record) {
        var startIndex = record.indexOf(Constants.MAP_NAME_KEY) + Constants.MAP_NAME_KEY.length,
            endIndex = record.indexOf(Constants.BACKSLASH_KEY, startIndex);
        return record.slice(startIndex, endIndex);
    };

    this.getPlayer = function (record) {
        var player = {};

        player.id = me.getPlayerID(record);
        player.name = GamesLogParserService.getPlayerName(record);
        player.nameId = player.name.replace(' ', '').toLowerCase();
        player.team = GamesLogParserService.getPlayerTeam(record);
        player.kills = [];
        player.deaths = [];
        player.humiliations = [];
        player.teammatesKills = [];
        return player;
    };

    this.getPlayerID = function(record) {
        var idStr = record.slice(record.indexOf(Constants.PLAYER_INFO_KEY) + Constants.PLAYER_INFO_KEY.length, record.indexOf(Constants.PLAYER_NAME_KEY));
        return parseInt(idStr, 10);
    };

    this.getPlayerName = function(record) {
        return record.slice(record.indexOf(Constants.PLAYER_NAME_KEY) + Constants.PLAYER_NAME_KEY.length, record.indexOf(Constants.BACKSLASH_KEY, record.indexOf(Constants.PLAYER_NAME_KEY) + Constants.PLAYER_NAME_KEY.length));
    };

    this.getKill = function(record) {
        var killStr = record.slice(record.indexOf('Kill: ') + 'Kill: '.length, record.indexOf(':', record.indexOf('Kill: ') + 'Kill: '.length)),
            idsArr = killStr.split(' '),
            killerID = parseInt(idsArr[0], 10),
            victimID = parseInt(idsArr[1], 10),
            killModeID = parseInt(idsArr[2], 10),
            killerName = record.slice(record.indexOf(killStr + ': ') + (killStr + ': ').length, record.indexOf(' killed')),
            victimName = record.slice(record.indexOf('killed ') + 'killed '.length, record.indexOf(' by'));
        return {killer: killerID,
            killerName:killerName,
            victim: victimID,
            victimName: victimName,
            mode: killModeID
        };
    };

    this.getTopPlayer = function(prop, players) {
        var topPlayer = null,
            player = null;
        for (var playerName in players) {
            player = players[playerName];
            if (topPlayer) {
                if (player[prop].length > topPlayer[prop].length) {
                    topPlayer = player;
                }
            } else {
                topPlayer = player;
            }
        }
        return topPlayer;
    };

    this.registerKill = function(kill, map) {
        var killerPlayer = map.players[kill.killerName],
            victimPlayer = map.players[kill.victimName];
        if (killerPlayer && victimPlayer) {
            killerPlayer.kills.push(kill);
            victimPlayer.deaths.push(kill);
            if (killerPlayer.team === victimPlayer.team) {
                me.stats.players[kill.killerName].teammatesKills.push(kill);
            } else if (kill.mode === 2) {
                me.stats.players[kill.killerName].humiliations.push(kill);
            }
            calculatePlayerToPlayerKills(kill);
        }
    };

    function calculatePlayerToPlayerKills(kill) {
        var killerPlayer = me.stats.players[kill.killerName],
            victimPlayer = me.stats.players[kill.victimName];
        if (killerPlayer && victimPlayer) {
            killerPlayer.kills.push(kill);
            victimPlayer.deaths.push(kill);
        }
    }

    this.registerStatsPlayer = function(player) {
        if (!me.stats.players[player.name]) {
            me.stats.players[player.name] = player;
        }
        if (me.stats.players[player.name].team !== player.team) {
            me.stats.players[player.name].team = player.team;
        }
    };

	this.getKillsStats = function(log) {
		if (me.stats) {
            return me.stats;
        }
        var i,
            record,
            map,
            kill,
            player;
        me.stats = {};
        me.stats.maps = {};
        me.stats.players = {};

        for (i = 0; i < log.length; i++) {
            record = log[i];
            if (!record) {
                continue;
            }
            if (GamesLogParserService.isMapStart(record)) {
                map = me.initMap(record, i);
                me.stats.maps[i] = map;
            }
            // Player
            if (GamesLogParserService.isClientUserinfoChanged(record)) {
                player = me.getPlayer(record);

                for (var name in map.players) {
                    if (map.players[name] && map.players[name].name === player.name) {
                        player = angular.copy(map.players[name]);
                        delete map.players[name];
                        break;
                    }
                }
                map.players[player.name] = player;
                me.registerStatsPlayer(player);
            }
            // Kill
            if (record.indexOf('Kill: ') !== -1) {
                kill = me.getKill(record);
                if (kill.victim !== kill.killer) {
                    me.registerKill(kill, map);
                }
            }
            // Exit
            if (record.indexOf('ShutdownGame:') !== -1) {
                map.topKiller = me.getTopPlayer('kills', map.players);
                map.topVictim = me.getTopPlayer('deaths', map.players);
            }
        }
        me.stats.topKiller = me.getTopPlayer('kills', me.stats.players);
        me.stats.topVictim = me.getTopPlayer('deaths', me.stats.players);
        me.stats.topHumilator = me.getTopPlayer('humiliations', me.stats.players);
        me.stats.topFifthColumn = me.getTopPlayer('teammatesKills', me.stats.players);
        me.stats.humiliations = getAggragatedArraysByProp('humiliations', me.stats.players);
        me.stats.teammatesKills = getAggragatedArraysByProp('teammatesKills', me.stats.players);
        return me.stats;
	};

    this.getPlayerWeaponsStats = function(player) {
        var modes=  {},
            result = [],
            killMode,
            deathMode;
        if (player) {
            for (var kill in player.kills) {
                killMode = player.kills[kill].mode;
                if (modes[killMode] === undefined) {
                    modes[killMode] = {id:killMode, kills:0, deaths:0};
                    continue;
                } else {
                    modes[killMode].kills += 1;
                }
            }
            for (var death in player.deaths) {
                deathMode = player.deaths[death].mode;
                if (modes[deathMode] === undefined) {
                    modes[deathMode] = {id:deathMode, kills:0, deaths:0};
                    continue;
                } else {
                    modes[deathMode].deaths += 1;
                }
            }

            for (var mode in modes) {
                result.push(modes[mode]);
            }
        }
        return result;
    };

    function getAggragatedArraysByProp(prop, players) {
        var result = [],
            player,
            killer,
            kill,
            aggregator;
        for (var item in players) {
            aggregator = {};
            player = players[item];
            if (player[prop].length > 0) {
                killer = {
                    name: player.name,
                    nameId: player.nameId,
                    count: player[prop].length,
                    victims: []
                };
                for (var i = 0; i < player[prop].length; i++) {
                    kill = player[prop][i];
                    if (!aggregator[kill.victimName]) {
                        aggregator[kill.victimName] = {name:kill.victimName, count:0};
                    }
                    aggregator[kill.victimName].count++;
                }
                killer.victims = objectToArray(aggregator);
                result.push(killer);
            }
        }
        return result;
    }

    function objectToArray(items) {
        var result = [];
        angular.forEach(items, function(value) {
            result.push(value);
        });
        return result;
    }
}]);<commit_msg>Ongoing: Don't calculate suicides and consider a kill only when the victim and killer are opponents<commit_after>'use strict';

angular.module('quakeStatsApp').service('KillsService', ['GamesLogParserService', 'Constants', function(GamesLogParserService, Constants) {
	this.stats = null;
    this.alainKills = 0;
	var me = this;

    this.initMap = function(record, startIndex) {
        var map = {};
        map.name = me.getMapKey(record);
        map.startIndex = startIndex;
        map.players = {};
        return map;
    };

    this.getMapKey = function(record) {
        var startIndex = record.indexOf(Constants.MAP_NAME_KEY) + Constants.MAP_NAME_KEY.length,
            endIndex = record.indexOf(Constants.BACKSLASH_KEY, startIndex);
        return record.slice(startIndex, endIndex);
    };

    this.getPlayer = function (record) {
        var player = {};

        player.id = me.getPlayerID(record);
        player.name = GamesLogParserService.getPlayerName(record);
        player.nameId = player.name.replace(' ', '').toLowerCase();
        player.team = GamesLogParserService.getPlayerTeam(record);
        player.kills = [];
        player.deaths = [];
        player.humiliations = [];
        player.teammatesKills = [];
        return player;
    };

    this.getPlayerID = function(record) {
        var idStr = record.slice(record.indexOf(Constants.PLAYER_INFO_KEY) + Constants.PLAYER_INFO_KEY.length, record.indexOf(Constants.PLAYER_NAME_KEY));
        return parseInt(idStr, 10);
    };

    this.getPlayerName = function(record) {
        return record.slice(record.indexOf(Constants.PLAYER_NAME_KEY) + Constants.PLAYER_NAME_KEY.length, record.indexOf(Constants.BACKSLASH_KEY, record.indexOf(Constants.PLAYER_NAME_KEY) + Constants.PLAYER_NAME_KEY.length));
    };

    this.getKill = function(record) {
        var killStr = record.slice(record.indexOf('Kill: ') + 'Kill: '.length, record.indexOf(':', record.indexOf('Kill: ') + 'Kill: '.length)),
            idsArr = killStr.split(' '),
            killerID = parseInt(idsArr[0], 10),
            victimID = parseInt(idsArr[1], 10),
            killModeID = parseInt(idsArr[2], 10),
            killerName = record.slice(record.indexOf(killStr + ': ') + (killStr + ': ').length, record.indexOf(' killed')),
            victimName = record.slice(record.indexOf('killed ') + 'killed '.length, record.indexOf(' by'));
        return {killer: killerID,
            killerName:killerName,
            victim: victimID,
            victimName: victimName,
            mode: killModeID
        };
    };

    this.getTopPlayer = function(prop, players) {
        var topPlayer = null,
            player = null;
        for (var playerName in players) {
            player = players[playerName];
            if (topPlayer) {
                if (player[prop].length > topPlayer[prop].length) {
                    topPlayer = player;
                }
            } else {
                topPlayer = player;
            }
        }
        return topPlayer;
    };

    this.registerKill = function(kill, map) {
        var killerPlayer = map.players[kill.killerName],
            victimPlayer = map.players[kill.victimName];
        if (killerPlayer && victimPlayer) {
            if (kill.killerName !== kill.victimName) {
                victimPlayer.deaths.push(kill);
            }
            if (killerPlayer.team === victimPlayer.team) {
                me.stats.players[kill.killerName].teammatesKills.push(kill);
            } else {
                killerPlayer.kills.push(kill);
                if (kill.mode === 2) {
                    me.stats.players[kill.killerName].humiliations.push(kill);
                }
            }
            calculatePlayerToPlayerKills(kill);
        }
    };

    function calculatePlayerToPlayerKills(kill) {
        var killerPlayer = me.stats.players[kill.killerName],
            victimPlayer = me.stats.players[kill.victimName];
        if (killerPlayer && victimPlayer) {
            if (kill.killerName !== kill.victimName) {
                victimPlayer.deaths.push(kill);
            }
            if (killerPlayer.team !== victimPlayer.team) {
                killerPlayer.kills.push(kill);
            }
        }
    }

    this.registerStatsPlayer = function(player) {
        if (!me.stats.players[player.name]) {
            me.stats.players[player.name] = player;
        }
        if (me.stats.players[player.name].team !== player.team) {
            me.stats.players[player.name].team = player.team;
        }
    };

	this.getKillsStats = function(log) {
		if (me.stats) {
            return me.stats;
        }
        var i,
            record,
            map,
            kill,
            player;
        me.stats = {};
        me.stats.maps = {};
        me.stats.players = {};

        for (i = 0; i < log.length; i++) {
            record = log[i];
            if (!record) {
                continue;
            }
            if (GamesLogParserService.isMapStart(record)) {
                map = me.initMap(record, i);
                me.stats.maps[i] = map;
            }
            // Player
            if (GamesLogParserService.isClientUserinfoChanged(record)) {
                player = me.getPlayer(record);

                for (var name in map.players) {
                    if (map.players[name] && map.players[name].name === player.name) {
                        player = angular.copy(map.players[name]);
                        delete map.players[name];
                        break;
                    }
                }
                map.players[player.name] = player;
                me.registerStatsPlayer(player);
            }
            // Kill
            if (record.indexOf('Kill: ') !== -1) {
                kill = me.getKill(record);
                if (kill.victim !== kill.killer) {
                    me.registerKill(kill, map);
                }
            }
            // Exit
            if (record.indexOf('ShutdownGame:') !== -1) {
                map.topKiller = me.getTopPlayer('kills', map.players);
                map.topVictim = me.getTopPlayer('deaths', map.players);
            }
        }
        me.stats.topKiller = me.getTopPlayer('kills', me.stats.players);
        me.stats.topVictim = me.getTopPlayer('deaths', me.stats.players);
        me.stats.topHumilator = me.getTopPlayer('humiliations', me.stats.players);
        me.stats.topFifthColumn = me.getTopPlayer('teammatesKills', me.stats.players);
        me.stats.humiliations = getAggragatedArraysByProp('humiliations', me.stats.players);
        me.stats.teammatesKills = getAggragatedArraysByProp('teammatesKills', me.stats.players);
        return me.stats;
	};

    this.getPlayerWeaponsStats = function(player) {
        var modes=  {},
            result = [],
            killMode,
            deathMode;
        if (player) {
            for (var kill in player.kills) {
                killMode = player.kills[kill].mode;
                if (modes[killMode] === undefined) {
                    modes[killMode] = {id:killMode, kills:0, deaths:0};
                    continue;
                } else {
                    modes[killMode].kills += 1;
                }
            }
            for (var death in player.deaths) {
                deathMode = player.deaths[death].mode;
                if (modes[deathMode] === undefined) {
                    modes[deathMode] = {id:deathMode, kills:0, deaths:0};
                    continue;
                } else {
                    modes[deathMode].deaths += 1;
                }
            }

            for (var mode in modes) {
                result.push(modes[mode]);
            }
        }
        return result;
    };

    function getAggragatedArraysByProp(prop, players) {
        var result = [],
            player,
            killer,
            kill,
            aggregator;
        for (var item in players) {
            aggregator = {};
            player = players[item];
            if (player[prop].length > 0) {
                killer = {
                    name: player.name,
                    nameId: player.nameId,
                    count: player[prop].length,
                    victims: []
                };
                for (var i = 0; i < player[prop].length; i++) {
                    kill = player[prop][i];
                    if (!aggregator[kill.victimName]) {
                        aggregator[kill.victimName] = {name:kill.victimName, count:0};
                    }
                    aggregator[kill.victimName].count++;
                }
                killer.victims = objectToArray(aggregator);
                result.push(killer);
            }
        }
        return result;
    }

    function objectToArray(items) {
        var result = [];
        angular.forEach(items, function(value) {
            result.push(value);
        });
        return result;
    }
}]);<|endoftext|>