<commit_before>"use strict";

describe("Factory: apListItemFactory", function () {

    beforeEach(module("angularPoint"));

    var factory,
        mockModel,
        mockLookupModel,
        mockListItem,
        apCachedXML,
        $httpBackend,
        utils;

    beforeEach(inject(function (_apListItemFactory_, _mockModel_, _mockLookupModel_, _$httpBackend_, _apCachedXML_
        , apMockUtils) {
        factory = _apListItemFactory_;
        mockModel = _mockModel_;
        mockLookupModel = _mockLookupModel_;
        $httpBackend = _$httpBackend_;
        apCachedXML = _apCachedXML_;
        mockModel.importMocks();
        mockListItem = mockModel.getCache()[1];
        utils = apMockUtils;

    }));

    describe('Function create', function () {
        it("instantiates a new List item using constructor", function () {
            expect(factory.create()).toEqual(new factory.ListItem);
        })
    });

    describe('Method: deleteItem', function () {
        it('removes entity with ID of 1 from the cache', function () {
            mockListItem.deleteItem()
                .then(function () {
                    expect(mockModel.getCache('primary')[1]).toBeUndefined();
                });
            $httpBackend.flush();
        });
    });

    describe('Method: validateEntity', function () {
        it('validates a valid entity.', function () {
            mockListItem.boolean = false;
            expect(mockListItem.validateEntity()).toBe(true);

        });

        it('rejects an invalid entity.', function () {
            mockListItem.boolean = 'this is a test';
            expect(mockListItem.validateEntity()).toBe(false);
        });
    });

    describe('Method: getFieldDefinition', function () {
        it('returns the field definition.', function () {
            expect(mockListItem.getFieldDefinition('json').objectType).toEqual('JSON');
        });

        it('returns undefined if a valid field isn\'t provided.', function () {
            expect(mockListItem.getFieldDefinition('invalidField')).toBeUndefined();
        })

    });

    describe('Method: getFormattedValue', function () {
        it('throws an error if the provided field name isn\'t valid', function () {
            expect(function () {
                mockListItem.getFormattedValue('invalidField');
            }).toThrow();
        });

        it('returns a stringified date without params', function () {
            expect(mockListItem.getFormattedValue('date')).toEqual('8/19/14 12:00 AM');
        });

        it('returns a stringified json date with params', function () {
            expect(mockListItem.getFormattedValue('date', {dateFormat: 'json'}))
                .toEqual('2014-08-19T' + utils.getTimezoneOffsetString() + ':00.000Z');
        });
    });

    describe('Method: getLookupReference', function () {
        var mockLookupItem,
            mockLookupReference;

        beforeEach(function () {
            mockLookupModel.importMocks();
            mockLookupItem = mockLookupModel.getCache('primary')[1];
            mockLookupReference = mockListItem.getLookupReference('lookup');
        });

        it('returns the entity a lookup item is referencing', function () {
            expect(mockLookupReference).toEqual(mockLookupItem);
        });

        it('should throw an error if a field name isn\'t provided', function () {
            expect(function () {
                mockListItem.getLookupReference();
            }).toThrow();
        });

        it('returns an empty string if the lookup is empty', function () {
            mockListItem.lookup = '';
            expect(mockListItem.getLookupReference('lookup')).toEqual('');
        });

        it('throws an error if the fieldDefinition.List isn\'t available', function () {
            delete mockListItem.getFieldDefinition('lookup').List;
            expect(function () {
                mockListItem.getLookupReference('lookup');
            }).toThrow();
        });

    });

    describe('Method: resolvePermissions', function () {

        it('allows admin to approve.', function () {
            //Full rights mask
            mockListItem.permMask = '0x7FFFFFFFFFFFFFFF';
            var adminUserPermissions = mockListItem.resolvePermissions();
            expect(adminUserPermissions.ApproveItems).toBe(true);
        });
        it('prevents read-only user from approving.', function () {
            //Limited user (view only)
            mockListItem.permMask = '0x0000000000000001';
            var standardUserPermissions = mockListItem.resolvePermissions();
            expect(standardUserPermissions.ApproveItems).toBe(false);
        });
        it('allows a user with edit rights to edit.', function () {
            //User can edit
            mockListItem.permMask = '0x0000000000000004';
            var standardUserPermissions = mockListItem.resolvePermissions();
            expect(standardUserPermissions.EditListItems).toBe(true);
        });

    });

    describe('Method: saveChanges', function () {
        describe('successful calls', function () {
            beforeEach(function () {
                expect(mockListItem.integer).toEqual(12);
                mockListItem.integer = 13;
                mockListItem.saveChanges()
                    .then(function (response) {
                        expect(response.integer).toEqual(13);
                    });
                $httpBackend.flush();
            });
            it('has the updated value', function () {
                expect(mockListItem.integer).toEqual(13);
            });
            it('is also updated in the other caches because they should be referencing the same object', function () {
                expect(mockModel.getCache('secondary')[1]).toEqual(mockListItem);
            });
        });

        //describe('the ability to identity an error', function () {
        //    it('rejects the promise with an error message', function () {
        //        mockXMLService.xhrStub('errorUpdatingListItem');
        //        mockListItem.saveChanges()
        //            .then(function (response) {
        //
        //            }, function (err) {
        //                expect(_.isString(err)).toBeTrue();
        //            });
        //        $rootScope.$digest();
        //    });
        //});
    });

    describe('Method: saveFields', function () {
        it('has the initial value before updating', function () {
            expect(mockListItem.integer).toEqual(12);
        });
        it('has the updated value after updating', function () {
            mockListItem.integer = 29;
            mockListItem.saveFields('integer')
                .then(function (response) {
                    expect(response.integer).toEqual(29);
                });
            $httpBackend.flush();
        });
        it('shows the updating value in the secondary cache', function () {
            mockListItem.integer = 41;
            mockListItem.saveFields('integer')
                .then(function (response) {

                });
            $httpBackend.flush();
            expect(mockModel.getCache('secondary')[1].integer).toEqual(41);
        });
        //it('resolves the promise with the updated entity', function () {
        //    mockXMLService.xhrStub('UpdateListItem');
        //    mockListItem.saveFields('integer')
        //        .then(function (response) {
        //            expect(response.integer).toEqual(13);
        //        });
        //    $rootScope.$digest();
        //});
        //it('rejects the promise with an error message', function () {
        //    $httpBackend.whenPOST('/test/_vti_bin/Lists.asmx')
        //        .respond(function (method, url, data) {
        //            return [200, apCachedXML.ErrorUpdatingListItem];
        //        });
        //    mockListItem.saveFields('integer')
        //        .then(function (response) {
        //
        //        }, function (err) {
        //            expect(_.isString(err)).toBeTrue();
        //        });
        //    $httpBackend.flush();
        //});

    });

    describe('Method: getAttachmentCollection', function () {
        it('returns an array of attachments for the list item', function () {
            //mockXMLService.xhrStub('getAttachmentCollection');
            mockListItem.getAttachmentCollection()
                .then(function (response) {
                    expect(response.length).toEqual(1);
                });
            $httpBackend.flush();
        });
    });

    describe('Method: deleteAttachment', function () {
        it('resolves the promise when deleted', function () {
            //mockXMLService.xhrStub('deleteAttachment');
            mockListItem.deleteAttachment(mockListItem.attachments[0])
                .then(function (response) {
                    expect(response).toBeDefined();
                });
            $httpBackend.flush();
        });
    });

    describe('Method: getFieldVersionHistory', function () {
        it('parses the version history for a field and returns all 3 versions', function () {
            //mockXMLService.xhrStub('GetVersionCollection');
            mockListItem.getFieldVersionHistory('integer')
                .then(function (response) {
                    expect(response.length).toEqual(3);
                });
            $httpBackend.flush();
        });
        it('works without passing any any fields to dynamically build field array', function () {
            //mockXMLService.xhrStub('GetVersionCollection');
            mockListItem.getFieldVersionHistory()
                .then(function (response) {
                    expect(response.length).toEqual(3);
                });
            $httpBackend.flush();
        });
    });

});
<commit_msg>Daylight savings time bug.<commit_after>"use strict";

