<commit_before>import store from './store'
import refresh from './refresh'
import _ from 'lodash'
import geolib from 'geolib'
import $ from 'jquery'
import { NEARBY_METERS } from './constants'

//
// Action functions
//

// Action to load fiber data asynchrnously
export function loadDataAsync(){

  $.ajax('/data/boulder.json').done(function(json) {
    store.geometries = json

    let fibers = {}

    store.fibers = _.map(json, (d) => {

      // TODO: implement the correct logic to compute the center of the geometry
      // hint: use geolib.getCenter()

      const center = geolib.getCenter(d.coordinates)

      return {
        geometry: d,
        center: center
      }
    })

    refresh()
  })
}

// Action to set a position selected by the user
export function setSelectedPosition(latlng) {
  store.selectedPosition = latlng

  _.forEach(store.fibers, forEachFiberSetIsSelected)

  _.forEach(store.fibers, forEachFiberSetCost)

  refresh()
}

//
// private helper function
//

// helper to set each fiber's 'isSelected' flag based on whether this fiber is
// nearby with respect to the position selected by the user
function forEachFiberSetIsSelected(fiber){

   // TODO: implement the logic to set fiber.isSelected if the fiber's geometry center
   // is within a certain distance from the selected position 'NEARBY_METERS'
   // hint: use geolib.getDistance()

   const fiberPosition = {
 latitude: fiber.geometry.coordinates[0][1],
 longitude: fiber.geometry.coordinates[0][0]
 }

 if(geolib.getDistance(store.selectedPosition, fiberPosition) < NEARBY_METERS){
 	  fiber.isSelected = true
   }
  else{
  fiber.isSelected = false
}
/*  var center = geolib.getCenter(fiber.geometry.coordinates)
  var selected = store.selectedPosition
  if (geolib.getDistance(center, selected)<=NEARBY_METERS){
    fiber.isSelected = true
  }*/
}

// helper to set the cost of connecting this fiber to the selected position
function forEachFiberSetCost(fiber){

  // TODO: implement the logic to calcualte the cost of connecting from the selected
  // position to this fiber, and the distance between them.

  const fiberPosition = {
latitude: fiber.geometry.coordinates[0][1],
longitude: fiber.geometry.coordinates[0][0]
}

fiber.distance = geolib.getDistance(store.selectedPosition, fiberPosition)
  fiber.cost = Math.round((40 * fiber.distance)) //Assuming $40/metre of fiber
}
<commit_msg>stuff<commit_after>import store from './store'
import refresh from './refresh'
import _ from 'lodash'
import geolib from 'geolib'
import $ from 'jquery'
import { NEARBY_METERS } from './constants'

//
// Action functions
//

// Action to load fiber data asynchrnously
export function loadDataAsync(){

  $.ajax('/data/boulder.json').done(function(json) {
    store.geometries = json

    let fibers = {}

    store.fibers = _.map(json, (d) => {

      // TODO: implement the correct logic to compute the center of the geometry
      // hint: use geolib.getCenter()

      const center = geolib.getCenter(d.coordinates)

      return {
        geometry: d,
        center: center
      }
    })

    refresh()
  })
}

// Action to set a position selected by the user
export function setSelectedPosition(latlng) {
  store.selectedPosition = latlng

  _.forEach(store.fibers, forEachFiberSetIsSelected)

  _.forEach(store.fibers, forEachFiberSetCost)

  refresh()
}

//
// private helper function
//

// helper to set each fiber's 'isSelected' flag based on whether this fiber is
// nearby with respect to the position selected by the user
function forEachFiberSetIsSelected(fiber){

   // TODO: implement the logic to set fiber.isSelected if the fiber's geometry center
   // is within a certain distance from the selected position 'NEARBY_METERS'
   // hint: use geolib.getDistance()

   const fiberPosition = {
 latitude: fiber.geometry.coordinates[0][1],
 longitude: fiber.geometry.coordinates[0][0]
 }

 if(geolib.getDistance(store.selectedPosition, fiberPosition) < NEARBY_METERS){
 	  fiber.isSelected = true
   }
  else{
  fiber.isSelected = false
}
/*  var center = geolib.getCenter(fiber.geometry.coordinates)
  var selected = store.selectedPosition
  if (geolib.getDistance(center, selected)<=NEARBY_METERS){
    fiber.isSelected = true
  }*/
}

// helper to set the cost of connecting this fiber to the selected position
function forEachFiberSetCost(fiber){

  // TODO: implement the logic to calcualte the cost of connecting from the selected
  // position to this fiber, and the distance between them.

  const fiberPosition = {
    latitude: fiber.geometry.coordinates[0][1],
    longitude: fiber.geometry.coordinates[0][0]
    }

fiber.distance = geolib.getDistance(store.selectedPosition, fiberPosition)
fiber.cost = Math.round((40 * fiber.distance)) //Assuming $40/metre of fiber
}
<|endoftext|>


<commit_before>// Module dependencies
var path = require('path'),
    fs = require('fs'),
    i18n = require('i18next'),
    settings = require('./config/settings')();

module.exports = function(app) {

    var log = app.locals.logger;

    function changeUserLanguage(req, res) {
        var lng = req.params.__lng__;
        if (settings.supportedLngs.indexOf(lng) >= 0) {
            log.debug('Changed the language from %s to %s', i18n.lng(), lng);
            i18n.persistCookie(req, res, lng); // set cookie value for the language
            res.send(200);
        } else {
            log.warn('You cannot change the language to %s', lng);
            res.send(403);
        }
    }

    function requireAuthentication(req, res, next) {
        if (req.session && req.session.userName) {
            next();
        } else {
            res.redirect('/login?continue=' + req.url);
        }
    }

    function renderView(req, res, view) {
        var lng = res.locals.i18n.lng();
        if (settings.supportedLngs.indexOf(lng) < 0) {
            lng = settings.i18next.fallbackLng || settings.supportedLngs[0];
            i18n.persistCookie(req, res, lng); // set cookie value for the languge
        }
        res.render(view, {
            'lang': lng,
            'title': res.locals.t('title'),
            'dir': res.locals.t('config:dir')
        });
    }

    // api: change user language
    app.get('/api/locale/:__lng__', [
        changeUserLanguage
    ]);

    // api: all
    app.all('/api/*', [
        requireAuthentication
    ]);

    // default view
    app.get('/*', function(req, res, next) {
        var view = req.params[0] || 'index';
        var file = view + '.hogan';
        if (fs.existsSync(path.resolve(__dirname, 'views', file))) {
            renderView(req, res, view);
            return;
        }

        next();
    });

    /*
    app.get('/404', function(req, res, next){
        // trigger a 404 since no other middleware
        // will match /404 after this one, and we're not
        // responding here
        next();
    });

    app.get('/403', function(req, res, next){
        // trigger a 403 error
        var err = new Error('not allowed!');
        err.status = 403;
        next(err);
    });

    app.get('/500', function(req, res, next){
        // trigger a generic (500) error
        next(new Error('keyboard cat!'));
    });
    */

    return module.exports;

};
<commit_msg>bug fixes<commit_after>// Module dependencies
var path = require('path'),
    fs = require('fs'),
    i18n = require('i18next'),
    settings = require('./config/settings')();

module.exports = function(app) {

    var log = app.locals.logger;

    function changeUserLanguage(req, res) {
        var lng = req.params.__lng__;
        if (settings.supportedLngs.indexOf(lng) >= 0) {
            log.debug('Changed the language from %s to %s', i18n.lng(), lng);
            i18n.persistCookie(req, res, lng); // set cookie value for the language
            res.send(200);
        } else {
            log.warn('You cannot change the language to %s', lng);
            res.send(403);
        }
    }

    function requireAuthentication(req, res, next) {
        if (req.session && req.session.userName) {
            next();
        } else {
            res.redirect('/login?continue=' + req.url);
        }
    }

    function renderView(req, res, view) {
        var lng = res.locals.i18n.lng();
        if (settings.supportedLngs.indexOf(lng) < 0) {
            lng = settings.i18next.fallbackLng || settings.supportedLngs[0];
            i18n.persistCookie(req, res, lng); // set cookie value for the languge
        }
        res.render(view, {
            'version': settings.version,
            'lang': lng,
            'title': res.locals.t('title'),
            'dir': res.locals.t('config:dir')
        });
    }

    // api: change user language
    app.get('/api/locale/:__lng__', [
        changeUserLanguage
    ]);

    // api: all
    app.all('/api/*', [
        requireAuthentication
    ]);

    // default view
    app.get('/*', function(req, res, next) {
        var view = req.params[0] || 'index';
        var file = view + '.hogan';
        if (fs.existsSync(path.resolve(__dirname, 'views', file))) {
            renderView(req, res, file);
            return;
        }

        next();
    });

    /*
    app.get('/404', function(req, res, next){
        // trigger a 404 since no other middleware
        // will match /404 after this one, and we're not
        // responding here
        next();
    });

    app.get('/403', function(req, res, next){
        // trigger a 403 error
        var err = new Error('not allowed!');
        err.status = 403;
        next(err);
    });

    app.get('/500', function(req, res, next){
        // trigger a generic (500) error
        next(new Error('keyboard cat!'));
    });
    */

    return module.exports;

};
<|endoftext|>


