<commit_before>import { PureComponent } from 'react';
import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';

class Route extends PureComponent {
  render() {
    if (this.props.route === this.props.name) {
      return this.props.children;
    }
    return null;
  }
}

const getRoute = state => state.router.route;

const mapStateToProps = createStructuredSelector({
  route: getRoute
});

export default connect(mapStateToProps)(Route);
<commit_msg>Use functional component for Route<commit_after>import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';

const Route = ({ route, name, children }) => {
  if (route === name) {
    return children;
  }
  return null;
};

const getRoute = state => state.router.route;

const mapStateToProps = createStructuredSelector({
  route: getRoute
});

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


<commit_before>'use strict';

const assert = require('../../utils/assert.js');
const preq = require('preq');
const server = require('../../utils/server.js');

describe('mobile-sections', function() {

    this.timeout(20000);

    before(() => server.start());

    const localUri = (title, domain = 'en.wikipedia.org') => {
        return `${server.config.uri}${domain}/v1/page/mobile-sections/${title}`;
    };

    it('Mismatched title and revision id give 404', () => {
        const title = '%2Fr%2FThe_Donald';
        const rev = 752758357; // belongs to Roald Dahl
        const uri = localUri(`${title}/${rev}`);
        return preq.get({ uri })
        .catch((res) => {
            assert.equal(res.status, 404);
        });
    });

    it('Malformed revision id gives bad request', () => {
        const title = '%2Fr%2FThe_Donald'; // belongs to Roald Dahl
        const rev = 'Reddit';
        const uri = localUri(`${title}/${rev}`);
        return preq.get({ uri })
        .catch((res) => {
            assert.equal(res.status, 400, 'Should be integer');
        });
    });

    it('Missing title should respond with 404', () => {
        const uri = localUri('weoiuyrxcmxn', 'test.wikipedia.org');
        return preq.get({ uri })
        .then(() => {
            assert.fail('expected an exception to be thrown');
        }).catch((res) => {
            assert.equal(res.status, 404);
        });
    });

    it('Sections/deep page should have a lead object with expected properties', () => {
        const title = 'Sections%2Fdeep';
        const uri = localUri(title, 'test.wikipedia.org');
        return preq.get({ uri })
        .then((res) => {
            const lead = res.body.lead;
            const lastMod = lead.lastmodified;
            const prot = lead.protection;
            assert.equal(res.status, 200);
            assert.ok(lastMod.startsWith('20'), `${lastMod} should start with 20`); // 2015-
            assert.equal(lead.displaytitle, 'Sections/deep');
            assert.equal(lead.wikibase_item, undefined);
            assert.equal(lead.description, undefined);
            assert.ok(prot.constructor === Object, 'lead.protection should be an Object');
            assert.ok(!Object.keys(lead.protection).length, 'Page should not be protected');
            assert.equal(lead.editable, true);
            assert.ok(lead.sections.length >= 6, 'Expected at least six section elements');
            assert.equal(lead.sections[0].id, 0);
            assert.ok(lead.sections[0].text.length > 0, 'Expected text to be non-empty');
        });
    });

    it('en Main page should have a lead object with expected properties', () => {
        const uri = localUri('Main_Page');
        return preq.get({ uri })
            .then((res) => {
                const lead = res.body.lead;
                const lastMod = lead.lastmodified;
                assert.equal(res.status, 200);
                assert.ok(lastMod.startsWith('20'), `${lastMod} should start with 20`); // 2015-
                assert.equal(lead.displaytitle, 'Main Page');
                assert.equal(lead.normalizedtitle, 'Main Page');
                assert.equal(lead.wikibase_item, 'Q5296');
                assert.deepEqual(lead.protection, {
                    edit: [
                        'sysop'
                    ],
                    move: [
                        'sysop'
                    ]
                });
                assert.equal(lead.editable, false);
                assert.equal(lead.mainpage, true);
                assert.ok(lead.languagecount > 10);
                assert.ok(lead.sections.length > 0, 'Expected at least one section element');
                assert.equal(lead.sections[0].id, 0);
                assert.ok(lead.sections[0].text.length > 0, 'Expected text to be non-empty');
            });
    });

    it('Description from local wiki should be used', () => {
        const uri = localUri(encodeURIComponent('User:BSitzmann_(WMF)/MCS/Test/Description'),
            'test.wikipedia.org');
        return preq.get({ uri })
        .then((res) => {
            const lead = res.body.lead;
            assert.deepEqual(lead.description, 'funny description, haha');
            assert.deepEqual(lead.description_source, 'local');
        });
    });

    it('Titles with special chars should not error out when parsing pronunciation files', () => {
        const uri = localUri('Sunn_O)))', 'vi.wikipedia.org');
        return preq.get({ uri })
            .then((res) => {
                const lead = res.body.lead;
                const lastMod = lead.lastmodified;
                assert.equal(res.status, 200);
                assert.ok(lastMod.startsWith('20'), `${lastMod} should start with 20`); // 2015-
                assert.equal(lead.displaytitle, 'Sunn O)))');
                assert.equal(lead.normalizedtitle, 'Sunn O)))');
                assert.ok(lead.sections.length > 0, 'Expected at least one section element');
                assert.equal(lead.sections[0].id, 0);
                assert.ok(lead.sections[0].text.length > 0, 'Expected text to be non-empty');
            });
    });

    it("Page with known past 'text-decoration' error should load successfully", () => {
        const title = '%E6%9F%A5%E5%85%8B%C2%B7%E8%91%9B%E9%87%8C%E8%8A%AC%E7%B4%8D%E5%A5%87';
        const uri = localUri(title, 'zh.wikipedia.org');
        return preq.get({ uri })
            .then((res) => {
                assert.equal(res.status, 200);
            });
    });

    it('Beta cluster request should load successfully', () => {
        const uri = localUri('Foobar', 'en.wikipedia.beta.wmflabs.org');
        return preq.get({ uri })
            .then((res) => {
                assert.equal(res.status, 200);
            });
    });

    it('Page with irregular Spoken Wikipedia template usage should load correctly', () => {
        const filename = 'File:En-Alliterative_verse-article.ogg';
        const title = 'Alliterative_verse';
        const uri = localUri(title);
        return preq.get({ uri })
            .then((res) => {
                assert.equal(res.status, 200);
                assert.equal(res.body.lead.spoken.files[0], filename);
            });
    });

    it('Internal links should have title attribute', () => {
        const title = 'User:BSitzmann_%28WMF%29%2FMCS%2FTest%2FTitleLinkEncoding';
        const uri = localUri(title);
        const expectedText = ' {
                assert.equal(res.status, 200);
                assert.contains(res.body.lead.sections[0].text, expectedText);
            });
    });

    it('Any sections that contain references should have a reference flag', () => {
        const uri = localUri('Barack_Obama');
        const sections = [ 'Notes and references', 'Notes', 'References', 'Further reading' ];
        return preq.get({ uri })
            .then((res) => {
                assert.equal(res.status, 200);
                res.body.remaining.sections.forEach((section) => {
                    if (sections.indexOf(section.line) > -1) {
                        const ref = section.isReferenceSection === true;
                        assert.ok(ref, `${section.line} should have a reference flag`);
                    } else {
                        const noRef = section.isReferenceSection === undefined;
                        assert.ok(noRef, `${section.line} should have no reference flag`);
                    }
                });
            });
    });

    it('The last section can be marked as a reference section', () => {
        const uri = localUri('Vallejo_(ferry)');
        return preq.get({ uri })
            .then((res) => {
                assert.equal(res.status, 200);
                res.body.remaining.sections.forEach((section) => {
                    if ([ 'References' ].indexOf(section.line) > -1) {
                        const ref = section.isReferenceSection === true;
                        assert.ok(ref, `${section.line} should have a reference flag`);
                    } else {
                        const noRef = section.isReferenceSection === undefined;
                        assert.ok(noRef, `${section.line} should have no reference flag`);
                    }
                });
            });
    });

    it('Page with math formulas should load without error', () => {
        const title = 'Verallgemeinerter_Laplace-Operator';
        const uri = localUri(title, 'de.wikipedia.org');
        return preq.get({ uri })
            .then((res) => {
                assert.equal(res.status, 200);
            });
    });
});
<commit_msg>Dev: skip beta cluster test<commit_after>'use strict';

const assert = require('../../utils/assert.js');
const preq = require('preq');
const server = require('../../utils/server.js');

