<commit_before>#!/usr/bin/node

var ejs = require('ejs')
  , fs = require('fs')
  , context
  , headtpl
  , maintpl
  , footertpl;

var texts;

fs.readFile(__dirname + '/texts.json', function(err, data) {
	if(err) {
		throw err;
	}

	texts = JSON.parse(data);
	console.log('Finished parsing texts');
} );

/**
 * @todo requires an additional context variable
 */
exports.render = function(state, template) {
	/**
	* Render the templates once all data and
	* files are available.
	*/
	var render = function() {
		if(context && headtpl && maintpl && footertpl) {
			context.texts = texts;

			var head = ejs.render(headtpl, context);
			var main = ejs.render(maintpl, context);
			var footer = ejs.render(footertpl, context);

			var result = state.result;
			result.write(head);
			result.write(main);
			result.write(footer);
			result.end();
		}
	}

	//
	// READ CONTEXT
	//
	fs.readFile(__dirname + '/context.json', 'utf8', function(err, data) {
		if(err) {
			state.fail(err);
		}

		context = JSON.parse(data);

		render();
	} );

	//
	// READ TEMPLATES
	//
	fs.readFile(__dirname + '/templates/head.tpl', 'utf8', function(err, data) {
		if(err) {
			state.fail(err);
		}

		headtpl = data;

		render();
	} );

	fs.readFile(__dirname + '/templates' + template, 'utf8', function(err, data) {
		if(err) {
			state.fail(err);
		}

		maintpl = data;

		render();
	} );

	fs.readFile(__dirname + '/templates/footer.tpl', 'utf8', function(err, data) {
		if(err) {
			state.fail(err);
		}

		footertpl = data;

		render();
	} );
}
<commit_msg>Fix handing out wrong template.<commit_after>#!/usr/bin/node

var ejs = require('ejs')
  , fs = require('fs')
  , context
  , headtpl
  , maintpl
  , footertpl;

var texts;

fs.readFile(__dirname + '/texts.json', function(err, data) {
	if(err) {
		throw err;
	}

	texts = JSON.parse(data);
	console.log('Finished parsing texts');
} );

/**
 * @todo requires an additional context variable
 */