<commit_before>L.Edit = L.Edit || {};

L.Edit.SimpleShape = L.Handler.extend({
	options: {
		moveIcon: new L.DivIcon({
			iconSize: new L.Point(8, 8),
			className: 'leaflet-div-icon leaflet-editing-icon leaflet-edit-move'
		}),
		resizeIcon: new L.DivIcon({
			iconSize: new L.Point(8, 8),
			className: 'leaflet-div-icon leaflet-editing-icon leaflet-edit-resize'
		})
	},

	initialize: function (shape, options) {
		this._shape = shape;
		L.Util.setOptions(this, options);
	},

	addHooks: function () {
		if (this._shape._map) {
			this._map = this._shape._map;

			if (!this._markerGroup) {
				this._initMarkers();
			}
			this._map.addLayer(this._markerGroup);
		}
	},

	removeHooks: function () {
		if (this._shape._map) {
			this._unbindMarker(this._moveMarker);

			for (var i = 0, l = this._resizeMarkers.length; i < l; i++) {
				this._unbindMarker(this._resizeMarkers[i]);
			}
			this._resizeMarkers = null;

			this._map.removeLayer(this._markerGroup);
			delete this._markerGroup;
		}

		this._map = null;
	},

	updateMarkers: function () {
		this._markerGroup.clearLayers();
		this._initMarkers();
	},

	_initMarkers: function () {
		if (!this._markerGroup) {
			this._markerGroup = new L.LayerGroup();
		}

		// Create center marker
		this._createMoveMarker();

		// Create edge marker
		this._createResizeMarker();
	},

	_createMoveMarker: function () {
		// Children override
	},

	_createResizeMarker: function () {
		// Children override
	},

	_createMarker: function (latlng, icon) {
		var marker = new L.Marker(latlng, {
			draggable: true,
			icon: icon,
			zIndexOffset: 10
		});

		this._bindMarker(marker);

		this._markerGroup.addLayer(marker);

		return marker;
	},

	_bindMarker: function (marker) {
		marker
			.on('dragstart', this._onMarkerDragStart, this)
			.on('drag', this._onMarkerDrag, this)
			.on('dragend', this._onMarkerDragEnd, this);
	},

	_unbindMarker: function (marker) {
		marker
			.off('dragstart', this._onMarkerDragStart, this)
			.off('drag', this._onMarkerDrag, this)
			.off('dragend', this._onMarkerDragEnd, this);
	},

	_onMarkerDragStart: function (e) {
		var marker = e.target;
		marker.setOpacity(0);
	},

	_fireEdit: function () {
		this._shape.edited = true;
		this._shape.fire('edit');
	},

	_onMarkerDrag: function (e) {
		var marker = e.target,
			latlng = marker.getLatLng();

		if (marker === this._moveMarker) {
			this._move(latlng);
		} else {
			this._resize(latlng);
		}

		this._shape.redraw();
	},

	_onMarkerDragEnd: function (e) {
		var marker = e.target;
		marker.setOpacity(1);

		this._shape.fire('edit');
		this._fireEdit();
	},

	_move: function () {
		// Children override
	},

	_resize: function () {
		// Children override
	}
});<commit_msg>fix for: 2 identical events issued for one action<commit_after>L.Edit = L.Edit || {};

L.Edit.SimpleShape = L.Handler.extend({
	options: {
		moveIcon: new L.DivIcon({
			iconSize: new L.Point(8, 8),
			className: 'leaflet-div-icon leaflet-editing-icon leaflet-edit-move'
		}),
		resizeIcon: new L.DivIcon({
			iconSize: new L.Point(8, 8),
			className: 'leaflet-div-icon leaflet-editing-icon leaflet-edit-resize'
		})
	},

	initialize: function (shape, options) {
		this._shape = shape;
		L.Util.setOptions(this, options);
	},

	addHooks: function () {
		if (this._shape._map) {
			this._map = this._shape._map;

			if (!this._markerGroup) {
				this._initMarkers();
			}
			this._map.addLayer(this._markerGroup);
		}
	},

	removeHooks: function () {
		if (this._shape._map) {
			this._unbindMarker(this._moveMarker);

			for (var i = 0, l = this._resizeMarkers.length; i < l; i++) {
				this._unbindMarker(this._resizeMarkers[i]);
			}
			this._resizeMarkers = null;

			this._map.removeLayer(this._markerGroup);
			delete this._markerGroup;
		}

		this._map = null;
	},

	updateMarkers: function () {
		this._markerGroup.clearLayers();
		this._initMarkers();
	},

	_initMarkers: function () {
		if (!this._markerGroup) {
			this._markerGroup = new L.LayerGroup();
		}

		// Create center marker
		this._createMoveMarker();

		// Create edge marker
		this._createResizeMarker();
	},

	_createMoveMarker: function () {
		// Children override
	},

	_createResizeMarker: function () {
		// Children override
	},

	_createMarker: function (latlng, icon) {
		var marker = new L.Marker(latlng, {
			draggable: true,
			icon: icon,
			zIndexOffset: 10
		});

		this._bindMarker(marker);

		this._markerGroup.addLayer(marker);

		return marker;
	},

	_bindMarker: function (marker) {
		marker
			.on('dragstart', this._onMarkerDragStart, this)
			.on('drag', this._onMarkerDrag, this)
			.on('dragend', this._onMarkerDragEnd, this);
	},

	_unbindMarker: function (marker) {
		marker
			.off('dragstart', this._onMarkerDragStart, this)
			.off('drag', this._onMarkerDrag, this)
			.off('dragend', this._onMarkerDragEnd, this);
	},

	_onMarkerDragStart: function (e) {
		var marker = e.target;
		marker.setOpacity(0);
	},

	_fireEdit: function () {
		this._shape.edited = true;
		this._shape.fire('edit');
	},

	_onMarkerDrag: function (e) {
		var marker = e.target,
			latlng = marker.getLatLng();

		if (marker === this._moveMarker) {
			this._move(latlng);
		} else {
			this._resize(latlng);
		}

		this._shape.redraw();
	},

	_onMarkerDragEnd: function (e) {
		var marker = e.target;
		marker.setOpacity(1);

		this._fireEdit();
	},

	_move: function () {
		// Children override
	},

	_resize: function () {
		// Children override
	}
});
<|endoftext|>


<commit_before>const util    = require('util');
const express = require('express');
const app     = express();
const router  = express.Router();

const Config = require('./Config');

class WebInterface {

  constructor(state) {
    this.state = state;
    this.port  = Config.get('webPort') || 9000;
  }

  init() {
    router.get('/', (req, res) => res.json({ message: 'hooray! welcome to our api!' }));

    app.use('/api', router);

    app.listen(this.port);
    util.log(`WEB: Web API activated and running on port ${this.port}.`);

  }

}

module.exports = WebInterface;<commit_msg>Just send state if you ping RMUD.<commit_after>const util    = require('util');
const express = require('express');
const app     = express();
const router  = express.Router();

const Config = require('./Config');

class WebInterface {

  constructor(state) {
    this.state = state;
    this.port  = Config.get('webPort') || 9000;
  }

  init() {
    router.get('/', (req, res) => res.json(this.state));

    app.use('/api', router);

    app.listen(this.port);
    util.log(`WEB: Web API activated and running on port ${this.port}.`);

  }

}

module.exports = WebInterface;<|endoftext|>


<commit_before>import childProcess from "child_process";
import fs from "fs";
import _ from "lodash";
import compareVersions from "compare-versions";
import Accessories from "./Accessories";
import AccessoryHelper from "./AccessoryHelper";
import devices from "./devices";
import Subscriptions from "./Subscriptions";
import WinkClient from "./WinkClient";
import pkg from "../package.json";

export const pluginName = "homebridge-wink";
export const platformName = "Wink";

export default class WinkPlatform {
  constructor(log, config, api) {
    if (!config) {
      log("Plugin not configured.");
      return;
    }

    this.log = log;
    this.config = this.cleanConfig(config);
    this.api = api;

    this.checkVersion();

    this.definitions = devices(api.hap);
    this.accessories = new Accessories();
    this.accessoryHelper = new AccessoryHelper({
      config: this.config,
      definitions: this.definitions,
      hap: api.hap,
      log,
      onChange: this.handleAccessoryStateChange.bind(this)
    });
    this.client = new WinkClient({
      config: this.config,
      log,
      updateConfig: config => this.updateConfig(config)
    });
    this.interval = null;
    this.subscriptions = new Subscriptions();

    this.subscriptions.on("device-list", () => this.refreshDevices());
    this.subscriptions.on("device-update", device => {
      this.log(
        `Received update notification: ${device.name} (${device.object_type}/${device.object_id})`
      );
      this.updateDevice(device);
    });
    this.subscriptions.on("unknown-message", message => {
      this.log.warn("Received unknown notification:", message);
    });

    this.api.on("didFinishLaunching", this.didFinishLaunching.bind(this));
  }