describe("Factory: apListItemFactory", function () {

    beforeEach(module("angularPoint"));

    var factory,
        mockModel,
        mockLookupModel,
        mockListItem,
        apCachedXML,
        $httpBackend,
        utils;

    beforeEach(inject(function (_apListItemFactory_, _mockModel_, _mockLookupModel_, _$httpBackend_, _apCachedXML_
        , apMockUtils) {
        factory = _apListItemFactory_;
        mockModel = _mockModel_;
        mockLookupModel = _mockLookupModel_;
        $httpBackend = _$httpBackend_;
        apCachedXML = _apCachedXML_;
        mockModel.importMocks();
        mockListItem = mockModel.getCache()[1];
        utils = apMockUtils;

    }));

    describe('Function create', function () {
        it("instantiates a new List item using constructor", function () {
            expect(factory.create()).toEqual(new factory.ListItem);
        })
    });

    describe('Method: deleteItem', function () {
        it('removes entity with ID of 1 from the cache', function () {
            mockListItem.deleteItem()
                .then(function () {
                    expect(mockModel.getCache('primary')[1]).toBeUndefined();
                });
            $httpBackend.flush();
        });
    });

    describe('Method: validateEntity', function () {
        it('validates a valid entity.', function () {
            mockListItem.boolean = false;
            expect(mockListItem.validateEntity()).toBe(true);

        });

        it('rejects an invalid entity.', function () {
            mockListItem.boolean = 'this is a test';
            expect(mockListItem.validateEntity()).toBe(false);
        });
    });

    describe('Method: getFieldDefinition', function () {
        it('returns the field definition.', function () {
            expect(mockListItem.getFieldDefinition('json').objectType).toEqual('JSON');
        });

        it('returns undefined if a valid field isn\'t provided.', function () {
            expect(mockListItem.getFieldDefinition('invalidField')).toBeUndefined();
        })

    });

    describe('Method: getFormattedValue', function () {
        it('throws an error if the provided field name isn\'t valid', function () {
            expect(function () {
                mockListItem.getFormattedValue('invalidField');
            }).toThrow();
        });

        it('returns a stringified date without params', function () {
            expect(mockListItem.getFormattedValue('date')).toEqual('8/19/14 12:00 AM');
        });

        it('returns a stringified json date with params', function () {
            expect(mockListItem.getFormattedValue('date', {dateFormat: 'json'}))
                .toEqual('2014-08-19T07:00:00.000Z');
                //.toEqual('2014-08-19T' + utils.getTimezoneOffsetString() + ':00.000Z');
        });
    });

    describe('Method: getLookupReference', function () {
        var mockLookupItem,
            mockLookupReference;

        beforeEach(function () {
            mockLookupModel.importMocks();
            mockLookupItem = mockLookupModel.getCache('primary')[1];
            mockLookupReference = mockListItem.getLookupReference('lookup');
        });

        it('returns the entity a lookup item is referencing', function () {
            expect(mockLookupReference).toEqual(mockLookupItem);
        });

        it('should throw an error if a field name isn\'t provided', function () {
            expect(function () {
                mockListItem.getLookupReference();
            }).toThrow();
        });

        it('returns an empty string if the lookup is empty', function () {
            mockListItem.lookup = '';
            expect(mockListItem.getLookupReference('lookup')).toEqual('');
        });

        it('throws an error if the fieldDefinition.List isn\'t available', function () {
            delete mockListItem.getFieldDefinition('lookup').List;
            expect(function () {
                mockListItem.getLookupReference('lookup');
            }).toThrow();
        });

    });

    describe('Method: resolvePermissions', function () {

        it('allows admin to approve.', function () {
            //Full rights mask
            mockListItem.permMask = '0x7FFFFFFFFFFFFFFF';
            var adminUserPermissions = mockListItem.resolvePermissions();
            expect(adminUserPermissions.ApproveItems).toBe(true);
        });
        it('prevents read-only user from approving.', function () {
            //Limited user (view only)
            mockListItem.permMask = '0x0000000000000001';
            var standardUserPermissions = mockListItem.resolvePermissions();
            expect(standardUserPermissions.ApproveItems).toBe(false);
        });
        it('allows a user with edit rights to edit.', function () {
            //User can edit
            mockListItem.permMask = '0x0000000000000004';
            var standardUserPermissions = mockListItem.resolvePermissions();
            expect(standardUserPermissions.EditListItems).toBe(true);
        });

    });

    describe('Method: saveChanges', function () {
        describe('successful calls', function () {
            beforeEach(function () {
                expect(mockListItem.integer).toEqual(12);
                mockListItem.integer = 13;
                mockListItem.saveChanges()
                    .then(function (response) {
                        expect(response.integer).toEqual(13);
                    });
                $httpBackend.flush();
            });
            it('has the updated value', function () {
                expect(mockListItem.integer).toEqual(13);
            });
            it('is also updated in the other caches because they should be referencing the same object', function () {
                expect(mockModel.getCache('secondary')[1]).toEqual(mockListItem);
            });
        });

        //describe('the ability to identity an error', function () {
        //    it('rejects the promise with an error message', function () {
        //        mockXMLService.xhrStub('errorUpdatingListItem');
        //        mockListItem.saveChanges()
        //            .then(function (response) {
        //
        //            }, function (err) {
        //                expect(_.isString(err)).toBeTrue();
        //            });
        //        $rootScope.$digest();
        //    });
        //});
    });

    describe('Method: saveFields', function () {
        it('has the initial value before updating', function () {
            expect(mockListItem.integer).toEqual(12);
        });
        it('has the updated value after updating', function () {
            mockListItem.integer = 29;
            mockListItem.saveFields('integer')
                .then(function (response) {
                    expect(response.integer).toEqual(29);
                });
            $httpBackend.flush();
        });
        it('shows the updating value in the secondary cache', function () {
            mockListItem.integer = 41;
            mockListItem.saveFields('integer')
                .then(function (response) {

                });
            $httpBackend.flush();
            expect(mockModel.getCache('secondary')[1].integer).toEqual(41);
        });
        //it('resolves the promise with the updated entity', function () {
        //    mockXMLService.xhrStub('UpdateListItem');
        //    mockListItem.saveFields('integer')
        //        .then(function (response) {
        //            expect(response.integer).toEqual(13);
        //        });
        //    $rootScope.$digest();
        //});
        //it('rejects the promise with an error message', function () {
        //    $httpBackend.whenPOST('/test/_vti_bin/Lists.asmx')
        //        .respond(function (method, url, data) {
        //            return [200, apCachedXML.ErrorUpdatingListItem];
        //        });
        //    mockListItem.saveFields('integer')
        //        .then(function (response) {
        //
        //        }, function (err) {
        //            expect(_.isString(err)).toBeTrue();
        //        });
        //    $httpBackend.flush();
        //});

    });

    describe('Method: getAttachmentCollection', function () {
        it('returns an array of attachments for the list item', function () {
            //mockXMLService.xhrStub('getAttachmentCollection');
            mockListItem.getAttachmentCollection()
                .then(function (response) {
                    expect(response.length).toEqual(1);
                });
            $httpBackend.flush();
        });
    });

    describe('Method: deleteAttachment', function () {
        it('resolves the promise when deleted', function () {
            //mockXMLService.xhrStub('deleteAttachment');
            mockListItem.deleteAttachment(mockListItem.attachments[0])
                .then(function (response) {
                    expect(response).toBeDefined();
                });
            $httpBackend.flush();
        });
    });

    describe('Method: getFieldVersionHistory', function () {
        it('parses the version history for a field and returns all 3 versions', function () {
            //mockXMLService.xhrStub('GetVersionCollection');
            mockListItem.getFieldVersionHistory('integer')
                .then(function (response) {
                    expect(response.length).toEqual(3);
                });
            $httpBackend.flush();
        });
        it('works without passing any any fields to dynamically build field array', function () {
            //mockXMLService.xhrStub('GetVersionCollection');
            mockListItem.getFieldVersionHistory()
                .then(function (response) {
                    expect(response.length).toEqual(3);
                });
            $httpBackend.flush();
        });
    });

});
<|endoftext|>


<commit_before>import SPELLS from 'common/SPELLS';

import Module from 'Parser/Core/Module';

const debug = true;

class Atonement extends Module {
    healing = 0;
    totalAtones = 0;
  hasContrition = false;
  currentAtonementTargets = [];
  improperAtonementRefreshes = [];

  get atonementDuration() {
    return 15 + (this.hasContrition ? 3 : 0);
  }

  get numAtonementsActive(){
      return this.currentAtonementTargets.length;
  }
  on_initialized() {
      this.active = true;
    if (!this.owner.error) {
      this.hasContrition = this.owner.selectedCombatant.lv75Talent === SPELLS.CONTRITION_TALENT.id;
    }
  }

  on_byPlayer_applybuff(event) {
    const spellId = event.ability.guid;
    if (spellId !== SPELLS.ATONEMENT.id) {
      return;
    }

    var atonement = {
        target: event.targetID,
        lastAtonmentAppliedTimestamp: event.timestamp
    };
    this.currentAtonementTargets = this.currentAtonementTargets.filter(id => id.target !== atonement.target);
    this.currentAtonementTargets.push(atonement);
    this.totalAtones++;
    debug && console.log(`%c${this.owner.combatants.players[atonement.target].name} gained an atonement`, 'color:green', this.currentAtonementTargets);
    this.owner.triggerEvent('atonement_applied', event);

  }
  on_byPlayer_refreshbuff(event) {
    const spellId = event.ability.guid;
    if (spellId !== SPELLS.ATONEMENT.id) {
      return;
    }

    var atonement = {
        target: event.targetID,
        lastAtonmentAppliedTimestamp: event.timestamp
    };
    var refreshedTarget = this.currentAtonementTargets.find(id => id.target == atonement.target) || {};
    if (refreshedTarget == null){
        refreshedTarget.target = event.targetID;
        refreshedTarget.lastAtonmentAppliedTimestamp = this.owner.fight.start_time;
        debug && console.warn('Atonement: was applied prior to combat');
    }
    if ((event.timestamp - refreshedTarget.lastAtonmentAppliedTimestamp) < this.atonementDuration * 1000 - 3000) {
        this.improperAtonementRefreshes.push(refreshedTarget)
        debug && console.log(`%c${this.owner.combatants.players[atonement.target].name} refreshed an atonement too early %c${event.timestamp - refreshedTarget.lastAtonmentAppliedTimestamp}`, 'color:red', this.currentAtonementTargets);
    this.owner.triggerEvent('atonement_refresh_improper', event);
    }
    this.currentAtonementTargets = this.currentAtonementTargets.filter(id => id.target !== atonement.target);
    this.currentAtonementTargets.push(atonement);
    this.totalAtones++;
    debug && console.log(`%c${this.owner.combatants.players[atonement.target].name} refreshed an atonement`, 'color:green', this.currentAtonementTargets);
    this.owner.triggerEvent('atonement_refresh', event);
  }

    on_byPlayer_removebuff(event) {
    const spellId = event.ability.guid;
    if (spellId !== SPELLS.ATONEMENT.id) {
      return;
    }
    var atonement = {
        target: event.targetID,
        lastAtonmentAppliedTimestamp: event.timestamp
    };
    this.currentAtonementTargets = this.currentAtonementTargets.filter(id => id.target !== atonement.target);
    debug && console.log(`%c${this.owner.combatants.players[atonement.target].name} lost an atonement`, 'color:yellow', this.currentAtonementTargets);
    this.owner.triggerEvent('atonement_faded', event);
  }

  on_byPlayer_heal(event) {
    const spellId = event.ability.guid;
    if (spellId !== SPELLS.ATONEMENT.id) {
      return;
    }
    // if (!this.owner.toPlayer(event)) {
    //   return;
    // }
    if (this.lastAtonmentAppliedTimestamp === null) {
      // This can be `null` when Atonement wasn't applied in the combatlog. This often happens as Discs like to apply Atonement prior to combat.
      this.lastAtonmentAppliedTimestamp = this.owner.fight.start_time;
      debug && console.warn('Atonement: was applied prior to combat');
    }

    if ((event.timestamp - this.lastAtonmentAppliedTimestamp) < (this.atonementDuration * 1000)) {
      return;
    }

    debug && console.log('Atonement:', event.amount + (event.absorbed || 0), 'healing done to', event.targetID);
    this.healing += event.amount + (event.absorbed || 0);
  }
}

export default Atonement;
<commit_msg>Fix eslint / code style issues<commit_after>import SPELLS from 'common/SPELLS';

import Module from 'Parser/Core/Module';

const debug = true;

class Atonement extends Module {
  healing = 0;
  totalAtones = 0;
  hasContrition = false;
  currentAtonementTargets = [];
  improperAtonementRefreshes = [];

  get atonementDuration() {
    return 15 + (this.hasContrition ? 3 : 0);
  }

  get numAtonementsActive() {
    return this.currentAtonementTargets.length;
  }