exports.render = function(state, template) {
	var context, headtpl, maintpl, footertpl;

	/**
	* Render the templates once all data and
	* files are available.
	*/
	var render = function() {
		if(context && headtpl && maintpl && footertpl) {
			context.texts = texts;

			var head = ejs.render(headtpl, context);
			var main = ejs.render(maintpl, context);
			var footer = ejs.render(footertpl, context);

			var result = state.result;
			result.write(head);
			result.write(main);
			result.write(footer);
			result.end();

			console.log('Served ' + state.request.url);
		}
	}

	//
	// READ CONTEXT
	//
	fs.readFile(__dirname + '/context.json', 'utf8', function(err, data) {
		if(err) {
			state.fail(err);
		}

		context = JSON.parse(data);

		render();
	} );

	//
	// READ TEMPLATES
	//
	fs.readFile(__dirname + '/templates/head.tpl', 'utf8', function(err, data) {
		if(err) {
			state.fail(err);
		}

		headtpl = data;

		render();
	} );

	fs.readFile(__dirname + '/templates' + template, 'utf8', function(err, data) {
		if(err) {
			state.fail(err);
		}

		maintpl = data;

		render();
	} );

	fs.readFile(__dirname + '/templates/footer.tpl', 'utf8', function(err, data) {
		if(err) {
			state.fail(err);
		}

		footertpl = data;

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


<commit_before>import _ from "lodash";

import {
  default as React,
  PropTypes,
  Component,
} from "react";

import {
  default as GoogleMapHolder,
} from "./creators/GoogleMapHolder";

const USE_NEW_BEHAVIOR_TAG_NAME = `__new_behavior__`;/* CIRCULAR_DEPENDENCY */

export default class GoogleMapLoader extends Component {
  static propTypes = {
    containerElement: PropTypes.node.isRequired,
    /* CIRCULAR_DEPENDENCY. Uncomment when 5.0.0 comes:
    propTypesElementOfType(GoogleMap).isRequired, */
    googleMapElement: PropTypes.element.isRequired,
  };

  static defaultProps = {
    containerElement: (<div />),
  };

  state = {
    map: null,
  };

  mountGoogleMap(domEl) {
    if (this.state.map || domEl === null) {
      return;
    }
    const restProps = _.omit(this.props.googleMapElement.props, [`children`]);
    //
    // Create google.maps.Map instance so that dom is initialized before
    // React's children creators.
    //
    const map = GoogleMapHolder._createMap(domEl, restProps);
    this.setState({ map });
  }

  renderChild() {
    if (this.state.map) {
      // Notice: implementation details
      //
      // In this state, the DOM of google.maps.Map is already initialized in
      // my innerHTML. Adding extra React components will not clean it
      // in current version*. It will use prepend to add DOM of
      // GoogleMapHolder and become a sibling of the DOM of google.maps.Map
      // Not sure this is subject to change
      //
      // *current version: 0.13.3, 0.14.2
      //
      return React.cloneElement(this.props.googleMapElement, {
        map: this.state.map,
        // ------------ Deprecated ------------
        containerTagName: USE_NEW_BEHAVIOR_TAG_NAME,
      });
    }
  }

  render() {
    return React.cloneElement(this.props.containerElement, {
      ref: ::this.mountGoogleMap,
    }, this.renderChild());
  }
}
<commit_msg>feat(GoogleMapLoader): switch to new behaviour<commit_after>import _ from "lodash";

import {
  default as React,
  PropTypes,
  Component,
} from "react";

import {
  default as propTypesElementOfType,
} from "react-prop-types-element-of-type";

import {
  default as GoogleMap,
} from "./GoogleMap";

import {
  default as GoogleMapHolder,
} from "./creators/GoogleMapHolder";

export default class GoogleMapLoader extends Component {
  static propTypes = {
    containerElement: PropTypes.node.isRequired,
    googleMapElement: propTypesElementOfType(GoogleMap).isRequired,
  };

  static defaultProps = {
    containerElement: (<div />),
  };

  state = {
    map: null,
  };

  mountGoogleMap(domEl) {
    if (this.state.map || domEl === null) {
      return;
    }
    const restProps = _.omit(this.props.googleMapElement.props, [`children`]);
    //
    // Create google.maps.Map instance so that dom is initialized before
    // React's children creators.
    //
    const map = GoogleMapHolder._createMap(domEl, restProps);
    this.setState({ map });
  }

  renderChild() {
    if (this.state.map) {
      // Notice: implementation details
      //
      // In this state, the DOM of google.maps.Map is already initialized in
      // my innerHTML. Adding extra React components will not clean it
      // in current version*. It will use prepend to add DOM of
      // GoogleMapHolder and become a sibling of the DOM of google.maps.Map
      // Not sure this is subject to change
      //
      // *current version: 0.13.3, 0.14.2
      //
      return React.cloneElement(this.props.googleMapElement, {
        map: this.state.map,
      });
    }
  }

  render() {
    return React.cloneElement(this.props.containerElement, {
      ref: ::this.mountGoogleMap,
    }, this.renderChild());
  }
}
<|endoftext|>


<commit_before>var setupCommands = require('./setupCommands');
var crc = require('./crc16-xmodem');
var redis = require('redis');
var RedisBatch = require('./RedisBatch');
var Events = require('events').EventEmitter;
var util = require('util');

var RedisClustr = module.exports = function(config) {
  var self = this;

  Events.call(self);

  // handle just an array of clients
  if (Array.isArray(config)) {
    config = {
      servers: config
    };
  }

  self.config = config;
  self.clients = {};
  self.connections = {};

  for (var i = 0; i < config.servers.length; i++) {
    var c = config.servers[i];

    var name = c.host + ':' + c.port;

    self.clients[name] = {
      name: name,
      client: self.getClient(c.port, c.host),
      // slots will be reassigned as soon as we get a response from `cluster slots`
      slots: [ [ 0, Infinity ] ]
    };
  }

  // fetch slots from the cluster immediately to ensure slots are correct
  self.getSlots();

  // ability to update slots on an interval (should be unnecessary)
  if (config.slotInterval) setInterval(self.getSlots.bind(self), config.slotInterval);
};

util.inherits(RedisClustr, Events);

RedisClustr.prototype.getClient = function(port, host) {
  var self = this;
  var name = host + ':' + port;

  // already have a connection to this client, return that
  if (self.connections[name]) return self.connections[name];

  var createClient = self.config.createClient || redis.createClient;
  var cli = createClient(port, host, self.config.redisOptions);

  cli.on('error', function(err) {
    if (/Redis connection to .* failed.*/.test(err.message)) {
      self.emit('connectionError', err, cli);
      self.getSlots();
      return;
    }

    // re-emit the error ourselves
    self.emit('error', err, cli);
  });

  return self.connections[name] = cli;
};

RedisClustr.prototype.getSlots = function(clientIndex) {
  var self = this;

  if (self.slotting) return;
  self.slotting = true;

  clientIndex = clientIndex || 0;

  // get the client at the index we've been given (so we can iterate over clients if one/some are erroring)
  self.clients[Object.keys(self.clients)[clientIndex]].client.send_command('cluster', [ 'slots' ], function(err, slots) {
    if (err) {
      clientIndex++;

      // we've run out of clients to try...
      if (clientIndex >= self.clients.length) {
        self.slotting = false;
        self.emit('error', new Error('couldn\'t get slot allocation'));
        return;
      }

      // try the next client
      self.getSlots(clientIndex);
      return;
    }

    self.clients = {};

    for (var i = 0; i < slots.length; i++) {
      var s = slots[i];
      var start = s[0];
      var end = s[1];
      var cli = s[2];
      var name = s[2].join(':');

      if (!self.clients[name]) {
        self.clients[name] = {
          name: name,
          client: self.getClient(cli[1], cli[0]),
          slots: []
        };
      }

      // add this slot range to the client
      self.clients[name].slots.push([ start, end ]);
    }

    for (var i in self.connections) {
      if (!self.clients[i]) self.connections[i].quit();
    }

    self.slotting = false;
  });
};

RedisClustr.prototype.selectClient = function(key) {
  var self = this;

  if (Array.isArray(key)) key = key[0];

  // support for hash tags to keep keys on the same slot
  // http://redis.io/topics/cluster-spec#multiple-keys-operations
  var openKey = key.indexOf('{');
  if (openKey !== -1) {
    var closeKey = key.indexOf('}');

    // } in key and it's not {}
    if (closeKey !== -1 && closeKey !== openKey + 1) {
      key = key.substring(openKey + 1, closeKey);
    }
  }

  var slot = crc(key) % 16384;

  for (var c in self.clients) {
    var client = self.clients[c];
    for (var i = 0; i < client.slots.length; i++) {
      var range = client.slots[i];
      if (slot >= range[0] && slot <= range[1]) {
        return client;
      }
    }
  }
};

RedisClustr.prototype.command = function(cmd, args) {
  var self = this;

  args = Array.prototype.slice.call(args);
  var key = args[0];

  if (!key) {
    throw new Error('no key for command: ' + cmd);
  }

  var r = self.selectClient(key);

  var cb = function(){};
  if (typeof args[args.length - 1] === 'function') cb = args.pop();

  args.push(function(err) {
    if (err && err.message) {
      if (err.message.substr(0, 6) === 'MOVED ') {
        // key has been moved!
        // lets refetch slots from redis to get an up to date allocation
        self.getSlots();

        // REQUERY THE NEW ONE (we've got the correct details)
        var addr = err.message.split(' ')[2];
        var saddr = addr.split(':')
        var c = self.getClient(saddr[1], saddr[0]);
        c[cmd].apply(c, args);
        return;
      }

      if (/Redis connection to .* failed.*/.test(err.message)) {
        self.emit('connectionError', err, c);
        self.getSlots();
      }
    }

    cb.apply(cb, arguments);
  });

  r.client[cmd].apply(r.client, args);
};

// redis cluster requires multi-key commands to be split into individual commands
RedisClustr.prototype.multiKeyCommand = function(cmd, interval, args) {
  var self = this;

  var cb = function(){};

  var keys = Array.prototype.slice.call(args);
  if (typeof keys[keys.length -1] === 'function') cb = keys.pop();

  var first = keys[0];
  if (Array.isArray(first)) {
    keys = first;
  }

  // already split into an individual command
  if (keys.length === interval) {
    return self.command(cmd, args);
  }

  // batch the multi-key command into individual ones
  var b = self.batch();
  for (var i = 0; i < keys.length; i += interval) {
    b[cmd].apply(b, keys.slice(i, i + interval));
  }

  b.exec(cb);
};

setupCommands(RedisClustr);

RedisClustr.prototype.batch = RedisClustr.prototype.multi = function() {
  var self = this;
  return new RedisBatch(self);
};

RedisClustr.prototype.quit = function(cb) {
  var self = this;
  var todo = Object.keys(self.connections).length;

  for (var i in self.connections) {
    self.connections[i].client.quit(function() {
      if (!--todo) cb();
    });
  }
};
<commit_msg>follow ASK redirects properly<commit_after>var setupCommands = require('./setupCommands');
var crc = require('./crc16-xmodem');
var redis = require('redis');
var RedisBatch = require('./RedisBatch');
var Events = require('events').EventEmitter;
var util = require('util');

var RedisClustr = module.exports = function(config) {
  var self = this;

  Events.call(self);

  // handle just an array of clients
  if (Array.isArray(config)) {
    config = {
      servers: config
    };
  }

  self.config = config;
  self.clients = {};
  self.connections = {};

  for (var i = 0; i < config.servers.length; i++) {
    var c = config.servers[i];

    var name = c.host + ':' + c.port;

    self.clients[name] = {
      name: name,
      client: self.getClient(c.port, c.host),
      // slots will be reassigned as soon as we get a response from `cluster slots`
      slots: [ [ 0, Infinity ] ]
    };
  }

  // fetch slots from the cluster immediately to ensure slots are correct
  self.getSlots();

  // ability to update slots on an interval (should be unnecessary)
  if (config.slotInterval) setInterval(self.getSlots.bind(self), config.slotInterval);
};

util.inherits(RedisClustr, Events);

RedisClustr.prototype.getClient = function(port, host) {
  var self = this;
  var name = host + ':' + port;

  // already have a connection to this client, return that
  if (self.connections[name]) return self.connections[name];

  var createClient = self.config.createClient || redis.createClient;
  var cli = createClient(port, host, self.config.redisOptions);

  cli.on('error', function(err) {
    if (/Redis connection to .* failed.*/.test(err.message)) {
      self.emit('connectionError', err, cli);
      self.getSlots();
      return;
    }

    // re-emit the error ourselves
    self.emit('error', err, cli);
  });

  return self.connections[name] = cli;
};

RedisClustr.prototype.getSlots = function(clientIndex) {
  var self = this;

  if (self.slotting) return;
  self.slotting = true;

  clientIndex = clientIndex || 0;

  // get the client at the index we've been given (so we can iterate over clients if one/some are erroring)
  self.clients[Object.keys(self.clients)[clientIndex]].client.send_command('cluster', [ 'slots' ], function(err, slots) {
    if (err) {
      clientIndex++;

      // we've run out of clients to try...
      if (clientIndex >= self.clients.length) {
        self.slotting = false;
        self.emit('error', new Error('couldn\'t get slot allocation'));
        return;
      }

      // try the next client
      self.getSlots(clientIndex);
      return;
    }

    self.clients = {};

    for (var i = 0; i < slots.length; i++) {
      var s = slots[i];
      var start = s[0];
      var end = s[1];
      var cli = s[2];
      var name = s[2].join(':');

      if (!self.clients[name]) {
        self.clients[name] = {
          name: name,
          client: self.getClient(cli[1], cli[0]),
          slots: []
        };
      }

      // add this slot range to the client
      self.clients[name].slots.push([ start, end ]);
    }

    for (var i in self.connections) {
      if (!self.clients[i]) self.connections[i].quit();
    }

    self.slotting = false;
  });
};

RedisClustr.prototype.selectClient = function(key) {
  var self = this;

  if (Array.isArray(key)) key = key[0];

  // support for hash tags to keep keys on the same slot
  // http://redis.io/topics/cluster-spec#multiple-keys-operations
  var openKey = key.indexOf('{');
  if (openKey !== -1) {
    var closeKey = key.indexOf('}');

    // } in key and it's not {}
    if (closeKey !== -1 && closeKey !== openKey + 1) {
      key = key.substring(openKey + 1, closeKey);
    }
  }

  var slot = crc(key) % 16384;

  for (var c in self.clients) {
    var client = self.clients[c];
    for (var i = 0; i < client.slots.length; i++) {
      var range = client.slots[i];
      if (slot >= range[0] && slot <= range[1]) {
        return client;
      }
    }
  }
};

RedisClustr.prototype.command = function(cmd, args) {
  var self = this;

  args = Array.prototype.slice.call(args);
  var key = args[0];

  if (!key) {
    throw new Error('no key for command: ' + cmd);
  }

  var r = self.selectClient(key);

  var cb = function(){};
  if (typeof args[args.length - 1] === 'function') cb = args.pop();

  args.push(function(err) {
    if (err && err.message) {
      var moved = err.message.substr(0, 6) === 'MOVED ';
      var ask = err.message.substr(0, 4) === 'ASK ';

      if (moved || ask) {

        // key has been moved!
        // lets refetch slots from redis to get an up to date allocation
        if (moved) self.getSlots();

        // REQUERY THE NEW ONE (we've got the correct details)
        var addr = err.message.split(' ')[2];
        var saddr = addr.split(':')
        var c = self.getClient(saddr[1], saddr[0]);
        if (ask) c.send_command('asking');
        c[cmd].apply(c, args);
        return;
      }

      if (/Redis connection to .* failed.*/.test(err.message)) {
        self.emit('connectionError', err, c);
        self.getSlots();
      }
    }

    cb.apply(cb, arguments);
  });

  r.client[cmd].apply(r.client, args);
};

// redis cluster requires multi-key commands to be split into individual commands
RedisClustr.prototype.multiKeyCommand = function(cmd, interval, args) {
  var self = this;

  var cb = function(){};

  var keys = Array.prototype.slice.call(args);
  if (typeof keys[keys.length -1] === 'function') cb = keys.pop();

  var first = keys[0];
  if (Array.isArray(first)) {
    keys = first;
  }

  // already split into an individual command
  if (keys.length === interval) {
    return self.command(cmd, args);
  }

  // batch the multi-key command into individual ones
  var b = self.batch();
  for (var i = 0; i < keys.length; i += interval) {
    b[cmd].apply(b, keys.slice(i, i + interval));
  }

  b.exec(cb);
};

setupCommands(RedisClustr);

RedisClustr.prototype.batch = RedisClustr.prototype.multi = function() {
  var self = this;
  return new RedisBatch(self);
};

RedisClustr.prototype.quit = function(cb) {
  var self = this;
  var todo = Object.keys(self.connections).length;

  for (var i in self.connections) {
    self.connections[i].client.quit(function() {
      if (!--todo) cb();
    });
  }
};
<|endoftext|>


<commit_before>import React, { useMemo, useState } from 'react';
import styled from 'styled-components';
import PropTypes from 'prop-types';
import { Row, Box, TableLabel, Checkbox, Grid, GridItem } from '@strapi/parts';

import { useIntl } from 'react-intl';
import { get } from 'lodash';
import IS_DISABLED from 'ee_else_ce/pages/SettingsPage/pages/Roles/EditPage/components/PluginsAndSettings/SubCategory/utils/constants';
import { usePermissionsDataManager } from '../../../../../../../../hooks';
import { getCheckboxState, removeConditionKeyFromData } from '../../utils';
import ConditionsButton from '../../ConditionsButton';
import ConditionsModal from '../../ConditionsModal';
import { formatActions, getConditionsButtonState } from './utils';

const Border = styled.div`
  flex: 1;
  align-self: center;
  border-top: 1px solid ${({ theme }) => theme.colors.neutral150};
`;

const CheckboxWrapper = styled.div`
  position: relative;
  ${({ hasConditions, disabled, theme }) =>
    hasConditions &&
    `
    &:before {
      content: '';
      position: absolute;
      top: ${-4 / 16}rem;
      left: ${-8 / 16}rem;
      width: ${6 / 16}rem;
      height: ${6 / 16}rem;
      border-radius: ${20 / 16}rem;
      background: ${disabled ? theme.colors.neutral100 : theme.colors.primary600};
    }
  `}
`;

const SubCategory = ({ categoryName, isFormDisabled, subCategoryName, actions, pathToData }) => {
  const [isModalOpen, setModalOpen] = useState(false);
  const {
    modifiedData,
    onChangeParentCheckbox,
    onChangeSimpleCheckbox,
  } = usePermissionsDataManager();
  const { formatMessage } = useIntl();

  const mainData = get(modifiedData, pathToData, {});
  const dataWithoutCondition = useMemo(() => {
    return Object.keys(mainData).reduce((acc, current) => {
      acc[current] = removeConditionKeyFromData(mainData[current]);

      return acc;
    }, {});
  }, [mainData]);

  const { hasAllActionsSelected, hasSomeActionsSelected } = getCheckboxState(dataWithoutCondition);

  const handleToggleModalIsOpen = () => {
    setModalOpen(s => !s);
  };

  const handleModalClose = () => {
    setModalOpen(false);
  };
  // We need to format the actions so it matches the shape of the ConditionsModal actions props
  const formattedActions = formatActions(actions, modifiedData, pathToData);
  const doesButtonHasCondition = getConditionsButtonState(get(modifiedData, [...pathToData], {}));

  return (
    <>
      <Box>
        <Row justifyContent="space-between" alignItems="center">
          <Box paddingRight={4}>
            <TableLabel textColor="neutral600">{subCategoryName}</TableLabel>
          </Box>
          <Border />
          <Box paddingLeft={4}>
            <Checkbox
              name={pathToData.join('..')}
              disabled={isFormDisabled || IS_DISABLED}
              // Keep same signature as packages/core/admin/admin/src/components/Roles/Permissions/index.js l.91
              onValueChange={value => {
                onChangeParentCheckbox({
                  target: {
                    name: pathToData.join('..'),
                    value,
                  },
                });
              }}
              indeterminate={hasSomeActionsSelected}
              value={hasAllActionsSelected}
            >
              {formatMessage({ id: 'app.utils.select-all', defaultMessage: 'Select all' })}
            </Checkbox>
          </Box>
        </Row>
        <Row paddingTop={6} paddingBottom={6}>
          <Grid gap={2} style={{ flex: 1 }}>
            {formattedActions.map(({ checkboxName, value, action, displayName, hasConditions }) => {
              return (
                <GridItem col={3} key={action}>
                  <CheckboxWrapper
                    disabled={isFormDisabled || IS_DISABLED}
                    hasConditions={hasConditions}
                  >
                    <Checkbox
                      name={checkboxName}
                      disabled={isFormDisabled || IS_DISABLED}
                      // Keep same signature as packages/core/admin/admin/src/components/Roles/Permissions/index.js l.91
                      onValueChange={value => {
                        onChangeSimpleCheckbox({
                          target: {
                            name: checkboxName,
                            value,
                          },
                        });
                      }}
                      value={value}
                    >
                      {displayName}
                    </Checkbox>
                  </CheckboxWrapper>
                </GridItem>
              );
            })}
          </Grid>
          <ConditionsButton
            hasConditions={doesButtonHasCondition}
            onClick={handleToggleModalIsOpen}
            variant="tertiary"
          />
        </Row>
      </Box>
      {isModalOpen && (
        <ConditionsModal
          headerBreadCrumbs={[categoryName, subCategoryName]}
          actions={formattedActions}
          isFormDisabled={isFormDisabled}
          onClosed={handleModalClose}
          onToggle={handleToggleModalIsOpen}
        />
      )}
    </>
  );
};

SubCategory.propTypes = {
  actions: PropTypes.array.isRequired,
  categoryName: PropTypes.string.isRequired,
  isFormDisabled: PropTypes.bool.isRequired,
  subCategoryName: PropTypes.string.isRequired,
  pathToData: PropTypes.array.isRequired,
};

export default SubCategory;
<commit_msg>Fix word breaks in RBAC settings<commit_after>import React, { useMemo, useState } from 'react';
import styled from 'styled-components';
import PropTypes from 'prop-types';
import { Row, Box, TableLabel, Checkbox, Grid, GridItem } from '@strapi/parts';

import { useIntl } from 'react-intl';
import { get } from 'lodash';
import IS_DISABLED from 'ee_else_ce/pages/SettingsPage/pages/Roles/EditPage/components/PluginsAndSettings/SubCategory/utils/constants';
import { usePermissionsDataManager } from '../../../../../../../../hooks';
import { getCheckboxState, removeConditionKeyFromData } from '../../utils';
import ConditionsButton from '../../ConditionsButton';
import ConditionsModal from '../../ConditionsModal';
import { formatActions, getConditionsButtonState } from './utils';

const Border = styled.div`
  flex: 1;
  align-self: center;
  border-top: 1px solid ${({ theme }) => theme.colors.neutral150};
`;

const CheckboxWrapper = styled.div`
  position: relative;
  word-break: keep-all;
  ${({ hasConditions, disabled, theme }) =>
    hasConditions &&
    `
    &:before {
      content: '';
      position: absolute;
      top: ${-4 / 16}rem;
      left: ${-8 / 16}rem;
      width: ${6 / 16}rem;
      height: ${6 / 16}rem;
      border-radius: ${20 / 16}rem;
      background: ${disabled ? theme.colors.neutral100 : theme.colors.primary600};
    }
  `}
`;

const SubCategory = ({ categoryName, isFormDisabled, subCategoryName, actions, pathToData }) => {
  const [isModalOpen, setModalOpen] = useState(false);
  const {
    modifiedData,
    onChangeParentCheckbox,
    onChangeSimpleCheckbox,
  } = usePermissionsDataManager();
  const { formatMessage } = useIntl();

  const mainData = get(modifiedData, pathToData, {});
  const dataWithoutCondition = useMemo(() => {
    return Object.keys(mainData).reduce((acc, current) => {
      acc[current] = removeConditionKeyFromData(mainData[current]);

      return acc;
    }, {});
  }, [mainData]);

  const { hasAllActionsSelected, hasSomeActionsSelected } = getCheckboxState(dataWithoutCondition);

  const handleToggleModalIsOpen = () => {
    setModalOpen(s => !s);
  };

  const handleModalClose = () => {
    setModalOpen(false);
  };
  // We need to format the actions so it matches the shape of the ConditionsModal actions props
  const formattedActions = formatActions(actions, modifiedData, pathToData);
  const doesButtonHasCondition = getConditionsButtonState(get(modifiedData, [...pathToData], {}));

  return (
    <>
      <Box>
        <Row justifyContent="space-between" alignItems="center">
          <Box paddingRight={4}>
            <TableLabel textColor="neutral600">{subCategoryName}</TableLabel>
          </Box>
          <Border />
          <Box paddingLeft={4}>
            <Checkbox
              name={pathToData.join('..')}
              disabled={isFormDisabled || IS_DISABLED}
              // Keep same signature as packages/core/admin/admin/src/components/Roles/Permissions/index.js l.91
              onValueChange={value => {
                onChangeParentCheckbox({
                  target: {
                    name: pathToData.join('..'),
                    value,
                  },
                });
              }}
              indeterminate={hasSomeActionsSelected}
              value={hasAllActionsSelected}
            >
              {formatMessage({ id: 'app.utils.select-all', defaultMessage: 'Select all' })}
            </Checkbox>
          </Box>
        </Row>
        <Row paddingTop={6} paddingBottom={6}>
          <Grid gap={2} style={{ flex: 1 }}>
            {formattedActions.map(({ checkboxName, value, action, displayName, hasConditions }) => {
              return (
                <GridItem col={3} key={action}>
                  <CheckboxWrapper
                    disabled={isFormDisabled || IS_DISABLED}
                    hasConditions={hasConditions}
                  >
                    <Checkbox
                      name={checkboxName}
                      disabled={isFormDisabled || IS_DISABLED}
                      // Keep same signature as packages/core/admin/admin/src/components/Roles/Permissions/index.js l.91
                      onValueChange={value => {
                        onChangeSimpleCheckbox({
                          target: {
                            name: checkboxName,
                            value,
                          },
                        });
                      }}
                      value={value}
                    >
                      {displayName}
                    </Checkbox>
                  </CheckboxWrapper>
                </GridItem>
              );
            })}
          </Grid>
          <ConditionsButton
            hasConditions={doesButtonHasCondition}
            onClick={handleToggleModalIsOpen}
            variant="tertiary"
          />
        </Row>
      </Box>
      {isModalOpen && (
        <ConditionsModal
          headerBreadCrumbs={[categoryName, subCategoryName]}
          actions={formattedActions}
          isFormDisabled={isFormDisabled}
          onClosed={handleModalClose}
          onToggle={handleToggleModalIsOpen}
        />
      )}
    </>
  );
};

SubCategory.propTypes = {
  actions: PropTypes.array.isRequired,
  categoryName: PropTypes.string.isRequired,
  isFormDisabled: PropTypes.bool.isRequired,
  subCategoryName: PropTypes.string.isRequired,
  pathToData: PropTypes.array.isRequired,
};

export default SubCategory;
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * @fileoverview ProfilingView visualizes TRACE_EVENT events using the
 * tracing.Timeline component.
 */
cr.define('tracing', function() {
  /**
   * ProfilingView
   * @constructor
   * @extends {ui.TabPanel}
   */
  ProfilingView = cr.ui.define(cr.ui.TabPanel);

  ProfilingView.prototype = {
    __proto__: cr.ui.TabPanel.prototype,

    traceEvents_: [],
    systemTraceEvents_: [],

    decorate: function() {
      cr.ui.TabPanel.prototype.decorate.apply(this);

      // make the <list>/add/save/record element
      this.controlDiv_ = document.createElement('div');
      this.controlDiv_.className = 'control';
      this.appendChild(this.controlDiv_);

      var tracingEl = document.createElement('span');
      tracingEl.textContent = 'Tracing: ';

      this.recordBn_ = document.createElement('button');
      this.recordBn_.textContent = 'Record';
      this.recordBn_.addEventListener('click', this.onRecord_.bind(this));

      this.saveBn_ = document.createElement('button');
      this.saveBn_.textContent = 'Save';
      this.saveBn_.addEventListener('click', this.onSave_.bind(this));

      this.loadBn_ = document.createElement('button');
      this.loadBn_.textContent = 'Load';
      this.loadBn_.addEventListener('click', this.onLoad_.bind(this));

      this.container_ = document.createElement('div');
      this.container_.className = 'container';

      this.timelineView_ = new TimelineView();

      this.controlDiv_.appendChild(tracingEl);
      this.controlDiv_.appendChild(this.recordBn_);
      this.controlDiv_.appendChild(this.loadBn_);
      this.controlDiv_.appendChild(this.saveBn_);

      if (cr.isChromeOS) {
        this.systemTracingBn_ = document.createElement('input');
        this.systemTracingBn_.type = 'checkbox';
        this.systemTracingBn_.checked = true;

        var systemTracingLabelEl = document.createElement('div');
        systemTracingLabelEl.className = 'label';
        systemTracingLabelEl.textContent = 'System events';
        systemTracingLabelEl.appendChild(this.systemTracingBn_);

        this.controlDiv_.appendChild(systemTracingLabelEl);
      }

      this.container_.appendChild(this.timelineView_);
      this.appendChild(this.container_);

      document.addEventListener('keypress', this.onKeypress_.bind(this));

      tracingController.addEventListener('traceEnded',
          this.onRecordDone_.bind(this));
      tracingController.addEventListener('loadTraceFileComplete',
          this.onLoadTraceFileComplete_.bind(this));
      tracingController.addEventListener('saveTraceFileComplete',
          this.onSaveTraceFileComplete_.bind(this));
      tracingController.addEventListener('loadTraceFileCanceled',
          this.onLoadTraceFileCanceled_.bind(this));
      tracingController.addEventListener('saveTraceFileCanceled',
          this.onSaveTraceFileCanceled_.bind(this));
      this.refresh_();
    },

    refresh_: function() {
      var traceEvents = tracingController.traceEvents;
      var hasEvents = traceEvents && traceEvents.length;

      this.saveBn_.disabled = !hasEvents;

      if (!hasEvents) return;

      var m = new tracing.TimelineModel();
      m.importEvents(traceEvents, true, [tracingController.systemTraceEvents]);
      this.timelineView_.model = m;
    },

    onKeypress_: function(event) {
      if (event.keyCode == 114 && !tracingController.isTracingEnabled) {
        this.onRecord_();
      }
    },

    ///////////////////////////////////////////////////////////////////////////

    onRecord_: function() {
      tracingController.beginTracing(this.systemTracingBn_.checked);
    },

    onRecordDone_: function() {
      this.refresh_();
    },

    ///////////////////////////////////////////////////////////////////////////

    onSave_: function() {
      this.overlayEl_ = new tracing.Overlay();
      this.overlayEl_.className = 'profiling-overlay';

      var labelEl = document.createElement('div');
      labelEl.className = 'label';
      labelEl.textContent = 'Saving...';
      this.overlayEl_.appendChild(labelEl);
      this.overlayEl_.visible = true;

      tracingController.beginSaveTraceFile();
    },

    onSaveTraceFileComplete_: function(e) {
      this.overlayEl_.visible = false;
      this.overlayEl_ = undefined;
    },

    onSaveTraceFileCanceled_: function(e) {
      this.overlayEl_.visible = false;
      this.overlayEl_ = undefined;
    },

    ///////////////////////////////////////////////////////////////////////////

    onLoad_: function() {
      this.overlayEl_ = new tracing.Overlay();
      this.overlayEl_.className = 'profiling-overlay';

      var labelEl = document.createElement('div');
      labelEl.className = 'label';
      labelEl.textContent = 'Loading...';
      this.overlayEl_.appendChild(labelEl);
      this.overlayEl_.visible = true;

      tracingController.beginLoadTraceFile();
    },

    onLoadTraceFileComplete_: function(e) {
      this.overlayEl_.visible = false;
      this.overlayEl_ = undefined;

      this.refresh_();
    },

    onLoadTraceFileCanceled_: function(e) {
      this.overlayEl_.visible = false;
      this.overlayEl_ = undefined;
    }
  };

  return {
    ProfilingView: ProfilingView
  };
});
<commit_msg>Fix about:tracing recording on non-CrOS due to undefined systemTracingBn_ BUG=122844<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * @fileoverview ProfilingView visualizes TRACE_EVENT events using the
 * tracing.Timeline component.
 */
cr.define('tracing', function() {
  /**
   * ProfilingView
   * @constructor
   * @extends {ui.TabPanel}
   */
  ProfilingView = cr.ui.define(cr.ui.TabPanel);

  ProfilingView.prototype = {
    __proto__: cr.ui.TabPanel.prototype,

    traceEvents_: [],
    systemTraceEvents_: [],

    decorate: function() {
      cr.ui.TabPanel.prototype.decorate.apply(this);

      // make the <list>/add/save/record element
      this.controlDiv_ = document.createElement('div');
      this.controlDiv_.className = 'control';
      this.appendChild(this.controlDiv_);

      var tracingEl = document.createElement('span');
      tracingEl.textContent = 'Tracing: ';

      this.recordBn_ = document.createElement('button');
      this.recordBn_.textContent = 'Record';
      this.recordBn_.addEventListener('click', this.onRecord_.bind(this));

      this.saveBn_ = document.createElement('button');
      this.saveBn_.textContent = 'Save';
      this.saveBn_.addEventListener('click', this.onSave_.bind(this));

      this.loadBn_ = document.createElement('button');
      this.loadBn_.textContent = 'Load';
      this.loadBn_.addEventListener('click', this.onLoad_.bind(this));

      this.container_ = document.createElement('div');
      this.container_.className = 'container';

      this.timelineView_ = new TimelineView();

      this.controlDiv_.appendChild(tracingEl);
      this.controlDiv_.appendChild(this.recordBn_);
      this.controlDiv_.appendChild(this.loadBn_);
      this.controlDiv_.appendChild(this.saveBn_);

      if (cr.isChromeOS) {
        this.systemTracingBn_ = document.createElement('input');
        this.systemTracingBn_.type = 'checkbox';
        this.systemTracingBn_.checked = true;

        var systemTracingLabelEl = document.createElement('div');
        systemTracingLabelEl.className = 'label';
        systemTracingLabelEl.textContent = 'System events';
        systemTracingLabelEl.appendChild(this.systemTracingBn_);

        this.controlDiv_.appendChild(systemTracingLabelEl);
      }

      this.container_.appendChild(this.timelineView_);
      this.appendChild(this.container_);

      document.addEventListener('keypress', this.onKeypress_.bind(this));

      tracingController.addEventListener('traceEnded',
          this.onRecordDone_.bind(this));
      tracingController.addEventListener('loadTraceFileComplete',
          this.onLoadTraceFileComplete_.bind(this));
      tracingController.addEventListener('saveTraceFileComplete',
          this.onSaveTraceFileComplete_.bind(this));
      tracingController.addEventListener('loadTraceFileCanceled',
          this.onLoadTraceFileCanceled_.bind(this));
      tracingController.addEventListener('saveTraceFileCanceled',
          this.onSaveTraceFileCanceled_.bind(this));
      this.refresh_();
    },

    refresh_: function() {
      var traceEvents = tracingController.traceEvents;
      var hasEvents = traceEvents && traceEvents.length;

      this.saveBn_.disabled = !hasEvents;

      if (!hasEvents) return;

      var m = new tracing.TimelineModel();
      m.importEvents(traceEvents, true, [tracingController.systemTraceEvents]);
      this.timelineView_.model = m;
    },

    onKeypress_: function(event) {
      if (event.keyCode == 114 && !tracingController.isTracingEnabled) {
        this.onRecord_();
      }
    },

    ///////////////////////////////////////////////////////////////////////////

    onRecord_: function() {
      var systemTracingEnabled;
      if (this.systemTracingBn_)
        systemTracingEnabled = this.systemTracingBn_.checked;
      else
        systemTracingEnabled = false;
      tracingController.beginTracing(systemTracingEnabled);
    },

    onRecordDone_: function() {
      this.refresh_();
    },

    ///////////////////////////////////////////////////////////////////////////

    onSave_: function() {
      this.overlayEl_ = new tracing.Overlay();
      this.overlayEl_.className = 'profiling-overlay';

      var labelEl = document.createElement('div');
      labelEl.className = 'label';
      labelEl.textContent = 'Saving...';
      this.overlayEl_.appendChild(labelEl);
      this.overlayEl_.visible = true;

      tracingController.beginSaveTraceFile();
    },

    onSaveTraceFileComplete_: function(e) {
      this.overlayEl_.visible = false;
      this.overlayEl_ = undefined;
    },

    onSaveTraceFileCanceled_: function(e) {
      this.overlayEl_.visible = false;
      this.overlayEl_ = undefined;
    },

    ///////////////////////////////////////////////////////////////////////////

    onLoad_: function() {
      this.overlayEl_ = new tracing.Overlay();
      this.overlayEl_.className = 'profiling-overlay';

      var labelEl = document.createElement('div');
      labelEl.className = 'label';
      labelEl.textContent = 'Loading...';
      this.overlayEl_.appendChild(labelEl);
      this.overlayEl_.visible = true;

      tracingController.beginLoadTraceFile();
    },

    onLoadTraceFileComplete_: function(e) {
      this.overlayEl_.visible = false;
      this.overlayEl_ = undefined;

      this.refresh_();
    },

    onLoadTraceFileCanceled_: function(e) {
      this.overlayEl_.visible = false;
      this.overlayEl_ = undefined;
    }
  };

  return {
    ProfilingView: ProfilingView
  };
});
<|endoftext|>


<commit_before>/* eslint camelcase: 0, prefer-promise-reject-errors: 0 */
const config = require('../../../config')
const { authorisedRequest } = require('../../lib/authorised-request')

// Get a company and then pad out the interactions with related data
function getDitCompany (token, id) {
  return authorisedRequest(token, `${config.apiRoot}/v3/company/${id}`)
}

function getCHCompany (token, id) {
  return authorisedRequest(token, `${config.apiRoot}/v3/ch-company/${id}`)
}

function saveCompany (token, company) {
  return new Promise(async (resolve, reject) => {
    try {
      const parsedCompany = Object.assign({}, company)
      delete parsedCompany.companies_house_data
      delete parsedCompany.contacts
      delete parsedCompany.interactions

      let method
      let url

      if (parsedCompany.id && parsedCompany.id.length > 0) {
        method = 'PATCH'
        url = `${config.apiRoot}/v3/company/${parsedCompany.id}`
      } else {
        delete parsedCompany.id
        method = 'POST'
        url = `${config.apiRoot}/v3/company`
      }

      const data = await authorisedRequest(token, { url, method, body: parsedCompany })
      resolve(data)
    } catch (error) {
      if (typeof error.error === 'string') {
        reject({
          statusCode: error.response.statusCode,
          errors: { detail: error.response.statusMessage },
        })
      } else {
        reject({
          statusCode: error.response.statusCode,
          errors: error.error,
        })
      }
    }
  })
}

function archiveCompany (token, companyId, reason) {
  const options = {
    body: { reason },
    url: `${config.apiRoot}/v3/company/${companyId}/archive`,
    method: 'POST',
  }
  return authorisedRequest(token, options)
}

function unarchiveCompany (token, companyId) {
  return authorisedRequest(token, {
    method: 'POST',
    url: `${config.apiRoot}/v3/company/${companyId}/unarchive`,
  })
}

function updateCompany (token, companyId, body) {
  return authorisedRequest(token, {
    url: `${config.apiRoot}/v3/company/${companyId}`,
    method: 'PATCH',
    body,
  })
}

function getCompanyAuditLog (token, companyId, page = 1) {
  const limit = 10
  const offset = limit * (page - 1)
  return authorisedRequest(token, {
    url: `${config.apiRoot}/v3/company/${companyId}/audit`,
    qs: { limit, offset },
  })
}

function getCompanyTimeline (token, companyId, page = 1) {
  const limit = 10
  const offset = limit * (page - 1)
  return authorisedRequest(token, {
    url: `${config.apiRoot}/v3/company/${companyId}/timeline`,
    qs: { limit, offset },
  })
}

function getCompanySubsidiaries (token, companyId, page = 1) {
  const limit = 10
  const offset = limit * (page - 1)
  return authorisedRequest(token, {
    url: `${config.apiRoot}/v3/company`,
    qs: {
      limit,
      offset,
      sortby: 'name',
      global_headquarters_id: companyId,
    },
  })
}

function getCoreTeam (token, companyId) {
  return authorisedRequest(token, {
    url: `${config.apiRoot}/v3/company/${companyId}/core-team`,
  })
}

module.exports = {
  saveCompany,
  getDitCompany,
  getCHCompany,
  archiveCompany,
  unarchiveCompany,
  updateCompany,
  getCompanyAuditLog,
  getCompanyTimeline,
  getCompanySubsidiaries,
  getCoreTeam,
}
<commit_msg>Add function to get One List group core team<commit_after>/* eslint camelcase: 0, prefer-promise-reject-errors: 0 */
const config = require('../../../config')
const { authorisedRequest } = require('../../lib/authorised-request')

// Get a company and then pad out the interactions with related data
function getDitCompany (token, id) {
  return authorisedRequest(token, `${config.apiRoot}/v3/company/${id}`)
}

function getCHCompany (token, id) {
  return authorisedRequest(token, `${config.apiRoot}/v3/ch-company/${id}`)
}

function saveCompany (token, company) {
  return new Promise(async (resolve, reject) => {
    try {
      const parsedCompany = Object.assign({}, company)
      delete parsedCompany.companies_house_data
      delete parsedCompany.contacts
      delete parsedCompany.interactions

      let method
      let url

      if (parsedCompany.id && parsedCompany.id.length > 0) {
        method = 'PATCH'
        url = `${config.apiRoot}/v3/company/${parsedCompany.id}`
      } else {
        delete parsedCompany.id
        method = 'POST'
        url = `${config.apiRoot}/v3/company`
      }

      const data = await authorisedRequest(token, { url, method, body: parsedCompany })
      resolve(data)
    } catch (error) {
      if (typeof error.error === 'string') {
        reject({
          statusCode: error.response.statusCode,
          errors: { detail: error.response.statusMessage },
        })
      } else {
        reject({
          statusCode: error.response.statusCode,
          errors: error.error,
        })
      }
    }
  })
}

function archiveCompany (token, companyId, reason) {
  const options = {
    body: { reason },
    url: `${config.apiRoot}/v3/company/${companyId}/archive`,
    method: 'POST',
  }
  return authorisedRequest(token, options)
}

function unarchiveCompany (token, companyId) {
  return authorisedRequest(token, {
    method: 'POST',
    url: `${config.apiRoot}/v3/company/${companyId}/unarchive`,
  })
}

function updateCompany (token, companyId, body) {
  return authorisedRequest(token, {
    url: `${config.apiRoot}/v3/company/${companyId}`,
    method: 'PATCH',
    body,
  })
}

function getCompanyAuditLog (token, companyId, page = 1) {
  const limit = 10
  const offset = limit * (page - 1)
  return authorisedRequest(token, {
    url: `${config.apiRoot}/v3/company/${companyId}/audit`,
    qs: { limit, offset },
  })
}

function getCompanyTimeline (token, companyId, page = 1) {
  const limit = 10
  const offset = limit * (page - 1)
  return authorisedRequest(token, {
    url: `${config.apiRoot}/v3/company/${companyId}/timeline`,
    qs: { limit, offset },
  })
}

function getCompanySubsidiaries (token, companyId, page = 1) {
  const limit = 10
  const offset = limit * (page - 1)
  return authorisedRequest(token, {
    url: `${config.apiRoot}/v3/company`,
    qs: {
      limit,
      offset,
      sortby: 'name',
      global_headquarters_id: companyId,
    },
  })
}

function getCoreTeam (token, companyId) {
  return authorisedRequest(token, {
    url: `${config.apiRoot}/v3/company/${companyId}/core-team`,
  })
}

function getOneListGroupCoreTeam (token, companyId) {
  return authorisedRequest(token, {
    url: `${config.apiRoot}/v3/company/${companyId}/one-list-group-core-team`,
  })
}

module.exports = {
  saveCompany,
  getDitCompany,
  getCHCompany,
  archiveCompany,
  unarchiveCompany,
  updateCompany,
  getCompanyAuditLog,
  getCompanyTimeline,
  getCompanySubsidiaries,
  getCoreTeam,
  getOneListGroupCoreTeam,
}
<|endoftext|>


<commit_before>// wuw server
"use strict";

// import packages (api)
var express = require("express");
var expressValidator = require('express-validator');
var bodyParser = require("body-parser");
var util = require('util');
var mongoose = require("mongoose");
var morgan = require("morgan");

// import packages (parser)
// var cronjob = require('cron').CronJob;
// var parser = require("./parser");

// create cronjob for parser
// new cronjob("0 */15 * * * *", function(){
//     console.log(new Date() + ": starting parser...");
//     parser.startParser();
// }, null, true, "Europe/Berlin");

// create the express app & configure port
var app = express();
var port = process.env.PORT || 8088;

// api version & url
var apiVersion = 0;
var apiBaseUrl = "/api/v" + apiVersion;

// use morgan to log
app.use(morgan("dev"));

// configure body parser
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(expressValidator());

// allow cross origin resource sharing
app.use(function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    next();
});

// connect to mongodb
mongoose.connect("mongodb://localhost:27017/wuw");

// create models from our schemas
var Lecture = require("./model_lecture");
var Deadline = require("./model_deadline");

// routes
var router = express.Router();

// middleware to use for all requests
router.use(function(req, res, next) {
    // do logging
    //console.log("Something is happening...");
    next();
});

// test route to make sure everything is working (GET /$apiBaseUrl)
router.get("/", function(req, res) {
    res.status(200).json({ message: "welcome to the wuw api v" + apiVersion });
    res.end();
});

// on routes that end in /lectures
router.route("/lectures")

    // get all lectures (GET /$apiBaseUrl/lectures)
    .get(function(req, res) {
        Lecture.find({}).sort({startTime: 1}).exec(function(err, lectures) {
            if (err) { res.status(500).send(err); }
            res.status(200).json(lectures);
            res.end();
        });
    });

// on routes that end in /upcomingLectures
router.route("/upcomingLectures")

    // get all lectures (GET /$apiBaseUrl/lectures)
    .get(function(req, res) {
        Lecture.find({"endTime": {"$gte": new Date()}}).sort({startTime: 1}).exec(function(err, lectures) {
            if (err) { res.status(500).send(err); }
            res.status(200).json(lectures);
            res.end();
        });
    });

// on routes that end in /lectures/:lecture_id
router.route("/lectures/:lecture_id")

    // get lecture with that id (GET /$apiBaseUrl/lectures/:lecture_id)
    .get(function(req, res) {
        Lecture.findById(req.params.lecture_id, function(err, lecture) {
            if (err) { res.status(500).send(err); }
            res.status(200).json(lecture);
            res.end();
        });
    });

// on routes that end in /deadlines
router.route("/deadlines")

    // get all deadlines (GET /$apiBaseUrl/deadlines)
    .get(function(req, res) {
        Deadline.find(function(err, deadlines) {
            if (err) { res.status(500).send(err); }
            res.status(200).json(deadlines);
            res.end();
        });
    })

    // create a deadline (POST /$apiBaseUrl/deadlines)
    .post(function(req, res) {
        // create instance of Deadline model
        console.log(req.body);
        var deadline = new Deadline();

        // check inputs
        req.assert("deadline", "deadline must be a valid date").isDate();
        req.assert("deadline", "deadline must not be empty").notEmpty();
        req.assert("info", "info must not be empty").notEmpty();
        //req.assert("shortLectureName", "shortLectureName must not be empty").notEmpty();
        //req.assert("group", "group must not be empty").notEmpty();
        //req.assert("uuid", "oh kiddie...").notEmpty();

        // if there are errors, send 400
        var errors = req.validationErrors(true);
        if (errors) {
            res.status(400).send("There have been validation errors: " + util.inspect(errors));
            return;
        }

        // set attributes
        deadline.deadline = req.body.deadline;
        deadline.info = req.body.info;
        deadline.shortLectureName = req.body.shortLectureName;
        deadline.group = req.body.group;
        deadline.createdBy = req.body.uuid;

        // save deadline in mongodb
        deadline.save(function(err, deadline) {
            if (err) { res.send(err); }
            res.status(200).json({ message: "Deadline created!", id: deadline.id });
        });
    });

// on routes that end in /deadlines/:deadline_id
router.route("/deadlines/:deadline_id")

    // get deadline with that id (GET /$apiBaseUrl/deadlines/:deadline_id)
    .get(function(req, res) {
        Deadline.findById(req.params.deadline_id, function(err, deadline) {
            if (err) { res.status(500).send(err); }
            res.status(200).json(deadline);
            res.end();
        });
    })

    // update deadline with this id
    .put(function(req, res) {
        Deadline.findById(req.params.deadline_id, function(err, deadline) {
            if (err) { res.status(500).send(err); }

            // set new attributes
            deadline.deadline = req.body.deadline;
            deadline.shortLectureName = req.body.shortLectureName;
            deadline.group = req.body.group;

            deadline.save(function(err) {
                if (err) { res.send(err); }
                res.status(200).json({ message: "Deadline updated!" });
            });

        });
    })

    // delete the deadline with this id
    .delete(function(req, res) {
        Deadline.remove({
            _id: req.params.deadline_id
        }, function(err) {
            if (err) { res.status(500).send(err); }
            res.status(200).json({ message: "Deadline successfully deleted" });
        });
    });

// register the router & the base url
app.use(apiBaseUrl, router);

// start the server
var server = app.listen(port);
console.log("magic happens at http://localhost:" + port + apiBaseUrl);

var startApi = function() {
  if (!server) {
    server = app.listen(port);
  }
};

var stopApi = function() {
  server.close();
};

module.exports = { startApi: startApi, stopApi: stopApi };
<commit_msg>fix indentation<commit_after>// wuw server
"use strict";

// import packages (api)
var express = require("express");
var expressValidator = require('express-validator');
var bodyParser = require("body-parser");
var util = require('util');
var mongoose = require("mongoose");
var morgan = require("morgan");

// import packages (parser)
// var cronjob = require('cron').CronJob;
// var parser = require("./parser");

// create cronjob for parser
// new cronjob("0 */15 * * * *", function(){
//     console.log(new Date() + ": starting parser...");
//     parser.startParser();
// }, null, true, "Europe/Berlin");

// create the express app & configure port
var app = express();
var port = process.env.PORT || 8088;

// api version & url
var apiVersion = 0;
var apiBaseUrl = "/api/v" + apiVersion;

// use morgan to log
app.use(morgan("dev"));

// configure body parser
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(expressValidator());

// allow cross origin resource sharing
app.use(function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    next();
});

// connect to mongodb
mongoose.connect("mongodb://localhost:27017/wuw");

// create models from our schemas
var Lecture = require("./model_lecture");
var Deadline = require("./model_deadline");

// routes
var router = express.Router();

// middleware to use for all requests
router.use(function(req, res, next) {
    // do logging
    //console.log("Something is happening...");
    next();
});

// test route to make sure everything is working (GET /$apiBaseUrl)
router.get("/", function(req, res) {
    res.status(200).json({ message: "welcome to the wuw api v" + apiVersion });
    res.end();
});

// on routes that end in /lectures
router.route("/lectures")

    // get all lectures (GET /$apiBaseUrl/lectures)
    .get(function(req, res) {
        Lecture.find({}).sort({startTime: 1}).exec(function(err, lectures) {
            if (err) { res.status(500).send(err); }
            res.status(200).json(lectures);
            res.end();
        });
    });

// on routes that end in /upcomingLectures
router.route("/upcomingLectures")

    // get all lectures (GET /$apiBaseUrl/lectures)
    .get(function(req, res) {
        Lecture.find({"endTime": {"$gte": new Date()}}).sort({startTime: 1}).exec(function(err, lectures) {
            if (err) { res.status(500).send(err); }
            res.status(200).json(lectures);
            res.end();
        });
    });

// on routes that end in /lectures/:lecture_id
router.route("/lectures/:lecture_id")

    // get lecture with that id (GET /$apiBaseUrl/lectures/:lecture_id)
    .get(function(req, res) {
        Lecture.findById(req.params.lecture_id, function(err, lecture) {
            if (err) { res.status(500).send(err); }
            res.status(200).json(lecture);
            res.end();
        });
    });

// on routes that end in /deadlines
router.route("/deadlines")

    // get all deadlines (GET /$apiBaseUrl/deadlines)
    .get(function(req, res) {
        Deadline.find(function(err, deadlines) {
            if (err) { res.status(500).send(err); }
            res.status(200).json(deadlines);
            res.end();
        });
    })

    // create a deadline (POST /$apiBaseUrl/deadlines)
    .post(function(req, res) {
        // create instance of Deadline model
        console.log(req.body);
        var deadline = new Deadline();

        // check inputs
        req.assert("deadline", "deadline must be a valid date").isDate();
        req.assert("deadline", "deadline must not be empty").notEmpty();
        req.assert("info", "info must not be empty").notEmpty();
        //req.assert("shortLectureName", "shortLectureName must not be empty").notEmpty();
        //req.assert("group", "group must not be empty").notEmpty();
        //req.assert("uuid", "oh kiddie...").notEmpty();

        // if there are errors, send 400
        var errors = req.validationErrors(true);
        if (errors) {
            res.status(400).send("There have been validation errors: " + util.inspect(errors));
            return;
        }

        // set attributes
        deadline.deadline = req.body.deadline;
        deadline.info = req.body.info;
        deadline.shortLectureName = req.body.shortLectureName;
        deadline.group = req.body.group;
        deadline.createdBy = req.body.uuid;

        // save deadline in mongodb
        deadline.save(function(err, deadline) {
            if (err) { res.send(err); }
            res.status(200).json({ message: "Deadline created!", id: deadline.id });
        });
    });

// on routes that end in /deadlines/:deadline_id
router.route("/deadlines/:deadline_id")

    // get deadline with that id (GET /$apiBaseUrl/deadlines/:deadline_id)
    .get(function(req, res) {
        Deadline.findById(req.params.deadline_id, function(err, deadline) {
            if (err) { res.status(500).send(err); }
            res.status(200).json(deadline);
            res.end();
        });
    })

    // update deadline with this id
    .put(function(req, res) {
        Deadline.findById(req.params.deadline_id, function(err, deadline) {
            if (err) { res.status(500).send(err); }

            // set new attributes
            deadline.deadline = req.body.deadline;
            deadline.shortLectureName = req.body.shortLectureName;
            deadline.group = req.body.group;

            deadline.save(function(err) {
                if (err) { res.send(err); }
                res.status(200).json({ message: "Deadline updated!" });
            });

        });
    })

    // delete the deadline with this id
    .delete(function(req, res) {
        Deadline.remove({
            _id: req.params.deadline_id
        }, function(err) {
            if (err) { res.status(500).send(err); }
            res.status(200).json({ message: "Deadline successfully deleted" });
        });
    });

// register the router & the base url
app.use(apiBaseUrl, router);

// start the server
var server = app.listen(port);
console.log("magic happens at http://localhost:" + port + apiBaseUrl);

var startApi = function() {
    if (!server) {
        server = app.listen(port);
    }
};

var stopApi = function() {
    server.close();
};

module.exports = { startApi: startApi, stopApi: stopApi };
<|endoftext|>


<commit_before>const { Bagger } = require('./bagger');
const { BagItProfile } = require('./bagit_profile');
const fs = require('fs');
const { Job } = require('../core/job');
const os = require('os');
const { PackageOperation } = require('../core/package_operation');
const path = require('path');
const { Validator } = require('./validator');
const { Util } = require('../core/util');

var tmpFile = path.join(os.tmpdir(), 'TestBag.tar');
var tmpOutputDir = path.join(os.tmpdir(), 'dart-bagger-test');

afterEach(() => {
    // Skip deletion on Windows because
    // https://github.com/nodejs/node-v0.x-archive/issues/3051
	if (os.platform != 'win32') {
		if (fs.existsSync(tmpFile)) {
			fs.unlinkSync(tmpFile)
		}
	}
});

afterAll(() => {
	Util.deleteRecursive(tmpOutputDir);
});

function getJob(...sources) {
    var job = new Job();
    job.packageOp = new PackageOperation('TestBag', tmpFile);

    // Add the sources we want to pack into the bag
    job.packageOp.sourceFiles.push(...sources);

    // Load the profile that describes how to create the bag.
    var profilesDir = path.join(__dirname, '..', 'test', 'profiles');
    job.bagItProfile = BagItProfile.load(path.join(profilesDir, 'multi_manifest.json'));

    // Set required tags for this profile, otherwise the bag will be invalid.
    var access = job.bagItProfile.firstMatchingTag('tagName', 'Access');
    var title = job.bagItProfile.firstMatchingTag('tagName', 'Title');
    var description = job.bagItProfile.firstMatchingTag('tagName', 'Description');
    var sourceOrg = job.bagItProfile.firstMatchingTag('tagName', 'Source-Organization');
    access.userValue = 'Institution';
    title.userValue = 'Test Bag';
    description.userValue = 'Bag of files for unit testing.';
    sourceOrg.userValue = 'School of Hard Knocks';
    return job;
}

test('create() with one dir', done => {
    let sourceDir = path.join(__dirname, '..', 'util');
    let job = getJob(sourceDir);
    let bagger = new Bagger(job);

    bagger.on('finish', function() {
        let result = bagger.job.packageOp.result;
        expect(result.errors.length).toEqual(0);
        expect(result.succeeded()).toEqual(true);
        expect(result.started).not.toBeNull();
        expect(result.competed).not.toBeNull();
        expect(result.operation).toEqual('bagging');
        expect(result.provider).toEqual('DART bagger');
        expect(result.filepath.endsWith('TestBag.tar')).toEqual(true);
        expect(result.filesize).toBeGreaterThan(0);
        done();
    });

    bagger.create();
});

test('create() with one file', done => {
    let job = getJob(__filename);
    let bagger = new Bagger(job);

    bagger.on('finish', function() {
        let result = bagger.job.packageOp.result;
        expect(result.errors.length).toEqual(0);
        expect(result.succeeded()).toEqual(true);
        expect(result.filesize).toBeGreaterThan(0);
        // 2 manifests, 2 tag manifests, 3 tag files, 1 payload file
        expect(bagger.bagItFiles.length).toEqual(8);
        done();
    });

    bagger.create();
});

// This test times out consistently when run on Mac OSX
// with command `npm test -- --runInBand` or
// `npm test bagit/bagger.test.js -- --runInBand`.
//
// It passes consistently on Linux and when run on Mac
// with command `npm test -- -t 'with multiple dirs and files'`
//
// WTF??
test('create() with multiple dirs and files', done => {
    let utilDir = path.join(__dirname, '..', 'util');
    let bagsDir = path.join(__dirname, '..', 'test', 'bags');
    let job = getJob(utilDir, __filename, bagsDir);
    let bagger = new Bagger(job);

    bagger.on('finish', function() {
        let result = bagger.job.packageOp.result;
        expect(result.errors.length).toEqual(0);
        expect(result.succeeded()).toEqual(true);
        expect(result.filesize).toBeGreaterThan(0);

        let validator = new Validator(tmpFile, job.bagItProfile);
        validator.on('end', function(taskDesc) {
            expect(validator.errors).toEqual([]);
            expect(validator.payloadFiles().length).toBeGreaterThan(20);
            expect(validator.payloadManifests().length).toEqual(2);
            expect(validator.tagFiles().length).toEqual(3);
            expect(validator.tagManifests().length).toEqual(2);

            // Make sure tags were written correctly
            let bagInfoFile = validator.files['bag-info.txt'];
            expect(bagInfoFile).not.toBeNull();
            expect(bagInfoFile.keyValueCollection.first('Source-Organization')).toEqual('School of Hard Knocks');
            let aptInfoFile = validator.files['aptrust-info.txt'];
            expect(bagInfoFile).not.toBeNull();
            expect(aptInfoFile.keyValueCollection.first('Access')).toEqual('Institution');
            expect(aptInfoFile.keyValueCollection.first('Title')).toEqual('Test Bag');
            expect(aptInfoFile.keyValueCollection.first('Description')).toEqual('Bag of files for unit testing.');

            done();
        });
        validator.on('error', function(err) {
            // Report the error on the console.
            expect(err).toBeNull();
        });
        validator.validate();
    });

    bagger.create();
});

test('create() using FileSystemWriter', done => {
    let utilDir = path.join(__dirname, '..', 'util');
    let bagsDir = path.join(__dirname, '..', 'test', 'bags');
    let job = getJob(utilDir, __filename, bagsDir);
    job.packageOp.packageName = 'dart-bagger-test';
    job.packageOp.outputPath = tmpOutputDir;
    job.bagItProfile.serialization = 'optional';
    let bagger = new Bagger(job);

    bagger.on('finish', function() {
        let result = bagger.job.packageOp.result;
        expect(result.errors.length).toEqual(0);
        expect(result.succeeded()).toEqual(true);
        expect(result.filesize).toBeGreaterThan(0);

        let validator = new Validator(tmpOutputDir, job.bagItProfile);
        validator.on('end', function(taskDesc) {
            expect(validator.errors).toEqual([]);
            expect(validator.payloadFiles().length).toBeGreaterThan(20);
            expect(validator.payloadManifests().length).toEqual(2);
            expect(validator.tagFiles().length).toEqual(3);
            expect(validator.tagManifests().length).toEqual(2);

            // Make sure tags were written correctly
            let bagInfoFile = validator.files['bag-info.txt'];
            expect(bagInfoFile).not.toBeNull();
            expect(bagInfoFile.keyValueCollection.first('Source-Organization')).toEqual('School of Hard Knocks');
            let aptInfoFile = validator.files['aptrust-info.txt'];
            expect(bagInfoFile).not.toBeNull();
            expect(aptInfoFile.keyValueCollection.first('Access')).toEqual('Institution');
            expect(aptInfoFile.keyValueCollection.first('Title')).toEqual('Test Bag');
            expect(aptInfoFile.keyValueCollection.first('Description')).toEqual('Bag of files for unit testing.');

            done();
        });
        validator.validate();
    });

    // This shouldn't happen, but it does on Windows AppVeyor build.
    // Force test to fail here to see if we can track it down.
    bagger.on('error', function(err) {
        throw err;
    });

    bagger.create();
});
<commit_msg>Revert last change<commit_after>const { Bagger } = require('./bagger');
const { BagItProfile } = require('./bagit_profile');
const fs = require('fs');
const { Job } = require('../core/job');
const os = require('os');
const { PackageOperation } = require('../core/package_operation');
const path = require('path');
const { Validator } = require('./validator');
const { Util } = require('../core/util');

var tmpFile = path.join(os.tmpdir(), 'TestBag.tar');
var tmpOutputDir = path.join(os.tmpdir(), 'dart-bagger-test');

afterEach(() => {
    // Skip deletion on Windows because
    // https://github.com/nodejs/node-v0.x-archive/issues/3051
	if (os.platform != 'win32') {
		if (fs.existsSync(tmpFile)) {
			fs.unlinkSync(tmpFile)
		}
	}
});

afterAll(() => {
	Util.deleteRecursive(tmpOutputDir);
});

function getJob(...sources) {
    var job = new Job();
    job.packageOp = new PackageOperation('TestBag', tmpFile);

    // Add the sources we want to pack into the bag
    job.packageOp.sourceFiles.push(...sources);

    // Load the profile that describes how to create the bag.
    var profilesDir = path.join(__dirname, '..', 'test', 'profiles');
    job.bagItProfile = BagItProfile.load(path.join(profilesDir, 'multi_manifest.json'));

    // Set required tags for this profile, otherwise the bag will be invalid.
    var access = job.bagItProfile.firstMatchingTag('tagName', 'Access');
    var title = job.bagItProfile.firstMatchingTag('tagName', 'Title');
    var description = job.bagItProfile.firstMatchingTag('tagName', 'Description');
    var sourceOrg = job.bagItProfile.firstMatchingTag('tagName', 'Source-Organization');
    access.userValue = 'Institution';
    title.userValue = 'Test Bag';
    description.userValue = 'Bag of files for unit testing.';
    sourceOrg.userValue = 'School of Hard Knocks';
    return job;
}

test('create() with one dir', done => {
    let sourceDir = path.join(__dirname, '..', 'util');
    let job = getJob(sourceDir);
    let bagger = new Bagger(job);

    bagger.on('finish', function() {
        let result = bagger.job.packageOp.result;
        expect(result.errors.length).toEqual(0);
        expect(result.succeeded()).toEqual(true);
        expect(result.started).not.toBeNull();
        expect(result.competed).not.toBeNull();
        expect(result.operation).toEqual('bagging');
        expect(result.provider).toEqual('DART bagger');
        expect(result.filepath.endsWith('TestBag.tar')).toEqual(true);
        expect(result.filesize).toBeGreaterThan(0);
        done();
    });

    bagger.create();
});

test('create() with one file', done => {
    let job = getJob(__filename);
    let bagger = new Bagger(job);

    bagger.on('finish', function() {
        let result = bagger.job.packageOp.result;
        expect(result.errors.length).toEqual(0);
        expect(result.succeeded()).toEqual(true);
        expect(result.filesize).toBeGreaterThan(0);
        // 2 manifests, 2 tag manifests, 3 tag files, 1 payload file
        expect(bagger.bagItFiles.length).toEqual(8);
        done();
    });

    bagger.create();
});

// This test times out consistently when run on Mac OSX
// with command `npm test -- --runInBand` or
// `npm test bagit/bagger.test.js -- --runInBand`.
//
// It passes consistently on Linux and when run on Mac
// with command `npm test -- -t 'with multiple dirs and files'`
//
// WTF??
test('create() with multiple dirs and files', done => {
    let utilDir = path.join(__dirname, '..', 'util');
    let bagsDir = path.join(__dirname, '..', 'test', 'bags');
    let job = getJob(utilDir, __filename, bagsDir);
    let bagger = new Bagger(job);

    bagger.on('finish', function() {
        let result = bagger.job.packageOp.result;
        expect(result.errors.length).toEqual(0);
        expect(result.succeeded()).toEqual(true);
        expect(result.filesize).toBeGreaterThan(0);

        let validator = new Validator(tmpFile, job.bagItProfile);
        validator.on('end', function(taskDesc) {
            expect(validator.errors).toEqual([]);
            expect(validator.payloadFiles().length).toBeGreaterThan(20);
            expect(validator.payloadManifests().length).toEqual(2);
            expect(validator.tagFiles().length).toEqual(3);
            expect(validator.tagManifests().length).toEqual(2);

            // Make sure tags were written correctly
            let bagInfoFile = validator.files['bag-info.txt'];
            expect(bagInfoFile).not.toBeNull();
            expect(bagInfoFile.keyValueCollection.first('Source-Organization')).toEqual('School of Hard Knocks');
            let aptInfoFile = validator.files['aptrust-info.txt'];
            expect(bagInfoFile).not.toBeNull();
            expect(aptInfoFile.keyValueCollection.first('Access')).toEqual('Institution');
            expect(aptInfoFile.keyValueCollection.first('Title')).toEqual('Test Bag');
            expect(aptInfoFile.keyValueCollection.first('Description')).toEqual('Bag of files for unit testing.');

            done();
        });
        validator.on('error', function(err) {
            // Report the error on the console.
            expect(err).toBeNull();
        });
        validator.validate();
    });

    bagger.create();
});

test('create() using FileSystemWriter', done => {
    let utilDir = path.join(__dirname, '..', 'util');
    let bagsDir = path.join(__dirname, '..', 'test', 'bags');
    let job = getJob(utilDir, __filename, bagsDir);
    job.packageOp.packageName = 'dart-bagger-test';
    job.packageOp.outputPath = tmpOutputDir;
    job.bagItProfile.serialization = 'optional';
    let bagger = new Bagger(job);

    bagger.on('finish', function() {
        let result = bagger.job.packageOp.result;
        expect(result.errors.length).toEqual(0);
        expect(result.succeeded()).toEqual(true);
        expect(result.filesize).toBeGreaterThan(0);

        let validator = new Validator(tmpOutputDir, job.bagItProfile);
        validator.on('end', function(taskDesc) {
            expect(validator.errors).toEqual([]);
            expect(validator.payloadFiles().length).toBeGreaterThan(20);
            expect(validator.payloadManifests().length).toEqual(2);
            expect(validator.tagFiles().length).toEqual(3);
            expect(validator.tagManifests().length).toEqual(2);

            // Make sure tags were written correctly
            let bagInfoFile = validator.files['bag-info.txt'];
            expect(bagInfoFile).not.toBeNull();
            expect(bagInfoFile.keyValueCollection.first('Source-Organization')).toEqual('School of Hard Knocks');
            let aptInfoFile = validator.files['aptrust-info.txt'];
            expect(bagInfoFile).not.toBeNull();
            expect(aptInfoFile.keyValueCollection.first('Access')).toEqual('Institution');
            expect(aptInfoFile.keyValueCollection.first('Title')).toEqual('Test Bag');
            expect(aptInfoFile.keyValueCollection.first('Description')).toEqual('Bag of files for unit testing.');

            done();
        });
        validator.validate();
    });

    bagger.create();
});
<|endoftext|>


<commit_before>import React, {
  Component,
  cloneElement,
  createElement,
  isValidElement
} from 'react';
import {
  View,
  StyleSheet,
  FlatList,
  PanResponder,
  Animated,
  Easing
} from 'react-native';
import PropTypes from 'prop-types';
import isPromise from 'is-promise';

import Indicator from './Indicator';

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexGrow: 1,
    zIndex: -999,
  },
});