  updateConfig(newConfig) {
    const configPath = this.api.user.configPath();
    const file = fs.readFileSync(configPath);
    const config = JSON.parse(file);
    const platConfig = config.platforms.find(x => x.name == this.config.name);
    _.extend(platConfig, newConfig);
    const serializedConfig = JSON.stringify(config, null, "  ");
    fs.writeFileSync(configPath, serializedConfig, "utf8");
    _.extend(this.config, newConfig);
  }

  checkVersion() {
    childProcess.exec(`npm view ${pkg.name} version`, (error, stdout) => {
      const latestVersion = stdout && stdout.trim();
      if (latestVersion && compareVersions(stdout.trim(), pkg.version) > 0) {
        this.log.warn(
          `NOTICE: New version of ${pkg.name} available: ${latestVersion}`
        );
      }
    });
  }

  cleanConfig(config) {
    const newConfig = {
      debug: false,
      direct_access: true,
      fan_ids: [],
      hide_groups: [],
      hide_ids: [],
      window_ids: [],
      ...config
    };

    ["fan_ids", "hide_ids", "window_ids"].forEach(field => {
      newConfig[field] = newConfig[field].map(id => id.toString());
    });

    return newConfig;
  }

  handleAccessoryStateChange(accessory, state) {
    return this.client.updateDevice(accessory, state);
  }

  configureAccessory(accessory) {
    this.patchAccessory(accessory);
    this.accessories.add(accessory);
    this.log(
      `Loaded from cache: ${accessory.context.name} (${accessory.context
        .object_type}/${accessory.context.object_id})`
    );
  }

  patchAccessory(accessory, device) {
    if (device) {
      accessory.context = device;
    }
    accessory.definition = this.accessoryHelper.getDefinition(
      accessory.context
    );
    Object.defineProperty(accessory, "merged_state", {
      get: function() {
        return {
          ...this.context.last_reading,
          ...this.context.desired_state
        };
      }
    });
  }

  async didFinishLaunching() {
    const authenticated = await this.client.authenticate();

    if (authenticated) {
      this.accessories.forEach(accessory => {
        this.accessoryHelper.configureAccessory(accessory);
      });

      this.interval = setInterval(() => this.refreshDevices(), 60 * 60 * 1000);

      this.refreshDevices();
    }
  }

  addDevice(device) {
    const { uuid } = this.api.hap;
    const deviceId = uuid.isValid(device.uuid)
      ? device.uuid
      : uuid.generateUUID(device.uuid);
    const accessory = new this.api.platformAccessory(device.name, deviceId);
    this.patchAccessory(accessory, device);
    this.accessoryHelper.configureAccessory(accessory);
    this.api.registerPlatformAccessories(pluginName, platformName, [accessory]);
    this.accessories.add(accessory);
    this.log(
      `Added: ${accessory.context.name} (${accessory.context
        .object_type}/${accessory.context.object_id})`
    );
  }

  updateDevice(device) {
    const accessory = this.accessories.get(device);
    this.accessoryHelper.updateAccessoryState(accessory, device);
    this.subscriptions.subscribe(device.subscription);
  }

  async refreshDevices() {
    try {
      this.log("Refreshing devices...");

      // Request user - this should ensure that pubnub subscriptions don't stop working
      await this.client.getUser();

      const response = await this.client.getDevices();

      const data = this.annotateDevices(response.data);
      const devices = data.filter(x => x.valid).map(x => x.device);

      const toRemove = this.accessories.diffRemove(devices);
      const toUpdate = this.accessories.intersection(devices);
      const toAdd = this.accessories.diffAdd(devices);
      const toIgnore = data.filter(x => !x.valid);

      if (response.subscription) {
        this.subscriptions.subscribe(response.subscription);
      }

      toRemove.forEach(this.removeAccessory, this);
      toUpdate.forEach(this.updateDevice, this);
      toAdd.forEach(this.addDevice, this);
      toIgnore.forEach(this.ignoreDevice, this);

      this.log("Devices refreshed");
    } catch (e) {
      this.log.error("Failed to refresh devices.", e);
    }
  }

  annotateDevices(devices) {
    return devices
      .filter(device => device.object_type !== "hub")
      .filter(device => !device.hidden_at)
      .map(device => {
        const definition = this.definitions[device.object_type];
        const isSupported = !!definition;

        const hide_groups =
          isSupported &&
          (this.config.hide_groups.indexOf(definition.group) !== -1 ||
            this.config.hide_groups.indexOf(definition.type) !== -1);

        const hide_ids =
          isSupported && this.config.hide_ids.indexOf(device.object_id) !== -1;

        return {
          device,
          definition,
          isSupported,
          hide_groups,
          hide_ids,
          valid: isSupported && !(hide_groups || hide_ids)
        };
      });
  }

  ignoreDevice(data) {
    if (!this.accessories.ignore(data.device)) {
      return;
    }

    let reason = null;

    if (!data.isSupported) {
      reason = "Not supported by HomeKit";
    } else if (data.hide_groups) {
      reason = "Hidden by hide_groups config option";
    } else if (data.hide_ids) {
      reason = "Hidden by hide_ids config option";
    }

    if (reason) {
      this.log(
        `${reason}: ${data.device.name} (${data.device.object_type}/${data
          .device.object_id})`
      );
    }
  }

  removeAccessory(accessory) {
    if (this.accessories.remove(accessory)) {
      this.api.unregisterPlatformAccessories(pluginName, platformName, [
        accessory
      ]);
      this.log(
        `Removed: ${accessory.context.name} (${accessory.context
          .object_type}/${accessory.context.object_id})`
      );
    }
  }
}
<commit_msg>Fixed typo<commit_after>import childProcess from "child_process";
import fs from "fs";
import _ from "lodash";
import compareVersions from "compare-versions";
import Accessories from "./Accessories";
import AccessoryHelper from "./AccessoryHelper";
import devices from "./devices";
import Subscriptions from "./Subscriptions";
import WinkClient from "./WinkClient";
import pkg from "../package.json";

export const pluginName = "homebridge-wink";
export const platformName = "Wink";

export default class WinkPlatform {
  constructor(log, config, api) {
    if (!config) {
      log("Plugin not configured.");
      return;
    }

    this.log = log;
    this.config = this.cleanConfig(config);
    this.api = api;

    this.checkVersion();

    this.definitions = devices(api.hap);
    this.accessories = new Accessories();
    this.accessoryHelper = new AccessoryHelper({
      config: this.config,
      definitions: this.definitions,
      hap: api.hap,
      log,
      onChange: this.handleAccessoryStateChange.bind(this)
    });
    this.client = new WinkClient({
      config: this.config,
      log,
      updateConfig: config => this.updateConfig(config)
    });
    this.interval = null;
    this.subscriptions = new Subscriptions();

    this.subscriptions.on("device-list", () => this.refreshDevices());
    this.subscriptions.on("device-update", device => {
      this.log(
        `Received update notification: ${device.name} (${device.object_type}/${device.object_id})`
      );
      this.updateDevice(device);
    });
    this.subscriptions.on("unknown-message", message => {
      this.log.warn("Received unknown notification:", message);
    });

    this.api.on("didFinishLaunching", this.didFinishLaunching.bind(this));
  }

  updateConfig(newConfig) {
    const configPath = this.api.user.configPath();
    const file = fs.readFileSync(configPath);
    const config = JSON.parse(file);
    const platConfig = config.platforms.find(x => x.name == this.config.name);
    _.extend(platConfig, newConfig);
    const serializedConfig = JSON.stringify(config, null, "  ");
    fs.writeFileSync(configPath, serializedConfig, "utf8");
    _.extend(this.config, newConfig);
  }

  checkVersion() {
    childProcess.exec(`npm view ${pkg.name} version`, (error, stdout) => {
      const latestVersion = stdout && stdout.trim();
      if (latestVersion && compareVersions(stdout.trim(), pkg.version) > 0) {
        this.log.warn(
          `NOTICE: New version of ${pkg.name} available: ${latestVersion}`
        );
      }
    });
  }

  cleanConfig(config) {
    const newConfig = {
      debug: false,
      direct_access: true,
      fan_ids: [],
      hide_groups: [],
      hide_ids: [],
      window_ids: [],
      ...config
    };

    ["fan_ids", "hide_ids", "window_ids"].forEach(field => {
      newConfig[field] = newConfig[field].map(id => id.toString());
    });

    return newConfig;
  }

  handleAccessoryStateChange(accessory, state) {
    return this.client.updateDevice(accessory, state);
  }

  configureAccessory(accessory) {
    this.patchAccessory(accessory);
    this.accessories.add(accessory);
    this.log(
      `Loaded from cache: ${accessory.context.name} (${accessory.context
        .object_type}/${accessory.context.object_id})`
    );
  }

  patchAccessory(accessory, device) {
    if (device) {
      accessory.context = device;
    }
    accessory.definition = this.accessoryHelper.getDefinition(
      accessory.context
    );
    Object.defineProperty(accessory, "merged_state", {
      get: function() {
        return {
          ...this.context.last_reading,
          ...this.context.desired_state
        };
      }
    });
  }