describe('mobile-sections', function() {

    this.timeout(20000);

    before(() => server.start());

    const localUri = (title, domain = 'en.wikipedia.org') => {
        return `${server.config.uri}${domain}/v1/page/mobile-sections/${title}`;
    };

    it('Mismatched title and revision id give 404', () => {
        const title = '%2Fr%2FThe_Donald';
        const rev = 752758357; // belongs to Roald Dahl
        const uri = localUri(`${title}/${rev}`);
        return preq.get({ uri })
        .catch((res) => {
            assert.equal(res.status, 404);
        });
    });

    it('Malformed revision id gives bad request', () => {
        const title = '%2Fr%2FThe_Donald'; // belongs to Roald Dahl
        const rev = 'Reddit';
        const uri = localUri(`${title}/${rev}`);
        return preq.get({ uri })
        .catch((res) => {
            assert.equal(res.status, 400, 'Should be integer');
        });
    });

    it('Missing title should respond with 404', () => {
        const uri = localUri('weoiuyrxcmxn', 'test.wikipedia.org');
        return preq.get({ uri })
        .then(() => {
            assert.fail('expected an exception to be thrown');
        }).catch((res) => {
            assert.equal(res.status, 404);
        });
    });

    it('Sections/deep page should have a lead object with expected properties', () => {
        const title = 'Sections%2Fdeep';
        const uri = localUri(title, 'test.wikipedia.org');
        return preq.get({ uri })
        .then((res) => {
            const lead = res.body.lead;
            const lastMod = lead.lastmodified;
            const prot = lead.protection;
            assert.equal(res.status, 200);
            assert.ok(lastMod.startsWith('20'), `${lastMod} should start with 20`); // 2015-
            assert.equal(lead.displaytitle, 'Sections/deep');
            assert.equal(lead.wikibase_item, undefined);
            assert.equal(lead.description, undefined);
            assert.ok(prot.constructor === Object, 'lead.protection should be an Object');
            assert.ok(!Object.keys(lead.protection).length, 'Page should not be protected');
            assert.equal(lead.editable, true);
            assert.ok(lead.sections.length >= 6, 'Expected at least six section elements');
            assert.equal(lead.sections[0].id, 0);
            assert.ok(lead.sections[0].text.length > 0, 'Expected text to be non-empty');
        });
    });

    it('en Main page should have a lead object with expected properties', () => {
        const uri = localUri('Main_Page');
        return preq.get({ uri })
            .then((res) => {
                const lead = res.body.lead;
                const lastMod = lead.lastmodified;
                assert.equal(res.status, 200);
                assert.ok(lastMod.startsWith('20'), `${lastMod} should start with 20`); // 2015-
                assert.equal(lead.displaytitle, 'Main Page');
                assert.equal(lead.normalizedtitle, 'Main Page');
                assert.equal(lead.wikibase_item, 'Q5296');
                assert.deepEqual(lead.protection, {
                    edit: [
                        'sysop'
                    ],
                    move: [
                        'sysop'
                    ]
                });
                assert.equal(lead.editable, false);
                assert.equal(lead.mainpage, true);
                assert.ok(lead.languagecount > 10);
                assert.ok(lead.sections.length > 0, 'Expected at least one section element');
                assert.equal(lead.sections[0].id, 0);
                assert.ok(lead.sections[0].text.length > 0, 'Expected text to be non-empty');
            });
    });

    it('Description from local wiki should be used', () => {
        const uri = localUri(encodeURIComponent('User:BSitzmann_(WMF)/MCS/Test/Description'),
            'test.wikipedia.org');
        return preq.get({ uri })
        .then((res) => {
            const lead = res.body.lead;
            assert.deepEqual(lead.description, 'funny description, haha');
            assert.deepEqual(lead.description_source, 'local');
        });
    });

    it('Titles with special chars should not error out when parsing pronunciation files', () => {
        const uri = localUri('Sunn_O)))', 'vi.wikipedia.org');
        return preq.get({ uri })
            .then((res) => {
                const lead = res.body.lead;
                const lastMod = lead.lastmodified;
                assert.equal(res.status, 200);
                assert.ok(lastMod.startsWith('20'), `${lastMod} should start with 20`); // 2015-
                assert.equal(lead.displaytitle, 'Sunn O)))');
                assert.equal(lead.normalizedtitle, 'Sunn O)))');
                assert.ok(lead.sections.length > 0, 'Expected at least one section element');
                assert.equal(lead.sections[0].id, 0);
                assert.ok(lead.sections[0].text.length > 0, 'Expected text to be non-empty');
            });
    });

    it("Page with known past 'text-decoration' error should load successfully", () => {
        const title = '%E6%9F%A5%E5%85%8B%C2%B7%E8%91%9B%E9%87%8C%E8%8A%AC%E7%B4%8D%E5%A5%87';
        const uri = localUri(title, 'zh.wikipedia.org');
        return preq.get({ uri })
            .then((res) => {
                assert.equal(res.status, 200);
            });
    });

    // TODO: remove skip
    // beta cluster is down right now
    it.skip('Beta cluster request should load successfully', () => {
        const uri = localUri('Foobar', 'en.wikipedia.beta.wmflabs.org');
        return preq.get({ uri })
            .then((res) => {
                assert.equal(res.status, 200);
            });
    });

    it('Page with irregular Spoken Wikipedia template usage should load correctly', () => {
        const filename = 'File:En-Alliterative_verse-article.ogg';
        const title = 'Alliterative_verse';
        const uri = localUri(title);
        return preq.get({ uri })
            .then((res) => {
                assert.equal(res.status, 200);
                assert.equal(res.body.lead.spoken.files[0], filename);
            });
    });

    it('Internal links should have title attribute', () => {
        const title = 'User:BSitzmann_%28WMF%29%2FMCS%2FTest%2FTitleLinkEncoding';
        const uri = localUri(title);
        const expectedText = ' {
                assert.equal(res.status, 200);
                assert.contains(res.body.lead.sections[0].text, expectedText);
            });
    });

    it('Any sections that contain references should have a reference flag', () => {
        const uri = localUri('Barack_Obama');
        const sections = [ 'Notes and references', 'Notes', 'References', 'Further reading' ];
        return preq.get({ uri })
            .then((res) => {
                assert.equal(res.status, 200);
                res.body.remaining.sections.forEach((section) => {
                    if (sections.indexOf(section.line) > -1) {
                        const ref = section.isReferenceSection === true;
                        assert.ok(ref, `${section.line} should have a reference flag`);
                    } else {
                        const noRef = section.isReferenceSection === undefined;
                        assert.ok(noRef, `${section.line} should have no reference flag`);
                    }
                });
            });
    });

    it('The last section can be marked as a reference section', () => {
        const uri = localUri('Vallejo_(ferry)');
        return preq.get({ uri })
            .then((res) => {
                assert.equal(res.status, 200);
                res.body.remaining.sections.forEach((section) => {
                    if ([ 'References' ].indexOf(section.line) > -1) {
                        const ref = section.isReferenceSection === true;
                        assert.ok(ref, `${section.line} should have a reference flag`);
                    } else {
                        const noRef = section.isReferenceSection === undefined;
                        assert.ok(noRef, `${section.line} should have no reference flag`);
                    }
                });
            });
    });

    it('Page with math formulas should load without error', () => {
        const title = 'Verallgemeinerter_Laplace-Operator';
        const uri = localUri(title, 'de.wikipedia.org');
        return preq.get({ uri })
            .then((res) => {
                assert.equal(res.status, 200);
            });
    });
});
<|endoftext|>


<commit_before>/**
 * Homebridge-Garadget
 * @ Index.js Version 0.0.3
 * @ By xNinjasx
 */
//sets get json dependent
var request = require("request");

//sets homebridge
var Service, Characteristic;
module.exports = function(homebridge) {
    Service = homebridge.hap.Service;
    Characteristic = homebridge.hap.Characteristic;
    homebridge.registerAccessory("homebridge-garadget", "Garadget", DoorAccessory);
  }
/**
 * Creates DoorAccessory
 * Sets config
 */
function DoorAccessory(log, config) {
  this.log = log; // Debug log
  this.name = config["name"]; // Name that shows up in homekit app
  this.cloudURL = config["cloudURL"]; // Grabs the Particle cloud url
  this.access_token = config["access_token"]; // Grabs your token for deviceID
  this.deviceID = config["deviceID"]; // Grabs your deviceID
  this.bypass = config["bypass"]; // Bypass trigger
  this.args = config["args"]; // For the bypass onoff state
  this.services = [];
  //Suppose to set information about Accessory
  this.informationService = new Service.AccessoryInformation();
  this.informationService
    .setCharacteristic(Characteristic.Manufacturer, "Garadget")
    .setCharacteristic(Characteristic.Model, "Photon")
    .setCharacteristic(Characteristic.SerialNumber, "AABBCCDD1");
  //Checking for bypass
  if (this.bypass === "1") {
    this.garageservice = new Service.Switch(this.name); // Makes Switch Service - you can change "Switch" to "Lightbulb"
    this.garageservice
      .getCharacteristic(Characteristic.On)
      .on('set', this.setStatebypass.bind(this));
  } else {
    this.garageservice = new Service.GarageDoorOpener(this.name);
    this.garageservice
      .getCharacteristic(Characteristic.CurrentDoorState)
      .on('get', this.getState.bind(this));
    this.garageservice
      .getCharacteristic(Characteristic.TargetDoorState)
      .on('get', this.getState.bind(this))
      .on('set', this.setState.bind(this));
    this.garageservice
      .getCharacteristic(Characteristic.ObstructionDetected)
      .on('get', this.getOD.bind(this));
  }
}
/**
 * Gets Status of the Garadget
 */
DoorAccessory.prototype.getState = function(callback) {
    this.log("Getting current state...");

    request.get({
      url: this.cloudURL + this.deviceID + '/doorStatus?access_token=' + this.access_token
    }, function(err, response, body) {
      if (!err && response.statusCode == 200) {
        var json = JSON.parse(body);
        var state = DoorAccessory.prototype.parseStatus(json.result);
        this.log("Door state is %s", state);
        var closed = state == "closed"
        callback(null, closed); // success
      } else {
        this.log("Error getting state: %s", err);
        callback(err);
      }
    }.bind(this));
  }
/**
 * Sets Status of the Garadget
 */
DoorAccessory.prototype.setState = function(state, callback) {
    this.log("state = ", state);
    switch (state) {
      case 0:
        var doorState = 'open';
        break;
      case 1:
        var doorState = 'closed';
        break;
      case 2:
        var doorState = 'stop';
        break;
      case 3:
        var doorState = 'stop';
        break;
      case 4:
        var doorState = 'open';
        break;
    };
    this.log("Set state to %s", doorState);
    request.post({
      url: this.cloudURL + this.deviceID + '/setState',
      form: {
        access_token: this.access_token,
        args: doorState
      }
    }, function(err, response, body) {

      if (!err && response.statusCode == 200) {

        this.log("State change complete.");

        var currentState = (state == Characteristic.TargetDoorState.CLOSED) ? Characteristic.CurrentDoorState.CLOSED : Characteristic.CurrentDoorState.OPEN;

        this.garageservice
          .setCharacteristic(Characteristic.CurrentDoorState, currentState);
        callback(null); // success

      } else {

        this.log("Error '%s' setting door state. Response: %s", err, body);
        callback(err || new Error("Error setting door state."));
      }
    }.bind(this));
  }
/**
 * Sets Status of the Garadget for bypass trigger
 */
DoorAccessory.prototype.setStatebypass = function(state, callback) {
    this.log("state = ", state);
    var doorState = this.args.replace("{STATE}", (state ? "open" : "closed")); //flips on/off
    this.log("Set state to %s", doorState);
    request.post({
      url: this.cloudURL + this.deviceID + '/setState',
      form: {
        access_token: this.access_token,
        args: doorState
      }
    }, function(err, response, body) {

      if (!err && response.statusCode == 200) {

        this.log("State change complete.");
        callback(null); // success

      } else {

        this.log("Error '%s' setting door state. Response: %s", err, body);
        callback(err || new Error("Error setting door state."));
      }
    }.bind(this));
  }
/**
 * Gets Status of the Garadget
 * If this fails than update your token
 * On the homekit app, you will see the Obstruction Detected = YES
 * This indicates you to update your token
 */
DoorAccessory.prototype.getOD = function(callback) {
    this.log("Get ObstructionDetected...");
    request.get({
      url: this.cloudURL + this.deviceID + '/doorStatus?access_token=' + this.access_token
    }, function(err, response, body) {
      if (!err && response.statusCode == 200) {
        callback(null, 0); // success
      } else {
        this.log("Error getting state: %s", err);
        this.log("This means your access token expired. Replace in config.json");
        callback(null, 1); // failed
      }
    }.bind(this));
  }
/**
 * Gets services
 */
DoorAccessory.prototype.getServices = function() {
    return [this.garageservice];
  }
/**
 * Parse the status out of the json file
 */
DoorAccessory.prototype.parseStatus = function(p_status) {
  var split1 = p_status.split("|")
  var split2 = split1[0].split("=")
  var a_result = split2[1]
  return a_result;
}
<commit_msg>get status on bypass / Improved get status garadget<commit_after>/**
 * Homebridge-Garadget
 * @ Index.js Version 0.0.4
 * @ By xNinjasx
 */
//sets get json dependent
var request = require("request");

//sets homebridge
var Service, Characteristic;
module.exports = function(homebridge) {
    Service = homebridge.hap.Service;
    Characteristic = homebridge.hap.Characteristic;
    homebridge.registerAccessory("homebridge-garadget", "Garadget", DoorAccessory);
  }