const isPullingDown = (x, y) => y > 0 && (y > Math.abs(x));
const isPullingUp = (x, y) => y < 0 && (Math.abs(x) < Math.abs(y));
const isVerticalGesture = (x, y) => (Math.abs(x) < Math.abs(y));

export default class RefreshableFlatList extends Component {
  static propTypes = {
    minPullDownDistance: PropTypes.number,
    minPullUpDistance: PropTypes.number,
    scrollEventThrottle: PropTypes.number,
    onRefreshing: PropTypes.func,
    onLoadMore: PropTypes.func,
    minDisplayTime: PropTypes.number,
    onScroll: PropTypes.func,
    showTopIndicator: PropTypes.bool,
    showBottomIndicator: PropTypes.bool,
    topIndicatorComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
    bottomIndicatorComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
    topPullingIndicator: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
    topHoldingIndicator: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
    topRefreshingIndicator: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
    bottomPullingIndicator: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
    bottomHoldingIndicator: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
    bottomRefreshingIndicator: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
    topPullingPrompt: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
    topHoldingPrompt: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
    topRefreshingPrompt: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
    bottomPullingPrompt: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
    bottomHoldingPrompt: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
    bottomRefreshingPrompt: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
    styles: PropTypes.object,
  }

  static defaultProps = {
    minPullDownDistance: 54,
    minPullUpDistance: 54,
    scrollEventThrottle: 16,
    minDisplayTime: 300,
    showTopIndicator: true,
    showBottomIndicator: true,
    topIndicatorComponent: Indicator,
    bottomIndicatorComponent: Indicator,
    onScroll: () => {},
    onRefreshing: () => {},
    onLoadMore: () => {},
    topPullingIndicator: '',
    topHoldingIndicator: '',
    topRefreshingIndicator: '',
    bottomPullingIndicator: '',
    bottomHoldingIndicator: '',
    bottomRefreshingIndicator: '',
    topPullingPrompt: 'pull down to refresh',
    topHoldingPrompt: 'will refresh',
    topRefreshingPrompt: 'refreshing...',
    bottomPullingPrompt: 'pull up to load more',
    bottomHoldingPrompt: 'will load more',
    bottomRefreshingPrompt: 'loading...',
    styles: {}
  }