  async didFinishLaunching() {
    const authenticated = await this.client.authenticate();

    if (authenticated) {
      this.accessories.forEach(accessory => {
        this.accessoryHelper.configureAccessory(accessory);
      });

      this.interval = setInterval(() => this.refreshDevices(), 60 * 60 * 1000);

      this.refreshDevices();
    }
  }

  addDevice(device) {
    const { uuid } = this.api.hap;
    const deviceId = uuid.isValid(device.uuid)
      ? device.uuid
      : uuid.generate(device.uuid);
    const accessory = new this.api.platformAccessory(device.name, deviceId);
    this.patchAccessory(accessory, device);
    this.accessoryHelper.configureAccessory(accessory);
    this.api.registerPlatformAccessories(pluginName, platformName, [accessory]);
    this.accessories.add(accessory);
    this.log(
      `Added: ${accessory.context.name} (${accessory.context
        .object_type}/${accessory.context.object_id})`
    );
  }

  updateDevice(device) {
    const accessory = this.accessories.get(device);
    this.accessoryHelper.updateAccessoryState(accessory, device);
    this.subscriptions.subscribe(device.subscription);
  }

  async refreshDevices() {
    try {
      this.log("Refreshing devices...");

      // Request user - this should ensure that pubnub subscriptions don't stop working
      await this.client.getUser();

      const response = await this.client.getDevices();

      const data = this.annotateDevices(response.data);
      const devices = data.filter(x => x.valid).map(x => x.device);

      const toRemove = this.accessories.diffRemove(devices);
      const toUpdate = this.accessories.intersection(devices);
      const toAdd = this.accessories.diffAdd(devices);
      const toIgnore = data.filter(x => !x.valid);

      if (response.subscription) {
        this.subscriptions.subscribe(response.subscription);
      }

      toRemove.forEach(this.removeAccessory, this);
      toUpdate.forEach(this.updateDevice, this);
      toAdd.forEach(this.addDevice, this);
      toIgnore.forEach(this.ignoreDevice, this);

      this.log("Devices refreshed");
    } catch (e) {
      this.log.error("Failed to refresh devices.", e);
    }
  }

  annotateDevices(devices) {
    return devices
      .filter(device => device.object_type !== "hub")
      .filter(device => !device.hidden_at)
      .map(device => {
        const definition = this.definitions[device.object_type];
        const isSupported = !!definition;

        const hide_groups =
          isSupported &&
          (this.config.hide_groups.indexOf(definition.group) !== -1 ||
            this.config.hide_groups.indexOf(definition.type) !== -1);

        const hide_ids =
          isSupported && this.config.hide_ids.indexOf(device.object_id) !== -1;

        return {
          device,
          definition,
          isSupported,
          hide_groups,
          hide_ids,
          valid: isSupported && !(hide_groups || hide_ids)
        };
      });
  }

  ignoreDevice(data) {
    if (!this.accessories.ignore(data.device)) {
      return;
    }

    let reason = null;

    if (!data.isSupported) {
      reason = "Not supported by HomeKit";
    } else if (data.hide_groups) {
      reason = "Hidden by hide_groups config option";
    } else if (data.hide_ids) {
      reason = "Hidden by hide_ids config option";
    }

    if (reason) {
      this.log(
        `${reason}: ${data.device.name} (${data.device.object_type}/${data
          .device.object_id})`
      );
    }
  }

  removeAccessory(accessory) {
    if (this.accessories.remove(accessory)) {
      this.api.unregisterPlatformAccessories(pluginName, platformName, [
        accessory
      ]);
      this.log(
        `Removed: ${accessory.context.name} (${accessory.context
          .object_type}/${accessory.context.object_id})`
      );
    }
  }
}
<|endoftext|>


<commit_before>var spotify = require('../lib/spotify-node-applescript.js');
var expect = require('chai').expect;

describe('Spotify Controller', function(){

    // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    // Make sure spotify is open before running these tests
    // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    beforeEach(function(done){
        spotify.playTrackInContext('spotify:track:0R8P9KfGJCDULmlEoBagcO', 'spotify:album:6ZG5lRT77aJ3btmArcykra', function(){
            done();
        });
    });

    after(function(done){
        spotify.pause(function(){
            done();
        });
    });

    // Open and get track

    it('play track', function(done){
        spotify.playTrack('spotify:track:6JEK0CvvjDjjMUBFoXShNZ', function(){
            spotify.getTrack(function(error, track){
                expect(track.name).to.equal('Never Gonna Give You Up');
                done();
            });
        });
    });

    // Playback control

    it('should pause a track', function(done){
        spotify.pause(function(){
            spotify.getState(function(error, state){
                expect(state.state).to.equal('paused');
                done();
            });
        });
    });

    it('should resume playing a track after pausing', function(done){
        spotify.pause(function(){
            spotify.play(function(){
                spotify.getState(function(error, state){
                    expect(state.state).to.equal('playing');
                    done();
                });
            });
        });
    });

    it('should play and pause a track', function(done){
        spotify.playPause(function(){
            spotify.getState(function(error, state){
                expect(state.state).to.equal('paused');
                spotify.playPause(function(){
                    spotify.getState(function(error, state){
                        expect(state.state).to.equal('playing');
                        done();
                    });
                });
            });
        });
    });

    it('should return playing track', function(done){
        spotify.getTrack(function(error, track){
            expect(track.artist).to.equal('Coldplay');
            expect(track.name).to.equal('Trouble');
            done();
        });
    });

    it('should jump to a specific position of the song', function(done){
        // spotify needs some time to catch up with the jump or it will
        // simply return 0 as current player position
        setTimeout(function(){
            spotify.jumpTo(15, function(){
                spotify.getState(function(err, state){
                    expect(state.position).to.equal(15);
                    done();
                });
            });
        }, 1100);
    });

 	it('play next track', function(done){
		spotify.next(function(error, track){
			spotify.getTrack(function(error, track){
                expect(track.name).to.equal('Parachutes');
				done();
			});
		});
	});

	it('play previous track', function(done){
		spotify.previous(function(error, track){
			spotify.getTrack(function(error, track){
				expect(track.name).to.equal('Yellow');
				done();
			});
		});
	});

    // Volumen control

    it('should turn volume up', function(done){
        // first do volumeDown in case volume is already 100
        spotify.volumeDown(function(){
            spotify.getState(function(error, state){
                var volume = state.volume;
                spotify.volumeUp(function(){
                    spotify.getState(function(error, state){
                        expect(state.volume).to.be.greaterThan(volume);
                        done();
                    });
                });
            });
        });
    });

    it('should turn volume down', function(done){
        // first do volumeUp in case volume is already 0
        spotify.volumeUp(function(){
            spotify.getState(function(error, state){
                var volume = state.volume;
                spotify.volumeDown(function(){
                    spotify.getState(function(error, state){
                        expect(state.volume).to.be.lessThan(volume);
                        done();
                    });
                });
            });
        });
    });

    it('should set the volume', function(done){
        spotify.setVolume(0, function(){
            spotify.getState(function(err, state){
                if (err) throw err;

                expect(state.volume).to.equal(0);
                done();
            });
        });
    });

    it('should mute and unmute the volume', function(done){
        spotify.setVolume(50, function(){
            spotify.muteVolume(function(err, state){
                spotify.getState(function(err, state){
                    if (err) throw err;

                    // volume now should be 0
                    expect(state.volume).to.equal(0);

                    spotify.unmuteVolume(function(err, state){
                        spotify.getState(function(err, state){
                            if (err) throw err;

                            // volume now should be 50 again
                            // but spotify won't set volume exactly, so test if volume is within a range
                            expect(state.volume).to.be.within(45, 55);
                            done();
                        });
                    });
                });
            });
        });
    });

    // State retrieval

    it('should return current track', function(done){
        spotify.getTrack(function(error, track){
            expect(track.name).to.equal('Trouble');
            expect(track.artist).to.equal('Coldplay');
            expect(track.album).to.equal('Parachutes');
            expect(track.disc_number).to.equal(1);
            expect(track.duration).to.be.a('number');
            expect(track.played_count).to.be.a('number');
            expect(track.track_number).to.equal(6);
            expect(track.popularity).to.be.a('number');
            expect(track.id).to.equal('spotify:track:0R8P9KfGJCDULmlEoBagcO');
            expect(track.album_artist).to.equal('Coldplay');
            expect(track.spotify_url).to.equal('spotify:track:0R8P9KfGJCDULmlEoBagcO');

            done();
        });
    });

    it('should return player status', function(done){
        spotify.getState(function(error, state){
            expect(state.state).to.equal('playing');
            expect(state.volume).to.be.a('number');
            expect(state.position).to.be.a('number');
            expect(state.track_id).to.equal('spotify:track:0R8P9KfGJCDULmlEoBagcO');

            done();
        });
    });

    it('should return true when spotify is running', function(done) {
        spotify.isRunning(function(error, isRunning) {
            expect(error).to.be.null;
            expect(isRunning).to.be.true;
            done();
        });
    });

    it('should set the repeating to false', function(done){
        spotify.setRepeating(false, function(){
            spotify.isRepeating(function(err, repeating){
                if (err) throw err;

                expect(repeating).to.equal(false);
                done();
            });
        });
    });

    it('should set the repeating to true', function(done){
        spotify.setRepeating(true, function(){
            spotify.isRepeating(function(err, repeating){
                if (err) throw err;

                expect(repeating).to.equal(true);
                done();
            });
        });
    });

    it('should set the shuffling to false', function(done){
        spotify.setShuffling(false, function(){
            spotify.isShuffling(function(err, shuffling){
                if (err) throw err;

                expect(shuffling).to.equal(false);
                done();
            });
        });
    });

    it('should set the shuffling to true', function(done){
        spotify.setShuffling(true, function(){
            spotify.isShuffling(function(err, shuffling){
                if (err) throw err;

                expect(shuffling).to.equal(true);
                done();
            });
        });
    });

    it('should toggle the repeating', function(done){
        spotify.setRepeating(false, function(){
            spotify.toggleRepeating(function(err){
                spotify.isRepeating(function(err, repeating){
                    if (err) throw err;

                    expect(repeating).to.equal(true);
                    done();
                });
            })
        });
    });

    it('should toggle the shuffling', function(done){
        spotify.setShuffling(false, function(){
            spotify.toggleShuffling(function(err){
                spotify.isShuffling(function(err, shuffling){
                    if (err) throw err;

                    expect(shuffling).to.equal(true);
                    done();
                });
            })
        });
    });

    /*it('should return the path to the PNG of the current artwork', function(done){
        spotify.getArtwork(function(err, path){
            if (err) throw err;

            var fileName = path.split('/').splice(-1)[0];
            expect(fileName).to.equal('spotify_track_3AhXZa8sUQht0UEdBJgpGc.png');
            done();
        });
    });*/
});
<commit_msg>reset shuffle and repeat after running tests<commit_after>var spotify = require('../lib/spotify-node-applescript.js');
var expect = require('chai').expect;