/**
 * Creates DoorAccessory
 * Sets config
 */
function DoorAccessory(log, config) {
  this.log = log; // Debug log
  this.name = config["name"]; // Name that shows up in homekit app
  this.cloudURL = config["cloudURL"]; // Grabs the Particle cloud url
  this.access_token = config["access_token"]; // Grabs your token for deviceID
  this.deviceID = config["deviceID"]; // Grabs your deviceID
  this.bypass = config["bypass"]; // Bypass trigger
  this.args = config["args"]; // For the bypass onoff state
  this.services = [];
  //Suppose to set information about Accessory
  this.informationService = new Service.AccessoryInformation()
    .setCharacteristic(Characteristic.Manufacturer, "Garadget")
    .setCharacteristic(Characteristic.Model, "Photon")
    .setCharacteristic(Characteristic.SerialNumber, "AABBCCDD1");
  //Checking for bypass
  if (this.bypass === "1") {
    this.garageservice = new Service.Switch(this.name); // Makes Switch Service - you can change "Switch" to "Lightbulb"
    this.garageservice
      .getCharacteristic(Characteristic.On)
      .on('set', this.setStatebypass.bind(this))
	  .on('get', this.getStatebypass.bind(this));
  } else {
    this.garageservice = new Service.GarageDoorOpener(this.name);
    this.garageservice
      .getCharacteristic(Characteristic.CurrentDoorState)
      .on('get', this.getState.bind(this));
    this.garageservice
      .getCharacteristic(Characteristic.TargetDoorState)
      .on('get', this.getState.bind(this))
      .on('set', this.setState.bind(this));
    this.garageservice
      .getCharacteristic(Characteristic.ObstructionDetected)
      .on('get', this.getOD.bind(this));
  }
}
/**
 * Gets Status of the Garadget
 */
DoorAccessory.prototype.getState = function(callback) {
    this.log("Getting current state...");

    request.get({
      url: this.cloudURL + this.deviceID + '/doorStatus?access_token=' + this.access_token
    }, function(err, response, body) {
      if (!err && response.statusCode == 200) {
        var json = JSON.parse(body);
        var currentState = DoorAccessory.prototype.parseStatus(json.result);
        this.log("Door state is %s", currentState);
        switch (currentState) {
		case 'open':
        var currentState = 0;
        break;
		case 'closed':
        var currentState = 1;
        break;
		case 'opening':
        var currentState = 2;
        break;
		case 'closing':
        var currentState = 3;
        break;
		case 'stopped':
        var currentState = 4;
        break;
		};
		callback(null, currentState); // success
      } else {
        this.log("Error getting state: %s", err);
        callback(err);
      }
    }.bind(this));
  }
/**
 * Gets Status of the Garadget for bypass trigger
 */
DoorAccessory.prototype.getStatebypass = function(callback) {
    this.log("Getting current state...");

    request.get({
      url: this.cloudURL + this.deviceID + '/doorStatus?access_token=' + this.access_token
    }, function(err, response, body) {
      if (!err && response.statusCode == 200) {
        var json = JSON.parse(body);
        var state = DoorAccessory.prototype.parseStatus(json.result);
        this.log("Bypass state is %s", state);
        switch (state) {
		case 'open':
        var bypassState = 1;
        break;
		case 'closed':
        var bypassState = 0;
        break;
		};
		this.log("bypassState = %s", bypassState);
        callback(null, bypassState); // success
      } else {
        this.log("Error getting bypass state: %s", err);
        callback(err);
      }
    }.bind(this));
  }
/**
 * Sets Status of the Garadget
 */
DoorAccessory.prototype.setState = function(state, callback) {
    this.log("state = ", state);
    switch (state) {
      case 0:
        var doorState = 'open';
        break;
      case 1:
        var doorState = 'closed';
        break;
      case 2:
        var doorState = 'stop';
        break;
      case 3:
        var doorState = 'stop';
        break;
      case 4:
        var doorState = 'open';
        break;
    };
    this.log("Set state to %s", doorState);
    request.post({
      url: this.cloudURL + this.deviceID + '/setState',
      form: {
        access_token: this.access_token,
        args: doorState
      }
    }, function(err, response, body) {

      if (!err && response.statusCode == 200) {

        this.log("State change complete.");

        var currentState = (state == Characteristic.TargetDoorState.CLOSED) ? Characteristic.CurrentDoorState.CLOSED : Characteristic.CurrentDoorState.OPEN;

        this.garageservice
          .setCharacteristic(Characteristic.CurrentDoorState, currentState);
        callback(null); // success

      } else {

        this.log("Error '%s' setting door state. Response: %s", err, body);
        callback(err || new Error("Error setting door state."));
      }
    }.bind(this));
  }
/**
 * Sets Status of the Garadget for bypass trigger
 */
DoorAccessory.prototype.setStatebypass = function(state, callback) {
    this.log("state = ", state);
    var doorState = this.args.replace("{STATE}", (state ? "open" : "closed")); //flips on/off
    this.log("Set bypass state to %s", doorState);
    request.post({
      url: this.cloudURL + this.deviceID + '/setState',
      form: {
        access_token: this.access_token,
        args: doorState
      }
    }, function(err, response, body) {

      if (!err && response.statusCode == 200) {

        this.log("State bypass change complete.");
        callback(null); // success

      } else {

        this.log("Error '%s' setting bypass state. Response: %s", err, body);
        callback(err || new Error("Error setting bypass state."));
      }
    }.bind(this));
  }
/**
 * Gets Status of the Garadget
 * If this fails than update your token
 * On the homekit app, you will see the Obstruction Detected = YES
 * This indicates you to update your token
 */
DoorAccessory.prototype.getOD = function(callback) {
    this.log("Get ObstructionDetected...");
    request.get({
      url: this.cloudURL + this.deviceID + '/doorStatus?access_token=' + this.access_token
    }, function(err, response, body) {
      if (!err && response.statusCode == 200) {
		this.log("Access Key good...");
        callback(null, 0); // success
      } else {
        this.log("Error getting state: %s", err);
        this.log("This means your access token expired. Replace in config.json");
		callback(null, 1); // failed
      }
    }.bind(this));
  }
/**
 * Gets services
 */
DoorAccessory.prototype.getServices = function() {
    return [this.garageservice];
  }
/**
 * Parse the status out of the json file
 */
DoorAccessory.prototype.parseStatus = function(p_status) {
  var split1 = p_status.split("|")
  var split2 = split1[0].split("=")
  var a_result = split2[1]
  return a_result;
}
<|endoftext|>