  on_initialized() {
    this.active = true;
    if (!this.owner.error) {
      this.hasContrition = this.owner.selectedCombatant.lv75Talent === SPELLS.CONTRITION_TALENT.id;
    }
  }

  on_byPlayer_applybuff(event) {
    const spellId = event.ability.guid;
    if (spellId !== SPELLS.ATONEMENT.id) {
      return;
    }

    const atonement = {
      target: event.targetID,
      lastAtonmentAppliedTimestamp: event.timestamp
    };
    this.currentAtonementTargets = this.currentAtonementTargets.filter(id => id.target !== atonement.target);
    this.currentAtonementTargets.push(atonement);
    this.totalAtones++;
    debug && console.log(`%c${this.owner.combatants.players[atonement.target].name} gained an atonement`, 'color:green', this.currentAtonementTargets);
    this.owner.triggerEvent('atonement_applied', event);
  }
  on_byPlayer_refreshbuff(event) {
    const spellId = event.ability.guid;
    if (spellId !== SPELLS.ATONEMENT.id) {
      return;
    }

    const atonement = {
      target: event.targetID,
      lastAtonmentAppliedTimestamp: event.timestamp
    };
    let refreshedTarget = this.currentAtonementTargets.find(id => id.target === atonement.target);
    if (!refreshedTarget) {
      refreshedTarget = {
        target: event.targetID,
        lastAtonmentAppliedTimestamp: this.owner.fight.start_time,
      };
      debug && console.warn('Atonement: was applied prior to combat');
    }
    if ((event.timestamp - refreshedTarget.lastAtonmentAppliedTimestamp) < this.atonementDuration * 1000 - 3000) {
      this.improperAtonementRefreshes.push(refreshedTarget);
      debug && console.log(`%c${this.owner.combatants.players[atonement.target].name} refreshed an atonement too early %c${event.timestamp - refreshedTarget.lastAtonmentAppliedTimestamp}`, 'color:red', this.currentAtonementTargets);
      this.owner.triggerEvent('atonement_refresh_improper', event);
    }
    this.currentAtonementTargets = this.currentAtonementTargets.filter(id => id.target !== atonement.target);
    this.currentAtonementTargets.push(atonement);
    this.totalAtones++;
    debug && console.log(`%c${this.owner.combatants.players[atonement.target].name} refreshed an atonement`, 'color:green', this.currentAtonementTargets);
    this.owner.triggerEvent('atonement_refresh', event);
  }
  on_byPlayer_removebuff(event) {
    const spellId = event.ability.guid;
    if (spellId !== SPELLS.ATONEMENT.id) {
      return;
    }
    const atonement = {
      target: event.targetID,
      lastAtonmentAppliedTimestamp: event.timestamp
    };
    this.currentAtonementTargets = this.currentAtonementTargets.filter(id => id.target !== atonement.target);
    debug && console.log(`%c${this.owner.combatants.players[atonement.target].name} lost an atonement`, 'color:yellow', this.currentAtonementTargets);
    this.owner.triggerEvent('atonement_faded', event);
  }

  on_byPlayer_heal(event) {
    const spellId = event.ability.guid;
    if (spellId !== SPELLS.ATONEMENT.id) {
      return;
    }
    // if (!this.owner.toPlayer(event)) {
    //   return;
    // }
    if (this.lastAtonmentAppliedTimestamp === null) {
      // This can be `null` when Atonement wasn't applied in the combatlog. This often happens as Discs like to apply Atonement prior to combat.
      this.lastAtonmentAppliedTimestamp = this.owner.fight.start_time;
      debug && console.warn('Atonement: was applied prior to combat');
    }

    if ((event.timestamp - this.lastAtonmentAppliedTimestamp) < (this.atonementDuration * 1000)) {
      return;
    }

    debug && console.log('Atonement:', event.amount + (event.absorbed || 0), 'healing done to', event.targetID);
    this.healing += event.amount + (event.absorbed || 0);
  }
}

export default Atonement;
<|endoftext|>


<commit_before>import React from 'react';
import Cookies from "js-cookie";

class RetireForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      submitSuccess: false,
      retirementDate: null,
      reason: null,
      isDead: false,
      vacantSeat: false,
    }
    this.handleInputChange = this.handleInputChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

  handleSubmit(event) {
    const csrftoken = Cookies.get("csrftoken");
    const url = "/admin/people/retire/";
    const {retirementDate, reason, isDead, vacantSeat} = this.state;
    const reasoning = isDead ? 'Death' : reason;
    const retireData = {
      "name": this.props.name,
      "id": this.props.id,
      retirementDate,
      reason: reasoning,
      isDead,
      vacantSeat,
    };

    fetch(url, {
      method: "POST",
      credentials: "same-origin",
      headers: {
        "Accept": "application/json",
        "X-Requested-With": "XMLHttpRequest",
        "X-CSRFToken": csrftoken,
      },
      body: retireData,
    }).then(response => {
      this.setState({submitSuccess: true});
      return response.json();
    }).catch(error => {
      console.log(error);
    });
    event.preventDefault();
  }

  render() {
    const { submitSuccess } = this.state;

    return(

      {submitSuccess ? (

Retirement data saved successfully.

        ) : (
      <form onSubmit={this.handleSubmit}>
         Retirement Date:
          <input type="date" name="retirementDate" id="retirementDate" onChange={this.handleInputChange}/>

        Reason for Retirement:
          <input type="text" id="reason" name="reason" onChange={this.handleInputChange}/>

          Dead?
          <input
            name="isDead"
            type="checkbox"
            checked={this.state.isDead}
            onChange={this.handleInputChange} />

          Did they leave a vacancy?
          <input
            name="vacantSeat"
            type="checkbox"
            checked={this.state.vacantSeat}
            onChange={this.handleInputChange} />

        <input type="submit" className="button--primary button" value="Submit" />
      </form>
        )}

    )
  }

}

export default RetireForm;
<commit_msg>add requirement on retire form<commit_after>import React from 'react';
import Cookies from "js-cookie";

class RetireForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      submitSuccess: false,
      retirementDate: null,
      reason: null,
      isDead: false,
      vacantSeat: false,
    }
    this.handleInputChange = this.handleInputChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

  handleSubmit(event) {
    const csrftoken = Cookies.get("csrftoken");
    const url = "/admin/people/retire/";
    const {retirementDate, reason, isDead, vacantSeat} = this.state;
    const reasoning = isDead ? 'Death' : reason;
    const retireData = {
      "name": this.props.name,
      "id": this.props.id,
      retirementDate,
      reason: reasoning,
      isDead,
      vacantSeat,
    };

    fetch(url, {
      method: "POST",
      credentials: "same-origin",
      headers: {
        "Accept": "application/json",
        "X-Requested-With": "XMLHttpRequest",
        "X-CSRFToken": csrftoken,
      },
      body: retireData,
    }).then(response => {
      this.setState({submitSuccess: true});
      return response.json();
    }).catch(error => {
      console.log(error);
    });
    event.preventDefault();
  }

  render() {
    const { submitSuccess } = this.state;

    return(

      {submitSuccess ? (

Retirement data saved successfully.

        ) : (
      <form onSubmit={this.handleSubmit}>
         Retirement Date:
          <input type="date" name="retirementDate" id="retirementDate" required onChange={this.handleInputChange}/>

        Reason for Retirement:
          <input type="text" id="reason" name="reason" required onChange={this.handleInputChange}/>

          Dead?
          <input
            name="isDead"
            type="checkbox"
            checked={this.state.isDead}
            onChange={this.handleInputChange} />

          Did they leave a vacancy?
          <input
            name="vacantSeat"
            type="checkbox"
            checked={this.state.vacantSeat}
            onChange={this.handleInputChange} />

        <input type="submit" className="button--primary button" value="Submit" />
      </form>
        )}

    )
  }

}

export default RetireForm;
<|endoftext|>


<commit_before>/* jslint node: true, esnext: true */

"use strict";

//var views = require('co-views');
//const parse = require('co-body');

exports.initialize = function (manager) {

	return { * list(next) {
		this.body = Object.keys(manager.flowDefinitions).map(function(id) {
			const flow = manager.flowDefinitions[id];
			return {
				id: id,
				name: flow.name,
				description: flow.description
			};
		});

			//this.body = JSON.stringify(Object.keys(manager.flowDefinitions));
		}, * fetch(id, next) {
			//console.log(`fetch: ${id}`);
			this.body = manager.flowDefinitions[id];
		}, * delete(id, next) {
			manager.deleteFlow(id);
		}, * insert(id, next) {
			console.log("insert flow");
		}
	};
};
<commit_msg>gardening<commit_after>/* jslint node: true, esnext: true */

"use strict";

//var views = require('co-views');
//const parse = require('co-body');

exports.initialize = function (manager) {

	return { * list(next) {
		this.body = Object.keys(manager.flowDefinitions).map(function(id) {
			const flow = manager.flowDefinitions[id];
			return {
				id: id,
				name: flow.name,
				description: flow.description
			};
		});
		}, * fetch(id, next) {
			this.body = manager.flowDefinitions[id];
		}, * delete(id, next) {
			manager.deleteFlow(id);
		}, * insert(id, next) {
			console.log("insert flow");
		}
	};
};
<|endoftext|>


<commit_before>var color = require('../config/color');

exports.parseEmoticons = parseEmoticons;