describe('Spotify Controller', function(){

    // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    // Make sure spotify is open before running these tests
    // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    beforeEach(function(done){
        spotify.playTrackInContext('spotify:track:0R8P9KfGJCDULmlEoBagcO', 'spotify:album:6ZG5lRT77aJ3btmArcykra', function(){
            done();
        });
    });

    after(function(done){
        spotify.pause(function(){
            done();
        });
        spotify.setRepeating(false);
        spotify.setShuffling(false);
    });

    // Open and get track

    it('play track', function(done){
        spotify.playTrack('spotify:track:6JEK0CvvjDjjMUBFoXShNZ', function(){
            spotify.getTrack(function(error, track){
                expect(track.name).to.equal('Never Gonna Give You Up');
                done();
            });
        });
    });

    // Playback control

    it('should pause a track', function(done){
        spotify.pause(function(){
            spotify.getState(function(error, state){
                expect(state.state).to.equal('paused');
                done();
            });
        });
    });

    it('should resume playing a track after pausing', function(done){
        spotify.pause(function(){
            spotify.play(function(){
                spotify.getState(function(error, state){
                    expect(state.state).to.equal('playing');
                    done();
                });
            });
        });
    });

    it('should play and pause a track', function(done){
        spotify.playPause(function(){
            spotify.getState(function(error, state){
                expect(state.state).to.equal('paused');
                spotify.playPause(function(){
                    spotify.getState(function(error, state){
                        expect(state.state).to.equal('playing');
                        done();
                    });
                });
            });
        });
    });

    it('should return playing track', function(done){
        spotify.getTrack(function(error, track){
            expect(track.artist).to.equal('Coldplay');
            expect(track.name).to.equal('Trouble');
            done();
        });
    });

    it('should jump to a specific position of the song', function(done){
        // spotify needs some time to catch up with the jump or it will
        // simply return 0 as current player position
        setTimeout(function(){
            spotify.jumpTo(15, function(){
                spotify.getState(function(err, state){
                    expect(state.position).to.equal(15);
                    done();
                });
            });
        }, 1100);
    });

 	it('play next track', function(done){
		spotify.next(function(error, track){
			spotify.getTrack(function(error, track){
                expect(track.name).to.equal('Parachutes');
				done();
			});
		});
	});

	it('play previous track', function(done){
		spotify.previous(function(error, track){
			spotify.getTrack(function(error, track){
				expect(track.name).to.equal('Yellow');
				done();
			});
		});
	});

    // Volumen control

    it('should turn volume up', function(done){
        // first do volumeDown in case volume is already 100
        spotify.volumeDown(function(){
            spotify.getState(function(error, state){
                var volume = state.volume;
                spotify.volumeUp(function(){
                    spotify.getState(function(error, state){
                        expect(state.volume).to.be.greaterThan(volume);
                        done();
                    });
                });
            });
        });
    });

    it('should turn volume down', function(done){
        // first do volumeUp in case volume is already 0
        spotify.volumeUp(function(){
            spotify.getState(function(error, state){
                var volume = state.volume;
                spotify.volumeDown(function(){
                    spotify.getState(function(error, state){
                        expect(state.volume).to.be.lessThan(volume);
                        done();
                    });
                });
            });
        });
    });

    it('should set the volume', function(done){
        spotify.setVolume(0, function(){
            spotify.getState(function(err, state){
                if (err) throw err;

                expect(state.volume).to.equal(0);
                done();
            });
        });
    });

    it('should mute and unmute the volume', function(done){
        spotify.setVolume(50, function(){
            spotify.muteVolume(function(err, state){
                spotify.getState(function(err, state){
                    if (err) throw err;

                    // volume now should be 0
                    expect(state.volume).to.equal(0);

                    spotify.unmuteVolume(function(err, state){
                        spotify.getState(function(err, state){
                            if (err) throw err;

                            // volume now should be 50 again
                            // but spotify won't set volume exactly, so test if volume is within a range
                            expect(state.volume).to.be.within(45, 55);
                            done();
                        });
                    });
                });
            });
        });
    });

    // State retrieval

    it('should return current track', function(done){
        spotify.getTrack(function(error, track){
            expect(track.name).to.equal('Trouble');
            expect(track.artist).to.equal('Coldplay');
            expect(track.album).to.equal('Parachutes');
            expect(track.disc_number).to.equal(1);
            expect(track.duration).to.be.a('number');
            expect(track.played_count).to.be.a('number');
            expect(track.track_number).to.equal(6);
            expect(track.popularity).to.be.a('number');
            expect(track.id).to.equal('spotify:track:0R8P9KfGJCDULmlEoBagcO');
            expect(track.album_artist).to.equal('Coldplay');
            expect(track.spotify_url).to.equal('spotify:track:0R8P9KfGJCDULmlEoBagcO');

            done();
        });
    });

    it('should return player status', function(done){
        spotify.getState(function(error, state){
            expect(state.state).to.equal('playing');
            expect(state.volume).to.be.a('number');
            expect(state.position).to.be.a('number');
            expect(state.track_id).to.equal('spotify:track:0R8P9KfGJCDULmlEoBagcO');

            done();
        });
    });

    it('should return true when spotify is running', function(done) {
        spotify.isRunning(function(error, isRunning) {
            expect(error).to.be.null;
            expect(isRunning).to.be.true;
            done();
        });
    });

    it('should set the repeating to false', function(done){
        spotify.setRepeating(false, function(){
            spotify.isRepeating(function(err, repeating){
                if (err) throw err;

                expect(repeating).to.equal(false);
                done();
            });
        });
    });

    it('should set the repeating to true', function(done){
        spotify.setRepeating(true, function(){
            spotify.isRepeating(function(err, repeating){
                if (err) throw err;

                expect(repeating).to.equal(true);
                done();
            });
        });
    });

    it('should set the shuffling to false', function(done){
        spotify.setShuffling(false, function(){
            spotify.isShuffling(function(err, shuffling){
                if (err) throw err;

                expect(shuffling).to.equal(false);
                done();
            });
        });
    });

    it('should set the shuffling to true', function(done){
        spotify.setShuffling(true, function(){
            spotify.isShuffling(function(err, shuffling){
                if (err) throw err;

                expect(shuffling).to.equal(true);
                done();
            });
        });
    });

    it('should toggle the repeating', function(done){
        spotify.setRepeating(false, function(){
            spotify.toggleRepeating(function(err){
                spotify.isRepeating(function(err, repeating){
                    if (err) throw err;

                    expect(repeating).to.equal(true);
                    done();
                });
            })
        });
    });

    it('should toggle the shuffling', function(done){
        spotify.setShuffling(false, function(){
            spotify.toggleShuffling(function(err){
                spotify.isShuffling(function(err, shuffling){
                    if (err) throw err;

                    expect(shuffling).to.equal(true);
                    done();
                });
            })
        });
    });

    /*it('should return the path to the PNG of the current artwork', function(done){
        spotify.getArtwork(function(err, path){
            if (err) throw err;

            var fileName = path.split('/').splice(-1)[0];
            expect(fileName).to.equal('spotify_track_3AhXZa8sUQht0UEdBJgpGc.png');
            done();
        });
    });*/
});
<|endoftext|>