<commit_before>(function () {

var
  D = Flotr.DOM,
  _ = Flotr._,
  flotr = Flotr,
  S_MOUSETRACK = 'opacity:0.7;background-color:#000;color:#fff;display:none;position:absolute;padding:2px 8px;-moz-border-radius:4px;border-radius:4px;white-space:nowrap;';

Flotr.addPlugin('hit', {
  callbacks: {
    'flotr:mousemove': function(e, pos) {
      //if(this.selectionInterval == null &&
      if (this.options.mouse.track || _.any(this.series, function(s){return s.mouse && s.mouse.track;}))
        this.hit.hit(pos);
    },
    'mouseout': function() {
      this.hit.clearHit();
    }
  },
  /**
   * Try a method on a graph type.  If the method exists, execute it.
   * @param {Object} series
   * @param {String} method  Method name.
   * @param {Array} args  Arguments applied to method.
   * @return executed successfully or failed.
   */
  executeOnType: function(s, method, args){
    var
      success = false,
      options;

    if (!_.isArray(s)) s = [s];

    function e(s, index) {
      _.each(_.keys(flotr.graphTypes), function (type) {
        if (s[type] && s[type].show && this[type][method]) {
          options = this.getOptions(s, type);

          options.fill = !!s.mouse.fillColor;
          options.fillStyle = this.processColor(s.mouse.fillColor || '#ffffff', {opacity: s.mouse.fillOpacity});
          options.color = s.mouse.lineColor;
          options.context = this.octx;
          options.index = index;

          if (args) options.args = args;
          this[type][method].call(this[type], options);
          success = true;
        }
      }, this);
    }
    _.each(s, e, this);

    return success;
  },
  /**
   * Updates the mouse tracking point on the overlay.
   */
  drawHit: function(n){
    var octx = this.octx,
      s = n.series;

    if(s.mouse.lineColor != null){
      octx.save();
      octx.lineWidth = (s.points ? s.points.lineWidth : 1);
      octx.strokeStyle = s.mouse.lineColor;
      octx.fillStyle = this.processColor(s.mouse.fillColor || '#ffffff', {opacity: s.mouse.fillOpacity});
      octx.translate(this.plotOffset.left, this.plotOffset.top);

      if (!this.hit.executeOnType(s, 'drawHit', n)) {
        var xa = n.xaxis,
          ya = n.yaxis;

        octx.beginPath();
          // TODO fix this (points) should move to general testable graph mixin
          octx.arc(xa.d2p(n.x), ya.d2p(n.y), s.points.radius || s.mouse.radius, 0, 2 * Math.PI, true);
          octx.fill();
          octx.stroke();
        octx.closePath();
      }
      octx.restore();
    }
    this.prevHit = n;
  },
  /**
   * Removes the mouse tracking point from the overlay.
   */
  clearHit: function(){
    var prev = this.prevHit,
        octx = this.octx,
        plotOffset = this.plotOffset;
    octx.save();
    octx.translate(plotOffset.left, plotOffset.top);
    if(prev && !this.hit.executeOnType(prev.series, 'clearHit', this.prevHit)){
      // TODO fix this (points) should move to general testable graph mixin
      var
        s = prev.series,
        lw = (s.bars ? s.bars.lineWidth : 1),
        offset = (s.points.radius || s.mouse.radius) + lw;
      octx.clearRect(
        prev.xaxis.d2p(prev.x) - offset,
        prev.yaxis.d2p(prev.y) - offset,
        offset*2,
        offset*2
      );
      D.hide(this.mouseTrack);
    }
    octx.restore();
  },
  /**
   * Retrieves the nearest data point from the mouse cursor. If it's within
   * a certain range, draw a point on the overlay canvas and display the x and y
   * value of the data.
   * @param {Object} mouse - Object that holds the relative x and y coordinates of the cursor.
   */
  hit: function(mouse){
    var
      series = this.series,
      options = this.options,
      prevHit = this.prevHit,
      data, sens, xsens, ysens, x, y, xa, ya, mx, my, i, n;

    // Nearest data element.
    n = {
      dist:Number.MAX_VALUE,
      x:null,
      y:null,
      relX:mouse.relX,
      relY:mouse.relY,
      absX:mouse.absX,
      absY:mouse.absY,
      sAngle:null,
      eAngle:null,
      fraction: null,
      mouse:null,
      xaxis:null,
      yaxis:null,
      series:null,
      index:null,
      seriesIndex:null
    };

    // TODO what is trackAll?
    // TODO bars trackY
    if (options.mouse.trackAll) {
      for (i = 0; i < series.length; i++) {
        s = series[i];
        data = s.data;
        xa = s.xaxis;
        ya = s.yaxis;
        xsens = (2*options.points.lineWidth)/xa.scale * s.mouse.sensibility;
        mx = xa.p2d(mouse.relX);
        my = ya.p2d(mouse.relY);

        for(var j = 0; j < data.length; j++){
          x = data[j][0];
          y = data[j][1];

          if (y === null ||
              xa.min > x || xa.max < x ||
              ya.min > y || ya.max < y ||
              mx < xa.min || mx > xa.max ||
              my < ya.min || my > ya.max) continue;

          var xdiff = Math.abs(x - mx);

          // Bars and Pie are not supported yet. Not sure how it should look with bars or Pie
          if((!s.bars.show && xdiff < xsens)
              || (s.bars.show && xdiff < s.bars.barWidth/2)
              || (y < 0 && my < 0 && my > y)) {

            var distance = xdiff;

            if (distance < n.dist) {
              n.dist = distance;
              n.x = x;
              n.y = y;
              n.xaxis = xa;
              n.yaxis = ya;
              n.mouse = s.mouse;
              n.series = s;
              n.allSeries = series; // include all series
              n.index = j;
            }
          }
        }
      }
    }
    else if (this.hit.executeOnType(series, 'hit', [mouse, n])) {
      if (n.seriesIndex !== null) {
        n.series = series[n.seriesIndex];
        n.mouse = n.series.mouse;
        n.xaxis = n.series.xaxis;
        n.yaxis = n.series.yaxis;
      }
    } else {
      for (i = 0; i < series.length; i++) {
        s = series[i];
        if(!s.mouse.track) continue;

        data = s.data;
        xa = s.xaxis;
        ya = s.yaxis;
        sens = 2 * (options.points ? options.points.lineWidth : 1) * s.mouse.sensibility;
        xsens = sens/xa.scale;
        ysens = sens/ya.scale;
        mx = xa.p2d(mouse.relX);
        my = ya.p2d(mouse.relY);

        for(var j = 0, xpow, ypow; j < data.length; j++){
          x = data[j][0];
          y = data[j][1];

          var
            xdiff = Math.abs(x + s.bars.barWidth/2 - mx),
            ydiff = Math.abs(y - my);

          if (y === null ||
              xa.min > x || xa.max < x ||
              ya.min > y || ya.max < y) continue;

          // we use a different set of criteria to determin if there has been a hit
          // depending on what type of graph we have
          if(xdiff < xsens && (!s.mouse.trackY || ydiff < ysens)) {
            console.log('hitme');

              /*
              // Bars check
              // For horizontal bars there is need to use y-axis tracking, so s.mouse.trackY is ignored
              (s.bars.show && (!s.bars.horizontal && xdiff < s.bars.barWidth/2 + 1/xa.scale // Check x bar boundary, with adjustment for scale (when bars ~1px)
              && (!s.mouse.trackY || (y > 0 && my > 0 && my < y) || (y < 0 && my < 0 && my > y)))
              || (s.bars.horizontal && ydiff < s.bars.barWidth/2 + 1/ya.scale // Check x bar boundary, with adjustment for scale (when bars ~1px)
              && ((x > 0 && mx > 0 && mx < x) || (x < 0 && mx < 0 && mx > x))))
              ) {
              */

            var distance = Math.sqrt(xdiff*xdiff + ydiff*ydiff);
            if(distance < n.dist){
              n.dist = distance;
              n.x = x;
              n.y = y;
              n.xaxis = xa;
              n.yaxis = ya;
              n.mouse = s.mouse;
              n.series = s;
              n.allSeries = series;
              n.index = j;
              n.seriesIndex = i;
            }
          }
        }
      }
    }

    if(n.series && (n.mouse && n.mouse.track && !prevHit || (prevHit /*&& (n.x != prevHit.x || n.y != prevHit.y)*/))){
      if(n.x !== null && n.y !== null){
        this.hit.clearHit();
        this.hit.drawMouseTrack(n);
        this.hit.drawHit(n);
        Flotr.EventAdapter.fire(this.el, 'flotr:hit', [n, this]);
      }
      else if(prevHit){
        this.hit.clearHit();
      }
    }
    else if(prevHit) {
      this.hit.clearHit();
    }
  },

  drawMouseTrack : function (n) {

    var
      pos         = '',
      s           = n.series,
      p           = n.mouse.position,
      m           = n.mouse.margin,
      elStyle     = S_MOUSETRACK,
      mouseTrack  = this.mouseTrack,
      plotOffset  = this.plotOffset,
      left        = plotOffset.left,
      right       = plotOffset.right,
      bottom      = plotOffset.bottom,
      top         = plotOffset.top,
      decimals    = n.mouse.trackDecimals,
      options     = this.options;

    // Create
    if (!mouseTrack) {
      mouseTrack = D.node('

');
      this.mouseTrack = mouseTrack;
      D.insert(this.el, mouseTrack);
    }

    if (!n.mouse.relative) { // absolute to the canvas

      if      (p.charAt(0) == 'n') pos += 'top:' + (m + top) + 'px;bottom:auto;';
      else if (p.charAt(0) == 's') pos += 'bottom:' + (m + bottom) + 'px;top:auto;';
      if      (p.charAt(1) == 'e') pos += 'right:' + (m + right) + 'px;left:auto;';
      else if (p.charAt(1) == 'w') pos += 'left:' + (m + left) + 'px;right:auto;';

    // Bars
    } else if (s.bars.show) {
        pos += 'bottom:' + (m - top - n.yaxis.d2p(n.y/2) + this.canvasHeight) + 'px;top:auto;';
        pos += 'left:' + (m + left + n.xaxis.d2p(n.x - options.bars.barWidth/2)) + 'px;right:auto;';

    // Pie
    } else if (s.pie.show) {
      var center = {
          x: (this.plotWidth)/2,
          y: (this.plotHeight)/2
        },
        radius = (Math.min(this.canvasWidth, this.canvasHeight) * s.pie.sizeRatio) / 2,
        bisection = n.sAngle<n.eAngle ? (n.sAngle + n.eAngle) / 2: (n.sAngle + n.eAngle + 2* Math.PI) / 2;

      pos += 'bottom:' + (m - top - center.y - Math.sin(bisection) * radius/2 + this.canvasHeight) + 'px;top:auto;';
      pos += 'left:' + (m + left + center.x + Math.cos(bisection) * radius/2) + 'px;right:auto;';

    // Default
    } else {
      if      (p.charAt(0) == 'n') pos += 'bottom:' + (m - top - n.yaxis.d2p(n.y) + this.canvasHeight) + 'px;top:auto;';
      else if (p.charAt(0) == 's') pos += 'top:' + (m + top + n.yaxis.d2p(n.y)) + 'px;bottom:auto;';
      if      (p.charAt(1) == 'e') pos += 'left:' + (m + left + n.xaxis.d2p(n.x)) + 'px;right:auto;';
      else if (p.charAt(1) == 'w') pos += 'right:' + (m - left - n.xaxis.d2p(n.x) + this.canvasWidth) + 'px;left:auto;';
    }

    elStyle += pos;
    mouseTrack.style.cssText = elStyle;

    if (!decimals || decimals < 0) decimals = 0;

    mouseTrack.innerHTML = n.mouse.trackFormatter({
      x: n.x.toFixed(decimals),
      y: n.y.toFixed(decimals),
      series: n.series,
      index: n.index,
      nearest: n,
      fraction: n.fraction
    });

    D.show(mouseTrack);
  }
});
})();
<commit_msg>Major refactoring of hit plugin to use general distance function, which can be graph specific.<commit_after>(function () {

var
  D = Flotr.DOM,
  _ = Flotr._,
  flotr = Flotr,
  S_MOUSETRACK = 'opacity:0.7;background-color:#000;color:#fff;display:none;position:absolute;padding:2px 8px;-moz-border-radius:4px;border-radius:4px;white-space:nowrap;';

Flotr.addPlugin('hit', {
  callbacks: {
    'flotr:mousemove': function(e, pos) {
      //if(this.selectionInterval == null &&
      if (this.options.mouse.track || _.any(this.series, function(s){return s.mouse && s.mouse.track;}))
        this.hit.hit(pos);
    },
    'mouseout': function() {
      this.hit.clearHit();
    }
  },
  /**
   * Try a method on a graph type.  If the method exists, execute it.
   * @param {Object} series
   * @param {String} method  Method name.
   * @param {Array} args  Arguments applied to method.
   * @return executed successfully or failed.
   */
  executeOnType: function(s, method, args){
    var
      success = false,
      options;

    if (!_.isArray(s)) s = [s];

    function e(s, index) {
      _.each(_.keys(flotr.graphTypes), function (type) {
        if (s[type] && s[type].show && this[type][method]) {
          options = this.getOptions(s, type);

          options.fill = !!s.mouse.fillColor;
          options.fillStyle = this.processColor(s.mouse.fillColor || '#ffffff', {opacity: s.mouse.fillOpacity});
          options.color = s.mouse.lineColor;
          options.context = this.octx;
          options.index = index;

          if (args) options.args = args;
          this[type][method].call(this[type], options);
          success = true;
        }
      }, this);
    }
    _.each(s, e, this);

    return success;
  },
  /**
   * Updates the mouse tracking point on the overlay.
   */
  drawHit: function(n){
    var octx = this.octx,
      s = n.series;

    if(s.mouse.lineColor != null){
      octx.save();
      octx.lineWidth = (s.points ? s.points.lineWidth : 1);
      octx.strokeStyle = s.mouse.lineColor;
      octx.fillStyle = this.processColor(s.mouse.fillColor || '#ffffff', {opacity: s.mouse.fillOpacity});
      octx.translate(this.plotOffset.left, this.plotOffset.top);

      if (!this.hit.executeOnType(s, 'drawHit', n)) {
        var xa = n.xaxis,
          ya = n.yaxis;

        octx.beginPath();
          // TODO fix this (points) should move to general testable graph mixin
          octx.arc(xa.d2p(n.x), ya.d2p(n.y), s.points.radius || s.mouse.radius, 0, 2 * Math.PI, true);
          octx.fill();
          octx.stroke();
        octx.closePath();
      }
      octx.restore();
    }
    this.prevHit = n;
  },
  /**
   * Removes the mouse tracking point from the overlay.
   */
  clearHit: function(){
    var prev = this.prevHit,
        octx = this.octx,
        plotOffset = this.plotOffset;
    octx.save();
    octx.translate(plotOffset.left, plotOffset.top);
    if(prev && !this.hit.executeOnType(prev.series, 'clearHit', this.prevHit)){
      // TODO fix this (points) should move to general testable graph mixin
      var
        s = prev.series,
        lw = (s.bars ? s.bars.lineWidth : 1),
        offset = (s.points.radius || s.mouse.radius) + lw;
      octx.clearRect(
        prev.xaxis.d2p(prev.x) - offset,
        prev.yaxis.d2p(prev.y) - offset,
        offset*2,
        offset*2
      );
      D.hide(this.mouseTrack);
    }
    octx.restore();
  },
  /**
   * Retrieves the nearest data point from the mouse cursor. If it's within
   * a certain range, draw a point on the overlay canvas and display the x and y
   * value of the data.
   * @param {Object} mouse - Object that holds the relative x and y coordinates of the cursor.
   */
  hit: function(mouse){
    var
      options = this.options,
      prevHit = this.prevHit,
      closest = this.hit.closest(mouse),
      sensibility, dataIndex, seriesIndex, series, value, xaxis, yaxis;

    // Nearest data element.
    // dist, x, y, relX, relY, absX, absY, sAngle, eAngle, fraction, mouse,
    // xaxis, yaxis, series, index, seriesIndex
    n = {
      relX:mouse.relX,
      relY:mouse.relY,
      absX:mouse.absX,
      absY:mouse.absY
    };

    if (closest) {

      closest     = options.mouse.trackY ? closest.point : closest.x;
      dataIndex   = closest.dataIndex;
      seriesIndex = closest.seriesIndex;
      series      = this.series[seriesIndex];
      xaxis       = series.xaxis;
      yaxis       = series.yaxis;
      sensibility = 2 * series.mouse.sensibility;

      if
        (options.mouse.trackAll ||
        (closest.distanceX < sensibility / xaxis.scale &&
        (!options.mouse.trackY || closest.distanceY < sensibility / yaxis.scale)))
      {
        n.series      = series;
        n.xaxis       = series.xaxis;
        n.yaxis       = series.yaxis;
        n.mouse       = series.mouse;
        n.x           = closest.x;
        n.y           = closest.y;
        n.dist        = closest.distance;
        n.index       = dataIndex;
        n.seriesIndex = seriesIndex;
      }
    }

    if(n.series && (n.mouse && n.mouse.track && !prevHit || (prevHit /*&& (n.x != prevHit.x || n.y != prevHit.y)*/))){
      if(n.x !== null && n.y !== null){
        this.hit.clearHit();
        this.hit.drawMouseTrack(n);
        this.hit.drawHit(n);
        Flotr.EventAdapter.fire(this.el, 'flotr:hit', [n, this]);
      }
      else if(prevHit){
        this.hit.clearHit();
      }
    }
    else if(prevHit) {
      this.hit.clearHit();
    }
  },

  closest : function (mouse) {

    var
      series    = this.series,
      options   = this.options,
      mouseX    = mouse.x,
      mouseY    = mouse.y,
      compare   = Number.MAX_VALUE,
      compareX  = Number.MAX_VALUE,
      closest   = {},
      closestX  = {},
      distance,
      serie,
      data,
      x, y,
      distanceX, distanceY,
      i, j;

    function setClosest (o) {
      o.distance = distance;
      o.distanceX = distanceX;
      o.distanceY = distanceY;
      o.seriesIndex = i;
      o.dataIndex = j;
      o.x = x;
      o.y = y;
    }

    for (i = 0; i < series.length; i++) {

      serie = series[i];
      data = serie.data;

      for (j = data.length; j--;) {

        x = data[j][0];
        y = data[j][1];
        distanceX = Math.abs(x - mouseX);
        distanceY = Math.abs(y - mouseY);

        // Skip square root for speed
        distance = distanceX * distanceX + distanceY * distanceY;

        if (distance < compare) {
          compare = distance;
          setClosest(closest);
        }

        if (distanceX < compareX) {
          compareX = distanceX;
          setClosest(closestX);
        }
      }
    }

    return {
      point : closest,
      x : closestX
    };
  },

  drawMouseTrack : function (n) {

    var
      pos         = '',
      s           = n.series,
      p           = n.mouse.position,
      m           = n.mouse.margin,
      elStyle     = S_MOUSETRACK,
      mouseTrack  = this.mouseTrack,
      plotOffset  = this.plotOffset,
      left        = plotOffset.left,
      right       = plotOffset.right,
      bottom      = plotOffset.bottom,
      top         = plotOffset.top,
      decimals    = n.mouse.trackDecimals,
      options     = this.options;

    // Create
    if (!mouseTrack) {
      mouseTrack = D.node('

');
      this.mouseTrack = mouseTrack;
      D.insert(this.el, mouseTrack);
    }

    if (!n.mouse.relative) { // absolute to the canvas

      if      (p.charAt(0) == 'n') pos += 'top:' + (m + top) + 'px;bottom:auto;';
      else if (p.charAt(0) == 's') pos += 'bottom:' + (m + bottom) + 'px;top:auto;';
      if      (p.charAt(1) == 'e') pos += 'right:' + (m + right) + 'px;left:auto;';
      else if (p.charAt(1) == 'w') pos += 'left:' + (m + left) + 'px;right:auto;';

    // Bars
    } else if (s.bars.show) {
        pos += 'bottom:' + (m - top - n.yaxis.d2p(n.y/2) + this.canvasHeight) + 'px;top:auto;';
        pos += 'left:' + (m + left + n.xaxis.d2p(n.x - options.bars.barWidth/2)) + 'px;right:auto;';

    // Pie
    } else if (s.pie.show) {
      var center = {
          x: (this.plotWidth)/2,
          y: (this.plotHeight)/2
        },
        radius = (Math.min(this.canvasWidth, this.canvasHeight) * s.pie.sizeRatio) / 2,
        bisection = n.sAngle<n.eAngle ? (n.sAngle + n.eAngle) / 2: (n.sAngle + n.eAngle + 2* Math.PI) / 2;

      pos += 'bottom:' + (m - top - center.y - Math.sin(bisection) * radius/2 + this.canvasHeight) + 'px;top:auto;';
      pos += 'left:' + (m + left + center.x + Math.cos(bisection) * radius/2) + 'px;right:auto;';

    // Default
    } else {
      if      (p.charAt(0) == 'n') pos += 'bottom:' + (m - top - n.yaxis.d2p(n.y) + this.canvasHeight) + 'px;top:auto;';
      else if (p.charAt(0) == 's') pos += 'top:' + (m + top + n.yaxis.d2p(n.y)) + 'px;bottom:auto;';
      if      (p.charAt(1) == 'e') pos += 'left:' + (m + left + n.xaxis.d2p(n.x)) + 'px;right:auto;';
      else if (p.charAt(1) == 'w') pos += 'right:' + (m - left - n.xaxis.d2p(n.x) + this.canvasWidth) + 'px;left:auto;';
    }

    elStyle += pos;
    mouseTrack.style.cssText = elStyle;

    if (!decimals || decimals < 0) decimals = 0;

    mouseTrack.innerHTML = n.mouse.trackFormatter({
      x: n.x.toFixed(decimals),
      y: n.y.toFixed(decimals),
      series: n.series,
      index: n.index,
      nearest: n,
      fraction: n.fraction
    });

    D.show(mouseTrack);
  }

});
})();
<|endoftext|>


<commit_before>"use strict";

const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");

const config = {
  entry: {
    app: "./src/core/bootstrap.js"
  },
  output: {
    path: path.resolve(__dirname + "/build/"),
    filename: "bundle.js"
  },
  module: {
    loaders: [{
      test: /\.js$/,
      exclude: /node_modules/,
      use: [{
        loader: "babel-loader"
      }]
    }, {
      test: /\.html$/,
      loader: "raw-loader",
      exclude: path.resolve("./src/index.html")
    }]
  },
  plugins: [
    new HtmlWebpackPlugin({
      filename: "index.html",
      template: "./src/index.html"
    }),

    new webpack.optimize.CommonsChunkPlugin({
      name: "common",
      filename: "common.js",
      minChunks: (module) => {
        // this assumes your vendor imports exist in the node_modules directory
        return module.context && module.context.indexOf("node_modules") !== -1;
      }
    }),

    new webpack.NamedModulesPlugin(),
    new webpack.HotModuleReplacementPlugin()
  ],
  devServer: {
    contentBase: path.resolve("build"),
    hot: true,
    host: "localhost",
    port: 8080
  }
};

module.exports = config;
<commit_msg>Edit configs<commit_after>"use strict";

const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ExtractTextPlugin = require("extract-text-webpack-plugin");

const config = {
  entry: {
    app: "./src/core/bootstrap.js"
  },
  output: {
    path: path.resolve(__dirname + "/build/"),
    filename: "bundle.js"
  },
  module: {
    rules: [
      // js
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [{
          loader: "babel-loader"
        }]
      },

      // html
      {
        test: /\.html$/,
        loader: "raw-loader",
        exclude: path.resolve("./src/index.html")
      },

      // css
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extract({
          fallback: "style-loader",
          use: "css-loader"
        })
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      filename: "index.html",
      template: "./src/index.html"
    }),

    new webpack.optimize.CommonsChunkPlugin({
      name: "common",
      filename: "common.js",
      minChunks: (module) => {
        // this assumes your vendor imports exist in the node_modules directory
        return module.context && module.context.indexOf("node_modules") !== -1;
      }
    }),

    new webpack.NamedModulesPlugin(),
    new webpack.HotModuleReplacementPlugin(),

    new ExtractTextPlugin("styles.css")
  ],
  devServer: {
    contentBase: path.resolve("build"),
    hot: true,
    host: "localhost",
    port: 8080
  }
};