var emotes = {
	':absol:': 'http://cbc.pokecommunity.com/config/emoticons/absol.png',
	':arceus:': 'http://cbc.pokecommunity.com/config/emoticons/arceus.png',
	':armycat:': 'http://cbc.pokecommunity.com/config/emoticons/armycat.png',
	':azelf:': 'http://cbc.pokecommunity.com/config/emoticons/azelf.png',
	':bidoof:': 'http://cbc.pokecommunity.com/config/emoticons/bidoof.png',
	':bowie:': 'http://cbc.pokecommunity.com/config/emoticons/bowie.png',
	':bye:': 'http://cbc.pokecommunity.com/config/emoticons/bye.gif',
	':castform:': 'http://cbc.pokecommunity.com/config/emoticons/castform.png',
	':catflip:': 'http://cbc.pokecommunity.com/config/emoticons/catflip.png',
	':charizard:': 'http://cbc.pokecommunity.com/config/emoticons/charizard.png',
	':clown:': 'http://cbc.pokecommunity.com/config/emoticons/clown.png',
	':cookie:': 'http://cbc.pokecommunity.com/config/emoticons/cookie.png',
	':dk:': 'http://cbc.pokecommunity.com/config/emoticons/dk.png',
	':electrode:': 'http://cbc.pokecommunity.com/config/emoticons/electrode.png',
	':espurr:': 'http://cbc.pokecommunity.com/config/emoticons/espurr.png',
	':flirt:': 'http://cbc.pokecommunity.com/config/emoticons/flirt.png',
	':gav:': 'http://cbc.pokecommunity.com/config/emoticons/gav.png',
	':gloom:': 'http://cbc.pokecommunity.com/config/emoticons/gloom.png',
	':growlithe:': 'http://cbc.pokecommunity.com/config/emoticons/growlithe.png',
	':hamster:': 'http://cbc.pokecommunity.com/config/emoticons/hamster.png',
	':helix:': 'http://cbc.pokecommunity.com/config/emoticons/helix.png',
	':houndoom:': 'http://cbc.pokecommunity.com/config/emoticons/houndoom.png',
	':jigglypuff:': 'http://cbc.pokecommunity.com/config/emoticons/jigglypuff.png',
	':jynx:': 'http://cbc.pokecommunity.com/config/emoticons/jynx.png',
	':kappa:': 'http://cbc.pokecommunity.com/config/emoticons/kappa.png',
	':keepo:': 'http://cbc.pokecommunity.com/config/emoticons/keepo.png',
	':kermit:': 'http://cbc.pokecommunity.com/config/emoticons/kermit.png',
	':kreygasm:': 'http://cbc.pokecommunity.com/config/emoticons/kreygasm.png',
	':lapras:': 'http://cbc.pokecommunity.com/config/emoticons/lapras.png',
	':lileep:': 'http://cbc.pokecommunity.com/config/emoticons/lileep.png',
	':ludicolo:': 'http://cbc.pokecommunity.com/config/emoticons/ludicolo.png',
	':luvdisc:': 'http://cbc.pokecommunity.com/config/emoticons/luvdisc.png',
	':magikarp:': 'http://cbc.pokecommunity.com/config/emoticons/magikarp.png',
	':meganium:': 'http://cbc.pokecommunity.com/config/emoticons/meganium.png',
	':meowstic:': 'http://cbc.pokecommunity.com/config/emoticons/meowstic.png',
	':meowsticf:': 'http://cbc.pokecommunity.com/config/emoticons/meowsticf.png',
	':metagross:': 'http://cbc.pokecommunity.com/config/emoticons/metagross.png',
	':moo:': 'http://cbc.pokecommunity.com/config/emoticons/moo.gif',
	':nw:': 'http://cbc.pokecommunity.com/config/emoticons/nw.gif',
	':oddish:': 'http://cbc.pokecommunity.com/config/emoticons/oddish.png',
	':pear:': 'http://cbc.pokecommunity.com/config/emoticons/pear.png',
	':pjsalt:': 'http://cbc.pokecommunity.com/config/emoticons/pjsalt.png',
	':pogchamp:': 'http://cbc.pokecommunity.com/config/emoticons/pogchamp.png',
	':potato:': 'http://cbc.pokecommunity.com/config/emoticons/potato.png',
	':psyduck:': 'http://cbc.pokecommunity.com/config/emoticons/psyduck.png',
	':pyoshi:': 'http://cbc.pokecommunity.com/config/emoticons/pyoshi.png',
	':seduce:': 'http://cbc.pokecommunity.com/config/emoticons/seduce.png',
	':senpai:': 'http://cbc.pokecommunity.com/config/emoticons/senpai.png',
	':sims:': 'http://cbc.pokecommunity.com/config/emoticons/sims.png',
	':slowpoke:': 'http://cbc.pokecommunity.com/config/emoticons/slowpoke.png',
	':snorlax:': 'http://cbc.pokecommunity.com/config/emoticons/snorlax.png',
	':spheal:': 'http://cbc.pokecommunity.com/config/emoticons/spheal.png',
	':sri:': 'http://cbc.pokecommunity.com/config/emoticons/sri.png',
	':strut:': 'http://cbc.pokecommunity.com/config/emoticons/strut.png',
	':suicune:': 'http://cbc.pokecommunity.com/config/emoticons/suicune.png',
	':superman:': 'http://cbc.pokecommunity.com/config/emoticons/superman.png',
	':sweep:': 'http://cbc.pokecommunity.com/config/emoticons/sweep.gif',
	':taco:': 'http://cbc.pokecommunity.com/config/emoticons/taco.png',
	':vulpix:': 'http://cbc.pokecommunity.com/config/emoticons/vulpix.png',
	':weezing:': 'http://cbc.pokecommunity.com/config/emoticons/weezing.png',
	':why:': 'http://cbc.pokecommunity.com/config/emoticons/why.png',
	':wobbuffet:': 'http://cbc.pokecommunity.com/config/emoticons/wobbuffet.png',
	':wooper:': 'http://cbc.pokecommunity.com/config/emoticons/wooper.png',
	':wynaut:': 'http://cbc.pokecommunity.com/config/emoticons/wynaut.png',
	':y:': 'http://cbc.pokecommunity.com/config/emoticons/y.png',
	':yoshi:': 'http://cbc.pokecommunity.com/config/emoticons/yoshi.png'
};