<commit_before>/**
 * @file Thead component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';

// Components
import Th from '../_Th';

// Statics
import HorizontalAlign from '../_statics/HorizontalAlign';
import SelectMode from '../_statics/SelectMode';
import SelectAllMode from '../_statics/SelectAllMode';
import SortingType from '../_statics/SortingType';
import TableFragment from '../_statics/TableFragment';
import Direction from '../_statics/Direction';

// Vendors
import Util from '../_vendors/Util';
import TC from '../_vendors/TableCalculation';
import classNames from 'classnames';
import ScrollBar from '../_vendors/ScrollBar';

class Thead extends Component {

    static Align = HorizontalAlign;
    static SelectMode = SelectMode;
    static SelectAllMode = SelectAllMode;
    static SortingType = SortingType;

    constructor(props, ...restArgs) {
        super(props, ...restArgs);
    }

    getColumnsSpan = row => {

        const {data, onRequestColumnsSpan} = this.props;

        return onRequestColumnsSpan ?
            onRequestColumnsSpan(TableFragment.HEAD, row, data)
            :
            TC.getColumnsSpan(TableFragment.HEAD, row, data);

    };

    getStyle = (column, colIndex, columns) => {
        const {columnKeyField, columnsWidth, defaultColumnWidth, hasVerticalScroll} = this.props;
        return {
            ...column.headStyle,
            ...TC.getStickyColumnStyle(column?.fixed, colIndex, columns,
                columnKeyField, columnsWidth, defaultColumnWidth, hasVerticalScroll)
        };
    };

    handleClick = e => {
        const {data, disabled, onHeadClick} = this.props;
        !disabled && onHeadClick && onHeadClick(data, e);
    };

    render() {

        const {

                className, style, columns, columnsWidth, data, disabled, ignoreColumnSpan,
                hasFixedRightColumn, hasVerticalScroll, sorting, columnKeyField,
                defaultSortingType, sortingAscIconCls, sortingDescIconCls, defaultColumnWidth,
                onSortChange,

                ...restProps

            } = this.props,
            verticalScrollBarSize = ScrollBar.getSize(Direction.VERTICAL);

        return (

                {
                    columns && columns.map((row, rowIndex) => {

                        if (!row) {
                            return null;
                        }

                        const columnsSpan = this.getColumnsSpan(row);

                        return (

                                {
                                    columnsSpan ?
                                        columnsSpan.map(({column, span}, colIndex) => column ?
                                            <Th {...restProps}
                                                key={colIndex}
                                                column={column}
                                                columnKeyField={columnKeyField}
                                                className={classNames(column.headClassName, {
                                                    'fixed-left': column.fixed === HorizontalAlign.LEFT,
                                                    'last-fixed-left': column.fixed === HorizontalAlign.LEFT
                                                        && columnsSpan?.[colIndex + 1]?.column?.fixed
                                                        !== HorizontalAlign.LEFT,
                                                    'fixed-right': column.fixed === HorizontalAlign.RIGHT,
                                                    'first-fixed-right': column.fixed === HorizontalAlign.RIGHT
                                                        && columnsSpan?.[colIndex - 1]?.column?.fixed
                                                        !== HorizontalAlign.RIGHT
                                                })}
                                                style={this.getStyle(column, colIndex, row)}
                                                width={(
                                                    columnsWidth && columnKeyField
                                                    && columnsWidth.get(TC.getColumnKey(column, columnKeyField))
                                                ) || defaultColumnWidth}
                                                data={data}
                                                title={column.headTitle}
                                                renderer={column.headRenderer}
                                                align={column.headAlign || column.align}
                                                colIndex={colIndex}
                                                rowSpan={column.rowSpan}
                                                colSpan={ignoreColumnSpan ? null : column.colSpan}
                                                noWrap={TC.handleNoWrap(column.headNoWrap, column.noWrap, {
                                                    data,
                                                    rowIndex,
                                                    colIndex: colIndex,
                                                    tableData: data
                                                })}
                                                sorting={sorting}
                                                defaultSortingType={column.defaultSortingType || defaultSortingType}
                                                sortingAscIconCls={sortingAscIconCls}
                                                sortingDescIconCls={sortingDescIconCls}
                                                sortable={column.sortable}
                                                sortingProp={column.sortingProp}
                                                onSortChange={onSortChange}/>
                                            :
                                            null
                                        )
                                        :
                                        null
                                }

                                {
                                    hasVerticalScroll && columnsSpan && verticalScrollBarSize > 0 && rowIndex === 0 ?
                                        <th className={classNames('scroll-bar-th', {
                                            'fixed-right': hasFixedRightColumn
                                        })}
                                            style={{
                                                width: verticalScrollBarSize,
                                                ...(hasFixedRightColumn ? {
                                                    position: 'sticky',
                                                    right: 0
                                                } : null)
                                            }}
                                            rowSpan={columns.length}>

                                        :
                                        null
                                }

                        );

                    })
                }

        );

    }
}

Thead.propTypes = {

    className: PropTypes.string,
    style: PropTypes.object,

    /**
     * Children passed into table header.
     */
    columns: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.shape({

        /**
         * unique keyof column.
         */
        key: PropTypes.string,

        /**
         * fixed position of column ( 'left' / 'right' ).
         */
        fixed: PropTypes.oneOf(Util.enumerateValue(HorizontalAlign)),

        /**
         * width of column.
         */
        width: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.func]),

        /**
         * minimum width of column.
         */
        minWidth: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),

        /**
         * align of current column.
         */
        align: PropTypes.oneOf(Util.enumerateValue(HorizontalAlign)),

        /**
         * no wrap of current column.
         */
        noWrap: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),

        /**
         * The class name of header.
         */
        headClassName: PropTypes.string,

        /**
         * Override the styles of header.
         */
        headStyle: PropTypes.object,

        /**
         * align of table header cell
         */
        headAlign: PropTypes.oneOf(Util.enumerateValue(HorizontalAlign)),

        /**
         * The render content in table head.
         *  (1) callback:
         *      function (tableData, colIndex) {
         *          return colIndex;
         *      }
         *
         *  (2) others:
         *      render whatever you pass
         */
        headRenderer: PropTypes.any,

        /**
         * The title in table head.
         *  (1) callback:
         *      function (tableData, colIndex) {
         *          return colIndex;
         *      }
         *
         *  (2) others:
         *      render whatever you pass
         */
        headTitle: PropTypes.any,

        /**
         * column span of table header.
         *  (1) function callback:
         *      function (tableData, colIndex) {
         *          return null;
         *      }
         *
         *  (2) number:
         *      render whatever you pass
         */
        headSpan: PropTypes.oneOfType([PropTypes.number, PropTypes.func]),

        /**
         * no wrap of table header.
         */
        headNoWrap: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),

        /**
         * The class name of td.
         */
        bodyClassName: PropTypes.string,

        /**
         * Override the styles of td.
         */
        bodyStyle: PropTypes.object,

        /**
         * align of table body cell.
         */
        bodyAlign: PropTypes.oneOf(Util.enumerateValue(HorizontalAlign)),

        /**
         * The render content in table body.
         *  (1) callback:
         *      function (rowData, rowIndex, colIndex, parentData, tableData, collapsed, depth, path) {
         *          return rowData.id;
         *      }
         *
         *  (2) others:
         *      render whatever you pass
         */
        bodyRenderer: PropTypes.any,

        /**
         * The title in table body.
         *  (1) callback:
         *      function (rowData, rowIndex, colIndex, parentData, tableData, collapsed, depth, path) {
         *          return rowData.id;
         *      }
         *
         *  (2) others:
         *      render whatever you pass
         */
        bodyTitle: PropTypes.any,

        /**
         * column span of table body.
         *  (1) function callback:
         *      function (rowData, colIndex, rowIndex) {
         *          return null;
         *      }
         *
         *  (2) number:
         *      render whatever you pass
         */
        bodySpan: PropTypes.oneOfType([PropTypes.number, PropTypes.func]),

        /**
         * no wrap of table body.
         */
        bodyNoWrap: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),

        /**
         * The class name of footer.
         */
        footClassName: PropTypes.string,

        /**
         * Override the styles of footer.
         */
        footStyle: PropTypes.object,

        /**
         * align of table footer cell
         */
        footAlign: PropTypes.oneOf(Util.enumerateValue(HorizontalAlign)),

        /**
         * The render content in table foot.
         *  (1) callback:
         *      function (tableData, colIndex) {
         *          return colIndex;
         *      }
         *
         *  (2) others:
         *      render whatever you pass
         */
        footRenderer: PropTypes.any,

        /**
         * The title in table foot.
         *  (1) callback:
         *      function (tableData, colIndex) {
         *          return colIndex;
         *      }
         *
         *  (2) others:
         *      render whatever you pass
         */
        footTitle: PropTypes.any,

        /**
         * column span of table foot.
         *  (1) function callback:
         *      function (tableData, colIndex) {
         *          return null;
         *      }
         *
         *  (2) number:
         *      render whatever you pass
         */
        footSpan: PropTypes.oneOfType([PropTypes.number, PropTypes.func]),

        /**
         * no wrap of table foot.
         */
        footNoWrap: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),

        /**
         * If true,this column can be sorted.
         */
        sortable: PropTypes.bool,

        /**
         * Sorting property.
         */
        sortingProp: PropTypes.string,

        defaultSortingType: PropTypes.oneOf(Util.enumerateValue(SortingType))

    }))).isRequired,
    columnKeyField: PropTypes.string,
    columnsWidth: PropTypes.object,
    data: PropTypes.array,
    disabled: PropTypes.bool,
    ignoreColumnSpan: PropTypes.bool,

    /**
     * scroll
     */
    scrollEl: PropTypes.object,
    hasVerticalScroll: PropTypes.bool,

    /**
     * fixed
     */
    hasFixedRightColumn: PropTypes.bool,

    /**
     * sorting
     */
    sorting: PropTypes.shape({
        prop: PropTypes.string,
        type: PropTypes.oneOf(Util.enumerateValue(SortingType))
    }),
    defaultSortingType: PropTypes.oneOf(Util.enumerateValue(SortingType)),
    sortingAscIconCls: PropTypes.string,
    sortingDescIconCls: PropTypes.string,
    isClickSorting: PropTypes.bool,

    /**
     * column resizable
     */
    isColumnResizable: PropTypes.bool,
    defaultColumnWidth: PropTypes.number,
    minColumnWidth: PropTypes.number,
    maxColumnWidth: PropTypes.number,
    resizingColumn: PropTypes.object,

    onHeadClick: PropTypes.func,
    onSortChange: PropTypes.func,
    onRequestColumnsSpan: PropTypes.func,
    onColumnsWidthChange: PropTypes.func,
    onColumnResizeStart: PropTypes.func,
    onColumnResizeEnd: PropTypes.func

};