module.exports = config;
<|endoftext|>


<commit_before>/**
 * Redux reducers for working with virus data.
 *
 * @copyright 2017 Government of Canada
 * @license MIT
 * @author igboyes
 *
 */

import { merge, assign, concat, find, reject } from "lodash";
import {
    WS_UPDATE_VIRUS,
    WS_REMOVE_VIRUS,

    FIND_VIRUSES,
    GET_VIRUS,
    CREATE_VIRUS,
    ADD_ISOLATE,
    EDIT_ISOLATE,
    REMOVE_ISOLATE,
    SHOW_ADD_ISOLATE,
    SHOW_EDIT_ISOLATE,
    SHOW_REMOVE_ISOLATE,
    HIDE_VIRUS_MODAL,
    GET_VIRUS_HISTORY
} from "../actionTypes";

const virusesInitialState = {
    documents: null,

    detail: null,
    detailHistory: null,

    addIsolate: false,
    addIsolatePending: false,

    editIsolate: false,
    editIsolatePending: false,

    removeIsolate: false,
    removeIsolatePending: false,

    activeIsolateId: null,
    activeSequenceId: null,

    createError: "",
    createPending: false
};

export default function virusesReducer (state = virusesInitialState, action) {

    switch (action.type) {

        case WS_UPDATE_VIRUS:
            return assign({}, state, {
                viruses: concat(
                    reject(state.viruses, {id: action.virus_id}),
                    assign({}, find(state.viruses, {id: action.virus_id}), action.data)
                )
            });

        case WS_REMOVE_VIRUS:
            return assign({}, state, {
                viruses: reject(state.viruses, {id: action.virus_id})
            });

        case FIND_VIRUSES.REQUESTED:
            return assign({}, state, action.terms);

        case FIND_VIRUSES.SUCCEEDED:
            return assign({}, state, {
                documents: action.data.documents,
                page: action.data.page,
                pageCount: action.data.page_count,
                totalCount: action.data.total_count,
                foundCount: action.data.found_count,
                modifiedCount: action.data.modified_count
            });

        case FIND_VIRUSES.FAILED:
            return assign({}, state, {
                viruses: []
            });

        case GET_VIRUS.REQUESTED:
            return assign({}, state, {
                detail: null
            });

        case GET_VIRUS.SUCCEEDED:
            return assign({}, state, {
                detail: action.data,
                activeIsolateId: action.data.isolates.length ? action.data.isolates[0].id: null
            });

        case CREATE_VIRUS.REQUESTED:
            return assign({}, state, {
                pending: true
            });

        case CREATE_VIRUS.FAILED:
            return assign({}, state, {
                createError: action.error
            });

        case ADD_ISOLATE.REQUESTED:
            return assign({}, state, {
                addIsolatePending: true
            });

        case ADD_ISOLATE.SUCCEEDED:
            return merge({}, state, {
                addIsolate: false,
                addIsolatePending: false,
                detail: {
                    isolates: state.detail.isolates.concat([action.data])
                }
            });

        case EDIT_ISOLATE.REQUESTED:
            return assign({}, state, {
                editIsolateEnding: true
            });

        case EDIT_ISOLATE.SUCCEEDED:
            return merge({}, state, {
                editIsolate: false,
                editIsolatePending: false,
                detail: {
                    isolates: state.detail.isolates.map(isolate => {
                        if (isolate.id !== action.data.isolate_id) {
                            return isolate;
                        } else {
                            return assign({}, isolate, action.data);
                        }
                    })
                }
            });

        case REMOVE_ISOLATE.REQUESTED:
            return assign({}, state, {
                removeIsolate: true,
                removeIsolatePending: true
            });

        case REMOVE_ISOLATE.SUCCEEDED:
            return assign({}, state, {
                removeIsolate: false,
                removeIsolatePending: false,
                detail: assign({}, state.detail, {
                    isolates: reject(state.detail.isolates, {id: action.isolateId})
                })
            });

        case GET_VIRUS_HISTORY.REQUESTED:
            return assign({}, state, {
                detailHistory: null
            });

        case GET_VIRUS_HISTORY.SUCCEEDED:
            return assign({}, state, {
                detailHistory: action.data
            });

        case SHOW_ADD_ISOLATE:
            return assign({}, state, {
                addIsolate: true
            });

        case SHOW_EDIT_ISOLATE:
            return assign({}, state, {
                editIsolate: true
            });

        case SHOW_REMOVE_ISOLATE:
            return assign({}, state, {
                removeIsolate: true
            });

        case HIDE_VIRUS_MODAL:
            return assign({}, state, {
                addIsolate: false,
                editIsolate: false,
                removeIsolate: false
            });

        default:
            return state;
    }
}
<commit_msg>Fix updateIsolate reducer case<commit_after>/**
 * Redux reducers for working with virus data.
 *
 * @copyright 2017 Government of Canada
 * @license MIT
 * @author igboyes
 *
 */

