<commit_before>/*
 * Copyright (c) 2016, Two Sigma Open Source
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * * Neither the name of git-meta nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
"use strict";

/**
 * This module contains methods for pushing.
 */

const assert  = require("chai").assert;
const co      = require("co");
const colors  = require("colors");
const NodeGit = require("nodegit");

const DoWorkQueue         = require("./do_work_queue");
const GitUtil             = require("./git_util");
const SubmoduleUtil       = require("./submodule_util");
const SubmoduleConfigUtil = require("./submodule_config_util");
const SyntheticBranchUtil = require("./synthetic_branch_util");
const UserError           = require("./user_error");

// This magic SHA represents an empty tree in Git.

const EMPTY_TREE = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";

/**
 * For a given commit and remote, determine a reasonably close oid that has
 * already been pushed. This does *not* do a fetch, but rather just compares
 * against all available remote refs. To compare against all remotes, simply
 * pass a "*" wildcard.
 *
 * This works by building a revwalk and removing all ancestors of remote refs
 * for the given remote. It then reverses the result, and returns the first
 * parent of the oldest, unpushed commit. This is not an absolute last pushed
 * oid, but is a very good proxy to determine what to push.
 *
 * Returns a commit that exists in a remote ref, or null if no such commit
 * exists. If the given commit exists in a remote ref, will return itself.
 *
 * @async
 * @param {NodeGit.Repository} repo
 * @param {String}             remoteName
 * @param {NodeGit.Commit}     commit
 */
exports.getClosePushedCommit = co.wrap(function*(repo, remoteName, commit) {
    assert.instanceOf(repo, NodeGit.Repository);
    assert.isString(remoteName);
    assert.instanceOf(commit, NodeGit.Commit);

    // Search for the first commit that is not an ancestor of a remote ref, ie.
    // the first commit that is unpushed. First by topological, then resolving
    // by timestamp.

    const walk = NodeGit.Revwalk.create(repo);
    walk.sorting(NodeGit.Revwalk.SORT.TOPOLOGICAL,
                 NodeGit.Revwalk.SORT.TIME,
                 NodeGit.Revwalk.SORT.REVERSE);
    walk.hideGlob(`refs/remotes/${remoteName}`);
    walk.push(commit);

    // This occurs when walk.next() has no commits left -- in this case,
    // when there are no unpushed commits. Return the passed commit as the
    // last pushed commit.

    let firstNewOid;
    try {
        firstNewOid = yield walk.next();
    } catch (err) {
        if (NodeGit.Error.CODE.ITEROVER === err.errno)  {
            return commit;
        }
        throw err;
    }

    const firstNewCommit = yield repo.getCommit(firstNewOid);

    // If the first unpushed commit has no parents, then the entire set of
    // commits to push is new.

    if (0 === firstNewCommit.parentcount()) {
        return null;
    }
    return yield repo.getCommit(firstNewCommit.parentId(0));
});

/**
 * For a given proposed push, return a map from submodule to sha,
 * excluding any submodules that the server likely already has.
 *
 * Return in the map only those submodules that (1) exist locally, in
 * `.git/modules` and (2) are changed between `commit` and the merge base of
 * `commit` and each relevant branch.
 *
 * @async
 * @param {NodeGit.Repository} repo
 * @param {String}             remoteName
 * @param {String}             source
 * @param {NodeGit.Commit}     commit
 */
exports.getPushMap = co.wrap(function*(repo, remoteName, source,
                                       commit) {
    assert.instanceOf(repo, NodeGit.Repository);
    assert.isString(remoteName);
    assert.isString(source);
    assert.instanceOf(commit, NodeGit.Commit);

    const baseCommit = yield exports.getClosePushedCommit(repo, remoteName,
                                                          commit);
    let baseTree;
    if (null !== baseCommit) {
        baseTree = yield baseCommit.getTree();
    } else {
        baseTree = EMPTY_TREE;
    }

    const tree = yield commit.getTree();
    const diff = yield NodeGit.Diff.treeToTree(repo, baseTree, tree, null);
    const changes = SubmoduleUtil.getSubmoduleChangesFromDiff(diff, true);

    const pushMap = {};
    for (const path of Object.keys(changes)) {
        const change = changes[path];
        if (!change.deleted) {
            pushMap[path] = change.newSha;
        }
    }

    const openSubmodules = yield SubmoduleUtil.listOpenSubmodules(repo);
    const absorbedSubmodules =
        yield SubmoduleUtil.listAbsorbedSubmodules(repo);

    const availableSubmodules = new Set([...openSubmodules,
                                        ...absorbedSubmodules]);

    // Make sure we have the repositories and commits we want to push.
    for (const sub of Object.keys(pushMap)) {
        if (!availableSubmodules.has(sub)) {
            delete pushMap[sub];
            continue;
        }

        const subRepo = yield SubmoduleUtil.getBareRepo(repo, sub);
        try {
            yield subRepo.getCommit(pushMap[sub]);
        } catch (e) {
            delete pushMap[sub];
        }
    }

    return pushMap;
});

/**
 * For each open submodule that exists in the commit indicated by the specified
 * `source`, push a synthetic-meta-ref for the `source` commit.
 * If all sub-repo pushes succeed, push `source` to
 * to the specified `target` branch in `remoteName`.  If any pushes fail, throw
 * a `UserError` object.
 *
 * Note that this strategy is naive: it does not handle the following
 * situations:
 *
 * - closed submodules with commits that need to be pushed
 * - submodules that do not exist in the `source` commit, but did previously
 *   and need synthetic-meta-refs
 * - submodules with divergent histories, i.e., the commit we create the
 *   synthetic-meta-ref for doesn't contain one or more commits that need to be
 *   pushed in its history
 *
 * Addressing these situations would have a performance impact, requiring
 * calculation and traversal of all meta-repo commits being pushed.  We should
 * probably add a way to do an "exhaustive" push.
 *
 * @async
 * @param {NodeGit.Repository} repo
 * @param {String}             remoteName
 * @param {String}             source
 * @param {String}             target
 * @param {Boolean}            force
 */
exports.push = co.wrap(function *(repo, remoteName, source, target, force) {
    assert.instanceOf(repo, NodeGit.Repository);
    assert.isString(remoteName);
    assert.isString(source);
    assert.isString(target);
    assert.isBoolean(force);

    let remoteUrl = yield GitUtil.getUrlFromRemoteName(repo, remoteName);

    const annotatedCommit = yield GitUtil.resolveCommitish(repo, source);
    if (annotatedCommit === null) {
        throw new UserError(`No such ref: ${source}`);
    }
    const sha = annotatedCommit.id();
    const commit = yield repo.getCommit(sha);

    // First, push the submodules.
    const pushMap = yield exports.getPushMap(repo, `*`, source,
                                            commit);

    let errorMessage = "";

    const urls = yield SubmoduleConfigUtil.getSubmodulesFromCommit(repo,
                                                                   commit);

    const pushSub = co.wrap(function *(subName) {
        // Push to a synthetic branch; first, calculate name.

        const sha = pushMap[subName];
        const syntheticName =
                          SyntheticBranchUtil.getSyntheticBranchForCommit(sha);
        const subRepo = yield SubmoduleUtil.getRepo(repo, subName);

        // Resolve the submodule's URL against the URL of the meta-repo,
        // ignoring the remote that is configured in the open submodule.

        const subUrl = SubmoduleConfigUtil.resolveSubmoduleUrl(remoteUrl,
                                                               urls[subName]);

        // Always force push synthetic refs.  It should not be necessary, but
        // if something does go wrong forcing will allow us to auto-correct.
        // If they succeed, no need to print the output inside the submodules.

        const pushResult = yield GitUtil.push(subRepo,
                                              subUrl,
                                              sha,
                                              syntheticName,
                                              true,
                                              true);
        if (null !== pushResult) {
            errorMessage +=
           `Failed to push submodule ${colors.yellow(subName)}: ${pushResult}`;
        }
    });
    yield DoWorkQueue.doInParallel(Object.keys(pushMap), pushSub);

    // Throw an error if there were any problems pushing submodules; don't push
    // the meta-repo.

    if ("" !== errorMessage) {
        throw new UserError(errorMessage);
    }

    // Finally, push the meta-repo and throw on failure.

    const result = yield GitUtil.push(repo, remoteName, source, target, force);
    if (null !== result) {
        throw new UserError(`Failed to push meta-repo: ${result}`);
    }
});
<commit_msg>Do not fail to push when a changed submodule is closed; all we need is the bare repo<commit_after>/*
 * Copyright (c) 2016, Two Sigma Open Source
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * * Neither the name of git-meta nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
"use strict";

/**
 * This module contains methods for pushing.
 */