Thead.defaultProps = {

    columnKeyField: 'key',
    disabled: false,
    ignoreColumnSpan: false,

    /**
     * scroll
     */
    hasVerticalScroll: false,

    /**
     * fixed
     */
    hasFixedRightColumn: false,

    /**
     * sorting
     */
    defaultSortingType: SortingType.ASC,
    sortingAscIconCls: 'fas fa-sort-up',
    sortingDescIconCls: 'fas fa-sort-down',
    isClickSorting: true,

    /**
     * column resizable
     */
    isColumnResizable: false,
    defaultColumnWidth: 100,
    minColumnWidth: 64,
    maxColumnWidth: Infinity

};

export default Thead;
<commit_msg>update Thead<commit_after>/**
 * @file Thead component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';

// Components
import Th from '../_Th';

// Statics
import HorizontalAlign from '../_statics/HorizontalAlign';
import SelectMode from '../_statics/SelectMode';
import SelectAllMode from '../_statics/SelectAllMode';
import SortingType from '../_statics/SortingType';
import TableFragment from '../_statics/TableFragment';
import Direction from '../_statics/Direction';

// Vendors
import Util from '../_vendors/Util';
import TC from '../_vendors/TableCalculation';
import classNames from 'classnames';
import ScrollBar from '../_vendors/ScrollBar';

class Thead extends Component {

    static Align = HorizontalAlign;
    static SelectMode = SelectMode;
    static SelectAllMode = SelectAllMode;
    static SortingType = SortingType;

    constructor(props, ...restArgs) {
        super(props, ...restArgs);
    }

    getColumnsSpan = row => {

        const {data, onRequestColumnsSpan} = this.props;

        return onRequestColumnsSpan ?
            onRequestColumnsSpan(TableFragment.HEAD, row, data)
            :
            TC.getColumnsSpan(TableFragment.HEAD, row, data);

    };

    getStyle = (column, colIndex, columns) => {
        const {columnKeyField, columnsWidth, defaultColumnWidth, hasVerticalScroll} = this.props;
        return {
            ...column.headStyle,
            ...TC.getStickyColumnStyle(column?.fixed, colIndex, columns,
                columnKeyField, columnsWidth, defaultColumnWidth, hasVerticalScroll)
        };
    };

    handleClick = e => {
        const {data, disabled, onHeadClick} = this.props;
        !disabled && onHeadClick && onHeadClick(data, e);
    };

    render() {

        const {

                className, style, columns, columnsWidth, data, disabled, ignoreColumnSpan,
                hasFixedRightColumn, hasVerticalScroll, sorting, columnKeyField,
                defaultSortingType, sortingAscIconCls, sortingDescIconCls, defaultColumnWidth,
                onSortChange,

                ...restProps

            } = this.props,
            verticalScrollBarSize = ScrollBar.getSize(Direction.VERTICAL);

        return (

                {
                    columns && columns.map((row, rowIndex) => {

                        if (!row) {
                            return null;
                        }

                        const columnsSpan = this.getColumnsSpan(row);

                        return (

                                {
                                    columnsSpan ?
                                        columnsSpan.map(({column, span}, colIndex) => column ?
                                            <Th {...restProps}
                                                key={colIndex}
                                                column={column}
                                                columnKeyField={columnKeyField}
                                                className={classNames(column.headClassName, {
                                                    'fixed-left': column.fixed === HorizontalAlign.LEFT,
                                                    'last-fixed-left': column.fixed === HorizontalAlign.LEFT
                                                        && columnsSpan?.[colIndex + 1]?.column?.fixed
                                                        !== HorizontalAlign.LEFT,
                                                    'fixed-right': column.fixed === HorizontalAlign.RIGHT,
                                                    'first-fixed-right': column.fixed === HorizontalAlign.RIGHT
                                                        && columnsSpan?.[colIndex - 1]?.column?.fixed
                                                        !== HorizontalAlign.RIGHT
                                                })}
                                                style={this.getStyle(column, colIndex, row)}
                                                width={(
                                                    columnsWidth && columnKeyField
                                                    && columnsWidth.get(TC.getColumnKey(column, columnKeyField))
                                                ) || defaultColumnWidth}
                                                data={data}
                                                title={column.headTitle}
                                                renderer={column.headRenderer}
                                                align={column.headAlign || column.align}
                                                colIndex={colIndex}
                                                rowSpan={column.rowSpan}
                                                colSpan={ignoreColumnSpan ? null : column.colSpan}
                                                noWrap={TC.handleNoWrap(column.headNoWrap, column.noWrap, {
                                                    data,
                                                    rowIndex,
                                                    colIndex: colIndex,
                                                    tableData: data
                                                })}
                                                sorting={sorting}
                                                defaultSortingType={column.defaultSortingType || defaultSortingType}
                                                sortingAscIconCls={sortingAscIconCls}
                                                sortingDescIconCls={sortingDescIconCls}
                                                sortable={column.sortable}
                                                sortingProp={column.sortingProp}
                                                onSortChange={onSortChange}/>
                                            :
                                            null
                                        )
                                        :
                                        null
                                }

                                {
                                    hasVerticalScroll && columnsSpan && verticalScrollBarSize > 0 && rowIndex === 0 ?
                                        <th className={classNames('scroll-bar-th', {
                                            'fixed-right': hasFixedRightColumn
                                        })}
                                            style={{
                                                width: verticalScrollBarSize,
                                                ...(hasFixedRightColumn ? {
                                                    position: 'sticky',
                                                    right: 0
                                                } : null)
                                            }}
                                            rowSpan={columns.length}>

                                        :
                                        null
                                }

                        );

                    })
                }

        );

    }
}

Thead.propTypes = {

    className: PropTypes.string,
    style: PropTypes.object,

    /**
     * Children passed into table header.
     */
    columns: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.shape({

        /**
         * unique keyof column.
         */
        key: PropTypes.string,

        /**
         * fixed position of column ( 'left' / 'right' ).
         */
        fixed: PropTypes.oneOf(Util.enumerateValue(HorizontalAlign)),

        /**
         * width of column.
         */
        width: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.func]),

        /**
         * minimum width of column.
         */
        minWidth: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),

        /**
         * align of current column.
         */
        align: PropTypes.oneOf(Util.enumerateValue(HorizontalAlign)),

        /**
         * no wrap of current column.
         */
        noWrap: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),

        /**
         * The class name of header.
         */
        headClassName: PropTypes.string,

        /**
         * Override the styles of header.
         */
        headStyle: PropTypes.object,

        /**
         * align of table header cell
         */
        headAlign: PropTypes.oneOf(Util.enumerateValue(HorizontalAlign)),

        /**
         * The render content in table head.
         *  (1) callback:
         *      function (tableData, colIndex) {
         *          return colIndex;
         *      }
         *
         *  (2) others:
         *      render whatever you pass
         */
        headRenderer: PropTypes.any,

        /**
         * The title in table head.
         *  (1) callback:
         *      function (tableData, colIndex) {
         *          return colIndex;
         *      }
         *
         *  (2) others:
         *      render whatever you pass
         */
        headTitle: PropTypes.any,

        /**
         * column span of table header.
         *  (1) function callback:
         *      function (tableData, colIndex) {
         *          return null;
         *      }
         *
         *  (2) number:
         *      render whatever you pass
         */
        headSpan: PropTypes.oneOfType([PropTypes.number, PropTypes.func]),

        /**
         * no wrap of table header.
         */
        headNoWrap: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),

        /**
         * The class name of td.
         */
        bodyClassName: PropTypes.string,

        /**
         * Override the styles of td.
         */
        bodyStyle: PropTypes.object,

        /**
         * align of table body cell.
         */
        bodyAlign: PropTypes.oneOf(Util.enumerateValue(HorizontalAlign)),

        /**
         * The render content in table body.
         *  (1) callback:
         *      function (rowData, rowIndex, colIndex, parentData, tableData, collapsed, depth, path) {
         *          return rowData.id;
         *      }
         *
         *  (2) others:
         *      render whatever you pass
         */
        bodyRenderer: PropTypes.any,

        /**
         * The title in table body.
         *  (1) callback:
         *      function (rowData, rowIndex, colIndex, parentData, tableData, collapsed, depth, path) {
         *          return rowData.id;
         *      }
         *
         *  (2) others:
         *      render whatever you pass
         */
        bodyTitle: PropTypes.any,

        /**
         * column span of table body.
         *  (1) function callback:
         *      function (rowData, colIndex, rowIndex) {
         *          return null;
         *      }
         *
         *  (2) number:
         *      render whatever you pass
         */
        bodySpan: PropTypes.oneOfType([PropTypes.number, PropTypes.func]),

        /**
         * no wrap of table body.
         */
        bodyNoWrap: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),

        /**
         * The class name of footer.
         */
        footClassName: PropTypes.string,

        /**
         * Override the styles of footer.
         */
        footStyle: PropTypes.object,

        /**
         * align of table footer cell
         */
        footAlign: PropTypes.oneOf(Util.enumerateValue(HorizontalAlign)),

        /**
         * The render content in table foot.
         *  (1) callback:
         *      function (tableData, colIndex) {
         *          return colIndex;
         *      }
         *
         *  (2) others:
         *      render whatever you pass
         */
        footRenderer: PropTypes.any,

        /**
         * The title in table foot.
         *  (1) callback:
         *      function (tableData, colIndex) {
         *          return colIndex;
         *      }
         *
         *  (2) others:
         *      render whatever you pass
         */
        footTitle: PropTypes.any,

        /**
         * column span of table foot.
         *  (1) function callback:
         *      function (tableData, colIndex) {
         *          return null;
         *      }
         *
         *  (2) number:
         *      render whatever you pass
         */
        footSpan: PropTypes.oneOfType([PropTypes.number, PropTypes.func]),

        /**
         * no wrap of table foot.
         */
        footNoWrap: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),

        /**
         * If true, this column can be sorted.
         */
        sortable: PropTypes.bool,

        /**
         * Sorting property.
         */
        sortingProp: PropTypes.string,

        defaultSortingType: PropTypes.oneOf(Util.enumerateValue(SortingType)),

        /**
         * whether the column can be resized
         */
        resizable: PropTypes.bool

    }))).isRequired,
    columnKeyField: PropTypes.string,
    columnsWidth: PropTypes.object,
    data: PropTypes.array,
    disabled: PropTypes.bool,
    ignoreColumnSpan: PropTypes.bool,

    /**
     * scroll
     */
    scrollEl: PropTypes.object,
    hasVerticalScroll: PropTypes.bool,

    /**
     * fixed
     */
    hasFixedRightColumn: PropTypes.bool,

    /**
     * sorting
     */
    sorting: PropTypes.shape({
        prop: PropTypes.string,
        type: PropTypes.oneOf(Util.enumerateValue(SortingType))
    }),
    defaultSortingType: PropTypes.oneOf(Util.enumerateValue(SortingType)),
    sortingAscIconCls: PropTypes.string,
    sortingDescIconCls: PropTypes.string,
    isClickSorting: PropTypes.bool,

    /**
     * column resizable
     */
    defaultColumnWidth: PropTypes.number,
    minColumnWidth: PropTypes.number,
    maxColumnWidth: PropTypes.number,
    resizingColumn: PropTypes.object,

    onHeadClick: PropTypes.func,
    onSortChange: PropTypes.func,
    onRequestColumnsSpan: PropTypes.func,
    onColumnsWidthChange: PropTypes.func,
    onColumnResizeStart: PropTypes.func,
    onColumnResizeEnd: PropTypes.func

};