import { merge, assign, concat, find, reject } from "lodash";
import {
    WS_UPDATE_VIRUS,
    WS_REMOVE_VIRUS,

    FIND_VIRUSES,
    GET_VIRUS,
    CREATE_VIRUS,
    ADD_ISOLATE,
    EDIT_ISOLATE,
    REMOVE_ISOLATE,
    SHOW_ADD_ISOLATE,
    SHOW_EDIT_ISOLATE,
    SHOW_REMOVE_ISOLATE,
    HIDE_VIRUS_MODAL,
    GET_VIRUS_HISTORY
} from "../actionTypes";

const virusesInitialState = {
    documents: null,

    detail: null,
    detailHistory: null,

    addIsolate: false,
    addIsolatePending: false,

    editIsolate: false,
    editIsolatePending: false,

    removeIsolate: false,
    removeIsolatePending: false,

    activeIsolateId: null,
    activeSequenceId: null,

    createError: "",
    createPending: false
};

export default function virusesReducer (state = virusesInitialState, action) {

    switch (action.type) {

        case WS_UPDATE_VIRUS:
            return assign({}, state, {
                viruses: concat(
                    reject(state.viruses, {id: action.virus_id}),
                    assign({}, find(state.viruses, {id: action.virus_id}), action.data)
                )
            });

        case WS_REMOVE_VIRUS:
            return assign({}, state, {
                viruses: reject(state.viruses, {id: action.virus_id})
            });

        case FIND_VIRUSES.REQUESTED:
            return assign({}, state, action.terms);

        case FIND_VIRUSES.SUCCEEDED:
            return assign({}, state, {
                documents: action.data.documents,
                page: action.data.page,
                pageCount: action.data.page_count,
                totalCount: action.data.total_count,
                foundCount: action.data.found_count,
                modifiedCount: action.data.modified_count
            });

        case FIND_VIRUSES.FAILED:
            return assign({}, state, {
                viruses: []
            });

        case GET_VIRUS.REQUESTED:
            return assign({}, state, {
                detail: null
            });

        case GET_VIRUS.SUCCEEDED:
            return assign({}, state, {
                detail: action.data,
                activeIsolateId: action.data.isolates.length ? action.data.isolates[0].id: null
            });

        case CREATE_VIRUS.REQUESTED:
            return assign({}, state, {
                pending: true
            });

        case CREATE_VIRUS.FAILED:
            return assign({}, state, {
                createError: action.error
            });

        case ADD_ISOLATE.REQUESTED:
            return assign({}, state, {
                addIsolatePending: true
            });

        case ADD_ISOLATE.SUCCEEDED:
            return merge({}, state, {
                addIsolate: false,
                addIsolatePending: false,
                detail: {
                    isolates: state.detail.isolates.concat([action.data])
                }
            });

        case EDIT_ISOLATE.REQUESTED:
            return assign({}, state, {
                editIsolateEnding: true
            });

        case EDIT_ISOLATE.SUCCEEDED:
            return merge({}, state, {
                editIsolate: false,
                editIsolatePending: false,
                detail: {
                    isolates: state.detail.isolates.map(isolate => {
                        if (isolate.id !== action.data.id) {
                            return isolate;
                        } else {
                            return assign({}, isolate, action.data);
                        }
                    })
                }
            });

        case REMOVE_ISOLATE.REQUESTED:
            return assign({}, state, {
                removeIsolate: true,
                removeIsolatePending: true
            });

        case REMOVE_ISOLATE.SUCCEEDED:
            return assign({}, state, {
                removeIsolate: false,
                removeIsolatePending: false,
                detail: assign({}, state.detail, {
                    isolates: reject(state.detail.isolates, {id: action.isolateId})
                })
            });

        case GET_VIRUS_HISTORY.REQUESTED:
            return assign({}, state, {
                detailHistory: null
            });

        case GET_VIRUS_HISTORY.SUCCEEDED:
            return assign({}, state, {
                detailHistory: action.data
            });

        case SHOW_ADD_ISOLATE:
            return assign({}, state, {
                addIsolate: true
            });

        case SHOW_EDIT_ISOLATE:
            return assign({}, state, {
                editIsolate: true
            });

        case SHOW_REMOVE_ISOLATE:
            return assign({}, state, {
                removeIsolate: true
            });

        case HIDE_VIRUS_MODAL:
            return assign({}, state, {
                addIsolate: false,
                editIsolate: false,
                removeIsolate: false
            });

        default:
            return state;
    }
}
<|endoftext|>


<commit_before>var exports = module.exports;

function handleErrors(response) {
  return new Promise((resolve, reject) => {
    if (response.ok) {
      resolve(response);
    } else {
      reject(response.statusText);
    }
  })
}

// factory function that retains original fetch function in closure
function generatefetchReject(originalFetch) {
	return function() {url, opts}
		return originalFetch(url, opts)
			.then(handleErrors);
	}
}

exports.fill = function fill() {
	window.fetch = generatefetchReject(window.fetch);
	return true;
}

exports.fetchReject = generatefetchReject(window.fetch);
<commit_msg>Fix misplaced brackets<commit_after>var exports = module.exports;

function handleErrors(response) {
  return new Promise((resolve, reject) => {
    if (response.ok) {
      resolve(response);
    } else {
      reject(response.statusText);
    }
  })
}

// factory function that retains original fetch function in closure
function generatefetchReject(originalFetch) {
	return function(url, opts) {
		return originalFetch(url, opts)
			.then(handleErrors);
	}
}

exports.fill = function fill() {
	window.fetch = generatefetchReject(window.fetch);
	return true;
}

exports.fetchReject = generatefetchReject(window.fetch);
<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'
import { removeResource, requestResources, viewResource, addFilter, removeFilter } from '../../state/actions/resources'
import { red900 } from 'material-ui/styles/colors'
import { requestMetrics } from '../../state/actions/metrics'
import { compareStatuses } from '../../utils/resource-utils'
import { objectEmpty } from '../../comparators'
import { getResourceCellValue, renderResourceCell } from '../../utils/resource-column-utils'
import sizeMe from 'react-sizeme'
import { connect } from 'react-redux'
import IconDelete from 'material-ui/svg-icons/action/delete'
import FilterBox from '../FilterBox'
import FilterTable from '../filter-table/FilterTable'
import RowActionMenu from '../RowActionMenu'
import ConfirmationDialog from '../ConfirmationDialog'
import MultiResourceActionButton from '../MultiResourceActionButton'
import './PodsForNodePane.css'

const mapStateToProps = function(store) {
  return {
    resources: store.resources.resources,
    podsByEndpoint: store.resources.podsByEndpoint,
    accessEvaluator: store.session.accessEvaluator,
    linkGenerator: store.session.linkGenerator,
    maxResourceVersionByKind: store.resources.maxResourceVersionByKind,
    resourceRevision: store.resources.revision,
    podMetrics: store.metrics.pod,
    filterNames: store.resources.filterNames,
    autocomplete: store.resources.autocomplete.pods,
  }
}

const mapDispatchToProps = function(dispatch, ownProps) {
  return {
    viewResource: function(resource, view='config') {
      dispatch(viewResource(resource,view))
    },
    requestResources: function() {
      dispatch(requestResources())
    },
    requestMetrics: function() {
      dispatch(requestMetrics())
    },
    removeResource: function(...resources) {
      dispatch(removeResource(...resources))
    },
    addFilter: function(filterName) {
      dispatch(addFilter(filterName))
    },
    removeFilter: function(filterName, index) {
      dispatch(removeFilter(filterName, index))
    },
  }
}

const styles = {
  header: {
    fontWeight: 600,
    fontSize: '13px',
    color: 'white',
    fill: 'white',
  },
  cell: {
    paddingLeft: 2,
    paddingRight: 2,
  },
  deleteResourceButton: {
    margin: 0,
    top: 20,
    right: 40,
    bottom: 'auto',
    left: 'auto',
    position: 'absolute',
  },
}

