<commit_before>import Joi from 'joi'
import { ServiceTester } from '../tester.js'
import {
  isVPlusDottedVersionAtLeastOne,
  isVPlusDottedVersionNClausesWithOptionalSuffix,
} from '../test-validators.js'

// e.g. v19.3b0
const isBlackVersion = Joi.string().regex(/^v\d+(\.\d+)*(.*)?$/)
const isShortSha = Joi.string().regex(/[0-9a-f]{7}/)

export const t = new ServiceTester({
  id: 'GithubPipenv',
  title: 'GithubPipenv',
  pathPrefix: '/github/pipenv',
})

t.create('Locked Python version')
  .get('/locked/python-version/metabolize/rq-dashboard-on-heroku.json')
  .expectBadge({
    label: 'python',
    message: isVPlusDottedVersionAtLeastOne,
  })

t.create('Locked Python version (no pipfile.lock)')
  .get('/locked/python-version/metabolize/react-flexbox-svg.json')
  .expectBadge({
    label: 'python',
    message: 'repo not found, branch not found, or Pipfile.lock missing',
  })

t.create('Locked Python version (pipfile.lock has no python version)')
  .get('/locked/python-version/fikovnik/ShiftIt.json')
  .expectBadge({
    label: 'python',
    message: 'version not specified',
  })

t.create('Locked version of default dependency')
  .get(
    '/locked/dependency-version/metabolize/rq-dashboard-on-heroku/rq-dashboard.json'
  )
  .expectBadge({
    label: 'rq-dashboard',
    message: isVPlusDottedVersionNClausesWithOptionalSuffix,
  })

t.create('Locked version of default dependency (branch)')
  .get(
    '/locked/dependency-version/metabolize/rq-dashboard-on-heroku/rq-dashboard/master.json'
  )
  .expectBadge({
    label: 'rq-dashboard',
    message: isVPlusDottedVersionNClausesWithOptionalSuffix,
  })

t.create('Locked version of dev dependency')
  .get(
    '/locked/dependency-version/metabolize/rq-dashboard-on-heroku/dev/black.json'
  )
  .expectBadge({
    label: 'black',
    message: isBlackVersion,
  })

t.create('Locked version of dev dependency (branch)')
  .get(
    '/locked/dependency-version/metabolize/rq-dashboard-on-heroku/dev/black/master.json'
  )
  .expectBadge({
    label: 'black',
    message: isBlackVersion,
  })

t.create('Locked version of unknown dependency')
  .get(
    '/locked/dependency-version/metabolize/rq-dashboard-on-heroku/dev/i-made-this-up.json'
  )
  .expectBadge({
    label: 'dependency',
    message: 'dev dependency not found',
  })

t.create('Locked version of VCS dependency')
  .get(
    '/locked/dependency-version/DemocracyClub/aggregator-api/dc-base-theme.json'
  )
  .expectBadge({
    label: 'dc-base-theme',
    message: isShortSha,
  })