  constructor(props) {
    super(props);
    this.state = {
      refreshing: false,
      scrollStatus: 'NOT_EXCEEDED_MIN_PULL_DOWN_DISTANCE',
      flatListHeight: 0,
      contentHeight: 0,
      pullPan: new Animated.ValueXY({ x: 0, y: -54 }),
      width: 0,
      height: 0,
      scrollEnabled: false,
    };
    this.showBottomIndicator = this.props.showBottomIndicator;
    this.showTopIndicator = this.props.showTopIndicator;
    this.lastY = 0;
    this.contentOffset = 100;
  }

  componentWillMount() {
    this.panResponder = PanResponder.create({
      onStartShouldSetPanResponder: this.onShouldSetPanResponder,
      onMoveShouldSetPanResponder: this.onShouldSetPanResponder,
      onPanResponderGrant: () => {},
      onPanResponderTerminationRequest: () => false,
      onPanResponderMove: this.onPanResponderMove,
      onPanResponderRelease: this.onPanResponderRelease,
      onPanResponderTerminate: this.onPanResponderRelease,
    });
  }

  onShouldSetPanResponder = (e, gesture) => {
    if (!isVerticalGesture(gesture.dx, gesture.dy)) {
      return false;
    }

    if (!this.state.scrollEnabled) {
      // eslint-disable-next-line
      this.offsetY = this.state.pullPan.y._value;
      return true;
    }

    return false;
  }