Thead.defaultProps = {

    columnKeyField: 'key',
    disabled: false,
    ignoreColumnSpan: false,

    /**
     * scroll
     */
    hasVerticalScroll: false,

    /**
     * fixed
     */
    hasFixedRightColumn: false,

    /**
     * sorting
     */
    defaultSortingType: SortingType.ASC,
    sortingAscIconCls: 'fas fa-sort-up',
    sortingDescIconCls: 'fas fa-sort-down',
    isClickSorting: true,

    /**
     * column resizable
     */
    defaultColumnWidth: 100,
    minColumnWidth: 64,
    maxColumnWidth: Infinity

};

export default Thead;
<|endoftext|>


<commit_before>'use strict'

const fs = require('fs')

exports.debian = function (test) {
  test.expect(1)
  const actual = fs.readFileSync('dist/demo_0.1-2_i386/DEBIAN/control').toString()
  const expected = fs.readFileSync('test/control').toString()
  test.equal(actual, expected, 'CONTROL file created should equal sample.')
  test.done()
}

/*exports.changelog = function (test) {
  test.expect(1)
  const actual = fs.readFileSync('dist/demo_0.1-2_i386/usr/share/doc/changelog.Debian').toString()
  const expected = fs.readFileSync('test/changelog.Debian').toString()
  test.equal(actual, expected, 'changelog.Debian file created should equal sample.')
  test.done()
}*/
<commit_msg>Update test.js<commit_after>'use strict'

const fs = require('fs')

exports.debian = function (test) {
  test.expect(1)
  const actual = fs.readFileSync('dist/demo_0.1-2_i386/DEBIAN/control').toString()
  const expected = fs.readFileSync('test/control').toString()
  test.equal(actual, expected, 'CONTROL file created should equal sample.')
  test.done()
}

/* exports.changelog = function (test) {
  test.expect(1)
  const actual = fs.readFileSync('dist/demo_0.1-2_i386/usr/share/doc/changelog.Debian').toString()
  const expected = fs.readFileSync('test/changelog.Debian').toString()
  test.equal(actual, expected, 'changelog.Debian file created should equal sample.')
  test.done()
} */
<|endoftext|>


<commit_before>/**
 * @file Thead component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import TheadItem from '../_TheadItem';

class Thead extends Component {

    constructor(props, ...restArgs) {
        super(props, ...restArgs);
    }

    render() {

        const {className, style, columns, sort, sortAscIconCls, sortDescIconCls, hidden, onSort} = this.props;

        return (

                    {
                        columns && columns.map((item, index) => item ?
                            <TheadItem key={index}
                                       className={item.headerClassName}
                                       style={item.headerStyle}
                                       renderer={item.headerRenderer}
                                       colIndex={index}
                                       sortable={item.sortable}
                                       sortProp={item.sortProp}
                                       sort={sort}
                                       sortAscIconCls={sortAscIconCls}
                                       sortDescIconCls={sortDescIconCls}
                                       hidden={hidden}
                                       onSort={() => onSort(item)}/>
                            :
                            null
                        )
                    }

        );

    }
}

Thead.propTypes = {

    className: PropTypes.string,
    style: PropTypes.object,

    columns: PropTypes.array,
    sort: PropTypes.object,
    sortAscIconCls: PropTypes.string,
    sortDescIconCls: PropTypes.string,
    hidden: PropTypes.bool,

    onSort: PropTypes.func

};

Thead.defaultProps = {
    columns: [],
    hidden: false
};

export default Thead;
<commit_msg>update Thead<commit_after>/**
 * @file Thead component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import TheadItem from '../_TheadItem';

class Thead extends Component {

    constructor(props, ...restArgs) {
        super(props, ...restArgs);
    }

    render() {

        const {
            className, style, columns, sort, sortAscIconCls, sortDescIconCls, hidden,
            onSort
        } = this.props;

        return (

                    {
                        columns && columns.map((item, index) => item ?
                            <TheadItem key={index}
                                       className={item.headerClassName}
                                       style={item.headerStyle}
                                       renderer={item.headerRenderer}
                                       colIndex={index}
                                       sortable={item.sortable}
                                       sortProp={item.sortProp}
                                       sort={sort}
                                       sortAscIconCls={sortAscIconCls}
                                       sortDescIconCls={sortDescIconCls}
                                       hidden={hidden}
                                       onSort={() => onSort && onSort(item)}/>
                            :
                            null
                        )
                    }

        );

    }
}

Thead.propTypes = {

    className: PropTypes.string,
    style: PropTypes.object,

    columns: PropTypes.array,
    sort: PropTypes.object,
    sortAscIconCls: PropTypes.string,
    sortDescIconCls: PropTypes.string,
    hidden: PropTypes.bool,

    onSort: PropTypes.func

};

Thead.defaultProps = {
    columns: [],
    hidden: false
};

export default Thead;
<|endoftext|>