<commit_msg>fix: github pipenv service test (#7627)<commit_after>import Joi from 'joi'
import { ServiceTester } from '../tester.js'
import {
  isVPlusDottedVersionAtLeastOne,
  isVPlusDottedVersionNClausesWithOptionalSuffix,
} from '../test-validators.js'

// e.g. v19.3b0
const isBlackVersion = Joi.string().regex(/^v\d+(\.\d+)*(.*)?$/)
const isShortSha = Joi.string().regex(/[0-9a-f]{7}/)

export const t = new ServiceTester({
  id: 'GithubPipenv',
  title: 'GithubPipenv',
  pathPrefix: '/github/pipenv',
})

t.create('Locked Python version')
  .get('/locked/python-version/metabolize/rq-dashboard-on-heroku.json')
  .expectBadge({
    label: 'python',
    message: isVPlusDottedVersionAtLeastOne,
  })

t.create('Locked Python version (no pipfile.lock)')
  .get('/locked/python-version/metabolize/react-flexbox-svg.json')
  .expectBadge({
    label: 'python',
    message: 'repo not found, branch not found, or Pipfile.lock missing',
  })

t.create('Locked Python version (pipfile.lock has no python version)')
  .get('/locked/python-version/fikovnik/ShiftIt.json')
  .expectBadge({
    label: 'python',
    message: 'version not specified',
  })

t.create('Locked version of default dependency')
  .get(
    '/locked/dependency-version/metabolize/rq-dashboard-on-heroku/rq-dashboard.json'
  )
  .expectBadge({
    label: 'rq-dashboard',
    message: isVPlusDottedVersionNClausesWithOptionalSuffix,
  })

t.create('Locked version of default dependency (branch)')
  .get(
    '/locked/dependency-version/metabolize/rq-dashboard-on-heroku/rq-dashboard/master.json'
  )
  .expectBadge({
    label: 'rq-dashboard',
    message: isVPlusDottedVersionNClausesWithOptionalSuffix,
  })

t.create('Locked version of dev dependency')
  .get(
    '/locked/dependency-version/metabolize/rq-dashboard-on-heroku/dev/black.json'
  )
  .expectBadge({
    label: 'black',
    message: isBlackVersion,
  })

t.create('Locked version of dev dependency (branch)')
  .get(
    '/locked/dependency-version/metabolize/rq-dashboard-on-heroku/dev/black/master.json'
  )
  .expectBadge({
    label: 'black',
    message: isBlackVersion,
  })

t.create('Locked version of unknown dependency')
  .get(
    '/locked/dependency-version/metabolize/rq-dashboard-on-heroku/dev/i-made-this-up.json'
  )
  .expectBadge({
    label: 'dependency',
    message: 'dev dependency not found',
  })

t.create('Locked version of VCS dependency')
  .get('/locked/dependency-version/GSS-Cogs/databaker-docker/databaker.json')
  .expectBadge({
    label: 'databaker',
    message: isShortSha,
  })
<|endoftext|>


<commit_before>import React, { Component } from 'react';

class About extends Component {
  render() {

    if(this.props.data){
      var name = this.props.data.name;
      var profilepic= "images/"+this.props.data.image;
      var bio = this.props.data.bio;
      // var street = this.props.data.address.street;
      // var city = this.props.data.address.city;
      // var state = this.props.data.address.state;
      // var zip = this.props.data.address.zip;
      // var phone= this.props.data.phone;
      var email = this.props.data.email;
      var resumeDownload = this.props.data.resumedownload;
    }

    return (

About Me

{bio}

Contact Details

						   {name}

               {email}

                     Download Resume

    );
  }
}

export default About;
<commit_msg>update img alt tag<commit_after>import React, { Component } from 'react';

class About extends Component {
  render() {

    if(this.props.data){
      var name = this.props.data.name;
      var profilepic= "images/"+this.props.data.image;
      var bio = this.props.data.bio;
      // var street = this.props.data.address.street;
      // var city = this.props.data.address.city;
      // var state = this.props.data.address.state;
      // var zip = this.props.data.address.zip;
      // var phone= this.props.data.phone;
      var email = this.props.data.email;
      var resumeDownload = this.props.data.resumedownload;
    }

    return (

About Me

{bio}

Contact Details

						   {name}

               {email}

                     Download Resume

    );
  }
}

export default About;
<|endoftext|>


<commit_before>import Ember from 'ember';
import permissions from 'ember-osf/const/permissions';
import CpPanelBodyComponent from 'ember-collapsible-panel/components/cp-panel-body';
import PreprintFormFieldMixin from '../mixins/preprint-form-field';

export default CpPanelBodyComponent.extend(PreprintFormFieldMixin, {
    READ: permissions.READ,
    WRITE: permissions.WRITE,
    ADMIN: permissions.ADMIN,
    valid: Ember.computed.alias('newContributorId'),
    permissionToggle: false,
    bibliographicToggle: false,
    removalToggle: false,
    stillAdmin: Ember.computed('isAdmin', function() {
        return this.get('isAdmin');
    }),
    addState: 'emptyView', // There are 3 view states on left side of Authors panel. Default state just shows search bar.
    query: null,
    // Total contributor search results
    totalSearchResults: Ember.computed('searchResults.[]', function() {
        let searchResults = this.get('searchResults');
        if (searchResults && searchResults.links) {
            return searchResults.meta.pagination.total;
        } else {
            return;
        }
    }),
    // Total pages of contributor search results
    pages: Ember.computed('searchResults.[]', function() {
        let searchResults = this.get('searchResults');
        if (searchResults && searchResults.links) {
            return searchResults.meta.total;
        } else {
            return;
        }
    }),
    // Search results excluding users that are already contributors
    newSearchResults: Ember.computed('searchResults.[]', 'contributors.[]', 'addState', function() {
        let searchResults = this.get('searchResults');
        let contributors = this.get('contributors');
        let userIds = contributors.map((contrib) => contrib.get('userId'));
        return searchResults.filter((result) => !userIds.contains(result.id));
    }),
    actions: {
        // Adds contributor then redraws view - addition of contributor may change which update/remove contributor requests are permitted
        addContributor(user) {
            this.sendAction('addContributor', user.id, 'write', true);
                this.redrawTemplate();
        },
        // Adds unregistered contributor, then clears form and switches back to search view.
        // Should wait to transition until request has completed.
        addUnregisteredContributor(fullName, email) {
            let res = this.attrs.addUnregisteredContributor(fullName, email, 'write', true);
            res.then(() => {
                this.redrawTemplate();
                this.set('addState', 'searchView');
                this.set('fullName', '');
                this.set('email', '');
            }, function(reason) {
                console.log(reason.errors[0].detail);
            });

        },
        updateQuery(value) {
            this.set('query', value);
        },
        // Requests a particular page of user results
        findContributors(page) {
            var query = this.get('query');
            if (query) {
                this.attrs.findContributors(query, page).then(() => {
                    this.set('addState', 'searchView');
                }, function(reason) {
                    console.log(reason.errors[0].detail);
                });
            }
        },
        // Removes contributor then redraws contributor list view - removal of contributor may change
        // which additional update/remove requests are permitted.
        removeContributor(contrib) {
            this.attrs.removeContributor(contrib).then(() => {
                this.redrawTemplate();
                this.removedSelfAsAdmin(contrib, contrib.get('permission'));
                this.get('contributors').removeObject(contrib);
            });
        },
        // Updates contributor then redraws contributor list view - updating contributor
        // permissions may change which additional update/remove requests are permitted.
        updatePermissions(contributor, permission) {
            let permissionChanges = { [contributor.id]: permission.toLowerCase() };
            this.sendAction(
                'editContributors',
                this.get('contributors'),
                permissionChanges,
                {}
            );
            this.redrawTemplate();
            this.removedSelfAsAdmin(contributor, permission);

        },
        // Updates contributor then redraws contributor list view - updating contributor
        // bibliographic info may change which additional update/remove requests are permitted.
        updateBibliographic(contributor, isBibliographic) {
            let bibliographicChanges = { [contributor.id]: isBibliographic };
            this.sendAction(
                'editContributors',
                this.get('contributors'),
                {},
                bibliographicChanges
            );
            this.redrawTemplate();
        },
        // There are 3 view states on left side of Authors panel.  This switches to add unregistered contrib view.
        unregisteredView() {
            this.set('addState', 'unregisteredView');
        },
        // There are 3 view states on left side of Authors panel.  This switches to searching contributor results view.
        searchView() {
            this.set('addState', 'searchView');
            this.set('fullName', '');
            this.set('email', '');
        },
        // There are 3 view states on left side of Authors panel.  This switches to empty view and clears search results.
        emptyView() {
            this.set('addState', 'emptyView');
            this.set('searchQuery', '');
            Ember.$('.searchQuery')[0].value = '';
        },
        // TODO Add server request when API functionality in place.
        reorderItems(itemModels, draggedModel) {
            this.set('contributors', itemModels);
        }
    },
    // Temporary popover content for authors page. Will need to find alternative to jquery selectors.
    didInsertElement: function() {
        Ember.$('#permissions-popover').popover({
            content: '
' +
                '
Read
' +
                    '

View preprint

' +
                '
Read + Write
' +
                    '

Read privileges
 ' +
                        '
Add and configure preprint
 ' +
                        '
Add and edit content

' +
                '
Administrator

' +
                    '
Read and write privileges
' +
                    '
Manage authors
' +
                    '
Public-private settings

' +
                '
'
        });
        Ember.$('#bibliographic-popover').popover({
            content: 'Only checked authors will be included in preprint citations. ' +
            'Authors not in the citation can read and modify the preprint as normal.'
        });
        Ember.$('#author-popover').popover({
            content: 'Preprints must have at least one registered administrator and one author showing in the citation at all times.  ' +
            'A registered administrator is a user who has both confirmed their account and has administrator privileges.'
        });
    },
    /**
    * If user removes their own admin permissions, many things on the page must become
    * disabled.  Changing the stillAdmin flag to false will remove many of the options
    * on the page.
    */
    removedSelfAsAdmin(contributor, permission) {
        if (this.get('currentUser').id === contributor.get('userId') && permission !== 'ADMIN') {
            this.set('stillAdmin', false);
        }
    },
    redrawTemplate() {
        this.toggleProperty('removalToggle');
        this.toggleProperty('permissionToggle');
        this.toggleProperty('bibliographicToggle');
    }
});
<commit_msg>Attempt closure actions for addContributor.<commit_after>import Ember from 'ember';
import permissions from 'ember-osf/const/permissions';
import CpPanelBodyComponent from 'ember-collapsible-panel/components/cp-panel-body';
import PreprintFormFieldMixin from '../mixins/preprint-form-field';

export default CpPanelBodyComponent.extend(PreprintFormFieldMixin, {
    READ: permissions.READ,
    WRITE: permissions.WRITE,
    ADMIN: permissions.ADMIN,
    valid: Ember.computed.alias('newContributorId'),
    permissionToggle: false,
    bibliographicToggle: false,
    removalToggle: false,
    stillAdmin: Ember.computed('isAdmin', function() {
        return this.get('isAdmin');
    }),
    addState: 'emptyView', // There are 3 view states on left side of Authors panel. Default state just shows search bar.
    query: null,
    // Total contributor search results
    totalSearchResults: Ember.computed('searchResults.[]', function() {
        let searchResults = this.get('searchResults');
        if (searchResults && searchResults.links) {
            return searchResults.meta.pagination.total;
        } else {
            return;
        }
    }),
    // Total pages of contributor search results
    pages: Ember.computed('searchResults.[]', function() {
        let searchResults = this.get('searchResults');
        if (searchResults && searchResults.links) {
            return searchResults.meta.total;
        } else {
            return;
        }
    }),
    // Search results excluding users that are already contributors
    newSearchResults: Ember.computed('searchResults.[]', 'contributors.[]', 'addState', function() {
        let searchResults = this.get('searchResults');
        let contributors = this.get('contributors');
        let userIds = contributors.map((contrib) => contrib.get('userId'));
        return searchResults.filter((result) => !userIds.contains(result.id));
    }),
    actions: {
        // Adds contributor then redraws view - addition of contributor may change which update/remove contributor requests are permitted
        addContributor(user) {
            // this.sendAction('addContributor', user.id, 'write', true);
            this.attrs.addContributor(user.id, 'write', true).then(res => {
                this.redrawTemplate();
            }, function(reason) {
                console.log(reason);
            });
        },
        // Adds unregistered contributor, then clears form and switches back to search view.
        // Should wait to transition until request has completed.
        addUnregisteredContributor(fullName, email) {
            let res = this.attrs.addUnregisteredContributor(fullName, email, 'write', true);
            res.then(() => {
                this.redrawTemplate();
                this.set('addState', 'searchView');
                this.set('fullName', '');
                this.set('email', '');
            }, function(reason) {
                console.log(reason.errors[0].detail);
            });

        },
        updateQuery(value) {
            this.set('query', value);
        },
        // Requests a particular page of user results
        findContributors(page) {
            var query = this.get('query');
            if (query) {
                this.attrs.findContributors(query, page).then(() => {
                    this.set('addState', 'searchView');
                }, function(reason) {
                    console.log(reason.errors[0].detail);
                });
            }
        },
        // Removes contributor then redraws contributor list view - removal of contributor may change
        // which additional update/remove requests are permitted.
        removeContributor(contrib) {
            this.attrs.removeContributor(contrib).then(() => {
                this.redrawTemplate();
                this.removedSelfAsAdmin(contrib, contrib.get('permission'));
                this.get('contributors').removeObject(contrib);
            });
        },
        // Updates contributor then redraws contributor list view - updating contributor
        // permissions may change which additional update/remove requests are permitted.
        updatePermissions(contributor, permission) {
            let permissionChanges = { [contributor.id]: permission.toLowerCase() };
            this.sendAction(
                'editContributors',
                this.get('contributors'),
                permissionChanges,
                {}
            );
            this.redrawTemplate();
            this.removedSelfAsAdmin(contributor, permission);

        },
        // Updates contributor then redraws contributor list view - updating contributor
        // bibliographic info may change which additional update/remove requests are permitted.
        updateBibliographic(contributor, isBibliographic) {
            let bibliographicChanges = { [contributor.id]: isBibliographic };
            this.sendAction(
                'editContributors',
                this.get('contributors'),
                {},
                bibliographicChanges
            );
            this.redrawTemplate();
        },
        // There are 3 view states on left side of Authors panel.  This switches to add unregistered contrib view.
        unregisteredView() {
            this.set('addState', 'unregisteredView');
        },
        // There are 3 view states on left side of Authors panel.  This switches to searching contributor results view.
        searchView() {
            this.set('addState', 'searchView');
            this.set('fullName', '');
            this.set('email', '');
        },
        // There are 3 view states on left side of Authors panel.  This switches to empty view and clears search results.
        emptyView() {
            this.set('addState', 'emptyView');
            this.set('searchQuery', '');
            Ember.$('.searchQuery')[0].value = '';
        },
        // TODO Add server request when API functionality in place.
        reorderItems(itemModels, draggedModel) {
            this.set('contributors', itemModels);
        }
    },
    // Temporary popover content for authors page. Will need to find alternative to jquery selectors.
    didInsertElement: function() {
        Ember.$('#permissions-popover').popover({
            content: '
' +
                '
Read
' +
                    '

View preprint

' +
                '
Read + Write
' +
                    '

Read privileges
 ' +
                        '
Add and configure preprint
 ' +
                        '
Add and edit content

' +
                '
Administrator

' +
                    '
Read and write privileges
' +
                    '
Manage authors
' +
                    '
Public-private settings

' +
                '
'
        });
        Ember.$('#bibliographic-popover').popover({
            content: 'Only checked authors will be included in preprint citations. ' +
            'Authors not in the citation can read and modify the preprint as normal.'
        });
        Ember.$('#author-popover').popover({
            content: 'Preprints must have at least one registered administrator and one author showing in the citation at all times.  ' +
            'A registered administrator is a user who has both confirmed their account and has administrator privileges.'
        });
    },
    /**
    * If user removes their own admin permissions, many things on the page must become
    * disabled.  Changing the stillAdmin flag to false will remove many of the options
    * on the page.
    */
    removedSelfAsAdmin(contributor, permission) {
        if (this.get('currentUser').id === contributor.get('userId') && permission !== 'ADMIN') {
            this.set('stillAdmin', false);
        }
    },
    redrawTemplate() {
        this.toggleProperty('removalToggle');
        this.toggleProperty('permissionToggle');
        this.toggleProperty('bibliographicToggle');
    }
});
<|endoftext|>


<commit_before>import React, {Component} from 'react';
import { Link } from 'react-router';
import Footer from './Footer';
import { Navbar, Nav, NavItem } from 'react-bootstrap';
import SigninForm from './SigninForm';

class Header extends Component {
  render() {
    return (
        <Navbar inverse collapseOnSelect fixedTop >
        <Navbar.Header><Navbar.Brand>
               AutographaMT: Machine Translation Engine
          </Navbar.Brand><Navbar.Toggle />
        </Navbar.Header>
        <Navbar.Collapse >

            <NavItem eventKey={1} ><Link to={'/homepage'}>Sign in</Link></NavItem>
            <NavItem eventKey={2} ><Link to={'/signup'}>Sign up</Link></NavItem>

        </Navbar.Collapse>
      </Navbar>
    );
  }
}

class HomePage extends Component {
  render() {
      window.localStorage.clear();
    return (

    Welcome to Autographa MT: Machine Translation Engine

          <SigninForm />

    );
  }
}

export default HomePage;<commit_msg>Changes in path of images<commit_after>import React, {Component} from 'react';
import { Link } from 'react-router';
import Footer from './Footer';
import { Navbar, Nav, NavItem } from 'react-bootstrap';
import SigninForm from './SigninForm';

class Header extends Component {
  render() {
    return (
        <Navbar inverse collapseOnSelect fixedTop >
        <Navbar.Header><Navbar.Brand>
               AutographaMT: Machine Translation Engine
          </Navbar.Brand><Navbar.Toggle />
        </Navbar.Header>
        <Navbar.Collapse >

            <NavItem eventKey={1} ><Link to={'/homepage'}>  Signin</Link></NavItem>
            <NavItem eventKey={2} ><Link to={'/signup'}>Signup</Link></NavItem>

        </Navbar.Collapse>
      </Navbar>
    );
  }
}

class HomePage extends Component {
  render() {
      window.localStorage.clear();
    return (

    Welcome to Autographa MT: Machine Translation Engine

          <SigninForm />

    );
  }
}

export default HomePage;<|endoftext|>


<commit_before>function userInput(args) {
    var keys = [];
    var keysPressed = 0;
    var mouseCoordinates = { x: 0, y: 0 };

    var keyDown = function (e) {
        if (keys.indexOf(e.which) == -1)
            keys.push(e.which);

        notifyKeysChanged();
    };

    var keyUp = function (e) {
        keys.splice(keys.indexOf(e.which), 1);
        notifyKeysChanged();
    };

    function notifyKeysChanged() {
        var newKeys = buildDirectionKey();

        keysPressed = newKeys;
        args.inputChanged({ direction: keysPressed, mouse: mouseCoordinates });
    }

    function buildDirectionKey() {
        var keyPressed = keys.reduce(function (prev, current) {
            if (current === 87 || current === 119 || current === 38)
                return prev | keysInput.Up;

            if (current === 83 || current === 115 || current === 40)
                return prev | keysInput.Down;

            if (current === 65 || current === 97 || current === 37)
                return prev | keysInput.Left;

            if (current === 68 || current === 100 || current === 39)
                return prev | keysInput.Right;

            if (current === 1)
                return prev | keysInput.MouseLeft;
        }, 0);

        return keyPressed;
    }

    function mouseMove(e) {
        var targetRect = document.getElementById("arena").children[0].getBoundingClientRect();
        mouseCoordinates = { x: e.clientX - targetRect.left, y: e.clientY - targetRect.top };
        mouseCoordinates.x = mouseCoordinates.x - args.viewport().x;
        mouseCoordinates.y = -(mouseCoordinates.y - args.viewport().y);

        notifyKeysChanged();
    }

    function mouseDown(e) {
        if ((e.buttons && 1) && (keys.indexOf(1) === -1)) {
            keys.push(1);
        }
        notifyKeysChanged();
    }

    function mouseUp(e) {
        if (keys.indexOf(1) >= 0) {
            keys.splice(keys.indexOf(1), 1);
        }
        notifyKeysChanged();
    }

    (function () {
        document.addEventListener("keydown", keyDown);
        document.addEventListener("keyup", keyUp);
        document.addEventListener("mousemove", mouseMove);
        document.addEventListener("mousedown", mouseDown);
        document.addEventListener("mouseup", mouseUp);
    })();

    return {
        keys: keysPressed,
        mouse: function () { return mouseCoordinates; }
    };
};<commit_msg>include x viewport change in user input calcs<commit_after>function userInput(args) {
    var keys = [];
    var keysPressed = 0;
    var mouseCoordinates = { x: 0, y: 0 };

    var keyDown = function (e) {
        if (keys.indexOf(e.which) == -1)
            keys.push(e.which);

        notifyKeysChanged();
    };

    var keyUp = function (e) {
        keys.splice(keys.indexOf(e.which), 1);
        notifyKeysChanged();
    };

    function notifyKeysChanged() {
        var newKeys = buildDirectionKey();

        keysPressed = newKeys;
        args.inputChanged({ direction: keysPressed, mouse: mouseCoordinates });
    }

    function buildDirectionKey() {
        var keyPressed = keys.reduce(function (prev, current) {
            if (current === 87 || current === 119 || current === 38)
                return prev | keysInput.Up;

            if (current === 83 || current === 115 || current === 40)
                return prev | keysInput.Down;

            if (current === 65 || current === 97 || current === 37)
                return prev | keysInput.Left;

            if (current === 68 || current === 100 || current === 39)
                return prev | keysInput.Right;

            if (current === 1)
                return prev | keysInput.MouseLeft;
        }, 0);

        return keyPressed;
    }

    function mouseMove(e) {
        var targetRect = document.getElementById("arena").children[0].getBoundingClientRect();
        mouseCoordinates = { x: e.clientX - targetRect.left, y: e.clientY - targetRect.top };
        mouseCoordinates.x = mouseCoordinates.x + args.viewport().x;
        mouseCoordinates.y = -mouseCoordinates.y + args.viewport().y;

        notifyKeysChanged();
    }

    function mouseDown(e) {
        if ((e.buttons && 1) && (keys.indexOf(1) === -1)) {
            keys.push(1);
        }
        notifyKeysChanged();
    }

    function mouseUp(e) {
        if (keys.indexOf(1) >= 0) {
            keys.splice(keys.indexOf(1), 1);
        }
        notifyKeysChanged();
    }

    (function () {
        document.addEventListener("keydown", keyDown);
        document.addEventListener("keyup", keyUp);
        document.addEventListener("mousemove", mouseMove);
        document.addEventListener("mousedown", mouseDown);
        document.addEventListener("mouseup", mouseUp);
    })();

    return {
        keys: keysPressed,
        mouse: function () { return mouseCoordinates; }
    };
};<|endoftext|>


<commit_before>// Link.react-test.js
import React from 'react';
import renderer from 'react-test-renderer';
import { Classroom } from '../questions/classroom.jsx';

const questions = [
  {
    id: 1,
    user: 'Rolf',
    body: 'hvorfor gjør vi dette?',
  },
  {
    id: 2,
    user: 'Arne',
    body: 'kommer dette på eksamen?',
  },
  {
    id: 3,
    user: 'Kåre',
    body: 'hva er meningen med livet?',
  },
  {
    id: 4,
    user: 'Bjarne',
    body: 'finnes egentlig julenissen?',
  },
  {
    id: 5,
    user: 'Kåre',
    body: 'jeg skjønner ikke håndskriften din :(',
  },
];

function onSubmit(event) {
  event.preventdefault();
  console.log('onSubmit');
}

const classroom = {
  id: 0,
  title: 'test',
  lecturer: 'gruppe69',
};

test('Classroom looks like it should', () => {
  const component = renderer.create(
    <Classroom classroom={classroom} onSubmit={onSubmit} questions={questions} />);
  const tree = component.toJSON();
  expect(tree).toMatchSnapshot();
});
<commit_msg>change classroom-test to force a failure in travis<commit_after>// Link.react-test.js
import React from 'react';
import renderer from 'react-test-renderer';
import { Classroom } from '../questions/classroom.jsx';

const questions = [
  {
    id: 1,
    user: 'Rolf',
    body: 'hvorfor gjør vi dette?',
  },
  {
    id: 2,
    user: 'Arne',
    body: 'kommer dette på eksamen?',
  },
  {
    id: 3,
    user: 'Kåre',
    body: 'hva er meningen med livet?',
  },
  {
    id: 4,
    user: 'Bjarne',
    body: 'finnes egentlig julenissen?',
  },
  {
    id: 5,
    user: 'Rolf',
    body: 'jeg skjønner ikke håndskriften din :(',
  },
];

function onSubmit(event) {
  event.preventdefault();
  console.log('onSubmit');
}

const classroom = {
  id: 0,
  title: 'test',
  lecturer: 'gruppe69',
};

test('Classroom looks like it should', () => {
  const component = renderer.create(
    <Classroom classroom={classroom} onSubmit={onSubmit} questions={questions} />);
  const tree = component.toJSON();
  expect(tree).toMatchSnapshot();
});
<|endoftext|>


<commit_before>function updateCounter() {
    chrome.windows.getAll({populate: true}, function(wins) {
        // Count tabs and windows.
        var windows = [];
        var tabs = [];
        wins.forEach(function(win) {
            windows.push(win);
            win.tabs.forEach(function(tab){
                tabs.push(tab.url);
            });
        });

        if ( chrome.browserAction ) {
            // Set tooltip.
            var title = [
                'Tab Counter',
                'tabs: ' + tabs.length,
                'windows: ' + windows.length,
            ].join('\n');
            chrome.browserAction.setTitle({
                'title': title,
            });

            // Set extension icon text.
            var text = tabs.length + '';
            chrome.browserAction.setBadgeText({
                text: text,
            });
        } else {
            console.warn('chrome.browserAction is:', chrome.browserAction);
        }
    });
}

// Fired when a tab is created.
chrome.tabs.onCreated.addListener(function(
    /* Tab */ tab ) {
    updateCounter();
});

// Fired when a tab is closed.
chrome.tabs.onRemoved.addListener(function(
    /* integer */ tabId,
    /* object */ removeInfo ) {
    updateCounter();
});

// Open extensions page when extension button pressed.
chrome.browserAction.onClicked.addListener(function(tab) {
    chrome.tabs.query({ 'url': 'chrome://extensions/' }, function(tabs) {
        for ( var i = 0; i < tabs.length; i++ ) {
            chrome.tabs.update(tabs[i].id, {
                'active': true,
            });
            chrome.windows.update(tabs[i].windowId, {
                'focused': true,
            });
            return;
        }
        chrome.tabs.create({
            'url': 'chrome://extensions/',
            'windowId': tab.windowId,
        });
    });
});

updateCounter();
<commit_msg>Add TODO<commit_after>function updateCounter() {
    chrome.windows.getAll({populate: true}, function(wins) {
        // Count tabs and windows.
        var windows = [];
        var tabs = [];
        wins.forEach(function(win) {
            windows.push(win);
            win.tabs.forEach(function(tab){
                tabs.push(tab.url);
            });
        });

        if ( chrome.browserAction ) {
            // Set tooltip.
            var title = [
                'Tab Counter',
                'tabs: ' + tabs.length,
                'windows: ' + windows.length,
            ].join('\n');
            chrome.browserAction.setTitle({
                'title': title,
            });

            // Set extension icon text.
            var text = tabs.length + '';
            chrome.browserAction.setBadgeText({
                text: text,
            });
        } else {
            console.warn('chrome.browserAction is:', chrome.browserAction);
        }
    });
}

// TODO: Update counter when a window (last tab) is closed for number of windows to be accurate.

// Fired when a tab is created.
chrome.tabs.onCreated.addListener(function(
    /* Tab */ tab ) {
    updateCounter();
});

// Fired when a tab is closed.
chrome.tabs.onRemoved.addListener(function(
    /* integer */ tabId,
    /* object */ removeInfo ) {
    updateCounter();
});

// Open extensions page when extension button pressed.
chrome.browserAction.onClicked.addListener(function(tab) {
    chrome.tabs.query({ 'url': 'chrome://extensions/' }, function(tabs) {
        for ( var i = 0; i < tabs.length; i++ ) {
            chrome.tabs.update(tabs[i].id, {
                'active': true,
            });
            chrome.windows.update(tabs[i].windowId, {
                'focused': true,
            });
            return;
        }
        chrome.tabs.create({
            'url': 'chrome://extensions/',
            'windowId': tab.windowId,
        });
    });
});

updateCounter();
<|endoftext|>


<commit_before>import * as doctor from '../doctor';

function sicksyncDoctor(program, config) {
    program
        .command('doctor')
        .description('Runs through a gammut of checks to make sure sicksync is working properly')
        .action(() => {
          doctor.checkAll(config);
        });
};

export default sicksyncDoctor;
<commit_msg>Minor tweak to command for cleanup<commit_after>import { ary, partial } from 'lodash';

import { checkAll } from '../doctor';

function sicksyncDoctor(program, config) {
    program
        .command('doctor')
        .description('Runs through a gammut of checks to make sure sicksync is working properly')
        .action(partial(ary(checkAll, 1), config));
};

export default sicksyncDoctor;
<|endoftext|>


<commit_before>/* ========================================================================
 * Phonon: i18n.js v0.2.1
 * http://phonon.quarkdev.com
 * ========================================================================
 * Licensed under MIT (http://phonon.quarkdev.com)
 * ======================================================================== */

;(function (window, document) {

    var jsonCache = null;

    var opts = {
        localeFallback: null,
        localePreferred: window.navigator.userLanguage || window.navigator.language,
        directory: './',
        initCalled: false
    };

    /**
     * Checks if the given argument is a DOM element
     * @param {DOMObject} o the argument to test
     * @return true if the object is a DOM element, false otherwise
     * @private
     */
    var isElement = function (o) {
        return (typeof Node === 'object' ? o instanceof Node : o && typeof o === 'object' && typeof o.nodeType === 'number' && typeof o.nodeName === 'string');
    };

    /**
     * Binds some text to the given DOM element
     * @param {DOMObject} el
     * @param {String} text
     * @private
     */
    var setText = function (el, text) {
        if(!('textContent' in el)) {
            el.innerText = text;
        } else {
            el.textContent = text;
        }
    };

    /**
    * Binds some html to the given DOM element
    * @param {DOMObject} el
    * @param {String} text
    * @private
    */
    var setHtml = function (el, text){
        el.innerHTML = text;
    }

    /**
     * Binds the value to the given DOM element
     * @param {DOMObject} el
     * @param {String} text
     * @private
     */
    var setValue = function (el, text) {
        el.value = text;
    };

    /**
     * Binds the placeholder to the given DOM element
     * @param {DOMObject} el
     * @param {String} text
     * @private
     */
    var setPlaceholder = function (el, text) {
        el.setAttribute('placeholder', text);
    };

    /**
     * Reads data-i18n attributes and set JSON values
     * @param {Array} elements
     * @param {JSON} json
     * @private
     */
    var computeNodes = function (elements, json) {

        var i = elements.length - 1;

        for (; i >= 0; i--) {
            var el = elements[i];
            var data = el.getAttribute('data-i18n').trim();
            var r = /(?:\s|^)(\w+):\s*(.*?)(?=\s+\w+:|$)/g, m;

            while (m = r.exec(data)) {
                var key = m[1].trim();
                var value = m[2].trim().replace(',', '');
                if (json[value] !== undefined) {
                    if (key === 'text') {
                        setText(el, json[value]);
                    } else if (key === 'html') {
                        setHtml(el, json[value]);
                    } else if (key === 'value') {
                        setValue(el, json[value]);
                    } else if (key === 'placeholder') {
                        setPlaceholder(el, json[value]);
                    } else {
                        throw new Error('The property: ' + key + ' is unknown');
                    }
                } else {
                    console.error('The value: ' + value + ' does not exist in the JSON file');
                }
            }
        }
    };

    /**
     * Public API
     */

    var api = {};

    /**
     * @param {Object} options
     * @public
     */
    function init(options) {
        if (opts.initCalled) {
            throw new Error('The i18n module has already been instantiated');
        }

        if(typeof options.directory === 'string') {
            options.directory = ( (options.directory.indexOf('/', options.directory.length - '/'.length) !== -1) ? options.directory : options.directory + '/');
        }

        var prop;
        for (prop in options) {
            opts[prop] = options[prop];
        }

        opts.initCalled = true;
    }
    api.init = init;

    /**
     * Reads JSON data
     * @param {Function} callback
     */
    function getAll(callback) {
        if (!opts.initCalled) {
            throw new Error('Please, initialize The i18n module using the init method');
        }
        if (typeof callback !== 'function') {
            throw new Error('callback must be a function');
        }

        if(jsonCache !== null) {
            callback(jsonCache);
            return;
        }

        var xhr = new XMLHttpRequest();

        var locale = opts.localePreferred ? opts.localePreferred : opts.localeFallback;

        xhr.open('GET', opts.directory + locale + '.json', true);
        if(xhr.overrideMimeType) xhr.overrideMimeType('application/json; charset=utf-8');

        xhr.onreadystatechange = function () {
            if(xhr.readyState === 4 && (xhr.status === 200 || !xhr.status && xhr.responseText.length)) {
                if (xhr.status === 200) {

                    jsonCache = JSON.parse(xhr.responseText);
                    callback(JSON.parse(xhr.responseText));

                } else {

                    if(opts.localePreferred) {

                        // The preferred locale is not available
                        opts.localePreferred = null;

                        console.log('The language [' + locale + '] is not available, loading ' + opts.localeFallback);

                        getAll(function (json) {
                            jsonCache = json;
                            callback(json);
                        });
                    } else {
                        throw new Error('The default locale ['+opts.directory+opts.localeFallback+'.json] file is not found');
                    }
                }
            }
        };
        xhr.send('');
    }
    api.getAll = getAll;

    /**
     * Gets a value in the JSON file with a key or many keys (array)
     * @param {String | Array} key
     * @param {Function} callback
     */
    function get(key, callback) {
        if (typeof key !== 'string' && !(key instanceof Array)) {
            throw new Error('key must be a string or an array');
        }

        var isArray = (key instanceof Array ? true : false);

        if(jsonCache !== null) {
            if(!isArray) {
                callback(jsonCache[key]);
            } else {

                var l = key.length, i = l - 1, obj = {};

                for (; i >= 0; i--) {
                    obj[key[i]] = jsonCache[key[i]];
                }
                callback(obj);
            }
            return;
        }

        getAll(function(json) {
            if(!isArray) {
                callback(json[key]);
            } else {

                var l = key.length, i = l - 1, obj = {};

                for (; i >= 0; i--) {
                    obj[key[i]] = json[key[i]];
                }
                callback(obj);
            }
        });
    }
    api.get = get;

    /**
     * Binds the HTML Object with JSON data
     * @param {DOMObject} el (optional) if el is not set, the document will be binded
     * @param {Function} callback (optional)
     */
    function bind(el, callback) {
        var element = el || document;
        var callbackFunction = callback;

        if (arguments.length === 1) {
            if (typeof el === 'function') {
                element = document;
                callbackFunction = el;
            }
        }

        if (!isElement(element)) {
            throw new TypeError('Not valid element object ' + element);
        }

        var elements = element.querySelectorAll('[data-i18n]');

        if(jsonCache === null) {

            getAll(function (json) {

                computeNodes(elements, json);
                if (typeof callbackFunction === 'function') callbackFunction();
            });
        } else {
            computeNodes(elements, jsonCache);
            if (typeof callbackFunction === 'function') callbackFunction();
        }
    }
    api.bind = bind;

    /**
     * Sets the preferred language
     * @param {String} l the new language
     */
    function setPreference(preference) {
        if (typeof preference !== 'string') {
            throw new Error('The language must be a string');
        }
        opts.localePreferred = preference;
        // reset the cache
        jsonCache = null;

        return api;
    }
    api.setPreference = setPreference;

    /**
     * Returns the preferred language
     * @return {String}
     */
    function getPreference() {
        return opts.localePreferred;
    }
    api.getPreference = getPreference;

    /**
     * Returns the browser language
     * @return {String}
     */
    function getLocale() {
        return window.navigator.userLanguage || window.navigator.language;
    }
    api.getLocale = getLocale;

    phonon.i18n = function (opts) {

        if(typeof opts === 'object') {
            init(opts);
        }

        return {
            getAll: function (callback) {
                getAll(callback);
                return this;
            },
            get: function (key, callback) {
                get(key, callback);
                return this;
            },
            bind: function (el, callback) {
                bind(el, callback);
                return this;
            },
            setPreference: function (preference) {
                setPreference(preference);
                return this;
            },
            getPreference: function () {
                return getPreference();
            },
            getLocale: function () {
                return getLocale();
            }
        };
    };

}(window, document));
<commit_msg>Load improved<commit_after>/* ========================================================================
 * Phonon: i18n.js v0.2.1
 * http://phonon.quarkdev.com
 * ========================================================================
 * Licensed under MIT (http://phonon.quarkdev.com)
 * ======================================================================== */
;(function (window, document) {

    var jsonCache = null;

    var opts = {
        localeFallback: null,
        localePreferred: window.navigator.userLanguage || window.navigator.language,
        directory: './',
        initCalled: false
    };

    /**
     * Checks if the given argument is a DOM element
     * @param {DOMObject} o the argument to test
     * @return true if the object is a DOM element, false otherwise
     * @private
     */
    var isElement = function (o) {
        return (typeof Node === 'object' ? o instanceof Node : o && typeof o === 'object' && typeof o.nodeType === 'number' && typeof o.nodeName === 'string');
    };

    /**
     * Binds some text to the given DOM element
     * @param {DOMObject} el
     * @param {String} text
     * @private
     */
    var setText = function (el, text) {
        if(!('textContent' in el)) {
            el.innerText = text;
        } else {
            el.textContent = text;
        }
    };

    /**
    * Binds some html to the given DOM element
    * @param {DOMObject} el
    * @param {String} text
    * @private
    */
    var setHtml = function (el, text){
        el.innerHTML = text;
    }

    /**
     * Binds the value to the given DOM element
     * @param {DOMObject} el
     * @param {String} text
     * @private
     */
    var setValue = function (el, text) {
        el.value = text;
    };

    /**
     * Binds the placeholder to the given DOM element
     * @param {DOMObject} el
     * @param {String} text
     * @private
     */
    var setPlaceholder = function (el, text) {
        el.setAttribute('placeholder', text);
    };

    /**
     * Reads data-i18n attributes and set JSON values
     * @param {Array} elements
     * @param {JSON} json
     * @private
     */
    var computeNodes = function (elements, json) {

        var i = elements.length - 1;

        for (; i >= 0; i--) {
            var el = elements[i];
            var data = el.getAttribute('data-i18n').trim();
            var r = /(?:\s|^)(\w+):\s*(.*?)(?=\s+\w+:|$)/g, m;

            while (m = r.exec(data)) {
                var key = m[1].trim();
                var value = m[2].trim().replace(',', '');
                if (json[value] !== undefined) {
                    if (key === 'text') {
                        setText(el, json[value]);
                    } else if (key === 'html') {
                        setHtml(el, json[value]);
                    } else if (key === 'value') {
                        setValue(el, json[value]);
                    } else if (key === 'placeholder') {
                        setPlaceholder(el, json[value]);
                    } else {
                        throw new Error('The property: ' + key + ' is unknown');
                    }
                } else {
                    console.error('The value: ' + value + ' does not exist in the JSON file');
                }
            }
        }
    };

    /**
     * Public API
     */

    var api = {};

    /**
     * @param {Object} options
     * @public
     */
    function init(options) {
        if (opts.initCalled) {
            throw new Error('The i18n module has already been instantiated');
        }

        if(typeof options.directory === 'string') {
            options.directory = ( (options.directory.indexOf('/', options.directory.length - '/'.length) !== -1) ? options.directory : options.directory + '/');
        }

        var prop;
        for (prop in options) {
            opts[prop] = options[prop];
        }

        opts.initCalled = true;
    }
    api.init = init;

    /**
     * Reads JSON data
     * @param {Function} callback
     */
    function getAll(callback) {
        if (!opts.initCalled) {
            throw new Error('Please, initialize The i18n module using the init method');
        }
        if (typeof callback !== 'function') {
            throw new Error('callback must be a function');
        }

        if(jsonCache !== null) {
            callback(jsonCache);
            return;
        }

        var xhr = new XMLHttpRequest();

        var locale = opts.localePreferred ? opts.localePreferred : opts.localeFallback;

        xhr.open('GET', opts.directory + locale + '.json', true);
        if(xhr.overrideMimeType) xhr.overrideMimeType('application/json; charset=utf-8');

        xhr.onreadystatechange = function () {
            if(xhr.readyState === 4 && (xhr.status === 200 || !xhr.status && xhr.responseText.length)) {
                jsonCache = JSON.parse(xhr.responseText);
                callback(JSON.parse(xhr.responseText));
            } else if(xhr.readyState === 4 && !(xhr.status === 200 || !xhr.status && xhr.responseText.length)) {
                if(opts.localePreferred) {

                    // The preferred locale is not available
                    opts.localePreferred = null;

                    console.log('The language [' + locale + '] is not available, loading ' + opts.localeFallback);

                    getAll(function (json) {
                        jsonCache = json;
                        callback(json);
                    });
                } else {
                    throw new Error('The default locale ['+opts.directory+opts.localeFallback+'.json] file is not found');
                }
            }
        };
        xhr.send('');
    }
    api.getAll = getAll;

    /**
     * Gets a value in the JSON file with a key or many keys (array)
     * @param {String | Array} key
     * @param {Function} callback
     */
    function get(key, callback) {
        if (typeof key !== 'string' && !(key instanceof Array)) {
            throw new Error('key must be a string or an array');
        }

        var isArray = (key instanceof Array ? true : false);

        if(jsonCache !== null) {
            if(!isArray) {
                callback(jsonCache[key]);
            } else {

                var l = key.length, i = l - 1, obj = {};

                for (; i >= 0; i--) {
                    obj[key[i]] = jsonCache[key[i]];
                }
                callback(obj);
            }
            return;
        }

        getAll(function(json) {
            if(!isArray) {
                callback(json[key]);
            } else {

                var l = key.length, i = l - 1, obj = {};

                for (; i >= 0; i--) {
                    obj[key[i]] = json[key[i]];
                }
                callback(obj);
            }
        });
    }
    api.get = get;

    /**
     * Binds the HTML Object with JSON data
     * @param {DOMObject} el (optional) if el is not set, the document will be binded
     * @param {Function} callback (optional)
     */
    function bind(el, callback) {
        var element = el || document;
        var callbackFunction = callback;

        if (arguments.length === 1) {
            if (typeof el === 'function') {
                element = document;
                callbackFunction = el;
            }
        }

        if (!isElement(element)) {
            throw new TypeError('Not valid element object ' + element);
        }

        var elements = element.querySelectorAll('[data-i18n]');

        if(jsonCache === null) {

            getAll(function (json) {

                computeNodes(elements, json);
                if (typeof callbackFunction === 'function') callbackFunction();
            });
        } else {
            computeNodes(elements, jsonCache);
            if (typeof callbackFunction === 'function') callbackFunction();
        }
    }
    api.bind = bind;

    /**
     * Sets the preferred language
     * @param {String} l the new language
     */
    function setPreference(preference) {
        if (typeof preference !== 'string') {
            throw new Error('The language must be a string');
        }
        opts.localePreferred = preference;
        // reset the cache
        jsonCache = null;

        return api;
    }
    api.setPreference = setPreference;

    /**
     * Returns the preferred language
     * @return {String}
     */
    function getPreference() {
        return opts.localePreferred;
    }
    api.getPreference = getPreference;

    /**
     * Returns the browser language
     * @return {String}
     */
    function getLocale() {
        return window.navigator.userLanguage || window.navigator.language;
    }
    api.getLocale = getLocale;

    phonon.i18n = function (opts) {

        if(typeof opts === 'object') {
            init(opts);
        }

        return {
            getAll: function (callback) {
                getAll(callback);
                return this;
            },
            get: function (key, callback) {
                get(key, callback);
                return this;
            },
            bind: function (el, callback) {
                bind(el, callback);
                return this;
            },
            setPreference: function (preference) {
                setPreference(preference);
                return this;
            },
            getPreference: function () {
                return getPreference();
            },
            getLocale: function () {
                return getLocale();
            }
        };
    };

}(window, document));
<|endoftext|>


<commit_before>/**
 * ws-chat-client.js
 *
 * depends on jQuery and jQuery UI.
 */

// Page UI object.
var Page = {
  registerHandlers : function () {
    var self = this;
    $('#join_form').submit(function (event) { return self.onJoin(event); });
    $('#leave').click(function (event) { return self.onLeave(event); });
    $('#post_form').submit(function (event) { return self.onPost(event); });
  },

  onJoin : function (event) {
    return false;
  },

  onLeave : function (event) {
    return false;
  },

  onPost : function (event) {
    // DUMMY
    var post = {
      time: '2011-12-28 12:34:56',
      name: 'foobar',
      post: 'This is a dummy post.',
    };

    this.addUserPost(post);
    return false;
  },

  addUserPost : function (post) {
    var $log = $('<div />').addClass('log msg_user').hide();
    $log.append($('<span />').addClass('msg_time').text(post.time));
    $log.append($('<span />').addClass('msg_name').text(post.name));
    $log.append($('<span />').addClass('msg_post').text(post.post));

    $('#log').prepend($log);
    $log.show('drop', {direction: 'up'}, 'fast');
  }
};

$(function () {
  Page.registerHandlers();
});
<commit_msg>Implemented methods for #info manipulation.<commit_after>/**
 * ws-chat-client.js
 *
 * depends on jQuery and jQuery UI.
 */

// Page UI object.
var Page = {
  info : function (message) {
    $('#info p').text(message);
    $('#info').css('background-color', '')
              .show('highlight', 'slow');
  },

  notice : function (message) {
    $('#info p').text(message);
    $('#info').css('background-color', 'lightsalmon')
              .show('highlight', {color: 'red'}, 'slow');
  },

  registerHandlers : function () {
    var self = this;
    $('#join_form').submit(function (event) { return self.onJoin(event); });
    $('#leave').click(function (event) { return self.onLeave(event); });
    $('#post_form').submit(function (event) { return self.onPost(event); });
  },

  onJoin : function (event) {
    return false;
  },

  onLeave : function (event) {
    return false;
  },

  onPost : function (event) {
    // DUMMY
    var post = {
      time: '2011-12-28 12:34:56',
      name: 'foobar',
      post: 'This is a dummy post.',
    };

    this.addUserPost(post);
    return false;
  },

  addUserPost : function (post) {
    var $log = $('<div />').addClass('log msg_user').hide();
    $log.append($('<span />').addClass('msg_time').text(post.time));
    $log.append($('<span />').addClass('msg_name').text(post.name));
    $log.append($('<span />').addClass('msg_post').text(post.post));

    $('#log').prepend($log);
    $log.show('drop', {direction: 'up'}, 'fast');
  }
};

$(function () {
  Page.registerHandlers();
});
<|endoftext|>


<commit_before>import {types as tt} from "./tokentype"
import {Parser} from "./state"
import {lineBreak, skipWhiteSpace} from "./whitespace"

const pp = Parser.prototype

// ## Parser utilities

const literal = /^(?:'((?:\\.|[^'])*?)'|"((?:\\.|[^"])*?)")/
pp.strictDirective = function(start) {
  for (;;) {
    // Try to find string literal.
    skipWhiteSpace.lastIndex = start
    start += skipWhiteSpace.exec(this.input)[0].length
    let match = literal.exec(this.input.slice(start))
    if (!match) return false
    if ((match[1] || match[2]) === "use strict") {
      skipWhiteSpace.lastIndex = start + match[0].length
      let spaceAfter = skipWhiteSpace.exec(this.input), end = spaceAfter.index + spaceAfter[0].length
      let next = this.input.charAt(end)
      return next == ";" || next == "}" ||
        (lineBreak.test(spaceAfter[0]) &&
         !(/[(`\.\[+\-\/*%<>=,?^&]/.test(next) || next == "!" && this.input.charAt(end + 1) == "="))
    }
    start += match[0].length

    // Skip semicolon, if any.
    skipWhiteSpace.lastIndex = start
    start += skipWhiteSpace.exec(this.input)[0].length
    if (this.input[start] === ";")
      start++
  }
}

// Predicate that tests whether the next token is of the given
// type, and if yes, consumes it as a side effect.

pp.eat = function(type) {
  if (this.type === type) {
    this.next()
    return true
  } else {
    return false
  }
}

// Tests whether parsed token is a contextual keyword.

pp.isContextual = function(name) {
  return this.type === tt.name && this.value === name && !this.containsEsc
}

// Consumes contextual keyword if possible.

pp.eatContextual = function(name) {
  if (!this.isContextual(name)) return false
  this.next()
  return true
}

// Asserts that following token is given contextual keyword.

pp.expectContextual = function(name) {
  if (!this.eatContextual(name)) this.unexpected()
}

// Test whether a semicolon can be inserted at the current position.

pp.canInsertSemicolon = function() {
  return this.type === tt.eof ||
    this.type === tt.braceR ||
    lineBreak.test(this.input.slice(this.lastTokEnd, this.start))
}

pp.insertSemicolon = function() {
  if (this.canInsertSemicolon()) {
    if (this.options.onInsertedSemicolon)
      this.options.onInsertedSemicolon(this.lastTokEnd, this.lastTokEndLoc)
    return true
  }
}

// Consume a semicolon, or, failing that, see if we are allowed to
// pretend that there is a semicolon at this position.

pp.semicolon = function() {
  if (!this.eat(tt.semi) && !this.insertSemicolon()) this.unexpected()
}

pp.afterTrailingComma = function(tokType, notNext) {
  if (this.type === tokType) {
    if (this.options.onTrailingComma)
      this.options.onTrailingComma(this.lastTokStart, this.lastTokStartLoc)
    if (!notNext)
      this.next()
    return true
  }
}

// Expect a token of a given type. If found, consume it, otherwise,
// raise an unexpected token error.

pp.expect = function(type) {
  this.eat(type) || this.unexpected()
}

// Raise an unexpected token error.

pp.unexpected = function(pos) {
  this.raise(pos != null ? pos : this.start, "Unexpected token")
}

export function DestructuringErrors() {
  this.shorthandAssign =
  this.trailingComma =
  this.parenthesizedAssign =
  this.parenthesizedBind =
  this.doubleProto =
    -1
}

pp.checkPatternErrors = function(refDestructuringErrors, isAssign) {
  if (!refDestructuringErrors) return
  if (refDestructuringErrors.trailingComma > -1)
    this.raiseRecoverable(refDestructuringErrors.trailingComma, "Comma is not permitted after the rest element")
  let parens = isAssign ? refDestructuringErrors.parenthesizedAssign : refDestructuringErrors.parenthesizedBind
  if (parens > -1) this.raiseRecoverable(parens, "Parenthesized pattern")
}

pp.checkExpressionErrors = function(refDestructuringErrors, andThrow) {
  if (!refDestructuringErrors) return false
  let {shorthandAssign, doubleProto} = refDestructuringErrors
  if (!andThrow) return shorthandAssign >= 0 || doubleProto >= 0
  if (shorthandAssign >= 0)
    this.raise(shorthandAssign, "Shorthand property assignments are valid only in destructuring patterns")
  if (doubleProto >= 0)
    this.raiseRecoverable(doubleProto, "Redefinition of __proto__ property")
}

pp.checkYieldAwaitInDefaultParams = function() {
  if (this.yieldPos && (!this.awaitPos || this.yieldPos < this.awaitPos))
    this.raise(this.yieldPos, "Yield expression cannot be a default value")
  if (this.awaitPos)
    this.raise(this.awaitPos, "Await expression cannot be a default value")
}

pp.isSimpleAssignTarget = function(expr) {
  if (expr.type === "ParenthesizedExpression")
    return this.isSimpleAssignTarget(expr.expression)
  return expr.type === "Identifier" || expr.type === "MemberExpression"
}
<commit_msg>Fix lint complaints<commit_after>import {types as tt} from "./tokentype"
import {Parser} from "./state"
import {lineBreak, skipWhiteSpace} from "./whitespace"

const pp = Parser.prototype

// ## Parser utilities

const literal = /^(?:'((?:\\.|[^'])*?)'|"((?:\\.|[^"])*?)")/
pp.strictDirective = function(start) {
  for (;;) {
    // Try to find string literal.
    skipWhiteSpace.lastIndex = start
    start += skipWhiteSpace.exec(this.input)[0].length
    let match = literal.exec(this.input.slice(start))
    if (!match) return false
    if ((match[1] || match[2]) === "use strict") {
      skipWhiteSpace.lastIndex = start + match[0].length
      let spaceAfter = skipWhiteSpace.exec(this.input), end = spaceAfter.index + spaceAfter[0].length
      let next = this.input.charAt(end)
      return next === ";" || next === "}" ||
        (lineBreak.test(spaceAfter[0]) &&
         !(/[(`.[+\-/*%<>=,?^&]/.test(next) || next === "!" && this.input.charAt(end + 1) === "="))
    }
    start += match[0].length

    // Skip semicolon, if any.
    skipWhiteSpace.lastIndex = start
    start += skipWhiteSpace.exec(this.input)[0].length
    if (this.input[start] === ";")
      start++
  }
}

// Predicate that tests whether the next token is of the given
// type, and if yes, consumes it as a side effect.

pp.eat = function(type) {
  if (this.type === type) {
    this.next()
    return true
  } else {
    return false
  }
}

// Tests whether parsed token is a contextual keyword.

pp.isContextual = function(name) {
  return this.type === tt.name && this.value === name && !this.containsEsc
}

// Consumes contextual keyword if possible.

pp.eatContextual = function(name) {
  if (!this.isContextual(name)) return false
  this.next()
  return true
}

// Asserts that following token is given contextual keyword.

pp.expectContextual = function(name) {
  if (!this.eatContextual(name)) this.unexpected()
}

// Test whether a semicolon can be inserted at the current position.

pp.canInsertSemicolon = function() {
  return this.type === tt.eof ||
    this.type === tt.braceR ||
    lineBreak.test(this.input.slice(this.lastTokEnd, this.start))
}

pp.insertSemicolon = function() {
  if (this.canInsertSemicolon()) {
    if (this.options.onInsertedSemicolon)
      this.options.onInsertedSemicolon(this.lastTokEnd, this.lastTokEndLoc)
    return true
  }
}

// Consume a semicolon, or, failing that, see if we are allowed to
// pretend that there is a semicolon at this position.

pp.semicolon = function() {
  if (!this.eat(tt.semi) && !this.insertSemicolon()) this.unexpected()
}

pp.afterTrailingComma = function(tokType, notNext) {
  if (this.type === tokType) {
    if (this.options.onTrailingComma)
      this.options.onTrailingComma(this.lastTokStart, this.lastTokStartLoc)
    if (!notNext)
      this.next()
    return true
  }
}

// Expect a token of a given type. If found, consume it, otherwise,
// raise an unexpected token error.

pp.expect = function(type) {
  this.eat(type) || this.unexpected()
}

// Raise an unexpected token error.

pp.unexpected = function(pos) {
  this.raise(pos != null ? pos : this.start, "Unexpected token")
}

export function DestructuringErrors() {
  this.shorthandAssign =
  this.trailingComma =
  this.parenthesizedAssign =
  this.parenthesizedBind =
  this.doubleProto =
    -1
}

pp.checkPatternErrors = function(refDestructuringErrors, isAssign) {
  if (!refDestructuringErrors) return
  if (refDestructuringErrors.trailingComma > -1)
    this.raiseRecoverable(refDestructuringErrors.trailingComma, "Comma is not permitted after the rest element")
  let parens = isAssign ? refDestructuringErrors.parenthesizedAssign : refDestructuringErrors.parenthesizedBind
  if (parens > -1) this.raiseRecoverable(parens, "Parenthesized pattern")
}

pp.checkExpressionErrors = function(refDestructuringErrors, andThrow) {
  if (!refDestructuringErrors) return false
  let {shorthandAssign, doubleProto} = refDestructuringErrors
  if (!andThrow) return shorthandAssign >= 0 || doubleProto >= 0
  if (shorthandAssign >= 0)
    this.raise(shorthandAssign, "Shorthand property assignments are valid only in destructuring patterns")
  if (doubleProto >= 0)
    this.raiseRecoverable(doubleProto, "Redefinition of __proto__ property")
}

pp.checkYieldAwaitInDefaultParams = function() {
  if (this.yieldPos && (!this.awaitPos || this.yieldPos < this.awaitPos))
    this.raise(this.yieldPos, "Yield expression cannot be a default value")
  if (this.awaitPos)
    this.raise(this.awaitPos, "Await expression cannot be a default value")
}

pp.isSimpleAssignTarget = function(expr) {
  if (expr.type === "ParenthesizedExpression")
    return this.isSimpleAssignTarget(expr.expression)
  return expr.type === "Identifier" || expr.type === "MemberExpression"
}
<|endoftext|>


<commit_before>describe('Episode', function() {
    "use strict";

    var Episode, EpisodeResource, Item, $scope, $rootScope, columns, $window;
    var episode, episodeData, resource, tag_hierarchy, fields;
    var $routeParams;

    beforeEach(function() {
        module('opal.services', function($provide) {
            $provide.value('UserProfile', {
              load: function(){ return profile; }
            });
        });

        tag_hierarchy = {
            'mine'    : [],
            'tropical': [],
            'micro'   : [
                'ortho', 'haem'
            ]
        };

        columns = {
            "fields": {
                'demographics': {
                    name: "demographics",
                    single: true,
                    fields: [
                        {name: 'first_name', type: 'string'},
                        {name: 'surname', type: 'string'},
                        {name: 'date_of_birth', type: 'date'},
                    ]
                },
                "diagnosis": {
                    name: "diagnosis",
                    single: false,
                    sort: 'date_of_diagnosis',
                    fields: [
                        {name: 'date_of_diagnosis', type: 'date'},
                        {name: 'condition', type: 'string'},
                        {name: 'provisional', type: 'boolean'},
                    ]
                },
                microbiology_test: {
                    name: "microbiology_test",
                    single: false,
                    fields: [
                        {name: 'date_ordered', type: 'date'}
                    ]
                },
                general_note: {
                    name: 'general_note',
                    fields: [
                        {name: 'date', type: 'date'}
                    ]
                },
                microbiology_input: {
                    name: 'microbiology_input',
                    fields: [
                        {name: 'initials', type: 'string'},
                        {name: 'when', type: 'datetime'}
                    ]
                },
                antimicrobial: {
                    name: 'antimicrobial',
                    fields: [
                        {name: 'start_date', type: 'date'}
                    ]
                }
            },
            "list_schema": {
                "default": [
                    'demographics',
                    'diagnosis'
                ]
            }
        };

        episodeData = {
            id: 123,
            date_of_admission: "19/11/2013",
            category_name: 'inpatient',
            active: true,
            discharge_date: "25/05/2016",
            date_of_episode: "20/11/2013",
            start: "19/11/2013",
            end: "25/05/2016",
            tagging: [{
                mine: true,
                tropical: true
                }],
            demographics: [{
                id: 101,
                patient_id: 99,
                first_name: 'John',
                surname: "Smith",
                date_of_birth: '31/07/1980',
                hospital_number: '555'
            }],
            location: [{
                category: 'Inepisode',
                hospital: 'UCH',
                ward: 'T10',
                bed: '15',
                date_of_admission: '01/08/2013'
            }],
            diagnosis: [{
                id: 102,
                condition: 'Dengue',
                provisional: true,
                date_of_diagnosis: '20/04/2007'
            }, {
                id: 103,
                condition: 'Malaria',
                provisional: false,
                date_of_diagnosis: '03/19/2006'
            }]
        };

        fields = {};
        _.each(columns.fields, function(c){
            fields[c.name] = c;
        });

        inject(function($injector) {
            Episode = $injector.get('Episode');
            Item = $injector.get('Item');
            $rootScope  = $injector.get('$rootScope');
            $scope      = $rootScope.$new();
            $routeParams = $injector.get('$routeParams');
            $window      = $injector.get('$window');
        });
        $rootScope.fields = fields;

        episode = new Episode(angular.copy(episodeData));
    });

    describe('initialisation', function() {

        it('should throw if there is no patient ID', function() {
            expect(function(){ new Episode({});}).toThrow();
        });

        it('should cast dates on the episode if appropriate', function(){
            var episodeDataCloned = angular.copy(episodeData);
            var newEpisode = new Episode(episodeDataCloned);
            expect(moment(newEpisode.date_of_admission).format('DD/MM/YYYY')).toEqual("19/11/2013");
            expect(moment(newEpisode.start).format('DD/MM/YYYY')).toEqual("19/11/2013");
            expect(moment(newEpisode.end).format('DD/MM/YYYY')).toEqual("25/05/2016");
            expect(moment(newEpisode.date_of_episode).format('DD/MM/YYYY')).toEqual("20/11/2013");
            expect(moment(newEpisode.discharge_date).format('DD/MM/YYYY')).toEqual("25/05/2016");
        });
    });

    it('should compare comparators that are different', function() {
        var datacopy = angular.copy(episodeData);
        datacopy.location[0].bed = '87';
        var first       = new Episode(episodeData);
        var second      = new Episode(datacopy);
        expect(first.compare(second)).toEqual(-1);
        expect(second.compare(first)).toEqual(1);
    });

    it('should be equal for non UCH hospitals', function() {
        var datacopy = angular.copy(episodeData);
        datacopy.location[0].hospital = 'RFH';
        var first       = new Episode(datacopy);
        var second      = new Episode(datacopy);
        expect(first.compare(second)).toEqual(0);
    });

    it('should allow custom comparators to be passed.', function() {
        var comparators = [jasmine.createSpy().and.returnValue(-1000)];
        var first       = new Episode(episodeData);
        var second      = new Episode(episodeData);
        expect(first.compare(second, comparators)).toEqual(0);
        expect(comparators[0]).toHaveBeenCalledWith(first)
        expect(comparators[0]).toHaveBeenCalledWith(second)
    });

    it('Should have access to the attributes', function () {
        expect(episode.active).toEqual(true);
    });

    it('Should convert date attributes to Date objects', function () {
        expect(episode.date_of_admission).toEqual(new Date(2013, 10, 19));
    });

    it('should create Items', function() {
        expect(episode.demographics.length).toBe(1);
        expect(episode.diagnosis.length).toBe(2);
    });

    it('should have access to attributes of items', function() {
        expect(episode.id).toBe(123);
        expect(episode.demographics[0].first_name).toBe('John');
        expect(episode.demographics[0].surname).toBe('Smith');
    });

    it('should be able to get specific item', function() {
        expect(episode.getItem('diagnosis', 1).id).toEqual(102);
    });

    it('should return the name of the patient', function() {
        expect(episode.getFullName()).toEqual('John Smith');
    });

    it('should know how many items it has in each column', function() {
        expect(episode.getNumberOfItems('demographics')).toBe(1);
        expect(episode.getNumberOfItems('diagnosis')).toBe(2);
    });

    it('getTags() should get the current tags', function(){
        expect(episode.getTags()).toEqual(['mine', 'tropical']);
    });

    it('should return tags if tagging is an Item()', function() {
        episode.tagging = [{makeCopy: function(){ return {
            mine: true,
            tropical: true,
            id: 1,
            _client: {something: 'else'}
        }; }}];
        expect(episode.getTags()).toEqual(['mine', 'tropical']);
    });

    it('hasTags() Should know if the episode has a given tag', function () {
        expect(episode.hasTag('tropical')).toEqual(true);
    });

    it('newItem() should create an Item', function() {
        var dd = new moment();
        var item = episode.newItem('diagnosis', {
          columnName: 'diagnosis'
        });
        expect(item.columnName).toBe('diagnosis');
    });

    it('should be able to add a new item', function() {
        var item = new Item(
            {id: 104, condition: 'Ebola', provisional: false,
             date_of_diagnosis: '19/02/2005'},
            episode,
            columns.fields.diagnosis
        );
        expect(episode.getNumberOfItems('diagnosis')).toBe(2);
        episode.addItem(item);
        expect(episode.getNumberOfItems('diagnosis')).toBe(3);
    });

    it('should addItems() for items without an entry on episode', function() {
        var item = {columnName: 'notareal_column'};
        episode.addItem(item);
        expect(episode.notareal_column).toEqual([item]);
    });

    it('removeItem() should remove an item from our episode', function() {
        // Note: Diagnoses end up ordered differently to the declared order
        // above as they are sorted by date.
        expect(episode.diagnosis.length).toEqual(2);
        episode.removeItem(episode.diagnosis[1]);
        expect(episode.diagnosis.length).toEqual(1);
        expect(episode.diagnosis[0].id).toBe(103);
    });

    it('Should be able to produce a copy of attributes', function () {
        expect(episode.makeCopy()).toEqual({
            id: 123,
            date_of_admission: new Date(2013, 10, 19),
            date_of_episode: new Date(2013, 10, 20),
            discharge_date: new Date(2016, 4, 25),
            category_name: 'inpatient',
            consistency_token: undefined
        });
    });

    describe('communicating with server', function (){
        var $httpBackend, episode;

        beforeEach(function(){
            inject(function($injector){
                $httpBackend = $injector.get('$httpBackend');
            });
        });

        afterEach(function(){
            $httpBackend.verifyNoOutstandingExpectation();
            $httpBackend.verifyNoOutstandingRequest();
        });

        describe('saving an existing episode', function (){
            var attrsJsonDate;

            beforeEach(function(){
                attrsJsonDate = {
                    id               : 555,
                    active           : true,
                    date_of_admission: '20/11/2013',
                    discharge_date   : null,
                    demographics: [{
                        id: 101,
                        patient_id: 99,
                        first_name: 'John',
                        surname: "Smith",
                        date_of_birth: '31/07/1980',
                        hospital_number: '555'
                    }]
                };

                episode = new Episode(episodeData);

                $httpBackend.whenPUT('/api/v0.1/episode/555/')
                    .respond(attrsJsonDate);

            });

            it('Should hit server', function () {
                $httpBackend.expectPUT('/api/v0.1/episode/555/', attrsJsonDate);
                episode.save(attrsJsonDate);
                $httpBackend.flush();
            });

            it('Should update item attributes', function () {
                $httpBackend.expectPUT('/api/v0.1/episode/555/', attrsJsonDate);
                episode.save(attrsJsonDate);
                $httpBackend.flush();
                expect(episode.date_of_admission).toEqual(new Date(2013, 10, 20))
            });

            it('Should translate dates to strings', function () {
                var toSave = angular.copy(attrsJsonDate);
                toSave.date_of_admission = new Date(2013, 10, 20);
                $httpBackend.expectPUT('/api/v0.1/episode/555/', attrsJsonDate);
                episode.save(toSave);
                $httpBackend.flush();
            });

            it('should cope with consistency token errors', function() {
                spyOn($window, 'alert');
                $httpBackend.expectPUT('/api/v0.1/episode/555/', attrsJsonDate)
                    .respond(409, {'error': 'Consistency tokens'});
                episode.save(attrsJsonDate);
                $httpBackend.flush();
                expect($window.alert).toHaveBeenCalled();
            });

            it('should cope with 500 errors', function() {
                spyOn($window, 'alert');
                $httpBackend.expectPUT('/api/v0.1/episode/555/', attrsJsonDate)
                    .respond(500, {'error': 'Cripes!'});
                episode.save(attrsJsonDate);
                $httpBackend.flush();
                expect($window.alert).toHaveBeenCalledWith('Item could not be saved');
            });

        });

        describe('isDischarged()', function() {

            it('should return true', function() {
                expect(episode.isDischarged()).toEqual(true);
            });

        });

        describe('findByHospitalNumber()', function (){
            it('Should call the newPatient callback', function () {
                var mock_new = jasmine.createSpy('Mock for new patient')
                var search_url = '/search/patient/';
                search_url += '?hospital_number=notarealnumber'
                $httpBackend.expectGET(search_url).respond([]);

                Episode.findByHospitalNumber('notarealnumber', {newPatient: mock_new})

                $httpBackend.flush();
                $scope.$digest(); // Fire actual resolving
                expect(mock_new).toHaveBeenCalled();
            });

            it('Should cast the new patient and call the newForPatient callback', function () {
                var mock_new = jasmine.createSpy('Mock for new patient')
                var search_url = '/search/patient/';
                search_url += '?hospital_number=notarealnumber'
                $httpBackend.expectGET(search_url).respond([episodeData]);
                Episode.findByHospitalNumber('notarealnumber', {newForPatient: mock_new})
                $httpBackend.flush();
                $scope.$digest(); // Fire actual resolving

                expect(mock_new).toHaveBeenCalled();
                var call_args = mock_new.calls.argsFor(0)[0]
                expect(call_args.demographics[0].date_of_birth.format('DD/MM/YY')).toEqual('31/07/80');
                expect(call_args.demographics[0].first_name).toEqual('John');
                expect(call_args.demographics[0].surname).toEqual('Smith');
            });

        });

    });
});
<commit_msg>Add an explicit test for filtering out _client in getTags()<commit_after>describe('Episode', function() {
    "use strict";

    var Episode, EpisodeResource, Item, $scope, $rootScope, columns, $window;
    var episode, episodeData, resource, tag_hierarchy, fields;
    var $routeParams;

    beforeEach(function() {
        module('opal.services', function($provide) {
            $provide.value('UserProfile', {
              load: function(){ return profile; }
            });
        });

        tag_hierarchy = {
            'mine'    : [],
            'tropical': [],
            'micro'   : [
                'ortho', 'haem'
            ]
        };

        columns = {
            "fields": {
                'demographics': {
                    name: "demographics",
                    single: true,
                    fields: [
                        {name: 'first_name', type: 'string'},
                        {name: 'surname', type: 'string'},
                        {name: 'date_of_birth', type: 'date'},
                    ]
                },
                "diagnosis": {
                    name: "diagnosis",
                    single: false,
                    sort: 'date_of_diagnosis',
                    fields: [
                        {name: 'date_of_diagnosis', type: 'date'},
                        {name: 'condition', type: 'string'},
                        {name: 'provisional', type: 'boolean'},
                    ]
                },
                microbiology_test: {
                    name: "microbiology_test",
                    single: false,
                    fields: [
                        {name: 'date_ordered', type: 'date'}
                    ]
                },
                general_note: {
                    name: 'general_note',
                    fields: [
                        {name: 'date', type: 'date'}
                    ]
                },
                microbiology_input: {
                    name: 'microbiology_input',
                    fields: [
                        {name: 'initials', type: 'string'},
                        {name: 'when', type: 'datetime'}
                    ]
                },
                antimicrobial: {
                    name: 'antimicrobial',
                    fields: [
                        {name: 'start_date', type: 'date'}
                    ]
                }
            },
            "list_schema": {
                "default": [
                    'demographics',
                    'diagnosis'
                ]
            }
        };

        episodeData = {
            id: 123,
            date_of_admission: "19/11/2013",
            category_name: 'inpatient',
            active: true,
            discharge_date: "25/05/2016",
            date_of_episode: "20/11/2013",
            start: "19/11/2013",
            end: "25/05/2016",
            tagging: [{
                mine: true,
                tropical: true
                }],
            demographics: [{
                id: 101,
                patient_id: 99,
                first_name: 'John',
                surname: "Smith",
                date_of_birth: '31/07/1980',
                hospital_number: '555'
            }],
            location: [{
                category: 'Inepisode',
                hospital: 'UCH',
                ward: 'T10',
                bed: '15',
                date_of_admission: '01/08/2013'
            }],
            diagnosis: [{
                id: 102,
                condition: 'Dengue',
                provisional: true,
                date_of_diagnosis: '20/04/2007'
            }, {
                id: 103,
                condition: 'Malaria',
                provisional: false,
                date_of_diagnosis: '03/19/2006'
            }]
        };

        fields = {};
        _.each(columns.fields, function(c){
            fields[c.name] = c;
        });

        inject(function($injector) {
            Episode = $injector.get('Episode');
            Item = $injector.get('Item');
            $rootScope  = $injector.get('$rootScope');
            $scope      = $rootScope.$new();
            $routeParams = $injector.get('$routeParams');
            $window      = $injector.get('$window');
        });
        $rootScope.fields = fields;

        episode = new Episode(angular.copy(episodeData));
    });

    describe('initialisation', function() {

        it('should throw if there is no patient ID', function() {
            expect(function(){ new Episode({});}).toThrow();
        });

        it('should cast dates on the episode if appropriate', function(){
            var episodeDataCloned = angular.copy(episodeData);
            var newEpisode = new Episode(episodeDataCloned);
            expect(moment(newEpisode.date_of_admission).format('DD/MM/YYYY')).toEqual("19/11/2013");
            expect(moment(newEpisode.start).format('DD/MM/YYYY')).toEqual("19/11/2013");
            expect(moment(newEpisode.end).format('DD/MM/YYYY')).toEqual("25/05/2016");
            expect(moment(newEpisode.date_of_episode).format('DD/MM/YYYY')).toEqual("20/11/2013");
            expect(moment(newEpisode.discharge_date).format('DD/MM/YYYY')).toEqual("25/05/2016");
        });
    });

    it('should compare comparators that are different', function() {
        var datacopy = angular.copy(episodeData);
        datacopy.location[0].bed = '87';
        var first       = new Episode(episodeData);
        var second      = new Episode(datacopy);
        expect(first.compare(second)).toEqual(-1);
        expect(second.compare(first)).toEqual(1);
    });

    it('should be equal for non UCH hospitals', function() {
        var datacopy = angular.copy(episodeData);
        datacopy.location[0].hospital = 'RFH';
        var first       = new Episode(datacopy);
        var second      = new Episode(datacopy);
        expect(first.compare(second)).toEqual(0);
    });

    it('should allow custom comparators to be passed.', function() {
        var comparators = [jasmine.createSpy().and.returnValue(-1000)];
        var first       = new Episode(episodeData);
        var second      = new Episode(episodeData);
        expect(first.compare(second, comparators)).toEqual(0);
        expect(comparators[0]).toHaveBeenCalledWith(first)
        expect(comparators[0]).toHaveBeenCalledWith(second)
    });

    it('Should have access to the attributes', function () {
        expect(episode.active).toEqual(true);
    });

    it('Should convert date attributes to Date objects', function () {
        expect(episode.date_of_admission).toEqual(new Date(2013, 10, 19));
    });

    it('should create Items', function() {
        expect(episode.demographics.length).toBe(1);
        expect(episode.diagnosis.length).toBe(2);
    });

    it('should have access to attributes of items', function() {
        expect(episode.id).toBe(123);
        expect(episode.demographics[0].first_name).toBe('John');
        expect(episode.demographics[0].surname).toBe('Smith');
    });

    it('should be able to get specific item', function() {
        expect(episode.getItem('diagnosis', 1).id).toEqual(102);
    });

    it('should return the name of the patient', function() {
        expect(episode.getFullName()).toEqual('John Smith');
    });

    it('should know how many items it has in each column', function() {
        expect(episode.getNumberOfItems('demographics')).toBe(1);
        expect(episode.getNumberOfItems('diagnosis')).toBe(2);
    });

    it('getTags() should get the current tags', function(){
        expect(episode.getTags()).toEqual(['mine', 'tropical']);
    });

    it('should return tags if tagging is an Item()', function() {
        episode.tagging = [{makeCopy: function(){ return {
            mine: true,
            tropical: true,
            id: 1,
            _client: {something: 'else'}
        }; }}];
        expect(episode.getTags()).toEqual(['mine', 'tropical']);
    });

    it('should filter out _client from tags', function() {
        episode.tagging = [{makeCopy: function(){ return {
            mine: true,
            tropical: true,
            id: 1,
            _client: {something: 'else'}
        }; }}];
        expect(episode.getTags().indexOf('_client')).toEqual(-1);
    });

    it('hasTags() Should know if the episode has a given tag', function () {
        expect(episode.hasTag('tropical')).toEqual(true);
    });

    it('newItem() should create an Item', function() {
        var dd = new moment();
        var item = episode.newItem('diagnosis', {
          columnName: 'diagnosis'
        });
        expect(item.columnName).toBe('diagnosis');
    });

    it('should be able to add a new item', function() {
        var item = new Item(
            {id: 104, condition: 'Ebola', provisional: false,
             date_of_diagnosis: '19/02/2005'},
            episode,
            columns.fields.diagnosis
        );
        expect(episode.getNumberOfItems('diagnosis')).toBe(2);
        episode.addItem(item);
        expect(episode.getNumberOfItems('diagnosis')).toBe(3);
    });

    it('should addItems() for items without an entry on episode', function() {
        var item = {columnName: 'notareal_column'};
        episode.addItem(item);
        expect(episode.notareal_column).toEqual([item]);
    });

    it('removeItem() should remove an item from our episode', function() {
        // Note: Diagnoses end up ordered differently to the declared order
        // above as they are sorted by date.
        expect(episode.diagnosis.length).toEqual(2);
        episode.removeItem(episode.diagnosis[1]);
        expect(episode.diagnosis.length).toEqual(1);
        expect(episode.diagnosis[0].id).toBe(103);
    });

    it('Should be able to produce a copy of attributes', function () {
        expect(episode.makeCopy()).toEqual({
            id: 123,
            date_of_admission: new Date(2013, 10, 19),
            date_of_episode: new Date(2013, 10, 20),
            discharge_date: new Date(2016, 4, 25),
            category_name: 'inpatient',
            consistency_token: undefined
        });
    });

    describe('communicating with server', function (){
        var $httpBackend, episode;

        beforeEach(function(){
            inject(function($injector){
                $httpBackend = $injector.get('$httpBackend');
            });
        });

        afterEach(function(){
            $httpBackend.verifyNoOutstandingExpectation();
            $httpBackend.verifyNoOutstandingRequest();
        });

        describe('saving an existing episode', function (){
            var attrsJsonDate;

            beforeEach(function(){
                attrsJsonDate = {
                    id               : 555,
                    active           : true,
                    date_of_admission: '20/11/2013',
                    discharge_date   : null,
                    demographics: [{
                        id: 101,
                        patient_id: 99,
                        first_name: 'John',
                        surname: "Smith",
                        date_of_birth: '31/07/1980',
                        hospital_number: '555'
                    }]
                };

                episode = new Episode(episodeData);

                $httpBackend.whenPUT('/api/v0.1/episode/555/')
                    .respond(attrsJsonDate);

            });

            it('Should hit server', function () {
                $httpBackend.expectPUT('/api/v0.1/episode/555/', attrsJsonDate);
                episode.save(attrsJsonDate);
                $httpBackend.flush();
            });

            it('Should update item attributes', function () {
                $httpBackend.expectPUT('/api/v0.1/episode/555/', attrsJsonDate);
                episode.save(attrsJsonDate);
                $httpBackend.flush();
                expect(episode.date_of_admission).toEqual(new Date(2013, 10, 20))
            });

            it('Should translate dates to strings', function () {
                var toSave = angular.copy(attrsJsonDate);
                toSave.date_of_admission = new Date(2013, 10, 20);
                $httpBackend.expectPUT('/api/v0.1/episode/555/', attrsJsonDate);
                episode.save(toSave);
                $httpBackend.flush();
            });

            it('should cope with consistency token errors', function() {
                spyOn($window, 'alert');
                $httpBackend.expectPUT('/api/v0.1/episode/555/', attrsJsonDate)
                    .respond(409, {'error': 'Consistency tokens'});
                episode.save(attrsJsonDate);
                $httpBackend.flush();
                expect($window.alert).toHaveBeenCalled();
            });

            it('should cope with 500 errors', function() {
                spyOn($window, 'alert');
                $httpBackend.expectPUT('/api/v0.1/episode/555/', attrsJsonDate)
                    .respond(500, {'error': 'Cripes!'});
                episode.save(attrsJsonDate);
                $httpBackend.flush();
                expect($window.alert).toHaveBeenCalledWith('Item could not be saved');
            });

        });

        describe('isDischarged()', function() {

            it('should return true', function() {
                expect(episode.isDischarged()).toEqual(true);
            });

        });

        describe('findByHospitalNumber()', function (){
            it('Should call the newPatient callback', function () {
                var mock_new = jasmine.createSpy('Mock for new patient')
                var search_url = '/search/patient/';
                search_url += '?hospital_number=notarealnumber'
                $httpBackend.expectGET(search_url).respond([]);

                Episode.findByHospitalNumber('notarealnumber', {newPatient: mock_new})

                $httpBackend.flush();
                $scope.$digest(); // Fire actual resolving
                expect(mock_new).toHaveBeenCalled();
            });

            it('Should cast the new patient and call the newForPatient callback', function () {
                var mock_new = jasmine.createSpy('Mock for new patient')
                var search_url = '/search/patient/';
                search_url += '?hospital_number=notarealnumber'
                $httpBackend.expectGET(search_url).respond([episodeData]);
                Episode.findByHospitalNumber('notarealnumber', {newForPatient: mock_new})
                $httpBackend.flush();
                $scope.$digest(); // Fire actual resolving

                expect(mock_new).toHaveBeenCalled();
                var call_args = mock_new.calls.argsFor(0)[0]
                expect(call_args.demographics[0].date_of_birth.format('DD/MM/YY')).toEqual('31/07/80');
                expect(call_args.demographics[0].first_name).toEqual('John');
                expect(call_args.demographics[0].surname).toEqual('Smith');
            });

        });

    });
});
<|endoftext|>