  onPanResponderMove = (e, gesture) => {
    const contentOffset = this.state.contentHeight - this.state.flatListHeight;
    if (isPullingDown(gesture.dx, gesture.dy)) {
      if (this.lastY + (gesture.dy / 2) >= contentOffset && contentOffset > 0) {
        this.flatList.scrollToOffset({
          offset: this.contentOffset - (gesture.dy / 2)
        });
      } else {
        this.state.pullPan.setValue({ x: 0, y: this.offsetY + (gesture.dy / 2) });
        if (gesture.dy / 2 < this.props.minPullDownDistance) {
          this.setState({
            scrollStatus: 'NOT_EXCEEDED_MIN_PULL_DOWN_DISTANCE',
            scrollPosition: -(gesture.dy / 2)
          });
        } else {
          this.setState({
            scrollStatus: 'EXCEEDED_MIN_PULL_DOWN_DISTANCE',
            scrollPosition: -(gesture.dy / 2)
          });
        }
        this.isPulling = true;
      }
    } else if (isPullingUp(gesture.dx, gesture.dy)) {
      if (this.lastY < contentOffset) {
        this.flatList.scrollToOffset({
          offset: gesture.dy * -1
        });
      } else {
        this.state.pullPan.setValue({ x: 0, y: this.offsetY + (gesture.dy / 2) });
        let scrollPosition = Math.abs(gesture.dy / 2) + this.contentOffset;

        if (contentOffset < 0) {
          scrollPosition = this.state.contentHeight - Math.abs(gesture.dy / 2);
        }

        if (Math.abs(gesture.dy / 2) > this.props.minPullUpDistance) {
          this.setState({
            scrollStatus: 'EXCEEDED_MIN_PULL_UP_DISTANCE',
            scrollPosition
          });
        } else {
          this.setState({
            scrollStatus: 'NOT_EXCEEDED_MIN_PULL_UP_DISTANCE',
            scrollPosition
          });
        }
      }
    }
  }