const assert  = require("chai").assert;
const co      = require("co");
const colors  = require("colors");
const NodeGit = require("nodegit");

const DoWorkQueue         = require("./do_work_queue");
const GitUtil             = require("./git_util");
const SubmoduleUtil       = require("./submodule_util");
const SubmoduleConfigUtil = require("./submodule_config_util");
const SyntheticBranchUtil = require("./synthetic_branch_util");
const UserError           = require("./user_error");

// This magic SHA represents an empty tree in Git.

const EMPTY_TREE = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";

/**
 * For a given commit and remote, determine a reasonably close oid that has
 * already been pushed. This does *not* do a fetch, but rather just compares
 * against all available remote refs. To compare against all remotes, simply
 * pass a "*" wildcard.
 *
 * This works by building a revwalk and removing all ancestors of remote refs
 * for the given remote. It then reverses the result, and returns the first
 * parent of the oldest, unpushed commit. This is not an absolute last pushed
 * oid, but is a very good proxy to determine what to push.
 *
 * Returns a commit that exists in a remote ref, or null if no such commit
 * exists. If the given commit exists in a remote ref, will return itself.
 *
 * @async
 * @param {NodeGit.Repository} repo
 * @param {String}             remoteName
 * @param {NodeGit.Commit}     commit
 */
exports.getClosePushedCommit = co.wrap(function*(repo, remoteName, commit) {
    assert.instanceOf(repo, NodeGit.Repository);
    assert.isString(remoteName);
    assert.instanceOf(commit, NodeGit.Commit);

    // Search for the first commit that is not an ancestor of a remote ref, ie.
    // the first commit that is unpushed. First by topological, then resolving
    // by timestamp.

    const walk = NodeGit.Revwalk.create(repo);
    walk.sorting(NodeGit.Revwalk.SORT.TOPOLOGICAL,
                 NodeGit.Revwalk.SORT.TIME,
                 NodeGit.Revwalk.SORT.REVERSE);
    walk.hideGlob(`refs/remotes/${remoteName}`);
    walk.push(commit);

    // This occurs when walk.next() has no commits left -- in this case,
    // when there are no unpushed commits. Return the passed commit as the
    // last pushed commit.

    let firstNewOid;
    try {
        firstNewOid = yield walk.next();
    } catch (err) {
        if (NodeGit.Error.CODE.ITEROVER === err.errno)  {
            return commit;
        }
        throw err;
    }

    const firstNewCommit = yield repo.getCommit(firstNewOid);

    // If the first unpushed commit has no parents, then the entire set of
    // commits to push is new.

    if (0 === firstNewCommit.parentcount()) {
        return null;
    }
    return yield repo.getCommit(firstNewCommit.parentId(0));
});

/**
 * For a given proposed push, return a map from submodule to sha,
 * excluding any submodules that the server likely already has.
 *
 * Return in the map only those submodules that (1) exist locally, in
 * `.git/modules` and (2) are changed between `commit` and the merge base of
 * `commit` and each relevant branch.
 *
 * @async
 * @param {NodeGit.Repository} repo
 * @param {String}             remoteName
 * @param {String}             source
 * @param {NodeGit.Commit}     commit
 */
exports.getPushMap = co.wrap(function*(repo, remoteName, source,
                                       commit) {
    assert.instanceOf(repo, NodeGit.Repository);
    assert.isString(remoteName);
    assert.isString(source);
    assert.instanceOf(commit, NodeGit.Commit);

    const baseCommit = yield exports.getClosePushedCommit(repo, remoteName,
                                                          commit);
    let baseTree;
    if (null !== baseCommit) {
        baseTree = yield baseCommit.getTree();
    } else {
        baseTree = EMPTY_TREE;
    }

    const tree = yield commit.getTree();
    const diff = yield NodeGit.Diff.treeToTree(repo, baseTree, tree, null);
    const changes = SubmoduleUtil.getSubmoduleChangesFromDiff(diff, true);

    const pushMap = {};
    for (const path of Object.keys(changes)) {
        const change = changes[path];
        if (!change.deleted) {
            pushMap[path] = change.newSha;
        }
    }

    const openSubmodules = yield SubmoduleUtil.listOpenSubmodules(repo);
    const absorbedSubmodules =
        yield SubmoduleUtil.listAbsorbedSubmodules(repo);

    const availableSubmodules = new Set([...openSubmodules,
                                        ...absorbedSubmodules]);

    // Make sure we have the repositories and commits we want to push.
    for (const sub of Object.keys(pushMap)) {
        if (!availableSubmodules.has(sub)) {
            delete pushMap[sub];
            continue;
        }

        const subRepo = yield SubmoduleUtil.getBareRepo(repo, sub);
        try {
            yield subRepo.getCommit(pushMap[sub]);
        } catch (e) {
            delete pushMap[sub];
        }
    }

    return pushMap;
});

/**
 * For each open submodule that exists in the commit indicated by the specified
 * `source`, push a synthetic-meta-ref for the `source` commit.
 * If all sub-repo pushes succeed, push `source` to
 * to the specified `target` branch in `remoteName`.  If any pushes fail, throw
 * a `UserError` object.
 *
 * Note that this strategy is naive: it does not handle the following
 * situations:
 *
 * - closed submodules with commits that need to be pushed
 * - submodules that do not exist in the `source` commit, but did previously
 *   and need synthetic-meta-refs
 * - submodules with divergent histories, i.e., the commit we create the
 *   synthetic-meta-ref for doesn't contain one or more commits that need to be
 *   pushed in its history
 *
 * Addressing these situations would have a performance impact, requiring
 * calculation and traversal of all meta-repo commits being pushed.  We should
 * probably add a way to do an "exhaustive" push.
 *
 * @async
 * @param {NodeGit.Repository} repo
 * @param {String}             remoteName
 * @param {String}             source
 * @param {String}             target
 * @param {Boolean}            force
 */
exports.push = co.wrap(function *(repo, remoteName, source, target, force) {
    assert.instanceOf(repo, NodeGit.Repository);
    assert.isString(remoteName);
    assert.isString(source);
    assert.isString(target);
    assert.isBoolean(force);

    let remoteUrl = yield GitUtil.getUrlFromRemoteName(repo, remoteName);

    const annotatedCommit = yield GitUtil.resolveCommitish(repo, source);
    if (annotatedCommit === null) {
        throw new UserError(`No such ref: ${source}`);
    }
    const sha = annotatedCommit.id();
    const commit = yield repo.getCommit(sha);

    // First, push the submodules.
    const pushMap = yield exports.getPushMap(repo, `*`, source,
                                            commit);

    let errorMessage = "";

    const urls = yield SubmoduleConfigUtil.getSubmodulesFromCommit(repo,
                                                                   commit);

    const pushSub = co.wrap(function *(subName) {
        // Push to a synthetic branch; first, calculate name.

        const sha = pushMap[subName];
        const syntheticName =
                          SyntheticBranchUtil.getSyntheticBranchForCommit(sha);
        const subRepo = yield SubmoduleUtil.getBareRepo(repo, subName);

        // Resolve the submodule's URL against the URL of the meta-repo,
        // ignoring the remote that is configured in the open submodule.

        const subUrl = SubmoduleConfigUtil.resolveSubmoduleUrl(remoteUrl,
                                                               urls[subName]);

        // Always force push synthetic refs.  It should not be necessary, but
        // if something does go wrong forcing will allow us to auto-correct.
        // If they succeed, no need to print the output inside the submodules.

        const pushResult = yield GitUtil.push(subRepo,
                                              subUrl,
                                              sha,
                                              syntheticName,
                                              true,
                                              true);
        if (null !== pushResult) {
            errorMessage +=
           `Failed to push submodule ${colors.yellow(subName)}: ${pushResult}`;
        }
    });
    yield DoWorkQueue.doInParallel(Object.keys(pushMap), pushSub);

    // Throw an error if there were any problems pushing submodules; don't push
    // the meta-repo.

    if ("" !== errorMessage) {
        throw new UserError(errorMessage);
    }

    // Finally, push the meta-repo and throw on failure.

    const result = yield GitUtil.push(repo, remoteName, source, target, force);
    if (null !== result) {
        throw new UserError(`Failed to push meta-repo: ${result}`);
    }
});
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015-2016 Actor LLC. <https://actor.im>
 */

import { isFunction } from 'lodash';

import React, { Component, PropTypes } from 'react';
import { Container } from 'flux/utils';

import PeerUtils from '../utils/PeerUtils';