export default sizeMe({ monitorHeight: true, monitorWidth: true }) (
connect(mapStateToProps, mapDispatchToProps) (
class RelatedResourcesPane extends React.PureComponent {

  static propTypes = {
    node: PropTypes.object.isRequired,
  }

  static defaultProps = {
  }

  constructor(props) {
    super(props)
    this.state = {
      actionsOpen: false,
      deleteOpen: false,
      hoveredRow: -1,
      hoveredResources: null,
      selectedResources: [],
      relatedResources: [],
    }
    this.selectedIds = {}
    this.columns = [
      {
        id: 'kind',
        label: 'kind',
        sortable: true,
        headerStyle: styles.header,
        style: { ...styles.cell,
          width: '8%',
        },
      },
      {
        id: 'name',
        label: 'name',
        sortable: true,
        headerStyle: styles.header,
        style: { ...styles.cell,
          // width: '35%',
        },
      },
      {
        id: 'namespace',
        label: 'ns',
        sortable: true,
        headerStyle: styles.header,
        style: { ...styles.cell,
          width: 100,
        }
      },
      {
        id: 'cpu_utilized',
        label:
cpu
used
,
        sortable: true,
        isNumeric: true,
        headerStyle: {...styles.header,
          textAlign: 'center',
          whiteSpace: 'normal',
          lineHeight: '13px',
          padding: 0,
        },
        style: { ...styles.cell,
          width: '7%',
          textAlign: 'right',
          paddingRight: '2%',
        },
      },
      {
        id: 'mem_utilized',
        label:
Gi mem
used
,
        sortable: true,
        isNumeric: true,
        headerStyle: {...styles.header,
          textAlign: 'center',
          whiteSpace: 'normal',
          lineHeight: '13px',
          padding: 0,
        },
        style: { ...styles.cell,
          width: '7%',
          textAlign: 'right',
          paddingRight: '2%',
        },
      },
      {
        id: 'disk_utilized',
        label:
Gi disk
used
,
        sortable: true,
        isNumeric: true,
        headerStyle: {...styles.header,
          textAlign: 'center',
          whiteSpace: 'normal',
          lineHeight: '13px',
          padding: 0,
        },
        style: { ...styles.cell,
          width: '7%',
          textAlign: 'right',
          paddingRight: '2%',
        },
      },
      {
        id: 'status',
        label: 'status',
        headerStyle: styles.header,
        style: { ...styles.cell,
          width: '7%',
          verticalAlign: 'middle',
          textAlign: 'center',
          paddingLeft: '1%',
        },
        sortable: true,
        comparator: compareStatuses,
      },
      {
        id: 'age',
        label: 'age',
        sortable: true,
        headerStyle: {...styles.header,
          textAlign: 'center',
        },
        style: { ...styles.cell,
          width: '10%',
          textAlign: 'center',
        }
      },
      {
        id: 'actions',
        label: 'actions ',
        headerStyle: {...styles.header,
          paddingLeft: 0,
          paddingRight: 10,
        },
        style: { ...styles.cell,
          width: 55,
          lineHeight: '50px',
        },
        className: 'resource-actions',
      },
    ]
    for (let fn of [
      'renderCell',
      'getCellValue',
      'handleRowSelection',
      'handleCellClick',
    ]) {
      this[fn] = this[fn].bind(this)
    }
  }

  componentDidMount = () => {
    this.setState({
      relatedResources: this.resolveRelated(this.props.resource, this.props.resources),
    })
  }

  renderCell = (column, row) => {
    return renderResourceCell(column, row, this.props.podMetrics)
  }

  getCellValue = (column, row) => {
    return getResourceCellValue(column, row, this.props.podMetrics)
  }

  componentDidUpdate = () => {
    if (!this.state.actionsOpen) {
      this.actionsClicked = false
    }
  }

  handleActionsRequestClose = () => {
    this.setState({
      actionsOpen: false,
      hoveredRow: -1,
      hoveredResource: null,
    })
  }

  handleCellClick = (rowId, colId, resource, col) => {
    this.actionsClicked = false
    if (col.id === 'actions') {
      let trs = document.getElementsByClassName('pods filter-table')[1].children[0].children
      let that = this
      this.props.accessEvaluator.getObjectAccess(resource, 'workloads').then((access) => {
        that.setState({
          actionsOpen: true,
          actionsAnchor: trs[rowId].children[colId+1],
          hoveredRow: rowId,
          hoveredResource: resource,
          hoveredResourceAccess: access,
        })
      })

      this.actionsClicked = true
      return false
    } else {
      this.props.viewResource(resource)
      return false
    }
  }

  handleRowSelection = (selectedIds) => {
    if (!this.actionsClicked) {
      this.selectedIds = selectedIds
      this.deleteEnabled = !objectEmpty(selectedIds)
      this.deleteButton.setDisabled(!this.deleteEnabled)
    }
  }

  handleDelete = (resource) => {
    let resources = []
    if (resource) {
      resources.push(resource)
    } else if (this.selectedIds && Object.keys(this.selectedIds).length > 0) {
      for (let id in this.selectedIds) {
        resources.push(this.props.resources[id])
      }
    }

    this.setState({
      selectedResources: resources,
      deleteOpen: true,
      actionsOpen: false,
    })
  }

  handleRequestCloseDelete = () => {
    this.setState({
      deleteOpen: false,
      selectedResources: [],
    })
  }

  handleConfirmDelete = () => {
    this.setState({
      selectedResources: [],
      deleteOpen: false,
    })
    this.props.removeResource(...this.state.selectedResources)
    this.handleRowSelection({})
  }

  resolveRelated = (resource, resources) => {
    let related = []
    if (!!resources) {
      // resolved owned resources
      this.resolveOwned(resource, related)
      let relKeys = [].concat.apply([], related.map(r=>r.related ? Object.keys(r.related) : []))
      let relatedResources = {}
      while (relKeys.length > 0) {
        let key = relKeys.shift()
        if (!(key in relatedResources)) {
          let r = resources[key]
          relatedResources[key] = r
          if (r.related) {
            for (let relKey in r.related) {
              if (!(relKey in relatedResources)) {
                relKeys.push(relKey)
              }
            }
          }
        }
      }
      related.push(...Object.values(relatedResources))
    }
    return related.filter(e=>!e.isFiltered)
  }

  resolveOwned = (resource, related) => {
    if (resource.owned) {
      let owned = Object.values(resource.owned)
      while (owned.length) {
        let r = owned.shift()
        if (r.owned) {
          owned.push(...Object.values(r.owned))
        }
        related.push(r)
      }
    }
  }

  componentWillReceiveProps = (props) => {
    if (props.resourceRevision !== this.props.resourceRevision
      || props.filterNames !== this.props.filterNames
    ) {
      this.setState({
        relatedResources: this.resolveRelated(props.resource, props.resources)
      })
    }
  }

  shouldComponentUpdate = (nextProps, nextState) => {
    return nextState.actionsOpen !== this.state.actionsOpen
        || nextProps.resourceRevision !== this.props.resourceRevision
        || nextProps.contentTop !== this.props.contentTop
        || nextState.relatedResources !== this.state.relatedResources
        || nextProps.filterNames !== this.props.filterNames
  }

  render() {

    let { props } = this

    return (

        <FilterBox
          addFilter={props.addFilter}
          removeFilter={props.removeFilter}
          filterNames={props.filterNames}
          autocomplete={props.autocomplete}
          />

        <MultiResourceActionButton backgroundColor={red900}
          mini={true}
          style={styles.deleteResourceButton}
          disabled={!this.deleteEnabled}
          onTouchTap={this.handleDelete}
          ref={(ref)=>{this.deleteButton = ref}}
          data-rh={'Delete Selected...'}
          data-rh-at={'bottom'}>
            <IconDelete/>
        </MultiResourceActionButton>

        <FilterTable
          className={'pods'}
          columns={this.columns}
          data={this.state.relatedResources}
          height={`calc(100vh - ${props.contentTop + 177}px)`}
          multiSelectable={true}
          onRowSelection={this.handleRowSelection}
          onCellClick={this.handleCellClick}
          hoveredRow={this.state.hoveredRow}
          onRenderCell={this.renderCell}
          getCellValue={this.getCellValue}
          selectedIds={this.selectedIds}
          stripedRows={false}
          iconStyle={{fill: 'rgba(255,255,255,0.9)'}}
          iconInactiveStyle={{fill: 'rgba(255,255,255,0.5)'}}
          width={'calc(100vw - 60px)'}
          wrapperStyle={{marginLeft: -15, marginRight: -15, overflowX: 'hidden', overflowY: 'auto'}}
          headerStyle={{backgroundColor: 'rgba(185, 162, 131, 0.85)', color: 'white'}}
          />

      <RowActionMenu
        open={!!this.state.hoveredResource}
        handlers={{
          logs: ()=> { this.props.viewResource(this.state.hoveredResource,'logs') },
          term: ()=> { this.props.viewResource(this.state.hoveredResource,'terminal') },
          edit: ()=> { this.props.viewResource(this.state.hoveredResource,'edit') },
          delete: ()=>{ this.handleDelete(this.state.hoveredResources)},
          close: this.handleActionsRequestClose,
        }}
        access={this.state.hoveredResourceAccess}
        anchorEl={this.state.actionsAnchor}
        />

      <ConfirmationDialog
        open={this.state.deleteOpen}
        title={'Delete Resource(s):'}
        message={`Are you sure you want to delete the following ` +
          `${this.state.selectedResources.length > 1 ? this.state.selectedResources.length + ' ' : ''}` +
          `resource${this.state.selectedResources.length > 1 ? 's':''}?`}
        resources={this.state.selectedResources}
        onRequestClose={this.handleRequestCloseDelete}
        onConfirm={this.handleConfirmDelete}
        linkGenerator={this.props.linkGenerator}
        />

    )
  }

}))
<commit_msg>use workloads autocomplete for related resources<commit_after>import React from 'react'
import PropTypes from 'prop-types'
import { removeResource, requestResources, viewResource, addFilter, removeFilter } from '../../state/actions/resources'
import { red900 } from 'material-ui/styles/colors'
import { requestMetrics } from '../../state/actions/metrics'
import { compareStatuses } from '../../utils/resource-utils'
import { objectEmpty } from '../../comparators'
import { getResourceCellValue, renderResourceCell } from '../../utils/resource-column-utils'
import sizeMe from 'react-sizeme'
import { connect } from 'react-redux'
import IconDelete from 'material-ui/svg-icons/action/delete'
import FilterBox from '../FilterBox'
import FilterTable from '../filter-table/FilterTable'
import RowActionMenu from '../RowActionMenu'
import ConfirmationDialog from '../ConfirmationDialog'
import MultiResourceActionButton from '../MultiResourceActionButton'
import './PodsForNodePane.css'

const mapStateToProps = function(store) {
  return {
    resources: store.resources.resources,
    podsByEndpoint: store.resources.podsByEndpoint,
    accessEvaluator: store.session.accessEvaluator,
    linkGenerator: store.session.linkGenerator,
    maxResourceVersionByKind: store.resources.maxResourceVersionByKind,
    resourceRevision: store.resources.revision,
    podMetrics: store.metrics.pod,
    filterNames: store.resources.filterNames,
    autocomplete: store.resources.autocomplete.workloads,
  }
}