  onPanResponderRelease = () => {
    const delay = time => new Promise(resolve => setTimeout(resolve, time));
    const { showTopIndicator, showBottomIndicator } = this.props;
    const { scrollStatus } = this.state;

    if ((showTopIndicator && scrollStatus === 'EXCEEDED_MIN_PULL_DOWN_DISTANCE')
      || (showBottomIndicator && scrollStatus === 'EXCEEDED_MIN_PULL_UP_DISTANCE')) {
      let rerestScrollStatus = 'NOT_EXCEEDED_MIN_PULL_DOWN_DISTANCE';
      let toValue = { x: 0, y: 0 };
      let action = 'onRefreshing';

      if (scrollStatus.indexOf('UP') > -1) {
        toValue = { x: 0, y: -(this.props.minPullDownDistance + this.props.minPullDownDistance) };
        rerestScrollStatus = 'NOT_EXCEEDED_MIN_PULL_UP_DISTANCE';
        action = 'onLoadMore';
      }

      Animated.timing(this.state.pullPan, {
        toValue,
        easing: Easing.linear,
        duration: 300
      }).start();

      let loadingDataPromise = new Promise((resolve) => {
        const loadDataReturnValue = this.props[action](resolve);

        if (isPromise(loadDataReturnValue)) {
          loadingDataPromise = loadDataReturnValue;
        }

        Promise.all([
          loadingDataPromise,
          new Promise(r => this.setState({ refreshing: true }, r)),
          delay(this.props.minDisplayTime),
        ])
          .then(() => {
            Animated.timing(this.state.pullPan, {
              toValue: { x: 0, y: -this.props.minPullDownDistance },
              easing: Easing.linear,
              duration: 300
            }).start();

            this.setState({
              refreshing: false,
              scrollStatus: rerestScrollStatus,
            });
            this.isPulling = false;
          });
      });
    } else if ((showTopIndicator && scrollStatus === 'NOT_EXCEEDED_MIN_PULL_DOWN_DISTANCE')
      || (showBottomIndicator && scrollStatus === 'NOT_EXCEEDED_MIN_PULL_UP_DISTANCE')) {
      this.state.pullPan.setValue({ x: 0, y: -this.props.minPullDownDistance });
      this.isPulling = false;
    } else {
      this.state.pullPan.setValue({ x: 0, y: -this.props.minPullDownDistance });
      this.isPulling = false;
    }

    if (scrollStatus.indexOf('UP') > -1) {
      this.flatList.scrollToOffset({ offset: this.contentOffset - 1 });
    }
  }