var emotesKeys = Object.keys(emotes);
var patterns = [];
var metachars = /[[\]{}()*+?.\\|^$\-,&#\s]/g;

for (var i in emotes) {
	if (emotes.hasOwnProperty(i)) {
		patterns.push('(' + i.replace(metachars, '\\$&') + ')');
	}
}
var patternRegex = new RegExp(patterns.join('|'), 'g');

/**
 * Parse emoticons in message.
 *
 * @param {String} message
 * @param {Object} room
 * @param {Object} user
 * @param {Boolean} pm - returns a string if it is in private messages
 * @returns {Boolean|String}
 */
function parseEmoticons(message, room, user, pm) {
	if (typeof message !== 'string' || (!pm && room.disableEmoticons)) return false;

	var match = false;
	var len = emotesKeys.length;

	while (len--) {
		if (message && message.indexOf(emotesKeys[len]) >= 0) {
			match = true;
			break;
		}
	}

	if (!match) return false;

	// escape HTML
	message = Tools.escapeHTML(message);

	// add emotes
	message = message.replace(patternRegex, function (match) {
		var emote = emotes[match];
		if (match === ':gav:' || match === ':kermit:' || match === ':nw:' || match === ':superman:' || match === ':sweep:' || match === ':yoshi:') return typeof emote != 'undefined' ?
			'' :
			match;
		if (match === ':bowie:') return typeof emote != 'undefined' ?
			'' :
			match;
		if (match === ':catflip:') return typeof emote != 'undefined' ?
			'' :
			match;
		if (match === ':strut:') return typeof emote != 'undefined' ?
			'' :
			match;
		return typeof emote != 'undefined' ?
			'' :
			match;
	});

	// __italics__
	message = message.replace(/\_\_([^< ](?:[^<]*?[^< ])?)\_\_(?![^<]*?<\/a)/g, '$1');

	// **bold**
	message = message.replace(/\*\*([^< ](?:[^<]*?[^< ])?)\*\*/g, '$1');

	var group = user.getIdentity().charAt(0);
	if (room.auth) group = room.auth[user.userid] || group;

	var style = "background:none;border:0;padding:0 5px 0 0;font-family:Verdana,Helvetica,Arial,sans-serif;font-size:9pt;cursor:pointer";

	message = "
" + "" + group + "" + "<button name='parseCommand' value='/user " + user.name + "' style='" + style + "'>" + "" + user.name + ":" + "</button>" + message + "
";
	if (pm) return message;

	room.addRaw(message);

	return true;
}

/**
 * Create a two column table listing emoticons.
 *
 * @return {String} emotes table
 */
function create_table() {
	var emotes_name = Object.keys(emotes);
	var emotes_list = [];
	var emotes_group_list = [];
	var len = emotes_name.length;

	for (var i = 0; i < len; i++) {
		emotes_list.push("" +
			"" +
			emotes_name[i] + "	");
	}

	var emotes_list_right = emotes_list.splice(len / 2, len / 2);

	for (var i = 0; i < len / 2; i++) {
		var emote1 = emotes_list[i],
			emote2 = emotes_list_right[i];
		if (emote2) {
			emotes_group_list.push("
" + emote1 + emote2 + "
");
		} else {
			emotes_group_list.push("
" + emote1 + "
");
		}
	}

	return "List of Emoticons" + "
" + "
" + emotes_group_list.join("") + "
" + "
";
}

var emotes_table = create_table();

exports.commands = {
	blockemote: 'blockemoticons',
	blockemotes: 'blockemoticons',
	blockemoticon: 'blockemoticons',
	blockemoticons: function (target, room, user) {
		if (user.blockEmoticons === (target || true)) return this.sendReply("You are already blocking emoticons in private messages! To unblock, use /unblockemoticons");
		user.blockEmoticons = true;
		return this.sendReply("You are now blocking emoticons in private messages.");
	},
	blockemoticonshelp: ["/blockemoticons - Blocks emoticons in private messages. Unblock them with /unblockemoticons."],

	unblockemote: 'unblockemoticons',
	unblockemotes: 'unblockemoticons',
	unblockemoticon: 'unblockemoticons',
	unblockemoticons: function (target, room, user) {
		if (!user.blockEmoticons) return this.sendReply("You are not blocking emoticons in private messages! To block, use /blockemoticons");
		user.blockEmoticons = false;
		return this.sendReply("You are no longer blocking emoticons in private messages.");
	},
	unblockemoticonshelp: ["/unblockemoticons - Unblocks emoticons in private messages. Block them with /blockemoticons."],

	emotes: 'emoticons',
	emoticon: 'emoticons',
	emoticons: function (target, room, user) {
		if (!this.canBroadcast()) return;
		this.sendReplyBox("- List of Emoticons");
	},
	emoticonshelp: ["/emoticons - Get a list of emoticons."],

	toggleemote: 'toggleemoticons',
	toggleemotes: 'toggleemoticons',
	toggleemoticons: function (target, room, user) {
		if (!this.can('declare', null, room)) return false;
		room.disableEmoticons = !room.disableEmoticons;
		this.sendReply("Disallowing emoticons is set to " + room.disableEmoticons + " in this room.");
		if (room.disableEmoticons) {
			this.add("|raw|
Emoticons are disabled!
Emoticons will not work.
");
		} else {
			this.add("|raw|
Emoticons are enabled!
Emoticons will work now.
");
		}
	},
	toggleemoticonshelp: ["/toggleemoticons - Toggle emoticons on or off."]
};
<commit_msg>Add /emote alias<commit_after>var color = require('../config/color');

exports.parseEmoticons = parseEmoticons;

var emotes = {
	':absol:': 'http://cbc.pokecommunity.com/config/emoticons/absol.png',
	':arceus:': 'http://cbc.pokecommunity.com/config/emoticons/arceus.png',
	':armycat:': 'http://cbc.pokecommunity.com/config/emoticons/armycat.png',
	':azelf:': 'http://cbc.pokecommunity.com/config/emoticons/azelf.png',
	':bidoof:': 'http://cbc.pokecommunity.com/config/emoticons/bidoof.png',
	':bowie:': 'http://cbc.pokecommunity.com/config/emoticons/bowie.png',
	':bye:': 'http://cbc.pokecommunity.com/config/emoticons/bye.gif',
	':castform:': 'http://cbc.pokecommunity.com/config/emoticons/castform.png',
	':catflip:': 'http://cbc.pokecommunity.com/config/emoticons/catflip.png',
	':charizard:': 'http://cbc.pokecommunity.com/config/emoticons/charizard.png',
	':clown:': 'http://cbc.pokecommunity.com/config/emoticons/clown.png',
	':cookie:': 'http://cbc.pokecommunity.com/config/emoticons/cookie.png',
	':dk:': 'http://cbc.pokecommunity.com/config/emoticons/dk.png',
	':electrode:': 'http://cbc.pokecommunity.com/config/emoticons/electrode.png',
	':espurr:': 'http://cbc.pokecommunity.com/config/emoticons/espurr.png',
	':flirt:': 'http://cbc.pokecommunity.com/config/emoticons/flirt.png',
	':gav:': 'http://cbc.pokecommunity.com/config/emoticons/gav.png',
	':gloom:': 'http://cbc.pokecommunity.com/config/emoticons/gloom.png',
	':growlithe:': 'http://cbc.pokecommunity.com/config/emoticons/growlithe.png',
	':hamster:': 'http://cbc.pokecommunity.com/config/emoticons/hamster.png',
	':helix:': 'http://cbc.pokecommunity.com/config/emoticons/helix.png',
	':houndoom:': 'http://cbc.pokecommunity.com/config/emoticons/houndoom.png',
	':jigglypuff:': 'http://cbc.pokecommunity.com/config/emoticons/jigglypuff.png',
	':jynx:': 'http://cbc.pokecommunity.com/config/emoticons/jynx.png',
	':kappa:': 'http://cbc.pokecommunity.com/config/emoticons/kappa.png',
	':keepo:': 'http://cbc.pokecommunity.com/config/emoticons/keepo.png',
	':kermit:': 'http://cbc.pokecommunity.com/config/emoticons/kermit.png',
	':kreygasm:': 'http://cbc.pokecommunity.com/config/emoticons/kreygasm.png',
	':lapras:': 'http://cbc.pokecommunity.com/config/emoticons/lapras.png',
	':lileep:': 'http://cbc.pokecommunity.com/config/emoticons/lileep.png',
	':ludicolo:': 'http://cbc.pokecommunity.com/config/emoticons/ludicolo.png',
	':luvdisc:': 'http://cbc.pokecommunity.com/config/emoticons/luvdisc.png',
	':magikarp:': 'http://cbc.pokecommunity.com/config/emoticons/magikarp.png',
	':meganium:': 'http://cbc.pokecommunity.com/config/emoticons/meganium.png',
	':meowstic:': 'http://cbc.pokecommunity.com/config/emoticons/meowstic.png',
	':meowsticf:': 'http://cbc.pokecommunity.com/config/emoticons/meowsticf.png',
	':metagross:': 'http://cbc.pokecommunity.com/config/emoticons/metagross.png',
	':moo:': 'http://cbc.pokecommunity.com/config/emoticons/moo.gif',
	':nw:': 'http://cbc.pokecommunity.com/config/emoticons/nw.gif',
	':oddish:': 'http://cbc.pokecommunity.com/config/emoticons/oddish.png',
	':pear:': 'http://cbc.pokecommunity.com/config/emoticons/pear.png',
	':pjsalt:': 'http://cbc.pokecommunity.com/config/emoticons/pjsalt.png',
	':pogchamp:': 'http://cbc.pokecommunity.com/config/emoticons/pogchamp.png',
	':potato:': 'http://cbc.pokecommunity.com/config/emoticons/potato.png',
	':psyduck:': 'http://cbc.pokecommunity.com/config/emoticons/psyduck.png',
	':pyoshi:': 'http://cbc.pokecommunity.com/config/emoticons/pyoshi.png',
	':seduce:': 'http://cbc.pokecommunity.com/config/emoticons/seduce.png',
	':senpai:': 'http://cbc.pokecommunity.com/config/emoticons/senpai.png',
	':sims:': 'http://cbc.pokecommunity.com/config/emoticons/sims.png',
	':slowpoke:': 'http://cbc.pokecommunity.com/config/emoticons/slowpoke.png',
	':snorlax:': 'http://cbc.pokecommunity.com/config/emoticons/snorlax.png',
	':spheal:': 'http://cbc.pokecommunity.com/config/emoticons/spheal.png',
	':sri:': 'http://cbc.pokecommunity.com/config/emoticons/sri.png',
	':strut:': 'http://cbc.pokecommunity.com/config/emoticons/strut.png',
	':suicune:': 'http://cbc.pokecommunity.com/config/emoticons/suicune.png',
	':superman:': 'http://cbc.pokecommunity.com/config/emoticons/superman.png',
	':sweep:': 'http://cbc.pokecommunity.com/config/emoticons/sweep.gif',
	':taco:': 'http://cbc.pokecommunity.com/config/emoticons/taco.png',
	':vulpix:': 'http://cbc.pokecommunity.com/config/emoticons/vulpix.png',
	':weezing:': 'http://cbc.pokecommunity.com/config/emoticons/weezing.png',
	':why:': 'http://cbc.pokecommunity.com/config/emoticons/why.png',
	':wobbuffet:': 'http://cbc.pokecommunity.com/config/emoticons/wobbuffet.png',
	':wooper:': 'http://cbc.pokecommunity.com/config/emoticons/wooper.png',
	':wynaut:': 'http://cbc.pokecommunity.com/config/emoticons/wynaut.png',
	':y:': 'http://cbc.pokecommunity.com/config/emoticons/y.png',
	':yoshi:': 'http://cbc.pokecommunity.com/config/emoticons/yoshi.png'
};

var emotesKeys = Object.keys(emotes);
var patterns = [];
var metachars = /[[\]{}()*+?.\\|^$\-,&#\s]/g;

for (var i in emotes) {
	if (emotes.hasOwnProperty(i)) {
		patterns.push('(' + i.replace(metachars, '\\$&') + ')');
	}
}
var patternRegex = new RegExp(patterns.join('|'), 'g');

/**
 * Parse emoticons in message.
 *
 * @param {String} message
 * @param {Object} room
 * @param {Object} user
 * @param {Boolean} pm - returns a string if it is in private messages
 * @returns {Boolean|String}
 */
function parseEmoticons(message, room, user, pm) {
	if (typeof message !== 'string' || (!pm && room.disableEmoticons)) return false;

	var match = false;
	var len = emotesKeys.length;

	while (len--) {
		if (message && message.indexOf(emotesKeys[len]) >= 0) {
			match = true;
			break;
		}
	}

	if (!match) return false;

	// escape HTML
	message = Tools.escapeHTML(message);

	// add emotes
	message = message.replace(patternRegex, function (match) {
		var emote = emotes[match];
		if (match === ':gav:' || match === ':kermit:' || match === ':nw:' || match === ':superman:' || match === ':sweep:' || match === ':yoshi:') return typeof emote != 'undefined' ?
			'' :
			match;
		if (match === ':bowie:') return typeof emote != 'undefined' ?
			'' :
			match;
		if (match === ':catflip:') return typeof emote != 'undefined' ?
			'' :
			match;
		if (match === ':strut:') return typeof emote != 'undefined' ?
			'' :
			match;
		return typeof emote != 'undefined' ?
			'' :
			match;
	});

	// __italics__
	message = message.replace(/\_\_([^< ](?:[^<]*?[^< ])?)\_\_(?![^<]*?<\/a)/g, '$1');

	// **bold**
	message = message.replace(/\*\*([^< ](?:[^<]*?[^< ])?)\*\*/g, '$1');

	var group = user.getIdentity().charAt(0);
	if (room.auth) group = room.auth[user.userid] || group;

	var style = "background:none;border:0;padding:0 5px 0 0;font-family:Verdana,Helvetica,Arial,sans-serif;font-size:9pt;cursor:pointer";

	message = "
" + "" + group + "" + "<button name='parseCommand' value='/user " + user.name + "' style='" + style + "'>" + "" + user.name + ":" + "</button>" + message + "
";
	if (pm) return message;

	room.addRaw(message);

	return true;
}

/**
 * Create a two column table listing emoticons.
 *
 * @return {String} emotes table
 */
function create_table() {
	var emotes_name = Object.keys(emotes);
	var emotes_list = [];
	var emotes_group_list = [];
	var len = emotes_name.length;

	for (var i = 0; i < len; i++) {
		emotes_list.push("" +
			"" +
			emotes_name[i] + "	");
	}

	var emotes_list_right = emotes_list.splice(len / 2, len / 2);

	for (var i = 0; i < len / 2; i++) {
		var emote1 = emotes_list[i],
			emote2 = emotes_list_right[i];
		if (emote2) {
			emotes_group_list.push("
" + emote1 + emote2 + "
");
		} else {
			emotes_group_list.push("
" + emote1 + "
");
		}
	}

	return "List of Emoticons" + "
" + "
" + emotes_group_list.join("") + "
" + "
";
}

var emotes_table = create_table();

exports.commands = {
	blockemote: 'blockemoticons',
	blockemotes: 'blockemoticons',
	blockemoticon: 'blockemoticons',
	blockemoticons: function (target, room, user) {
		if (user.blockEmoticons === (target || true)) return this.sendReply("You are already blocking emoticons in private messages! To unblock, use /unblockemoticons");
		user.blockEmoticons = true;
		return this.sendReply("You are now blocking emoticons in private messages.");
	},
	blockemoticonshelp: ["/blockemoticons - Blocks emoticons in private messages. Unblock them with /unblockemoticons."],

	unblockemote: 'unblockemoticons',
	unblockemotes: 'unblockemoticons',
	unblockemoticon: 'unblockemoticons',
	unblockemoticons: function (target, room, user) {
		if (!user.blockEmoticons) return this.sendReply("You are not blocking emoticons in private messages! To block, use /blockemoticons");
		user.blockEmoticons = false;
		return this.sendReply("You are no longer blocking emoticons in private messages.");
	},
	unblockemoticonshelp: ["/unblockemoticons - Unblocks emoticons in private messages. Block them with /blockemoticons."],

	emote: 'emoticons',
	emotes: 'emoticons',
	emoticon: 'emoticons',
	emoticons: function (target, room, user) {
		if (!this.canBroadcast()) return;
		this.sendReplyBox("- List of Emoticons");
	},
	emoticonshelp: ["/emoticons - Get a list of emoticons."],

	toggleemote: 'toggleemoticons',
	toggleemotes: 'toggleemoticons',
	toggleemoticons: function (target, room, user) {
		if (!this.can('declare', null, room)) return false;
		room.disableEmoticons = !room.disableEmoticons;
		this.sendReply("Disallowing emoticons is set to " + room.disableEmoticons + " in this room.");
		if (room.disableEmoticons) {
			this.add("|raw|
Emoticons are disabled!
Emoticons will not work.
");
		} else {
			this.add("|raw|
Emoticons are enabled!
Emoticons will work now.
");
		}
	},
	toggleemoticonshelp: ["/toggleemoticons - Toggle emoticons on or off."]
};
<|endoftext|>


<commit_before>/* eslint-disable jsx-a11y/alt-text */
import React from 'react';
import {shallow} from 'enzyme';

import {BareCommitView} from '../../../lib/views/timeline-items/commit-view';

describe('CommitView', function() {
  it('prefers displaying usernames from `user.login`', function() {
    const item = {
      author: {
        name: 'author_name', avatarUrl: '',
        user: {
          login: 'author_login',
        },
      },
      committer: {
        name: 'committer_name', avatarUrl: '',
        user: {
          login: 'committer_login',
        },
      },
      sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5',
      message: 'commit message',
      messageHeadlineHTML: '
html
',
      commitURL: 'https://github.com/aaa/bbb/commit/123abc',
    };
    const app = <BareCommitView item={item} />;
    const instance = shallow(app);
    assert.isTrue(
      instance.containsMatchingElement(),
    );
    assert.isTrue(
      instance.containsMatchingElement(),
    );
  });

  it('displays the names if the are no usernames ', function() {
    const item = {
      author: {
        name: 'author_name', avatarUrl: '',
        user: null,
      },
      committer: {
        name: 'committer_name', avatarUrl: '',
        user: null,
      },
      sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5',
      authoredByCommitter: false,
      message: 'commit message',
      messageHeadlineHTML: '
html
',
      commitURL: 'https://github.com/aaa/bbb/commit/123abc',
    };
    const app = <BareCommitView item={item} />;
    const instance = shallow(app);
    assert.isTrue(
      instance.containsMatchingElement(),
    );
    assert.isTrue(
      instance.containsMatchingElement(),
    );
  });

  it('ignores committer when it authored by the same person', function() {
    const item = {
      author: {
        name: 'author_name', avatarUrl: '',
        user: {
          login: 'author_login',
        },
      },
      committer: {
        name: 'author_name', avatarUrl: '',
        user: null,
      },
      sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5',
      authoredByCommitter: true,
      message: 'commit message',
      messageHeadlineHTML: '
html
',
      commitURL: 'https://github.com/aaa/bbb/commit/123abc',
    };
    const app = <BareCommitView item={item} />;
    const instance = shallow(app);
    assert.isTrue(
      instance.containsMatchingElement(),
    );
    assert.isFalse(
      instance.containsMatchingElement(),
    );
  });

  it('ignores the committer when it is authored by GitHub', function() {
    const item = {
      author: {
        name: 'author_name', avatarUrl: '',
        user: {
          login: 'author_login',
        },
      },
      committer: {
        name: 'GitHub', avatarUrl: '',
        user: null,
      },
      sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5',
      authoredByCommitter: false,
      message: 'commit message',
      messageHeadlineHTML: '
html
',
      commitURL: 'https://github.com/aaa/bbb/commit/123abc',
    };
    const app = <BareCommitView item={item} />;
    const instance = shallow(app);
    assert.isTrue(
      instance.containsMatchingElement(),
    );
    assert.isFalse(
      instance.containsMatchingElement(),
    );
  });

  it('ignores the committer when it uses the GitHub no-reply address', function() {
    const item = {
      author: {
        name: 'author_name', avatarUrl: '',
        user: {
          login: 'author_login',
        },
      },
      committer: {
        name: 'Someone', email: 'noreply@github.com', avatarUrl: '',
        user: null,
      },
      sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5',
      authoredByCommitter: false,
      message: 'commit message',
      messageHeadlineHTML: '
html
',
      commitURL: 'https://github.com/aaa/bbb/commit/123abc',
    };
    const app = <BareCommitView item={item} />;
    const instance = shallow(app);
    assert.isTrue(
      instance.containsMatchingElement(),
    );
    assert.isFalse(
      instance.containsMatchingElement(),
    );
  });

  it('renders avatar URLs', function() {
    const item = {
      author: {
        name: 'author_name', avatarUrl: 'URL1',
        user: {
          login: 'author_login',
        },
      },
      committer: {
        name: 'GitHub', avatarUrl: 'URL2',
        user: {
          login: 'committer_login',
        },
      },
      sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5',
      authoredByCommitter: false,
      message: 'commit message',
      messageHeadlineHTML: '
html
',
      commitURL: 'https://github.com/aaa/bbb/commit/123abc',
    };
    const app = <BareCommitView item={item} />;
    const instance = shallow(app);
    assert.isTrue(
      instance.containsMatchingElement(),
    );
    assert.isTrue(
      instance.containsMatchingElement(),
    );
  });

  it('shows the full commit message as tooltip', function() {
    const item = {
      author: {
        name: 'author_name', avatarUrl: '',
        user: {
          login: 'author_login',
        },
      },
      committer: {
        name: 'author_name', avatarUrl: '',
        user: null,
      },
      sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5',
      authoredByCommitter: true,
      message: 'full message',
      messageHeadlineHTML: '
html
',
      commitURL: 'https://github.com/aaa/bbb/commit/123abc',
    };
    const app = <BareCommitView item={item} />;
    const instance = shallow(app);
    assert.isTrue(
      instance.containsMatchingElement(),
    );
  });

  it('renders commit message headline', function() {
    const item = {
      author: {
        name: 'author_name', avatarUrl: '',
        user: {
          login: 'author_login',
        },
      },
      committer: {
        name: 'author_name', avatarUrl: '',
        user: null,
      },
      sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5',
      authoredByCommitter: true,
      message: 'full message',
      messageHeadlineHTML: '
inner HTML
',
      commitURL: 'https://github.com/aaa/bbb/commit/123abc',
    };
    const app = <BareCommitView item={item} />;
    const instance = shallow(app);
    assert.match(instance.html(), /
inner HTML<\/h1>/);
  });

  it('renders commit sha', function() {
    const item = {
      author: {
        name: 'author_name', avatarUrl: '',
        user: {
          login: 'author_login',
        },
      },
      committer: {
        name: 'author_name', avatarUrl: '',
        user: null,
      },
      sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5',
      authoredByCommitter: true,
      message: 'full message',
      messageHeadlineHTML: '
inner HTML
',
      commitURL: 'https://github.com/aaa/bbb/commit/123abc',
    };
    const app = <BareCommitView item={item} />;
    const instance = shallow(app);
    assert.match(instance.text(), /e6c80aa3/);
  });

  it('opens a CommitDetailItem on click when the commit is on a branch', function() {
    const item = {
      author: {
        name: 'author_name', avatarUrl: '',
        user: {
          login: 'author_login',
        },
      },
      committer: {
        name: 'author_name', avatarUrl: '',
        user: null,
      },
      sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5',
      authoredByCommitter: true,
      message: 'full message',
      messageHeadlineHTML: '
inner HTML
',
      commitURL: 'https://github.com/aaa/bbb/commit/123abc',
    };

    const openCommit = sinon.spy();
    const app = <BareCommitView item={item} onBranch={true} openCommit={openCommit} />;
    const wrapper = shallow(app);

    assert.isTrue(wrapper.find('.commit-message-headline button').exists());

    wrapper.find('.commit-message-headline button').simulate('click');
    assert.isTrue(openCommit.calledWith({sha: item.sha}));
  });

  it('renders the message headline as a span when the commit is not on a branch', function() {
    const item = {
      author: {
        name: 'author_name', avatarUrl: '',
        user: {
          login: 'author_login',
        },
      },
      committer: {
        name: 'author_name', avatarUrl: '',
        user: null,
      },
      sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5',
      authoredByCommitter: true,
      message: 'full message',
      messageHeadlineHTML: '
inner HTML
',
      commitURL: 'https://github.com/aaa/bbb/commit/123abc',
    };

    const openCommit = sinon.spy();
    const app = <BareCommitView item={item} onBranch={false} openCommit={openCommit} />;
    const wrapper = shallow(app);

    assert.isTrue(wrapper.find('.commit-message-headline span').exists());
    assert.isFalse(wrapper.find('.commit-message-headline button').exists());
  });
});
<commit_msg>fix commit-view tests<commit_after>/* eslint-disable jsx-a11y/alt-text */
import React from 'react';
import {shallow} from 'enzyme';

import {BareCommitView} from '../../../lib/views/timeline-items/commit-view';

describe('CommitView', function() {
  it('prefers displaying usernames from `user.login`', function() {
    const commit = {
      author: {
        name: 'author_name', avatarUrl: '',
        user: {
          login: 'author_login',
        },
      },
      committer: {
        name: 'committer_name', avatarUrl: '',
        user: {
          login: 'committer_login',
        },
      },
      sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5',
      message: 'commit message',
      messageHeadlineHTML: '
html
',
      commitURL: 'https://github.com/aaa/bbb/commit/123abc',
    };
    const app = <BareCommitView commit={commit} />;
    const instance = shallow(app);
    assert.isTrue(
      instance.containsMatchingElement(),
    );
    assert.isTrue(
      instance.containsMatchingElement(),
    );
  });

  it('displays the names if the are no usernames ', function() {
    const commit = {
      author: {
        name: 'author_name', avatarUrl: '',
        user: null,
      },
      committer: {
        name: 'committer_name', avatarUrl: '',
        user: null,
      },
      sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5',
      authoredByCommitter: false,
      message: 'commit message',
      messageHeadlineHTML: '
html
',
      commitURL: 'https://github.com/aaa/bbb/commit/123abc',
    };
    const app = <BareCommitView commit={commit} onBranch={false} />;
    const instance = shallow(app);
    assert.isTrue(
      instance.containsMatchingElement(),
    );
    assert.isTrue(
      instance.containsMatchingElement(),
    );
  });

  it('ignores committer when it authored by the same person', function() {
    const commit = {
      author: {
        name: 'author_name', avatarUrl: '',
        user: {
          login: 'author_login',
        },
      },
      committer: {
        name: 'author_name', avatarUrl: '',
        user: null,
      },
      sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5',
      authoredByCommitter: true,
      message: 'commit message',
      messageHeadlineHTML: '
html
',
      commitURL: 'https://github.com/aaa/bbb/commit/123abc',
    };
    const app = <BareCommitView commit={commit} />;
    const instance = shallow(app);
    assert.isTrue(
      instance.containsMatchingElement(),
    );
    assert.isFalse(
      instance.containsMatchingElement(),
    );
  });

  it('ignores the committer when it is authored by GitHub', function() {
    const commit = {
      author: {
        name: 'author_name', avatarUrl: '',
        user: {
          login: 'author_login',
        },
      },
      committer: {
        name: 'GitHub', avatarUrl: '',
        user: null,
      },
      sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5',
      authoredByCommitter: false,
      message: 'commit message',
      messageHeadlineHTML: '
html
',
      commitURL: 'https://github.com/aaa/bbb/commit/123abc',
    };
    const app = <BareCommitView commit={commit} />;
    const instance = shallow(app);
    assert.isTrue(
      instance.containsMatchingElement(),
    );
    assert.isFalse(
      instance.containsMatchingElement(),
    );
  });

  it('ignores the committer when it uses the GitHub no-reply address', function() {
    const commit = {
      author: {
        name: 'author_name', avatarUrl: '',
        user: {
          login: 'author_login',
        },
      },
      committer: {
        name: 'Someone', email: 'noreply@github.com', avatarUrl: '',
        user: null,
      },
      sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5',
      authoredByCommitter: false,
      message: 'commit message',
      messageHeadlineHTML: '
html
',
      commitURL: 'https://github.com/aaa/bbb/commit/123abc',
    };
    const app = <BareCommitView commit={commit} />;
    const instance = shallow(app);
    assert.isTrue(
      instance.containsMatchingElement(),
    );
    assert.isFalse(
      instance.containsMatchingElement(),
    );
  });

  it('renders avatar URLs', function() {
    const commit = {
      author: {
        name: 'author_name', avatarUrl: 'URL1',
        user: {
          login: 'author_login',
        },
      },
      committer: {
        name: 'GitHub', avatarUrl: 'URL2',
        user: {
          login: 'committer_login',
        },
      },
      sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5',
      authoredByCommitter: false,
      message: 'commit message',
      messageHeadlineHTML: '
html
',
      commitURL: 'https://github.com/aaa/bbb/commit/123abc',
    };
    const app = <BareCommitView commit={commit} />;
    const instance = shallow(app);
    assert.isTrue(
      instance.containsMatchingElement(),
    );
    assert.isTrue(
      instance.containsMatchingElement(),
    );
  });

  it('shows the full commit message as tooltip', function() {
    const commit = {
      author: {
        name: 'author_name', avatarUrl: '',
        user: {
          login: 'author_login',
        },
      },
      committer: {
        name: 'author_name', avatarUrl: '',
        user: null,
      },
      sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5',
      authoredByCommitter: true,
      message: 'full message',
      messageHeadlineHTML: '
html
',
      commitURL: 'https://github.com/aaa/bbb/commit/123abc',
    };
    const app = <BareCommitView commit={commit} />;
    const instance = shallow(app);
    assert.isTrue(
      instance.containsMatchingElement(),
    );
  });

  it('renders commit message headline', function() {
    const commit = {
      author: {
        name: 'author_name', avatarUrl: '',
        user: {
          login: 'author_login',
        },
      },
      committer: {
        name: 'author_name', avatarUrl: '',
        user: null,
      },
      sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5',
      authoredByCommitter: true,
      message: 'full message',
      messageHeadlineHTML: '
inner HTML
',
      commitURL: 'https://github.com/aaa/bbb/commit/123abc',
    };
    const app = <BareCommitView commit={commit} />;
    const instance = shallow(app);
    assert.match(instance.html(), /
inner HTML<\/h1>/);
  });

  it('renders commit sha', function() {
    const commit = {
      author: {
        name: 'author_name', avatarUrl: '',
        user: {
          login: 'author_login',
        },
      },
      committer: {
        name: 'author_name', avatarUrl: '',
        user: null,
      },
      sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5',
      authoredByCommitter: true,
      message: 'full message',
      messageHeadlineHTML: '
inner HTML
',
      commitURL: 'https://github.com/aaa/bbb/commit/123abc',
    };
    const app = <BareCommitView commit={commit} />;
    const instance = shallow(app);
    assert.match(instance.text(), /e6c80aa3/);
  });

  it('opens a CommitDetailcommit on click when the commit is on a branch', function() {
    const commit = {
      author: {
        name: 'author_name', avatarUrl: '',
        user: {
          login: 'author_login',
        },
      },
      committer: {
        name: 'author_name', avatarUrl: '',
        user: null,
      },
      sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5',
      authoredByCommitter: true,
      message: 'full message',
      messageHeadlineHTML: '
inner HTML
',
      commitURL: 'https://github.com/aaa/bbb/commit/123abc',
    };

    const openCommit = sinon.spy();
    const app = <BareCommitView commit={commit} onBranch={true} openCommit={openCommit} />;
    const wrapper = shallow(app);

    assert.isTrue(wrapper.find('.commit-message-headline button').exists());

    wrapper.find('.commit-message-headline button').simulate('click');
    assert.isTrue(openCommit.calledWith({sha: commit.sha}));
  });

  it('renders the message headline as a span when the commit is not on a branch', function() {
    const commit = {
      author: {
        name: 'author_name', avatarUrl: '',
        user: {
          login: 'author_login',
        },
      },
      committer: {
        name: 'author_name', avatarUrl: '',
        user: null,
      },
      sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5',
      authoredByCommitter: true,
      message: 'full message',
      messageHeadlineHTML: '
inner HTML
',
      commitURL: 'https://github.com/aaa/bbb/commit/123abc',
    };

    const openCommit = sinon.spy();
    const app = <BareCommitView commit={commit} onBranch={false} openCommit={openCommit} />;
    const wrapper = shallow(app);

    assert.isTrue(wrapper.find('.commit-message-headline span').exists());
    assert.isFalse(wrapper.find('.commit-message-headline button').exists());
  });
});
<|endoftext|>


<commit_before>var _clone = require('lodash/lang/clone');
var _merge = require('lodash/object/merge');
var _uniqueId = require('lodash/utility/uniqueId');

var async = require('async');
var soundManager = require('../vendor/soundManager2').soundManager;

var constants = require('../constants');
var helpers = require('../helpers');
var soundcloud = require('./network/soundcloud');

soundManager.setup({
    debugMode: false,
    forceUseGlobalHTML5Audio: true
});

var AudioInterface = function(flux, parameters) {
    // Initialize configuration.
    var defaultParameters = {
        cache: true,
        volume: 100
    };

    this.parameters = _merge(defaultParameters, parameters);
    this.resolveCache = {};
    this.soundCache = {};
    this.nowPlaying = null;

    var actions = flux.actions;
    var self = this;
    var urlRegex = new RegExp(/[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/gi);

    function createSound(track, autoPlay) {
        var sound = soundManager.createSound({
            autoLoad: true,
            autoPlay: autoPlay,
            id: track.id,
            onfinish: function() {
                actions.player.audioInterface.onTrackFinish(this.id);
            },
            onload: function() {
                actions.player.audioInterface.onTrackReady(this.id);
            },
            onpause: function() {
                actions.player.audioInterface.onTrackPlayingChange(this.id, false);
            },
            onplay: function() {
                self.nowPlaying = this;
                actions.player.audioInterface.onTrackPlayStart(this.id);
            },
            onresume: function() {
                actions.player.audioInterface.onTrackPlayingChange(this.id, true);
            },
            url: track.resolved.stream_url,
            volume: self.parameters.volume,
            whileloading: function() {
                //actions.player.audioInterface.onTrackLoadAmountChange(this.id, this.bytesLoaded);
            },
            whileplaying: function() {
                actions.player.audioInterface.onTrackPlayPositionChange(this.id, this.position);
            }
        });

        return sound;
    }

    this.loadTrack = function(track, autoPlay, callback) {
        if(track.sound) {
            this.seekTrack(track, 0, true);
            track.sound._a && track.sound.setVolume(self.parameters.volume);

            if(autoPlay && (track.sound.paused || track.sound.playState === 0)) {
                track.sound.play();
            }
        }

        async.waterfall([
            function(next) {
                if(!track.resolved) {
                    return this.resolveTrack(track, next);
                } else {
                    return next(null, [track]);
                }
            }.bind(this),
            function(tracks, next) {
                var trackToPlay = tracks[0];
                var trackSound = trackToPlay.sound;

                if(!trackToPlay.error) {
                    if(!trackSound) {
                        trackToPlay.sound = createSound(trackToPlay, autoPlay);

                        async.nextTick(function() {
                            actions.player.audioInterface.onTrackSoundAdded(trackToPlay);
                        });
                    } else if(autoPlay) {
                        var oldPosition = trackSound.position;

                        trackSound.play();
                        trackSound.setPosition(oldPosition);
                    }
                }

                return next(null, trackToPlay);
            }
        ], function(err, trackToPlay) {
            if(err) {
                actions.player.audioInterface.onTrackError(trackToPlay.id, err);
            }

            if(typeof callback === 'function') {
                return callback(err);
            }
        });
    };

    this.resolveTrack = function(originalTrack, tracksPerArtist, callback) {
        var streamUrl;

        if(typeof originalTrack === 'object') {
            streamUrl = originalTrack.stream_url;
        } else if(typeof originalTrack === 'string') {
            streamUrl = originalTrack;
        } else {
            return callback('Unrecognized track passed to resolveTrack: ' + originalTrack);
        }

        if(typeof tracksPerArtist === 'function') {
            callback = tracksPerArtist;
            tracksPerArtist = 10;
        }

        if(self.parameters.cache && self.resolveCache[streamUrl]) {
            return async.nextTick(function() {
                actions.player.audioInterface.onTrackResolved(originalTrack.id, self.resolveCache[streamUrl]);

                if(typeof callback === 'function') {
                    return callback(null, self.resolveCache[streamUrl]);
                }
            });
        }

        async.waterfall([
            function(next) {
                if(streamUrl && streamUrl.search(/soundcloud\.com/i) !== -1) {
                    return soundcloud.resolve(originalTrack, tracksPerArtist, next);
                } else if(streamUrl && streamUrl.match(urlRegex)) {
                    return next(null, [{
                        stream_url: streamUrl
                    }]);
                } else {
                    return next(new Error('I don\'t know how to deal with that URL.', streamUrl));
                }
            }
        ], function(err, resolvedTracks) {
            // Since the single original track object may resolve into multiple tracks (in the case of a user or set
            // URL), we have to turn that original track into an array of new ones with new IDs.
            resolvedTracks = resolvedTracks || [originalTrack];
            resolvedTracks = resolvedTracks.map(function(resolvedTrack, index) {
                var track = _clone(originalTrack);
                var randomID = _uniqueId('track_');

                if(index === 0) {
                    track.id = originalTrack.id || randomID;
                } else {
                    track.id = randomID;
                }

                track.id = String(track.id);
                track.resolved = resolvedTrack;
                delete track.playing;

                if(err) {
                    track.error = true;

                    if(err.status === 404) {
                        track.errorMessage = 'We couldn\'t find this track.'
                    } else {
                        track.errorMessage = err.message;
                    }
                }

                return track;
            });

            if(self.parameters.cache) {
                self.resolveCache[streamUrl] = resolvedTracks;
            }

            actions.player.audioInterface.onTrackResolved(originalTrack.id, resolvedTracks);

            if(typeof callback === 'function') {
                return callback(err, resolvedTracks);
            }
        });
    };

    this.seekTrack = function(track, position, triggerTrackPlayStarted) {
        async.waterfall([
            function(next) {
                if(!track.sound) {
                    return this.loadTrack(track, true, next);
                } else {
                    return next();
                }
            }.bind(this)
        ], function(err) {
            if(err) {
                return;
            }

            track.sound.setPosition(position);
            track.sound.options.position = position;

            actions.player.audioInterface.onTrackPlayPositionChange(track.id, position);

            if(track.sound.paused || track.sound.playState === 0) {
                track.sound.play();
            }

            if(triggerTrackPlayStarted) {
                actions.player.audioInterface.onTrackPlayStart(track.id);
            }
        });
    };

    this.setVolume = function(level) {
        self.parameters.volume = level;

        if(self.nowPlaying) {
            self.nowPlaying.setVolume(level);
        }
    };

    this.togglePause = function(track, paused) {
        // Prevent soundManager from resetting the track's position.
        var currentPosition;

        if(track.sound) {
            currentPosition = track.sound.position;

            if(typeof paused === 'undefined') {
                track.sound.togglePause();
            } else if(paused) {
                track.sound.pause();
            } else {
                track.sound.play();
            }

            track.sound.setPosition(currentPosition);
        } else {
            this.loadTrack(track, true);
        }
    };

    return {
        loadTrack: this.loadTrack,
        resolveTrack: this.resolveTrack,
        seekTrack: this.seekTrack,
        setVolume: this.setVolume,
        togglePause: this.togglePause
    };
};

module.exports = AudioInterface;
<commit_msg>Revert "Revert "Made the streaming error message clearer.""<commit_after>var _clone = require('lodash/lang/clone');
var _merge = require('lodash/object/merge');
var _uniqueId = require('lodash/utility/uniqueId');

var async = require('async');
var soundManager = require('../vendor/soundManager2').soundManager;

var constants = require('../constants');
var helpers = require('../helpers');
var soundcloud = require('./network/soundcloud');

soundManager.setup({
    debugMode: false,
    forceUseGlobalHTML5Audio: true
});

var AudioInterface = function(flux, parameters) {
    // Initialize configuration.
    var defaultParameters = {
        cache: true,
        volume: 100
    };

    this.parameters = _merge(defaultParameters, parameters);
    this.resolveCache = {};
    this.soundCache = {};
    this.nowPlaying = null;

    var actions = flux.actions;
    var self = this;
    var urlRegex = new RegExp(/[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/gi);

    function createSound(track, autoPlay) {
        var sound = soundManager.createSound({
            autoLoad: true,
            autoPlay: autoPlay,
            id: track.id,
            onfinish: function() {
                actions.player.audioInterface.onTrackFinish(this.id);
            },
            onload: function() {
                actions.player.audioInterface.onTrackReady(this.id);
            },
            onpause: function() {
                actions.player.audioInterface.onTrackPlayingChange(this.id, false);
            },
            onplay: function() {
                self.nowPlaying = this;
                actions.player.audioInterface.onTrackPlayStart(this.id);
            },
            onresume: function() {
                actions.player.audioInterface.onTrackPlayingChange(this.id, true);
            },
            url: track.resolved.stream_url,
            volume: self.parameters.volume,
            whileloading: function() {
                //actions.player.audioInterface.onTrackLoadAmountChange(this.id, this.bytesLoaded);
            },
            whileplaying: function() {
                actions.player.audioInterface.onTrackPlayPositionChange(this.id, this.position);
            }
        });

        return sound;
    }

    this.loadTrack = function(track, autoPlay, callback) {
        if(track.sound) {
            this.seekTrack(track, 0, true);
            track.sound._a && track.sound.setVolume(self.parameters.volume);

            if(autoPlay && (track.sound.paused || track.sound.playState === 0)) {
                track.sound.play();
            }
        }

        async.waterfall([
            function(next) {
                if(!track.resolved) {
                    return this.resolveTrack(track, next);
                } else {
                    return next(null, [track]);
                }
            }.bind(this),
            function(tracks, next) {
                var trackToPlay = tracks[0];
                var trackSound = trackToPlay.sound;

                if(!trackToPlay.error) {
                    if(!trackSound) {
                        trackToPlay.sound = createSound(trackToPlay, autoPlay);

                        async.nextTick(function() {
                            actions.player.audioInterface.onTrackSoundAdded(trackToPlay);
                        });
                    } else if(autoPlay) {
                        var oldPosition = trackSound.position;

                        trackSound.play();
                        trackSound.setPosition(oldPosition);
                    }
                }

                return next(null, trackToPlay);
            }
        ], function(err, trackToPlay) {
            if(err) {
                actions.player.audioInterface.onTrackError(trackToPlay.id, err);
            }

            if(typeof callback === 'function') {
                return callback(err);
            }
        });
    };

    this.resolveTrack = function(originalTrack, tracksPerArtist, callback) {
        var streamUrl;

        if(typeof originalTrack === 'object') {
            streamUrl = originalTrack.stream_url;
        } else if(typeof originalTrack === 'string') {
            streamUrl = originalTrack;
        } else {
            return callback('Unrecognized track passed to resolveTrack: ' + originalTrack);
        }

        if(typeof tracksPerArtist === 'function') {
            callback = tracksPerArtist;
            tracksPerArtist = 10;
        }

        if(self.parameters.cache && self.resolveCache[streamUrl]) {
            return async.nextTick(function() {
                actions.player.audioInterface.onTrackResolved(originalTrack.id, self.resolveCache[streamUrl]);

                if(typeof callback === 'function') {
                    return callback(null, self.resolveCache[streamUrl]);
                }
            });
        }

        async.waterfall([
            function(next) {
                if(streamUrl && streamUrl.search(/soundcloud\.com/i) !== -1) {
                    return soundcloud.resolve(originalTrack, tracksPerArtist, next);
                } else if(streamUrl && streamUrl.match(urlRegex)) {
                    return next(null, [{
                        stream_url: streamUrl
                    }]);
                } else {
                    return next(new Error('I don\'t know how to deal with that URL.', streamUrl));
                }
            }
        ], function(err, resolvedTracks) {
            // Since the single original track object may resolve into multiple tracks (in the case of a user or set
            // URL), we have to turn that original track into an array of new ones with new IDs.
            resolvedTracks = resolvedTracks || [originalTrack];
            resolvedTracks = resolvedTracks.map(function(resolvedTrack, index) {
                var track = _clone(originalTrack);
                var randomID = _uniqueId('track_');

                if(index === 0) {
                    track.id = originalTrack.id || randomID;
                } else {
                    track.id = randomID;
                }

                track.id = String(track.id);
                track.resolved = resolvedTrack;
                delete track.playing;

                if(err) {
                    track.error = true;

                    if(err.status === 404) {
                        track.errorMessage = 'We can\'t stream this track.'
                    } else {
                        track.errorMessage = err.message;
                    }
                }

                return track;
            });

            if(self.parameters.cache) {
                self.resolveCache[streamUrl] = resolvedTracks;
            }

            actions.player.audioInterface.onTrackResolved(originalTrack.id, resolvedTracks);

            if(typeof callback === 'function') {
                return callback(err, resolvedTracks);
            }
        });
    };

    this.seekTrack = function(track, position, triggerTrackPlayStarted) {
        async.waterfall([
            function(next) {
                if(!track.sound) {
                    return this.loadTrack(track, true, next);
                } else {
                    return next();
                }
            }.bind(this)
        ], function(err) {
            if(err) {
                return;
            }

            track.sound.setPosition(position);
            track.sound.options.position = position;

            actions.player.audioInterface.onTrackPlayPositionChange(track.id, position);

            if(track.sound.paused || track.sound.playState === 0) {
                track.sound.play();
            }

            if(triggerTrackPlayStarted) {
                actions.player.audioInterface.onTrackPlayStart(track.id);
            }
        });
    };

    this.setVolume = function(level) {
        self.parameters.volume = level;

        if(self.nowPlaying) {
            self.nowPlaying.setVolume(level);
        }
    };

    this.togglePause = function(track, paused) {
        // Prevent soundManager from resetting the track's position.
        var currentPosition;

        if(track.sound) {
            currentPosition = track.sound.position;

            if(typeof paused === 'undefined') {
                track.sound.togglePause();
            } else if(paused) {
                track.sound.pause();
            } else {
                track.sound.play();
            }

            track.sound.setPosition(currentPosition);
        } else {
            this.loadTrack(track, true);
        }
    };

    return {
        loadTrack: this.loadTrack,
        resolveTrack: this.resolveTrack,
        seekTrack: this.seekTrack,
        setVolume: this.setVolume,
        togglePause: this.togglePause
    };
};

module.exports = AudioInterface;
<|endoftext|>