import DefaultMessages from './dialog/MessagesSection.react';
import DialogFooter from './dialog/DialogFooter.react';
import DefaultToolbar from './Toolbar.react';
import DefaultActivity from './Activity.react';
import DefaultSearch from './search/SearchSection.react';
import DefaultCall from './Call.react';
import ConnectionState from './common/ConnectionState.react';

import ActivityStore from '../stores/ActivityStore';
import DialogStore from '../stores/DialogStore';

import DialogActionCreators from '../actions/DialogActionCreators';

class DialogSection extends Component {
  static contextTypes = {
    router: PropTypes.object.isRequired,
    delegate: PropTypes.object.isRequired
  };

  static propTypes = {
    params: PropTypes.shape({
      id: PropTypes.string.isRequired
    }).isRequired
  };

  static getStores() {
    return [ActivityStore, DialogStore];
  }

  static calculateState() {
    return {
      peer: DialogStore.getCurrentPeer(),
      isMember: DialogStore.isMember(),
      isActivityOpen: ActivityStore.isOpen()
    };
  }

  constructor(props, context) {
    super(props, context);
    this.updatePeer(this.props.params.id);
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.params.id !== this.props.params.id) {
      this.updatePeer(nextProps.params.id);
    }
  }

  componentWillUnmount() {
    DialogActionCreators.selectDialogPeer(null);
  }

  updatePeer(id) {
    const peer = PeerUtils.stringToPeer(id);
    if (PeerUtils.hasPeer(peer)) {
      DialogActionCreators.selectDialogPeer(peer);
    } else {
      this.context.router.replace('/im');
    }
  }

  getActivityComponents() {
    const { features, components: { dialog } } = this.context.delegate;
    if (dialog && dialog.activity) {
      return dialog.activity;
    }

    const activity = [DefaultActivity];
    if (features.call) {
      activity.push(DefaultCall);
    }

    if (features.search) {
      activity.push(DefaultSearch);
    }

    return activity;
  }

  getComponents() {
    const { dialog } = this.context.delegate.components;
    const activity = this.getActivityComponents();

    if (dialog && !isFunction(dialog)) {
      return {
        activity,
        ToolbarSection: dialog.toolbar || DefaultToolbar,
        MessagesSection: isFunction(dialog.messages) ? dialog.messages : DefaultMessages
      };
    }

    return {
      activity,
      ToolbarSection: DefaultToolbar,
      MessagesSection: DefaultMessages
    };
  }

  render() {
    const { peer, isMember } = this.state;
    if (!peer) {
      return
;
    }

    const {
      ToolbarSection,
      MessagesSection,
      activity
    } = this.getComponents();

    return (

        <ToolbarSection />

            <ConnectionState/>
            <MessagesSection peer={peer} isMember={isMember} />
            <DialogFooter isMember={isMember} />

          {activity.map((Activity, index) => <Activity key={index} />)}

    );
  }
}

export default Container.create(DialogSection, {withProps: true});
<commit_msg>fix(web): fix typo in dialog activity resolving<commit_after>/*
 * Copyright (C) 2015-2016 Actor LLC. <https://actor.im>
 */

import { isFunction } from 'lodash';

import React, { Component, PropTypes } from 'react';
import { Container } from 'flux/utils';

import PeerUtils from '../utils/PeerUtils';

import DefaultMessages from './dialog/MessagesSection.react';
import DialogFooter from './dialog/DialogFooter.react';
import DefaultToolbar from './Toolbar.react';
import DefaultActivity from './Activity.react';
import DefaultSearch from './search/SearchSection.react';
import DefaultCall from './Call.react';
import ConnectionState from './common/ConnectionState.react';

import ActivityStore from '../stores/ActivityStore';
import DialogStore from '../stores/DialogStore';

import DialogActionCreators from '../actions/DialogActionCreators';

class DialogSection extends Component {
  static contextTypes = {
    router: PropTypes.object.isRequired,
    delegate: PropTypes.object.isRequired
  };

  static propTypes = {
    params: PropTypes.shape({
      id: PropTypes.string.isRequired
    }).isRequired
  };

  static getStores() {
    return [ActivityStore, DialogStore];
  }

  static calculateState() {
    return {
      peer: DialogStore.getCurrentPeer(),
      isMember: DialogStore.isMember(),
      isActivityOpen: ActivityStore.isOpen()
    };
  }

  constructor(props, context) {
    super(props, context);
    this.updatePeer(this.props.params.id);
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.params.id !== this.props.params.id) {
      this.updatePeer(nextProps.params.id);
    }
  }

  componentWillUnmount() {
    DialogActionCreators.selectDialogPeer(null);
  }

  updatePeer(id) {
    const peer = PeerUtils.stringToPeer(id);
    if (PeerUtils.hasPeer(peer)) {
      DialogActionCreators.selectDialogPeer(peer);
    } else {
      this.context.router.replace('/im');
    }
  }

  getActivityComponents() {
    const { features, components: { dialog } } = this.context.delegate;
    if (dialog && dialog.activity) {
      return dialog.activity;
    }

    const activity = [DefaultActivity];
    if (features.calls) {
      activity.push(DefaultCall);
    }

    if (features.search) {
      activity.push(DefaultSearch);
    }

    return activity;
  }

  getComponents() {
    const { dialog } = this.context.delegate.components;
    const activity = this.getActivityComponents();

    if (dialog && !isFunction(dialog)) {
      return {
        activity,
        ToolbarSection: dialog.toolbar || DefaultToolbar,
        MessagesSection: isFunction(dialog.messages) ? dialog.messages : DefaultMessages
      };
    }

    return {
      activity,
      ToolbarSection: DefaultToolbar,
      MessagesSection: DefaultMessages
    };
  }

  render() {
    const { peer, isMember } = this.state;
    if (!peer) {
      return
;
    }

    const {
      ToolbarSection,
      MessagesSection,
      activity
    } = this.getComponents();

    return (

        <ToolbarSection />

            <ConnectionState/>
            <MessagesSection peer={peer} isMember={isMember} />
            <DialogFooter isMember={isMember} />

          {activity.map((Activity, index) => <Activity key={index} />)}

    );
  }
}

export default Container.create(DialogSection, {withProps: true});
<|endoftext|>