  onScroll = (e) => {
    this.contentOffset = this.state.contentHeight - this.state.flatListHeight;
    this.lastY = e.nativeEvent.contentOffset.y + e.nativeEvent.contentInset.top;
    this.setState({ offsetY: this.lastY });

    if (this.lastY <= 0 || this.lastY >= this.contentOffset) {
      this.setState({ scrollEnabled: false });
    } else if (!this.isPulling) {
      this.setState({ scrollEnabled: true });
    }
  }

  onLayout = (e) => {
    if (this.state.width !== e.nativeEvent.layout.width || this.state.height !== e.nativeEvent.layout.height) {
      if (this.scrollContainer) {
        this.scrollContainer.setNativeProps({
          style: {
            width: e.nativeEvent.layout.width,
            height: e.nativeEvent.layout.height
          }
        });
      }

      this.setState({ width: e.nativeEvent.layout.width, height: e.nativeEvent.layout.height });
    }
  }

  renderIndicator(indicator) {
    if (!this.props.showTopIndicator && this.state.scrollStatus.indexOf('DOWN') > -1) {
      return null;
    } else if (!this.props.showBottomIndicator && this.state.scrollStatus.indexOf('UP') > -1) {
      return null;
    }

    const {
      topPullingIndicator,
      topHoldingIndicator,
      topRefreshingIndicator,
      bottomPullingIndicator,
      bottomHoldingIndicator,
      bottomRefreshingIndicator,
      topPullingPrompt,
      topHoldingPrompt,
      topRefreshingPrompt,
      bottomPullingPrompt,
      bottomHoldingPrompt,
      bottomRefreshingPrompt,
      styles
    } = this.props;
    const refreshingIndicatorProps = {
      topPullingIndicator,
      topHoldingIndicator,
      topRefreshingIndicator,
      bottomPullingIndicator,
      bottomHoldingIndicator,
      bottomRefreshingIndicator,
      topPullingPrompt,
      topHoldingPrompt,
      topRefreshingPrompt,
      bottomPullingPrompt,
      bottomHoldingPrompt,
      bottomRefreshingPrompt,
      styles,
      refreshing: this.state.refreshing,
      scrollPosition: this.state.offsetY,
      scrollStatus: this.state.scrollStatus
    };

    if (isValidElement(indicator)) {
      return cloneElement(indicator, refreshingIndicatorProps);
    }

    return createElement(indicator, refreshingIndicatorProps);
  }

  render() {
    const IndicatorWrapperStyle = {
      height: 54,
      justifyContent: 'flex-end',
    };

    return (
      <View style={[styles.container, this.props.style]} onLayout={this.onLayout}>
        <Animated.View ref={(c) => { this.ani = c; }} style={[this.state.pullPan.getLayout()]}>
          <View style={IndicatorWrapperStyle}>
            {this.renderIndicator(this.props.topIndicatorComponent)}
          </View>
          <View
            ref={(c) => { this.scrollContainer = c; }}
            {...this.panResponder.panHandlers}
            style={{ width: this.state.width, height: this.state.height }}
          >
            <FlatList
              {...this.props}
              ref={(ref) => { this.flatList = ref; }}
              scrollEnabled={this.state.scrollEnabled}
              onScroll={this.onScroll}
              onContentSizeChange={(w, h) => this.setState({ contentHeight: h })}
              onLayout={e => this.setState({ flatListHeight: e.nativeEvent.layout.height })}
            />
          </View>
          <View style={IndicatorWrapperStyle}>
            {this.renderIndicator(this.props.bottomIndicatorComponent)}
          </View>
        </Animated.View>
      </View>
    );
  }
}
<commit_msg>Increase container height for item overflow<commit_after>import React, {
  Component,
  cloneElement,
  createElement,
  isValidElement
} from 'react';
import {
  View,
  StyleSheet,
  FlatList,
  PanResponder,
  Animated,
  Easing
} from 'react-native';
import PropTypes from 'prop-types';
import isPromise from 'is-promise';