const mapDispatchToProps = function(dispatch, ownProps) {
  return {
    viewResource: function(resource, view='config') {
      dispatch(viewResource(resource,view))
    },
    requestResources: function() {
      dispatch(requestResources())
    },
    requestMetrics: function() {
      dispatch(requestMetrics())
    },
    removeResource: function(...resources) {
      dispatch(removeResource(...resources))
    },
    addFilter: function(filterName) {
      dispatch(addFilter(filterName))
    },
    removeFilter: function(filterName, index) {
      dispatch(removeFilter(filterName, index))
    },
  }
}

const styles = {
  header: {
    fontWeight: 600,
    fontSize: '13px',
    color: 'white',
    fill: 'white',
  },
  cell: {
    paddingLeft: 2,
    paddingRight: 2,
  },
  deleteResourceButton: {
    margin: 0,
    top: 20,
    right: 40,
    bottom: 'auto',
    left: 'auto',
    position: 'absolute',
  },
}

export default sizeMe({ monitorHeight: true, monitorWidth: true }) (
connect(mapStateToProps, mapDispatchToProps) (
class RelatedResourcesPane extends React.PureComponent {

  static propTypes = {
    node: PropTypes.object.isRequired,
  }

  static defaultProps = {
  }

  constructor(props) {
    super(props)
    this.state = {
      actionsOpen: false,
      deleteOpen: false,
      hoveredRow: -1,
      hoveredResources: null,
      selectedResources: [],
      relatedResources: [],
    }
    this.selectedIds = {}
    this.columns = [
      {
        id: 'kind',
        label: 'kind',
        sortable: true,
        headerStyle: styles.header,
        style: { ...styles.cell,
          width: '8%',
        },
      },
      {
        id: 'name',
        label: 'name',
        sortable: true,
        headerStyle: styles.header,
        style: { ...styles.cell,
          // width: '35%',
        },
      },
      {
        id: 'namespace',
        label: 'ns',
        sortable: true,
        headerStyle: styles.header,
        style: { ...styles.cell,
          width: 100,
        }
      },
      {
        id: 'cpu_utilized',
        label:
cpu
used
,
        sortable: true,
        isNumeric: true,
        headerStyle: {...styles.header,
          textAlign: 'center',
          whiteSpace: 'normal',
          lineHeight: '13px',
          padding: 0,
        },
        style: { ...styles.cell,
          width: '7%',
          textAlign: 'right',
          paddingRight: '2%',
        },
      },
      {
        id: 'mem_utilized',
        label:
Gi mem
used
,
        sortable: true,
        isNumeric: true,
        headerStyle: {...styles.header,
          textAlign: 'center',
          whiteSpace: 'normal',
          lineHeight: '13px',
          padding: 0,
        },
        style: { ...styles.cell,
          width: '7%',
          textAlign: 'right',
          paddingRight: '2%',
        },
      },
      {
        id: 'disk_utilized',
        label:
Gi disk
used
,
        sortable: true,
        isNumeric: true,
        headerStyle: {...styles.header,
          textAlign: 'center',
          whiteSpace: 'normal',
          lineHeight: '13px',
          padding: 0,
        },
        style: { ...styles.cell,
          width: '7%',
          textAlign: 'right',
          paddingRight: '2%',
        },
      },
      {
        id: 'status',
        label: 'status',
        headerStyle: styles.header,
        style: { ...styles.cell,
          width: '7%',
          verticalAlign: 'middle',
          textAlign: 'center',
          paddingLeft: '1%',
        },
        sortable: true,
        comparator: compareStatuses,
      },
      {
        id: 'age',
        label: 'age',
        sortable: true,
        headerStyle: {...styles.header,
          textAlign: 'center',
        },
        style: { ...styles.cell,
          width: '10%',
          textAlign: 'center',
        }
      },
      {
        id: 'actions',
        label: 'actions ',
        headerStyle: {...styles.header,
          paddingLeft: 0,
          paddingRight: 10,
        },
        style: { ...styles.cell,
          width: 55,
          lineHeight: '50px',
        },
        className: 'resource-actions',
      },
    ]
    for (let fn of [
      'renderCell',
      'getCellValue',
      'handleRowSelection',
      'handleCellClick',
    ]) {
      this[fn] = this[fn].bind(this)
    }
  }

  componentDidMount = () => {
    this.setState({
      relatedResources: this.resolveRelated(this.props.resource, this.props.resources),
    })
  }

  renderCell = (column, row) => {
    return renderResourceCell(column, row, this.props.podMetrics)
  }

  getCellValue = (column, row) => {
    return getResourceCellValue(column, row, this.props.podMetrics)
  }

  componentDidUpdate = () => {
    if (!this.state.actionsOpen) {
      this.actionsClicked = false
    }
  }

  handleActionsRequestClose = () => {
    this.setState({
      actionsOpen: false,
      hoveredRow: -1,
      hoveredResource: null,
    })
  }

  handleCellClick = (rowId, colId, resource, col) => {
    this.actionsClicked = false
    if (col.id === 'actions') {
      let trs = document.getElementsByClassName('pods filter-table')[1].children[0].children
      let that = this
      this.props.accessEvaluator.getObjectAccess(resource, 'workloads').then((access) => {
        that.setState({
          actionsOpen: true,
          actionsAnchor: trs[rowId].children[colId+1],
          hoveredRow: rowId,
          hoveredResource: resource,
          hoveredResourceAccess: access,
        })
      })

      this.actionsClicked = true
      return false
    } else {
      this.props.viewResource(resource)
      return false
    }
  }

  handleRowSelection = (selectedIds) => {
    if (!this.actionsClicked) {
      this.selectedIds = selectedIds
      this.deleteEnabled = !objectEmpty(selectedIds)
      this.deleteButton.setDisabled(!this.deleteEnabled)
    }
  }

  handleDelete = (resource) => {
    let resources = []
    if (resource) {
      resources.push(resource)
    } else if (this.selectedIds && Object.keys(this.selectedIds).length > 0) {
      for (let id in this.selectedIds) {
        resources.push(this.props.resources[id])
      }
    }

    this.setState({
      selectedResources: resources,
      deleteOpen: true,
      actionsOpen: false,
    })
  }

  handleRequestCloseDelete = () => {
    this.setState({
      deleteOpen: false,
      selectedResources: [],
    })
  }

  handleConfirmDelete = () => {
    this.setState({
      selectedResources: [],
      deleteOpen: false,
    })
    this.props.removeResource(...this.state.selectedResources)
    this.handleRowSelection({})
  }

  resolveRelated = (resource, resources) => {
    let related = []
    if (!!resources) {
      // resolved owned resources
      this.resolveOwned(resource, related)
      let relKeys = [].concat.apply([], related.map(r=>r.related ? Object.keys(r.related) : []))
      let relatedResources = {}
      while (relKeys.length > 0) {
        let key = relKeys.shift()
        if (!(key in relatedResources)) {
          let r = resources[key]
          relatedResources[key] = r
          if (r.related) {
            for (let relKey in r.related) {
              if (!(relKey in relatedResources)) {
                relKeys.push(relKey)
              }
            }
          }
        }
      }
      related.push(...Object.values(relatedResources))
    }
    return related.filter(e=>!e.isFiltered)
  }

  resolveOwned = (resource, related) => {
    if (resource.owned) {
      let owned = Object.values(resource.owned)
      while (owned.length) {
        let r = owned.shift()
        if (r.owned) {
          owned.push(...Object.values(r.owned))
        }
        related.push(r)
      }
    }
  }

  componentWillReceiveProps = (props) => {
    if (props.resourceRevision !== this.props.resourceRevision
      || props.filterNames !== this.props.filterNames
    ) {
      this.setState({
        relatedResources: this.resolveRelated(props.resource, props.resources)
      })
    }
  }

  shouldComponentUpdate = (nextProps, nextState) => {
    return nextState.actionsOpen !== this.state.actionsOpen
        || nextProps.resourceRevision !== this.props.resourceRevision
        || nextProps.contentTop !== this.props.contentTop
        || nextState.relatedResources !== this.state.relatedResources
        || nextProps.filterNames !== this.props.filterNames
  }

  render() {

    let { props } = this

    return (

        <FilterBox
          addFilter={props.addFilter}
          removeFilter={props.removeFilter}
          filterNames={props.filterNames}
          autocomplete={props.autocomplete}
          />

        <MultiResourceActionButton backgroundColor={red900}
          mini={true}
          style={styles.deleteResourceButton}
          disabled={!this.deleteEnabled}
          onTouchTap={this.handleDelete}
          ref={(ref)=>{this.deleteButton = ref}}
          data-rh={'Delete Selected...'}
          data-rh-at={'bottom'}>
            <IconDelete/>
        </MultiResourceActionButton>

        <FilterTable
          className={'pods'}
          columns={this.columns}
          data={this.state.relatedResources}
          height={`calc(100vh - ${props.contentTop + 177}px)`}
          multiSelectable={true}
          onRowSelection={this.handleRowSelection}
          onCellClick={this.handleCellClick}
          hoveredRow={this.state.hoveredRow}
          onRenderCell={this.renderCell}
          getCellValue={this.getCellValue}
          selectedIds={this.selectedIds}
          stripedRows={false}
          iconStyle={{fill: 'rgba(255,255,255,0.9)'}}
          iconInactiveStyle={{fill: 'rgba(255,255,255,0.5)'}}
          width={'calc(100vw - 60px)'}
          wrapperStyle={{marginLeft: -15, marginRight: -15, overflowX: 'hidden', overflowY: 'auto'}}
          headerStyle={{backgroundColor: 'rgba(185, 162, 131, 0.85)', color: 'white'}}
          />

      <RowActionMenu
        open={!!this.state.hoveredResource}
        handlers={{
          logs: ()=> { this.props.viewResource(this.state.hoveredResource,'logs') },
          term: ()=> { this.props.viewResource(this.state.hoveredResource,'terminal') },
          edit: ()=> { this.props.viewResource(this.state.hoveredResource,'edit') },
          delete: ()=>{ this.handleDelete(this.state.hoveredResources)},
          close: this.handleActionsRequestClose,
        }}
        access={this.state.hoveredResourceAccess}
        anchorEl={this.state.actionsAnchor}
        />

      <ConfirmationDialog
        open={this.state.deleteOpen}
        title={'Delete Resource(s):'}
        message={`Are you sure you want to delete the following ` +
          `${this.state.selectedResources.length > 1 ? this.state.selectedResources.length + ' ' : ''}` +
          `resource${this.state.selectedResources.length > 1 ? 's':''}?`}
        resources={this.state.selectedResources}
        onRequestClose={this.handleRequestCloseDelete}
        onConfirm={this.handleConfirmDelete}
        linkGenerator={this.props.linkGenerator}
        />

    )
  }

}))
<|endoftext|>