<commit_before>(function (global, factory) {
    if (typeof define === "function" && define.amd) {
        define(['exports', 'react'], factory);
    } else if (typeof exports !== "undefined") {
        factory(exports, require('react'));
    } else {
        var mod = {
            exports: {}
        };
        factory(mod.exports, global.react);
        global.index = mod.exports;
    }
})(this, function (exports, _react) {
    'use strict';

    Object.defineProperty(exports, "__esModule", {
        value: true
    });
    exports.ReactPainter = undefined;

    var _react2 = _interopRequireDefault(_react);

    function _interopRequireDefault(obj) {
        return obj && obj.__esModule ? obj : {
            default: obj
        };
    }

    var _slicedToArray = function () {
        function sliceIterator(arr, i) {
            var _arr = [];
            var _n = true;
            var _d = false;
            var _e = undefined;

            try {
                for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
                    _arr.push(_s.value);

                    if (i && _arr.length === i) break;
                }
            } catch (err) {
                _d = true;
                _e = err;
            } finally {
                try {
                    if (!_n && _i["return"]) _i["return"]();
                } finally {
                    if (_d) throw _e;
                }
            }

            return _arr;
        }

        return function (arr, i) {
            if (Array.isArray(arr)) {
                return arr;
            } else if (Symbol.iterator in Object(arr)) {
                return sliceIterator(arr, i);
            } else {
                throw new TypeError("Invalid attempt to destructure non-iterable instance");
            }
        };
    }();

    function _classCallCheck(instance, Constructor) {
        if (!(instance instanceof Constructor)) {
            throw new TypeError("Cannot call a class as a function");
        }
    }

    var _createClass = function () {
        function defineProperties(target, props) {
            for (var i = 0; i < props.length; i++) {
                var descriptor = props[i];
                descriptor.enumerable = descriptor.enumerable || false;
                descriptor.configurable = true;
                if ("value" in descriptor) descriptor.writable = true;
                Object.defineProperty(target, descriptor.key, descriptor);
            }
        }

        return function (Constructor, protoProps, staticProps) {
            if (protoProps) defineProperties(Constructor.prototype, protoProps);
            if (staticProps) defineProperties(Constructor, staticProps);
            return Constructor;
        };
    }();

    function _possibleConstructorReturn(self, call) {
        if (!self) {
            throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
        }

        return call && (typeof call === "object" || typeof call === "function") ? call : self;
    }

    function _inherits(subClass, superClass) {
        if (typeof superClass !== "function" && superClass !== null) {
            throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
        }

        subClass.prototype = Object.create(superClass && superClass.prototype, {
            constructor: {
                value: subClass,
                enumerable: false,
                writable: true,
                configurable: true
            }
        });
        if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
    }

    var ReactPainter = exports.ReactPainter = function (_Component) {
        _inherits(ReactPainter, _Component);

        function ReactPainter() {
            var _ref;

            _classCallCheck(this, ReactPainter);

            for (var _len = arguments.length, props = Array(_len), _key = 0; _key < _len; _key++) {
                props[_key] = arguments[_key];
            }

            var _this = _possibleConstructorReturn(this, (_ref = ReactPainter.__proto__ || Object.getPrototypeOf(ReactPainter)).call.apply(_ref, [this].concat(props)));

            _this.hashTable = {};
            _this.rawData = [];

            _this.onMouseDown = function (event) {
                _this.setState({
                    isMouseDown: true
                });

                _this.ctx.moveTo((event.pageX || event.touches[0].pageX) - _this.bcr.left, (event.pageY || event.touches[0].pageY) - _this.bcr.top);
            };

            _this.onMouseUp = function () {
                if (_this.state.isMouseDown) {
                    _this.setState({
                        isMouseDown: false
                    });

                    _this.hashTable = {};

                    // remove duplicates
                    _this.rawData = _this.rawData.filter(function (element) {
                        var key = JSON.stringify(element);
                        var match = Boolean(_this.hashTable[key]);

                        return match ? false : _this.hashTable[key] = true;
                    });
                }
            };

            _this.onMouseMove = function (event) {
                if (_this.state.isMouseDown) {
                    event.preventDefault();

                    var coordinates = [event.pageX || event.touches[0].pageX, event.pageY || event.touches[0].pageY];

                    _this.rawData.push(coordinates);
                    _this.drawOnCanvas(coordinates);
                    _this.props.onUpdate();
                }
            };

            _this.drawOnCanvas = function (coordinates) {
                var _coordinates = _slicedToArray(coordinates, 2),
                    left = _coordinates[0],
                    top = _coordinates[1];

                _this.ctx.lineTo(left - _this.bcr.left, top - _this.bcr.top);
                _this.ctx.stroke();
            };

            _this.state = {
                isMouseDown: false
            };
            return _this;
        }

        _createClass(ReactPainter, [{
            key: 'componentDidMount',
            value: function componentDidMount() {
                if (self && (!this.canvas.getContext || !this.canvas.getBoundingClientRect)) {
                    throw new Error('HTML5 Canvas is not supported in your browser.');
                }
                this.ctx = this.canvas.getContext('2d') || {};
                this.bcr = this.canvas.getBoundingClientRect() || {};
                this.setDefaultAppearance();
            }
        }, {
            key: 'componentWillUpdate',
            value: function componentWillUpdate(nextProps) {
                var _props = this.props,
                    lineThickness = _props.lineThickness,
                    lineColor = _props.lineColor;

                if (lineThickness !== nextProps.lineThickness || lineColor !== nextProps.lineColor) {
                    this.setDefaultAppearance();
                }
            }
        }, {
            key: 'setDefaultAppearance',
            value: function setDefaultAppearance() {
                var _props2 = this.props,
                    lineThickness = _props2.lineThickness,
                    lineColor = _props2.lineColor,
                    lineStyle = _props2.lineStyle;

                this.ctx.lineWidth = lineThickness;
                this.ctx.strokeStyle = lineColor;
                this.ctx.lineJoin = this.ctx.lineCap = lineStyle;
                this.ctx.shadowBlur = 2;
                this.ctx.shadowColor = this.props.lineColor;
            }
        }, {
            key: 'render',
            value: function render() {
                var _this2 = this;

                var _props3 = this.props,
                    className = _props3.className,
                    height = _props3.height,
                    width = _props3.width,
                    style = _props3.style;

                return _react2.default.createElement(
                    'div',
                    null,
                    _react2.default.createElement('canvas', {
                        ref: function ref(canvas) {
                            return _this2.canvas = canvas;
                        },
                        className: '' + className,
                        width: width,
                        height: height,
                        style: style,
                        onMouseDown: this.onMouseDown,
                        onTouchStart: this.onMouseDown,
                        onMouseUp: this.onMouseUp,
                        onTouchEnd: this.onMouseUp,
                        onMouseMove: this.onMouseMove,
                        onMouseOut: this.onMouseUp })
                );
            }
        }]);

        return ReactPainter;
    }(_react.Component);

    ReactPainter.propTypes = {
        className: _react.PropTypes.string,
        width: _react.PropTypes.number,
        height: _react.PropTypes.number,
        style: _react.PropTypes.object,
        lineThickness: _react.PropTypes.number,
        lineColor: _react.PropTypes.string,
        lineStyle: _react.PropTypes.string,
        onUpdate: _react.PropTypes.func
    };
    ReactPainter.defaultProps = {
        className: 'react-painter',
        width: 800,
        height: 600,
        style: {
            border: '1px solid #ccc'
        },
        lineThickness: 10,
        lineColor: '#333333',
        lineStyle: 'round', // acceptable: bevel, round, miter
        onUpdate: function onUpdate() {}
    };
    exports.default = ReactPainter;
});<commit_msg>the latest build<commit_after>(function (global, factory) {
    if (typeof define === "function" && define.amd) {
        define(['exports', 'react'], factory);
    } else if (typeof exports !== "undefined") {
        factory(exports, require('react'));
    } else {
        var mod = {
            exports: {}
        };
        factory(mod.exports, global.react);
        global.index = mod.exports;
    }
})(this, function (exports, _react) {
    'use strict';

    Object.defineProperty(exports, "__esModule", {
        value: true
    });
    exports.ReactPainter = undefined;

    var _react2 = _interopRequireDefault(_react);

    function _interopRequireDefault(obj) {
        return obj && obj.__esModule ? obj : {
            default: obj
        };
    }

    var _slicedToArray = function () {
        function sliceIterator(arr, i) {
            var _arr = [];
            var _n = true;
            var _d = false;
            var _e = undefined;

            try {
                for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
                    _arr.push(_s.value);

                    if (i && _arr.length === i) break;
                }
            } catch (err) {
                _d = true;
                _e = err;
            } finally {
                try {
                    if (!_n && _i["return"]) _i["return"]();
                } finally {
                    if (_d) throw _e;
                }
            }

            return _arr;
        }

        return function (arr, i) {
            if (Array.isArray(arr)) {
                return arr;
            } else if (Symbol.iterator in Object(arr)) {
                return sliceIterator(arr, i);
            } else {
                throw new TypeError("Invalid attempt to destructure non-iterable instance");
            }
        };
    }();

    function _classCallCheck(instance, Constructor) {
        if (!(instance instanceof Constructor)) {
            throw new TypeError("Cannot call a class as a function");
        }
    }

    var _createClass = function () {
        function defineProperties(target, props) {
            for (var i = 0; i < props.length; i++) {
                var descriptor = props[i];
                descriptor.enumerable = descriptor.enumerable || false;
                descriptor.configurable = true;
                if ("value" in descriptor) descriptor.writable = true;
                Object.defineProperty(target, descriptor.key, descriptor);
            }
        }

        return function (Constructor, protoProps, staticProps) {
            if (protoProps) defineProperties(Constructor.prototype, protoProps);
            if (staticProps) defineProperties(Constructor, staticProps);
            return Constructor;
        };
    }();

    function _possibleConstructorReturn(self, call) {
        if (!self) {
            throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
        }

        return call && (typeof call === "object" || typeof call === "function") ? call : self;
    }

    function _inherits(subClass, superClass) {
        if (typeof superClass !== "function" && superClass !== null) {
            throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
        }

        subClass.prototype = Object.create(superClass && superClass.prototype, {
            constructor: {
                value: subClass,
                enumerable: false,
                writable: true,
                configurable: true
            }
        });
        if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
    }

    var ReactPainter = exports.ReactPainter = function (_Component) {
        _inherits(ReactPainter, _Component);

        function ReactPainter() {
            var _ref;

            _classCallCheck(this, ReactPainter);

            for (var _len = arguments.length, props = Array(_len), _key = 0; _key < _len; _key++) {
                props[_key] = arguments[_key];
            }

            var _this = _possibleConstructorReturn(this, (_ref = ReactPainter.__proto__ || Object.getPrototypeOf(ReactPainter)).call.apply(_ref, [this].concat(props)));

            _this.hashTable = {};
            _this.rawData = [];

            _this.onMouseDown = function (event) {
                _this.setState({
                    isMouseDown: true
                });

                _this.ctx.moveTo((event.pageX || event.touches[0].pageX) - _this.bcr.left, (event.pageY || event.touches[0].pageY) - _this.bcr.top);
            };

            _this.onMouseUp = function () {
                if (_this.state.isMouseDown) {
                    _this.setState({
                        isMouseDown: false
                    });

                    _this.hashTable = {};

                    // remove duplicates
                    _this.rawData = _this.rawData.filter(function (element) {
                        var key = JSON.stringify(element);
                        var match = Boolean(_this.hashTable[key]);

                        return match ? false : _this.hashTable[key] = true;
                    });

                    _this.props.onUpdate({
                        raw: _this.rawData,
                        canvas: _this.canvas
                    });
                }
            };

            _this.onMouseMove = function (event) {
                if (_this.state.isMouseDown) {
                    event.preventDefault();

                    var coordinates = [event.pageX || event.touches[0].pageX, event.pageY || event.touches[0].pageY];

                    _this.rawData.push(coordinates);
                    _this.drawOnCanvas(coordinates);
                }
            };

            _this.drawOnCanvas = function (coordinates) {
                var _coordinates = _slicedToArray(coordinates, 2),
                    left = _coordinates[0],
                    top = _coordinates[1];

                _this.ctx.lineTo(left - _this.bcr.left, top - _this.bcr.top);
                _this.ctx.stroke();
            };

            _this.state = {
                isMouseDown: false
            };
            return _this;
        }

        _createClass(ReactPainter, [{
            key: 'componentDidMount',
            value: function componentDidMount() {
                if (self && (!this.canvas.getContext || !this.canvas.getBoundingClientRect)) {
                    throw new Error('HTML5 Canvas is not supported in your browser.');
                }
                this.ctx = this.canvas.getContext('2d') || {};
                this.bcr = this.canvas.getBoundingClientRect() || {};
                this.setDefaultAppearance();
            }
        }, {
            key: 'componentWillUpdate',
            value: function componentWillUpdate(nextProps) {
                var _props = this.props,
                    lineThickness = _props.lineThickness,
                    lineColor = _props.lineColor;

                if (lineThickness !== nextProps.lineThickness || lineColor !== nextProps.lineColor) {
                    this.setDefaultAppearance();
                }
            }
        }, {
            key: 'setDefaultAppearance',
            value: function setDefaultAppearance() {
                var _props2 = this.props,
                    lineThickness = _props2.lineThickness,
                    lineColor = _props2.lineColor,
                    lineStyle = _props2.lineStyle;

                this.ctx.lineWidth = lineThickness;
                this.ctx.strokeStyle = lineColor;
                this.ctx.lineJoin = this.ctx.lineCap = lineStyle;

                if (this.props.blur) {
                    this.ctx.shadowBlur = 2;
                    this.ctx.shadowColor = this.props.lineColor;
                }
            }
        }, {
            key: 'render',
            value: function render() {
                var _this2 = this;

                var _props3 = this.props,
                    className = _props3.className,
                    height = _props3.height,
                    width = _props3.width,
                    style = _props3.style;

                return _react2.default.createElement(
                    'div',
                    null,
                    _react2.default.createElement('canvas', {
                        ref: function ref(canvas) {
                            return _this2.canvas = canvas;
                        },
                        className: '' + className,
                        width: width,
                        height: height,
                        style: style,
                        onMouseDown: this.onMouseDown,
                        onTouchStart: this.onMouseDown,
                        onMouseUp: this.onMouseUp,
                        onTouchEnd: this.onMouseUp,
                        onMouseMove: this.onMouseMove,
                        onMouseOut: this.onMouseUp })
                );
            }
        }]);

        return ReactPainter;
    }(_react.Component);

    ReactPainter.propTypes = {
        className: _react.PropTypes.string,
        width: _react.PropTypes.number,
        height: _react.PropTypes.number,
        style: _react.PropTypes.object,
        blur: _react.PropTypes.bool,
        lineThickness: _react.PropTypes.number,
        lineColor: _react.PropTypes.string,
        lineStyle: _react.PropTypes.string,
        onUpdate: _react.PropTypes.func
    };
    ReactPainter.defaultProps = {
        className: 'react-painter',
        width: 800,
        height: 600,
        style: {
            border: '1px solid #ccc'
        },
        blur: true,
        lineThickness: 10,
        lineColor: '#333333',
        lineStyle: 'round', // acceptable: bevel, round, miter
        onUpdate: function onUpdate() {}
    };
    exports.default = ReactPainter;
});<|endoftext|>