import Indicator from './Indicator';

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexGrow: 1,
    zIndex: -999,
  },
});

const isPullingDown = (x, y) => y > 0 && (y > Math.abs(x));
const isPullingUp = (x, y) => y < 0 && (Math.abs(x) < Math.abs(y));
const isVerticalGesture = (x, y) => (Math.abs(x) < Math.abs(y));

export default class RefreshableFlatList extends Component {
  static propTypes = {
    minPullDownDistance: PropTypes.number,
    minPullUpDistance: PropTypes.number,
    scrollEventThrottle: PropTypes.number,
    onRefreshing: PropTypes.func,
    onLoadMore: PropTypes.func,
    minDisplayTime: PropTypes.number,
    onScroll: PropTypes.func,
    overflowHeight: PropTypes.number,
    showTopIndicator: PropTypes.bool,
    showBottomIndicator: PropTypes.bool,
    topIndicatorComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
    bottomIndicatorComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
    topPullingIndicator: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
    topHoldingIndicator: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
    topRefreshingIndicator: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
    bottomPullingIndicator: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
    bottomHoldingIndicator: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
    bottomRefreshingIndicator: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
    topPullingPrompt: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
    topHoldingPrompt: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
    topRefreshingPrompt: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
    bottomPullingPrompt: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
    bottomHoldingPrompt: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
    bottomRefreshingPrompt: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
    styles: PropTypes.object,
  }

  static defaultProps = {
    minPullDownDistance: 54,
    minPullUpDistance: 54,
    scrollEventThrottle: 16,
    minDisplayTime: 300,
    overflowHeight: 0,
    showTopIndicator: true,
    showBottomIndicator: true,
    topIndicatorComponent: Indicator,
    bottomIndicatorComponent: Indicator,
    onScroll: () => {},
    onRefreshing: () => {},
    onLoadMore: () => {},
    topPullingIndicator: '',
    topHoldingIndicator: '',
    topRefreshingIndicator: '',
    bottomPullingIndicator: '',
    bottomHoldingIndicator: '',
    bottomRefreshingIndicator: '',
    topPullingPrompt: 'pull down to refresh',
    topHoldingPrompt: 'will refresh',
    topRefreshingPrompt: 'refreshing...',
    bottomPullingPrompt: 'pull up to load more',
    bottomHoldingPrompt: 'will load more',
    bottomRefreshingPrompt: 'loading...',
    styles: {}
  }

  constructor(props) {
    super(props);
    this.state = {
      refreshing: false,
      scrollStatus: 'NOT_EXCEEDED_MIN_PULL_DOWN_DISTANCE',
      flatListHeight: 0,
      contentHeight: 0,
      pullPan: new Animated.ValueXY({ x: 0, y: -54 }),
      width: 0,
      height: 0,
      scrollEnabled: false,
    };
    this.showBottomIndicator = this.props.showBottomIndicator;
    this.showTopIndicator = this.props.showTopIndicator;
    this.lastY = 0;
    this.contentOffset = 100;
  }

  componentWillMount() {
    this.panResponder = PanResponder.create({
      onStartShouldSetPanResponder: this.onShouldSetPanResponder,
      onMoveShouldSetPanResponder: this.onShouldSetPanResponder,
      onPanResponderGrant: () => {},
      onPanResponderTerminationRequest: () => false,
      onPanResponderMove: this.onPanResponderMove,
      onPanResponderRelease: this.onPanResponderRelease,
      onPanResponderTerminate: this.onPanResponderRelease,
    });
  }

  onShouldSetPanResponder = (e, gesture) => {
    if (!isVerticalGesture(gesture.dx, gesture.dy)) {
      return false;
    }

    if (!this.state.scrollEnabled) {
      // eslint-disable-next-line
      this.offsetY = this.state.pullPan.y._value;
      return true;
    }

    return false;
  }

  onPanResponderMove = (e, gesture) => {
    const contentOffset = this.state.contentHeight - this.state.flatListHeight;
    if (isPullingDown(gesture.dx, gesture.dy)) {
      if (this.lastY + (gesture.dy / 2) >= contentOffset && contentOffset > 0) {
        this.flatList.scrollToOffset({
          offset: this.contentOffset - (gesture.dy / 2)
        });
      } else {
        this.state.pullPan.setValue({ x: 0, y: this.offsetY + (gesture.dy / 2) });
        if (gesture.dy / 2 < this.props.minPullDownDistance) {
          this.setState({
            scrollStatus: 'NOT_EXCEEDED_MIN_PULL_DOWN_DISTANCE',
            scrollPosition: -(gesture.dy / 2)
          });
        } else {
          this.setState({
            scrollStatus: 'EXCEEDED_MIN_PULL_DOWN_DISTANCE',
            scrollPosition: -(gesture.dy / 2)
          });
        }
        this.isPulling = true;
      }
    } else if (isPullingUp(gesture.dx, gesture.dy)) {
      if (this.lastY < contentOffset) {
        this.flatList.scrollToOffset({
          offset: gesture.dy * -1
        });
      } else {
        this.state.pullPan.setValue({ x: 0, y: this.offsetY + (gesture.dy / 2) });
        let scrollPosition = Math.abs(gesture.dy / 2) + this.contentOffset;

        if (contentOffset < 0) {
          scrollPosition = this.state.contentHeight - Math.abs(gesture.dy / 2);
        }

        if (Math.abs(gesture.dy / 2) > this.props.minPullUpDistance) {
          this.setState({
            scrollStatus: 'EXCEEDED_MIN_PULL_UP_DISTANCE',
            scrollPosition
          });
        } else {
          this.setState({
            scrollStatus: 'NOT_EXCEEDED_MIN_PULL_UP_DISTANCE',
            scrollPosition
          });
        }
      }
    }
  }

  onPanResponderRelease = () => {
    const delay = time => new Promise(resolve => setTimeout(resolve, time));
    const { showTopIndicator, showBottomIndicator } = this.props;
    const { scrollStatus } = this.state;

    if ((showTopIndicator && scrollStatus === 'EXCEEDED_MIN_PULL_DOWN_DISTANCE')
      || (showBottomIndicator && scrollStatus === 'EXCEEDED_MIN_PULL_UP_DISTANCE')) {
      let rerestScrollStatus = 'NOT_EXCEEDED_MIN_PULL_DOWN_DISTANCE';
      let toValue = { x: 0, y: 0 };
      let action = 'onRefreshing';

      if (scrollStatus.indexOf('UP') > -1) {
        toValue = { x: 0, y: -(this.props.minPullDownDistance + this.props.minPullDownDistance) };
        rerestScrollStatus = 'NOT_EXCEEDED_MIN_PULL_UP_DISTANCE';
        action = 'onLoadMore';
      }

      Animated.timing(this.state.pullPan, {
        toValue,
        easing: Easing.linear,
        duration: 300
      }).start();

      let loadingDataPromise = new Promise((resolve) => {
        const loadDataReturnValue = this.props[action](resolve);

        if (isPromise(loadDataReturnValue)) {
          loadingDataPromise = loadDataReturnValue;
        }

        Promise.all([
          loadingDataPromise,
          new Promise(r => this.setState({ refreshing: true }, r)),
          delay(this.props.minDisplayTime),
        ])
          .then(() => {
            Animated.timing(this.state.pullPan, {
              toValue: { x: 0, y: -this.props.minPullDownDistance },
              easing: Easing.linear,
              duration: 300
            }).start();

            this.setState({
              refreshing: false,
              scrollStatus: rerestScrollStatus,
            });
            this.isPulling = false;
          });
      });
    } else if ((showTopIndicator && scrollStatus === 'NOT_EXCEEDED_MIN_PULL_DOWN_DISTANCE')
      || (showBottomIndicator && scrollStatus === 'NOT_EXCEEDED_MIN_PULL_UP_DISTANCE')) {
      this.state.pullPan.setValue({ x: 0, y: -this.props.minPullDownDistance });
      this.isPulling = false;
    } else {
      this.state.pullPan.setValue({ x: 0, y: -this.props.minPullDownDistance });
      this.isPulling = false;
    }

    if (scrollStatus.indexOf('UP') > -1) {
      this.flatList.scrollToOffset({ offset: this.contentOffset - 1 });
    }
  }

  onScroll = (e) => {
    this.contentOffset = this.state.contentHeight - this.state.flatListHeight;
    this.lastY = e.nativeEvent.contentOffset.y + e.nativeEvent.contentInset.top;
    this.setState({ offsetY: this.lastY });

    if (this.lastY <= 0 || this.lastY >= this.contentOffset) {
      this.setState({ scrollEnabled: false });
    } else if (!this.isPulling) {
      this.setState({ scrollEnabled: true });
    }
  }

  onLayout = (e) => {
    if (this.state.width !== e.nativeEvent.layout.width || this.state.height !== e.nativeEvent.layout.height) {
      if (this.scrollContainer) {
        this.scrollContainer.setNativeProps({
          style: {
            width: e.nativeEvent.layout.width,
            height: e.nativeEvent.layout.height + this.props.overflowHeight
          }
        });
      }

      this.setState({ width: e.nativeEvent.layout.width, height: e.nativeEvent.layout.height + this.props.overflowHeight });
    }
  }

  renderIndicator(indicator) {
    if (!this.props.showTopIndicator && this.state.scrollStatus.indexOf('DOWN') > -1) {
      return null;
    } else if (!this.props.showBottomIndicator && this.state.scrollStatus.indexOf('UP') > -1) {
      return null;
    }

    const {
      topPullingIndicator,
      topHoldingIndicator,
      topRefreshingIndicator,
      bottomPullingIndicator,
      bottomHoldingIndicator,
      bottomRefreshingIndicator,
      topPullingPrompt,
      topHoldingPrompt,
      topRefreshingPrompt,
      bottomPullingPrompt,
      bottomHoldingPrompt,
      bottomRefreshingPrompt,
      styles
    } = this.props;
    const refreshingIndicatorProps = {
      topPullingIndicator,
      topHoldingIndicator,
      topRefreshingIndicator,
      bottomPullingIndicator,
      bottomHoldingIndicator,
      bottomRefreshingIndicator,
      topPullingPrompt,
      topHoldingPrompt,
      topRefreshingPrompt,
      bottomPullingPrompt,
      bottomHoldingPrompt,
      bottomRefreshingPrompt,
      styles,
      refreshing: this.state.refreshing,
      scrollPosition: this.state.offsetY,
      scrollStatus: this.state.scrollStatus
    };

    if (isValidElement(indicator)) {
      return cloneElement(indicator, refreshingIndicatorProps);
    }

    return createElement(indicator, refreshingIndicatorProps);
  }

  render() {
    const IndicatorWrapperStyle = {
      height: 54,
      justifyContent: 'flex-end',
    };

    return (
      <View style={[styles.container, this.props.style]} onLayout={this.onLayout}>
        <Animated.View ref={(c) => { this.ani = c; }} style={[this.state.pullPan.getLayout()]}>
          <View style={IndicatorWrapperStyle}>
            {this.renderIndicator(this.props.topIndicatorComponent)}
          </View>
          <View
            ref={(c) => { this.scrollContainer = c; }}
            {...this.panResponder.panHandlers}
            style={{ width: this.state.width, height: this.state.height }}
          >
            <FlatList
              {...this.props}
              ref={(ref) => { this.flatList = ref; }}
              scrollEnabled={this.state.scrollEnabled}
              onScroll={this.onScroll}
              onContentSizeChange={(w, h) => this.setState({ contentHeight: h })}
              onLayout={e => this.setState({ flatListHeight: e.nativeEvent.layout.height })}
            />
          </View>
          <View style={IndicatorWrapperStyle}>
            {this.renderIndicator(this.props.bottomIndicatorComponent)}
          </View>
        </Animated.View>
      </View>
    );
  }
}
<|endoftext|>