<commit_before>describe('Given the filterFeature Module', function () {

  var that, filterFeature, data;

  beforeEach(function () {

    data = [
      {data: {NAME: 'Gert', age: 21}, uid: 1},
      {data: {NAME: 'Peter', age: 23}, uid: 2},
      {data: {NAME: 'Peter', age: 35}, uid: 3},
      {data: {NAME: 'Max', age: 44}, uid: 4}
    ];

    var cf = crossfilter(data);

    that = {
      markers: {
        all: {},
        filter: {
          NAME: cf.dimension(function(d) {return d.data.NAME;}),
          age: cf.dimension(function(d) {return d.data.age;})
        }
      }
    };

    for (var x in data) {
      that.markers.all[data[x].uid] = data[x];
    }

    filterFeature = require('map-tools/filter')({}, that, 'markers');
  });

  describe('when no arguments are passed', function() {
    it('should return the entire collection', function() {
      var result = filterFeature();
      expect(result).to.eql(data)
    });
  });

  describe('when limit 1 is set with no order', function() {
    it('should return the highest value', function() {
      var result = filterFeature('age', {limit: 1});
      expect(result.uid).to.eql(4);
    });
  });

  describe('when limit 1 is set with DESC order', function(){

    it('should return the lowest number', function() {

      var result = filterFeature('age', {limit: 1, order: 'DESC'});
      expect(result.uid).to.eql(1);
    });

  });

  it('should filter exact values when passing an object', function () {
    var result = filterFeature({NAME: 'Peter'});
    expect(result).to.eql([data[2], data[1]]);
  });

  it('should return all elements order by the dimension, when passing the dimension name', function () {
    var result = filterFeature('NAME');
    expect(result).to.eql([data[2], data[1], data[3], data[0]]);
  });

  it('should return all elements order by the dimension, when passing the dimension name and order DESC', function () {
    var result = filterFeature('NAME', {order: 'DESC'});
    expect(result).to.eql([data[0], data[3], data[1], data[2]]);
  });

  it('should limit the results when using limit', function () {
    var result = filterFeature({NAME: 'Peter'}, {limit: 1});
    expect(result).to.eql(data[2]);
  });

});
<commit_msg>Improve code coverage.<commit_after>describe('Given the filterFeature Module', function () {

  var that, filterFeature, data;

  beforeEach(function () {

    data = [
      {data: {NAME: 'Gert', age: 21}, uid: 1},
      {data: {NAME: 'Peter', age: 23}, uid: 2},
      {data: {NAME: 'Peter', age: 35}, uid: 3},
      {data: {NAME: 'Max', age: 44}, uid: 4}
    ];

    that = {
      markers: {
        all: {}, filter: {},
        crossfilter: crossfilter(data)
      }
    };

    for (var x in data) {
      that.markers.all[data[x].uid] = data[x];
    }

    filterFeature = require('map-tools/filter')({}, that, 'markers');
  });

  describe('when no arguments are passed', function() {
    it('should return the entire collection', function() {
      var result = filterFeature();
      expect(result).to.eql(data)
    });
  });

  describe('when limit 1 is set with no order', function() {
    it('should return the highest value', function() {
      var result = filterFeature('age', {limit: 1});
      expect(result.uid).to.eql(4);
    });
  });

  describe('when limit 1 is set with DESC order', function(){

    it('should return the lowest number', function() {

      var result = filterFeature('age', {limit: 1, order: 'DESC'});
      expect(result.uid).to.eql(1);
    });

  });

  it('should filter exact values when passing an object', function () {
    var result = filterFeature({NAME: 'Peter'});
    expect(result).to.eql([data[2], data[1]]);
  });

  it('should return all elements order by the dimension, when passing the dimension name', function () {
    var result = filterFeature('NAME');
    expect(result).to.eql([data[2], data[1], data[3], data[0]]);
  });

  it('should return all elements order by the dimension, when passing the dimension name and order DESC', function () {
    var result = filterFeature('NAME', {order: 'DESC'});
    expect(result).to.eql([data[0], data[3], data[1], data[2]]);
  });

  it('should limit the results when using limit', function () {
    var result = filterFeature({NAME: 'Peter'}, {limit: 1});
    expect(result).to.eql(data[2]);
  });

});
<|endoftext|>


<commit_before>---

---
function fiscalYearBucket(row, field){
  var year = row[field.dataSource];
  switch (true){
    case (parseInt(year) < 1999):
      return '1990-1999'
    case (parseInt(year) < 2010):
      return '2000-2009'
    case (parseInt(year) < 2013):
      return '2010-2012'
    case (parseInt(year) == 2014):
      return '2014'
    case (parseInt(year) < 2018):
      return '2015-2017'
    case (year === 'LR 2018-2030'):
      return 'LR 2018-2030'
    case (year === 'LR 2031-2040'):
      return 'LR 2031-2040'
    default:
      return '2014-2019'
  }
}
function modelYearBucket(row, field){
  var year = row[field.dataSource];
  switch (true){
    case (year < 2020):
      return '2014-2019'
    case (year < 2030):
      return '2020-2029'
    case (year < 2040):
      return '2030-2039'
    case (year < 2050):
      return '2040-2049'
    default:
      return '2014-2019'
  }
}

// Define the structure of fields, if this is not defined then all fields will be assumed
// to be strings.  Name must match csv header row (which must exist) in order to parse correctly.
var fields = [
    // // filterable fields
    // {name: 'last_name',         type: 'string', filterable: true, filterType: 'regexp'},
    // {name: 'first_name',        type: 'string', filterable: true},
    // {name: 'state',             type: 'string', filterable: true},
    // {name: 'employer',          type: 'string', filterable: true},
    // {name: 'city',              type: 'string', filterable: true},
    // {name: 'invoice_date',      type: 'date',   filterable: true},

    {name: 'ARCID', type: 'string', filterable: true, summarizable: 'count'},
    {name: 'Description', type: 'string', filterable: true},
    {name: 'Jurisdiction', type: 'string', filterable: true},
    {name: 'ModelingNetworkYear', type: 'integer', filterable: true},
    {name: 'Sponsor', type: 'string', filterable: true},
    {name: 'ExistLanes', type: 'string', filterable: true},
    {name: 'ProposedLanes', type: 'string', filterable: true},
    {name: 'Length', type: 'string', filterable: true},
    {name: 'GDOTPI', type: 'string', filterable: true},
    {name: 'Limits', type: 'string', filterable: true},
    {name: 'Status', type: 'string', filterable: true},
    {name: 'ProjectType', type: 'string', filterable: true},
    {name: 'Analysis', type: 'string', filterable: true},
    {name: 'Phase', type: 'string', filterable: true},
    {name: 'PhaseStatus', type: 'string', filterable: true},
    {name: 'FiscalYear', type: 'string', filterable: true},
    {name: 'FundSource', type: 'string', filterable: true},
    // {name: 'Federal', type: 'integer', filterable: true},
    // {name: 'State', type: 'integer', filterable: true},
    // {name: 'Local', type: 'integer', filterable: true},
    // {name: 'Bond', type: 'integer', filterable: true},
    // {name: 'Total', type: 'integer', filterable: true},
    // {name: 'FederalSum', type: 'integer', filterable: true},
    // {name: 'StateSum', type: 'integer', filterable: true},
    // {name: 'LocalSum', type: 'integer', filterable: true},
    // {name: 'BondSum', type: 'integer', filterable: true},
    // {name: 'TotalSum', type: 'integer', filterable: true},

    // psuedo fields

    // {name: 'invoice_mm', type: 'string', filterable: true, pseudo: true,
    //   pseudoFunction: function(row){
    //       var date = new Date(row.invoice_date);
    //       return pivot.utils().padLeft((date.getMonth() + 1),2,'0')}
    // },
    // {name: 'invoice_yyyy_mm', type: 'string', filterable: true, pseudo: true,
    //   pseudoFunction: function(row){
    //     var date = new Date(row.invoice_date);
    //     return date.getFullYear() + '_' + pivot.utils().padLeft((date.getMonth() + 1),2,'0')}
    // },
    {name: 'ModelingNetworkYear', type: 'string', filterable: true, pseudo: true, columnLabelable: true,pseudoFunction: function(row){ return row.ModelingNetworkYear }},
    // {name: 'FiscalYear', type: 'string', filterable: true, pseudo: true, columnLabelable: true,pseudoFunction: function(row){ return row.FiscalYear }},
     // {name: 'ModelYearBucket', type: 'string', filterable: true, columnLabelable: true, pseudo: true, dataSource: 'ModelingNetworkYear', pseudoFunction: modelYearBucket},
     {name: 'FiscalYearBucket', type: 'string', filterable: true, columnLabelable: true, pseudo: true, dataSource: 'FiscalYear', pseudoFunction: fiscalYearBucket},

    // // summary fields
    {name: 'Federal',     type: 'integer',  rowLabelable: false, summarizable: 'sum', displayFunction: function(value){ return accounting.formatMoney(value)}},
    {name: 'State',     type: 'integer',  rowLabelable: false, summarizable: 'sum', displayFunction: function(value){ return accounting.formatMoney(value)}},
    {name: 'Local',     type: 'integer',  rowLabelable: false, summarizable: 'sum', displayFunction: function(value){ return accounting.formatMoney(value)}},
    {name: 'Bond',     type: 'integer',  rowLabelable: false, summarizable: 'sum', displayFunction: function(value){ return accounting.formatMoney(value)}},
    {name: 'Total',     type: 'integer',  rowLabelable: false, summarizable: 'sum', displayFunction: function(value){ return accounting.formatMoney(value)}},
    {name: 'FederalSum',     type: 'integer',  rowLabelable: false, summarizable: 'sum', displayFunction: function(value){ return accounting.formatMoney(value)}},
    {name: 'StateSum',     type: 'integer',  rowLabelable: false, summarizable: 'sum', displayFunction: function(value){ return accounting.formatMoney(value)}},
    {name: 'LocalSum',     type: 'integer',  rowLabelable: false, summarizable: 'sum', displayFunction: function(value){ return accounting.formatMoney(value)}},
    {name: 'BondSum',     type: 'integer',  rowLabelable: false, summarizable: 'sum', displayFunction: function(value){ return accounting.formatMoney(value)}},
    {name: 'TotalSum',     type: 'integer',  rowLabelable: false, summarizable: 'sum', displayFunction: function(value){ return accounting.formatMoney(value)}}
]
var dTable = null;

  function setupPivot(input){
    input.callbacks = {afterUpdateResults: function(){
      dTable = $('#results > table').dataTable({
        "sDom": "<'row'<'col-md-6'l><'col-md-6'f>>t<'row'<'col-md-6'i><'col-md-6'p>>",
        "iDisplayLength": 10,
        "aLengthMenu": [[10, 25, 50, 100, -1], [10, 25, 50, 100, "All"]],
        "sPaginationType": "bootstrap",
        "oLanguage": {
          "sLengthMenu": "_MENU_ records per page"
        }//,
        // "sScrollX": "100%",
        // "sScrollXInner": "150%",
        // "bScrollCollapse": true
      });
      //new FixedColumns( dTable );
    }};
    $('#pivot-demo').pivot_display('setup', input);
  };
  function JSON2CSV(objArray) {
    var array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;

    var str = '';
    var line = '';

    if (1){//($("#labels").is(':checked')) {
        var head = array[0];
        if ($("#quote").is(':checked')) {
            for (var index in array[0]) {
                var value = index + "";
                line += '"' + value.replace(/"/g, '""') + '",';
            }
        } else {
            for (var index in array[0]) {
                line += index + ',';
            }
        }

        line = line.slice(0, -1);
        str += line + '\r\n';
    }

    for (var i = 0; i < array.length; i++) {
        var line = '';

        if (1){//($("#quote").is(':checked')) {
            for (var index in array[i]) {
                var value = array[i][index] + "";
                line += '"' + value.replace(/"/g, '""') + '",';
            }
        } else {
            for (var index in array[i]) {
                line += array[i][index] + ',';
            }
        }

        line = line.slice(0, -1);
        str += line + '\r\n';
    }
    return str;

}

  var someLink = window.location || window.webkiURL//window.location//'http://0.0.0.0:4000/explore/pivot/download.json' //window.location
  var formBlob = null
  var csv = ''
  function exportResults(type) {
    var name = 'results.' + type
    var a = document.createElement("a");
    document.body.appendChild(a);
    a.style = "display: none";
    var json = pivot.results().all()
    if (type === 'json'){
      // alert('Exporting results as ' + type + '.')
      formBlob = new Blob([JSON.stringify(json)], { type: 'octet/stream' });

      url = window.URL.createObjectURL(formBlob);
    }
    else if (type === 'csv'){
      // alert('Exporting results as ' + type + '.')
      csv = JSON2CSV(json)
      formBlob = new Blob([csv], { type: 'text/csv',filename:'MyVerySpecial.csv' });

      url = window.URL.createObjectURL(formBlob);
    }
    else if (type === 'pdf'){
      alert('Exporting results as ' + type + '.')
      // use jsPDF library!
    }
    a.href = url;
        a.download = name;
        a.click();
        window.URL.revokeObjectURL(url);
  }

  $(document).ready(function() {

    setupPivot({url:'{{ site.baseurl}}/data/TIP/projects.csv', fields: fields, filters:{"FiscalYear":"2014"}, rowLabels:['ARCID', 'Jurisdiction', 'ProjectType', 'Phase', 'Status'], summaries:["Total"]})

    // prevent dropdown from closing after selection
    $('.stop-propagation').click(function(event){
      event.stopPropagation();
    });

    // **Sexy** In your console type pivot.config() to view your current internal structure (the full initialize object).  Pass it to setup and you have a canned report.
    $('#atl-project-funding').click(function(event){
      $('#pivot-demo').pivot_display('reprocess_display', {filters:{"Jurisdiction":"City of Atlanta"}, rowLabels:["ProjectType"], columnLabels:["ModelingNetworkYear"], summaries:["Total"]})
    });

    $('#cobb-phase-funding').click(function(event){
      $('#pivot-demo').pivot_display('reprocess_display', {filters:{"Jurisdiction":"Cobb County"},rowLabels:["Phase","ModelingNetworkYear"], summaries:["Total"]})
    });

    $('#fy-category-funding').click(function(event){
      $('#pivot-demo').pivot_display('reprocess_display', {rowLabels:["FundSource"],columnLabels:["FiscalYearBucket"],summaries:["Total"]})
    });
  });<commit_msg>changed default records to 25<commit_after>---

---
function fiscalYearBucket(row, field){
  var year = row[field.dataSource];
  switch (true){
    case (parseInt(year) < 1999):
      return '1990-1999'
    case (parseInt(year) < 2010):
      return '2000-2009'
    case (parseInt(year) < 2013):
      return '2010-2012'
    case (parseInt(year) == 2014):
      return '2014'
    case (parseInt(year) < 2018):
      return '2015-2017'
    case (year === 'LR 2018-2030'):
      return 'LR 2018-2030'
    case (year === 'LR 2031-2040'):
      return 'LR 2031-2040'
    default:
      return '2014-2019'
  }
}
function modelYearBucket(row, field){
  var year = row[field.dataSource];
  switch (true){
    case (year < 2020):
      return '2014-2019'
    case (year < 2030):
      return '2020-2029'
    case (year < 2040):
      return '2030-2039'
    case (year < 2050):
      return '2040-2049'
    default:
      return '2014-2019'
  }
}

// Define the structure of fields, if this is not defined then all fields will be assumed
// to be strings.  Name must match csv header row (which must exist) in order to parse correctly.
var fields = [
    // // filterable fields
    // {name: 'last_name',         type: 'string', filterable: true, filterType: 'regexp'},
    // {name: 'first_name',        type: 'string', filterable: true},
    // {name: 'state',             type: 'string', filterable: true},
    // {name: 'employer',          type: 'string', filterable: true},
    // {name: 'city',              type: 'string', filterable: true},
    // {name: 'invoice_date',      type: 'date',   filterable: true},

    {name: 'ARCID', type: 'string', filterable: true, summarizable: 'count'},
    {name: 'Description', type: 'string', filterable: true},
    {name: 'Jurisdiction', type: 'string', filterable: true},
    {name: 'ModelingNetworkYear', type: 'integer', filterable: true},
    {name: 'Sponsor', type: 'string', filterable: true},
    {name: 'ExistLanes', type: 'string', filterable: true},
    {name: 'ProposedLanes', type: 'string', filterable: true},
    {name: 'Length', type: 'string', filterable: true},
    {name: 'GDOTPI', type: 'string', filterable: true},
    {name: 'Limits', type: 'string', filterable: true},
    {name: 'Status', type: 'string', filterable: true},
    {name: 'ProjectType', type: 'string', filterable: true},
    {name: 'Analysis', type: 'string', filterable: true},
    {name: 'Phase', type: 'string', filterable: true},
    {name: 'PhaseStatus', type: 'string', filterable: true},
    {name: 'FiscalYear', type: 'string', filterable: true},
    {name: 'FundSource', type: 'string', filterable: true},
    // {name: 'Federal', type: 'integer', filterable: true},
    // {name: 'State', type: 'integer', filterable: true},
    // {name: 'Local', type: 'integer', filterable: true},
    // {name: 'Bond', type: 'integer', filterable: true},
    // {name: 'Total', type: 'integer', filterable: true},
    // {name: 'FederalSum', type: 'integer', filterable: true},
    // {name: 'StateSum', type: 'integer', filterable: true},
    // {name: 'LocalSum', type: 'integer', filterable: true},
    // {name: 'BondSum', type: 'integer', filterable: true},
    // {name: 'TotalSum', type: 'integer', filterable: true},

    // psuedo fields

    // {name: 'invoice_mm', type: 'string', filterable: true, pseudo: true,
    //   pseudoFunction: function(row){
    //       var date = new Date(row.invoice_date);
    //       return pivot.utils().padLeft((date.getMonth() + 1),2,'0')}
    // },
    // {name: 'invoice_yyyy_mm', type: 'string', filterable: true, pseudo: true,
    //   pseudoFunction: function(row){
    //     var date = new Date(row.invoice_date);
    //     return date.getFullYear() + '_' + pivot.utils().padLeft((date.getMonth() + 1),2,'0')}
    // },
    {name: 'ModelingNetworkYear', type: 'string', filterable: true, pseudo: true, columnLabelable: true,pseudoFunction: function(row){ return row.ModelingNetworkYear }},
    // {name: 'FiscalYear', type: 'string', filterable: true, pseudo: true, columnLabelable: true,pseudoFunction: function(row){ return row.FiscalYear }},
     // {name: 'ModelYearBucket', type: 'string', filterable: true, columnLabelable: true, pseudo: true, dataSource: 'ModelingNetworkYear', pseudoFunction: modelYearBucket},
     {name: 'FiscalYearBucket', type: 'string', filterable: true, columnLabelable: true, pseudo: true, dataSource: 'FiscalYear', pseudoFunction: fiscalYearBucket},

    // // summary fields
    {name: 'Federal',     type: 'integer',  rowLabelable: false, summarizable: 'sum', displayFunction: function(value){ return accounting.formatMoney(value)}},
    {name: 'State',     type: 'integer',  rowLabelable: false, summarizable: 'sum', displayFunction: function(value){ return accounting.formatMoney(value)}},
    {name: 'Local',     type: 'integer',  rowLabelable: false, summarizable: 'sum', displayFunction: function(value){ return accounting.formatMoney(value)}},
    {name: 'Bond',     type: 'integer',  rowLabelable: false, summarizable: 'sum', displayFunction: function(value){ return accounting.formatMoney(value)}},
    {name: 'Total',     type: 'integer',  rowLabelable: false, summarizable: 'sum', displayFunction: function(value){ return accounting.formatMoney(value)}},
    {name: 'FederalSum',     type: 'integer',  rowLabelable: false, summarizable: 'sum', displayFunction: function(value){ return accounting.formatMoney(value)}},
    {name: 'StateSum',     type: 'integer',  rowLabelable: false, summarizable: 'sum', displayFunction: function(value){ return accounting.formatMoney(value)}},
    {name: 'LocalSum',     type: 'integer',  rowLabelable: false, summarizable: 'sum', displayFunction: function(value){ return accounting.formatMoney(value)}},
    {name: 'BondSum',     type: 'integer',  rowLabelable: false, summarizable: 'sum', displayFunction: function(value){ return accounting.formatMoney(value)}},
    {name: 'TotalSum',     type: 'integer',  rowLabelable: false, summarizable: 'sum', displayFunction: function(value){ return accounting.formatMoney(value)}}
]
var dTable = null;

  function setupPivot(input){
    input.callbacks = {afterUpdateResults: function(){
      dTable = $('#results > table').dataTable({
        "sDom": "<'row'<'col-md-6'l><'col-md-6'f>>t<'row'<'col-md-6'i><'col-md-6'p>>",
        "iDisplayLength": 25,
        "aLengthMenu": [[10, 25, 50, 100, -1], [10, 25, 50, 100, "All"]],
        "sPaginationType": "bootstrap",
        "oLanguage": {
          "sLengthMenu": "_MENU_ records per page"
        }//,
        // "sScrollX": "100%",
        // "sScrollXInner": "150%",
        // "bScrollCollapse": true
      });
      //new FixedColumns( dTable );
    }};
    $('#pivot-demo').pivot_display('setup', input);
  };
  function JSON2CSV(objArray) {
    var array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;

    var str = '';
    var line = '';

    if (1){//($("#labels").is(':checked')) {
        var head = array[0];
        if ($("#quote").is(':checked')) {
            for (var index in array[0]) {
                var value = index + "";
                line += '"' + value.replace(/"/g, '""') + '",';
            }
        } else {
            for (var index in array[0]) {
                line += index + ',';
            }
        }

        line = line.slice(0, -1);
        str += line + '\r\n';
    }

    for (var i = 0; i < array.length; i++) {
        var line = '';

        if (1){//($("#quote").is(':checked')) {
            for (var index in array[i]) {
                var value = array[i][index] + "";
                line += '"' + value.replace(/"/g, '""') + '",';
            }
        } else {
            for (var index in array[i]) {
                line += array[i][index] + ',';
            }
        }

        line = line.slice(0, -1);
        str += line + '\r\n';
    }
    return str;

}

  var someLink = window.location || window.webkiURL//window.location//'http://0.0.0.0:4000/explore/pivot/download.json' //window.location
  var formBlob = null
  var csv = ''
  function exportResults(type) {
    var name = 'results.' + type
    var a = document.createElement("a");
    document.body.appendChild(a);
    a.style = "display: none";
    var json = pivot.results().all()
    if (type === 'json'){
      // alert('Exporting results as ' + type + '.')
      formBlob = new Blob([JSON.stringify(json)], { type: 'octet/stream' });

      url = window.URL.createObjectURL(formBlob);
    }
    else if (type === 'csv'){
      // alert('Exporting results as ' + type + '.')
      csv = JSON2CSV(json)
      formBlob = new Blob([csv], { type: 'text/csv',filename:'MyVerySpecial.csv' });

      url = window.URL.createObjectURL(formBlob);
    }
    else if (type === 'pdf'){
      alert('Exporting results as ' + type + '.')
      // use jsPDF library!
    }
    a.href = url;
        a.download = name;
        a.click();
        window.URL.revokeObjectURL(url);
  }

  $(document).ready(function() {

    setupPivot({url:'{{ site.baseurl}}/data/TIP/projects.csv', fields: fields, filters:{"FiscalYear":"2014"}, rowLabels:['ARCID', 'Jurisdiction', 'ProjectType', 'Phase', 'Status'], summaries:["Total"]})

    // prevent dropdown from closing after selection
    $('.stop-propagation').click(function(event){
      event.stopPropagation();
    });

    // **Sexy** In your console type pivot.config() to view your current internal structure (the full initialize object).  Pass it to setup and you have a canned report.
    $('#atl-project-funding').click(function(event){
      $('#pivot-demo').pivot_display('reprocess_display', {filters:{"Jurisdiction":"City of Atlanta"}, rowLabels:["ProjectType"], columnLabels:["ModelingNetworkYear"], summaries:["Total"]})
    });

    $('#cobb-phase-funding').click(function(event){
      $('#pivot-demo').pivot_display('reprocess_display', {filters:{"Jurisdiction":"Cobb County"},rowLabels:["Phase","ModelingNetworkYear"], summaries:["Total"]})
    });

    $('#fy-category-funding').click(function(event){
      $('#pivot-demo').pivot_display('reprocess_display', {rowLabels:["FundSource"],columnLabels:["FiscalYearBucket"],summaries:["Total"]})
    });
  });<|endoftext|>


<commit_before>Application.Controllers.controller("FilesController",
    ["$scope", "projectFiles", "applySearch",
        "pubsub", "mcfile", "$state", "pubsub", FilesController]);
function FilesController($scope, projectFiles, applySearch,
                         $filter, mcfile, $state, pubsub) {

    var f = projectFiles.model.projects[$scope.project.id].dir;

    // Root is name of project. Have it opened by default.
    $scope.files = [f];
    applySearch($scope, "searchInput", applyQuery);

    function applyQuery() {
        var search = {
            name: ""
        };

        if ($scope.searchInput === "") {
            $scope.files = [projectFiles.model.projects[$scope.project.id].dir];
        } else {
            var filesToSearch = projectFiles.model.projects[$scope.project.id].byMediaType.all;
            search.name = $scope.searchInput;
            $scope.files = $filter('filter')(filesToSearch, search);
        }
    }

    $scope.fileSrc = function (file) {
        return mcfile.src(file.id);
    };

    var columnDefs = [
        {
            displayName: "",
            field: "name",
            width: 350,
            cellClicked: cellClicked,
            cellRenderer: function (params) {
                return '' +
                    '' +
                    params.node.name + '';
            }
        }];

    $scope.gridOptions = {
        columnDefs: columnDefs,
        rowData: $scope.files,
        rowSelection: 'multiple',
        rowsAlreadyGrouped: true,
        enableColResize: true,
        enableSorting: true,
        rowHeight: 30,
        angularCompileRows: true,
        icons: {
            groupExpanded: '',
            groupContracted: ''
        },
        groupInnerCellRenderer: groupInnerCellRenderer
    };

    //groupInnerCellRenderer does not have ability to add ng click. So as
    // an alternative i used event listener to display the data directory
    function groupInnerCellRenderer(params) {
        var eCell = document.createElement('span');
        eCell.innerHTML = params.node.displayname;
        eCell.addEventListener('click', function () {
            projectFiles.setActiveDirectory(params.node);
            if ($state.current.name === 'projects.project.files') {
                $state.go('projects.project.files.edit', {'file_id': ''}, {reload: true});
            } else {
                pubsub.send('display-directory');
            }

        });
        return eCell;
    }

    function cellClicked(params) {
        projectFiles.setActiveFile(params.node);
        $state.go('projects.project.files.edit', {'file_id': params.node.df_id}, {reload: true});
    }

    function init() {
        projectFiles.setActiveDirectory($scope.files[0]);
    }

    init();
}
<commit_msg>Add pubsub wait to refresh the view of the tree when there is a change.<commit_after>Application.Controllers.controller("FilesController",
    ["$scope", "projectFiles", "applySearch",
        "pubsub", "mcfile", "$state", "pubsub", FilesController]);
function FilesController($scope, projectFiles, applySearch,
                         $filter, mcfile, $state, pubsub) {
    var f = projectFiles.model.projects[$scope.project.id].dir;

    // Root is name of project. Have it opened by default.
    $scope.files = [f];
    applySearch($scope, "searchInput", applyQuery);

    pubsub.waitOn($scope, 'files.refresh', function() {
        $scope.gridOptions.api.refreshView();
    });

    function applyQuery() {
        var search = {
            name: ""
        };

        if ($scope.searchInput === "") {
            $scope.files = [projectFiles.model.projects[$scope.project.id].dir];
        } else {
            var filesToSearch = projectFiles.model.projects[$scope.project.id].byMediaType.all;
            search.name = $scope.searchInput;
            $scope.files = $filter('filter')(filesToSearch, search);
        }
    }

    $scope.fileSrc = function (file) {
        return mcfile.src(file.id);
    };

    var columnDefs = [
        {
            displayName: "",
            field: "name",
            width: 350,
            cellClicked: cellClicked,
            cellRenderer: function (params) {
                return '' +
                    '' +
                    params.node.name + '';
            }
        }];

    $scope.gridOptions = {
        columnDefs: columnDefs,
        rowData: $scope.files,
        rowSelection: 'multiple',
        rowsAlreadyGrouped: true,
        enableColResize: true,
        enableSorting: true,
        rowHeight: 30,
        angularCompileRows: true,
        icons: {
            groupExpanded: '',
            groupContracted: ''
        },
        groupInnerCellRenderer: groupInnerCellRenderer
    };

    //groupInnerCellRenderer does not have ability to add ng click. So as
    // an alternative i used event listener to display the data directory
    function groupInnerCellRenderer(params) {
        var eCell = document.createElement('span');
        eCell.innerHTML = params.node.displayname;
        eCell.addEventListener('click', function () {
            projectFiles.setActiveDirectory(params.node);
            if ($state.current.name === 'projects.project.files') {
                $state.go('projects.project.files.edit', {'file_id': ''}, {reload: true});
            } else {
                pubsub.send('display-directory');
            }

        });
        return eCell;
    }

    function cellClicked(params) {
        projectFiles.setActiveFile(params.node);
        $state.go('projects.project.files.edit', {'file_id': params.node.df_id}, {reload: true});
    }

    function init() {
        projectFiles.setActiveDirectory($scope.files[0]);
    }

    init();
}
<|endoftext|>