<commit_before>const MESSAGES = {
	start: `Allo!💁 To get started, type:
	*/help* in a private chat - for more info on how to book a room;
	*/register* to register to use the bot.

	*/any* book any available meeting room at a time of your choosing;
	*/book* to start booking from a list of rooms available;
	*/exit* terminate current booking process;
	*/booked* in a private chat - for list of rooms you have booked;
	*/delete* in a private chat - delete a booking;
	*/view* see all bookings in hive.

	Thank you for using SweeZharBot™! If got problem please don't come and find Viviean thank you velly much 😛`,
	help: `Type:\n
	\n*/any* book any available meeting room at a time of your choosing;\n*/book* to start booking from a list of rooms available;\n*/exit* terminate current booking process;\n*/booked* in a private chat - for list of rooms you have booked;\n*/delete* in a private chat - delete a booking;\n*/view* see all bookings in hive.\n\nThank you for using SweeZharBot™! If got problem please don't come and find Viviean thank you velly much 😛`,
	unrecognisedCommands: `I don't understand your command, try using valid commands listed in /help menu.`,
	book: `Which room would you like to book?`,
	admin: 'Good luck ah, you will be veri beesy.',
	registered: 'Swee! You can start booking liao',
	newUserApproved: 'One more user approved hor.',
	view: 'Check out this link for the overall room booking schedules: https://sweedarbot.dcube.cf',
	delete: `You have successfully deleted your booking`,
	deleteErr: `Oops, something went wrong while deleting your booking.`,
	deleteInstruction: `\nClick on the following command to delete your booking: \n`,
	listBooking: `You have the following bookings scheduled: \n`,
	noBooking: `You don\'t have any upcoming room bookings 😧. \n\nYou won't be able to see your bookings through /booked command if you've manually booked through the admins. \nIf so, try checking your booking with /view instead :)`,
	noBookingAfterDelete: `Okay, you\'ve got more no upcoming room bookings liao. `,
	error: `Oops sorry ah, I think something spoil aledi.. you don\'t mind try again later ok? 😅`,
	confirm: `Swee lah! Your room booking is confirmed! 👍🏻`,
	tooLate: `Oh no 😱, I think your room kena snatched away by someone else. Maybe next time you try faster hand faster leg ok?`,
	private: `Please check your bookings in a private chat with me 😉`,
	canceled: `Cancelled your booking process. To check your current bookings type /booked.`,
	session_expired: 'Ehh you took too long to book. I wait until fed up! 😡😡😡\n\nTry restarting your booking session with /book or /any again.',
	session_terminated: '😢 I just cancelled your booking... you want to try again?',
	session_outdated: 'This booking session has expired. \nPlease refer to the latest booking message.',
	unauthenticated: 'Aiyo, you haven\'t /register leh',
	notBookedByMe: '\nThis room is not booked by you. Please contact @chanyan or @Doriskeith for more information.\n'
};

export { MESSAGES as default };
<commit_msg>Update Messages.js<commit_after>const MESSAGES = {
	start: `Allo!💁 To get started, type:
	*/help* in a private chat - for more info on how to book a room;
	*/register* to register to use the bot.

	*/any* book any available meeting room at a time of your choosing;
	*/book* to start booking from a list of rooms available;
	*/exit* terminate current booking process;
	*/booked* in a private chat - for list of rooms you have booked;
	*/delete* in a private chat - delete a booking;
	*/view* see all bookings in hive.

	Thank you for using SweeZharBot™! If got problem please don't come and find Viviean thank you velly much 😛`,
	help: `Type:\n
	\n*/any* book any available meeting room at a time of your choosing;\n*/book* to start booking from a list of rooms available;\n*/exit* terminate current booking process;\n*/booked* in a private chat - for list of rooms you have booked;\n*/delete* in a private chat - delete a booking;\n*/view* see all bookings in hive.\n\nThank you for using SweeZharBot™! If got problem please don't come and find Viviean thank you velly much 😛`,
	unrecognisedCommands: `I don't understand your command, try using valid commands listed in /help menu.`,
	book: `Which room would you like to book?`,
	admin: 'Good luck ah, you will be veri beesy.',
	registered: 'Swee! You can start booking liao',
	newUserApproved: 'One more user approved hor.',
	view: 'Check out this link for the overall room booking schedules: https://sweezharbot.dcube.cf',
	delete: `You have successfully deleted your booking`,
	deleteErr: `Oops, something went wrong while deleting your booking.`,
	deleteInstruction: `\nClick on the following command to delete your booking: \n`,
	listBooking: `You have the following bookings scheduled: \n`,
	noBooking: `You don\'t have any upcoming room bookings 😧. \n\nYou won't be able to see your bookings through /booked command if you've manually booked through the admins. \nIf so, try checking your booking with /view instead :)`,
	noBookingAfterDelete: `Okay, you\'ve got more no upcoming room bookings liao. `,
	error: `Oops sorry ah, I think something spoil aledi.. you don\'t mind try again later ok? 😅`,
	confirm: `Swee lah! Your room booking is confirmed! 👍🏻`,
	tooLate: `Oh no 😱, I think your room kena snatched away by someone else. Maybe next time you try faster hand faster leg ok?`,
	private: `Please check your bookings in a private chat with me 😉`,
	canceled: `Cancelled your booking process. To check your current bookings type /booked.`,
	session_expired: 'Ehh you took too long to book. I wait until fed up! 😡😡😡\n\nTry restarting your booking session with /book or /any again.',
	session_terminated: '😢 I just cancelled your booking... you want to try again?',
	session_outdated: 'This booking session has expired. \nPlease refer to the latest booking message.',
	unauthenticated: 'Aiyo, you haven\'t /register leh',
	notBookedByMe: '\nThis room is not booked by you. Please contact @chanyan or @Doriskeith for more information.\n'
};

export { MESSAGES as default };
<|endoftext|>


<commit_before>var utils = require('./utils'),
  uuid = require('node-uuid'),
  parsers = require('./message-parsers');

var amqpRPCQueues = {};

/**
 * Create a RPC-ready queue
 * @param  {string} queue the queue name in which we send a RPC request
 * @return {Promise}       Resolves when answer response queue is ready to receive messages
 */
function createRpcQueue(queue) {
  if (amqpRPCQueues[queue].queue) return Promise.resolve();

  //we create the callback queue using base queue name + appending config hostname and :res for clarity
  //ie. if hostname is gateway-http and queue is service-oauth, response queue will be service-oauth:gateway-http:res
  //it is important to have different hostname or no hostname on each module sending message or there will be conflicts
  var resQueue = queue + ':' + this.conn.config.hostname + ':res';
  return this.channel.assertQueue(resQueue, { durable: true, exclusive: true })
  .then((_queue) => {
    amqpRPCQueues[queue].queue = _queue.queue;

    //if channel is closed, we want to make sure we cleanup the queue so future calls will recreate it
    this.conn.addListener('close', () => { amqpRPCQueues[queue].queue = null; });

    return this.channel.consume(_queue.queue, maybeAnswer.call(this, queue), { noAck: true });
  })
  .then(() => {
    return queue;
  });
}

/**
 * Get a function to execute on channel consumer incoming message is received
 * @param  {string} queue name of the queue where messages are SENT
 * @return {function}       function executed by an amqp.node channel consume callback method
 */
function maybeAnswer(queue) {
  return (_msg) => {
    //check the correlation ID sent by the initial message using RPC
    var corrIdA = _msg.properties.correlationId;
    //if we found one, we execute the callback and delete it because it will never be received again anyway
    if (amqpRPCQueues[queue][corrIdA] !== undefined) {
      _msg = parsers.in(_msg);
      amqpRPCQueues[queue][corrIdA].resolve(_msg);
      this.conn.config.transport.info('amqp:producer', '[' + queue + '] < ', _msg);
      delete amqpRPCQueues[queue][corrIdA];
    }
  };
}

/**
 * Send message with or without rpc protocol, and check if RPC queues are created
 * @param  {string} queue   the queue to send `msg` on
 * @param  {any} msg     string, object, number.. anything bufferable/serializable
 * @param  {object} options contain rpc property (if true, enable rpc for this message)
 * @return {Promise}         Resolves when message is correctly sent, or when response is received when rpc is enabled
 */
function checkRpc (queue, msg, options) {
  //messages are persistent
  options.persistent = true;

  if (options.rpc) {
    if (!amqpRPCQueues[queue]) {
      amqpRPCQueues[queue] = {};
    }

    return createRpcQueue.call(this, queue)
    .then(() => {
      //generates a correlationId (random uuid) so we know which callback to execute on received response
      var corrId = uuid.v4();
      options.correlationId = corrId;
      //reply to us if you receive this message!
      options.replyTo = amqpRPCQueues[queue].queue;

      this.channel.sendToQueue(queue, msg, options);

      //defered promise that will resolve when response is received
      amqpRPCQueues[queue][corrId] = Promise.defer();
      return amqpRPCQueues[queue][corrId].promise;
    });
  }

  return this.channel.sendToQueue(queue, msg, options);
}

/**
 * Ensure channel exists and send message using `checkRpc`
 * @param  {string} queue   The destination queue on which we want to send a message
 * @param  {any} msg     Anything serializable/bufferable
 * @param  {object} options message options (persistent, durable, rpc, etc.)
 * @return {Promise}         checkRpc response
 */
function produce(queue, msg, options) {
  return this.conn.get()
  .then((_channel) => {
    this.channel = _channel;

    //undefined can't be serialized/buffered :p
    if (!msg) msg = null;

    //default options are persistent and durable because we do not want to miss any outgoing message
    //unless user specify it
    options = options || { persistent: true, durable: true };

    this.conn.config.transport.info('amqp:producer', '[' + queue + '] > ', msg);

    return checkRpc.call(this, queue, parsers.out(msg, options), options);
  })
  .catch((err) => {
    //add timeout between retries because we don't want to overflow the CPU
    this.conn.config.transport.error('amqp:producer', err);
    return utils.timeoutPromise(this.conn.config.timeout)
    .then(() => {
      return produce.call(this, queue, msg, options);
    });
  });
}

module.exports = function(_conn) {
  return {
    conn: _conn,
    produce: produce
  };
};
<commit_msg>Added ability to publish to named exchanges/routing key<commit_after>var utils = require('./utils'),
  uuid = require('node-uuid'),
  parsers = require('./message-parsers');

var amqpRPCQueues = {};

/**
 * Create a RPC-ready queue
 * @param  {string} queue the queue name in which we send a RPC request
 * @return {Promise}       Resolves when answer response queue is ready to receive messages
 */
function createRpcQueue(queue) {
  if (amqpRPCQueues[queue].queue) return Promise.resolve();

  //we create the callback queue using base queue name + appending config hostname and :res for clarity
  //ie. if hostname is gateway-http and queue is service-oauth, response queue will be service-oauth:gateway-http:res
  //it is important to have different hostname or no hostname on each module sending message or there will be conflicts
  var resQueue = queue + ':' + this.conn.config.hostname + ':res';
  return this.channel.assertQueue(resQueue, { durable: true, exclusive: true })
  .then((_queue) => {
    amqpRPCQueues[queue].queue = _queue.queue;

    //if channel is closed, we want to make sure we cleanup the queue so future calls will recreate it
    this.conn.addListener('close', () => { amqpRPCQueues[queue].queue = null; });

    return this.channel.consume(_queue.queue, maybeAnswer.call(this, queue), { noAck: true });
  })
  .then(() => {
    return queue;
  });
}

/**
 * Get a function to execute on channel consumer incoming message is received
 * @param  {string} queue name of the queue where messages are SENT
 * @return {function}       function executed by an amqp.node channel consume callback method
 */
function maybeAnswer(queue) {
  return (_msg) => {
    //check the correlation ID sent by the initial message using RPC
    var corrIdA = _msg.properties.correlationId;
    //if we found one, we execute the callback and delete it because it will never be received again anyway
    if (amqpRPCQueues[queue][corrIdA] !== undefined) {
      _msg = parsers.in(_msg);
      amqpRPCQueues[queue][corrIdA].resolve(_msg);
      this.conn.config.transport.info('amqp:producer', '[' + queue + '] < ', _msg);
      delete amqpRPCQueues[queue][corrIdA];
    }
  };
}

function publishOrSendToQueue(queue, msg, options) {
  if (!options.routingKey) {
    return this.channel.sendToQueue(queue, msg, options);
  } else {
    return this.channel.publish(queue, options.routingKey, msg, options);
  }
}

/**
 * Send message with or without rpc protocol, and check if RPC queues are created
 * @param  {string} queue   the queue to send `msg` on
 * @param  {any} msg     string, object, number.. anything bufferable/serializable
 * @param  {object} options contain rpc property (if true, enable rpc for this message)
 * @return {Promise}         Resolves when message is correctly sent, or when response is received when rpc is enabled
 */
function checkRpc (queue, msg, options) {
  //messages are persistent
  options.persistent = true;

  if (options.rpc) {
    if (!amqpRPCQueues[queue]) {
      amqpRPCQueues[queue] = {};
    }

    return createRpcQueue.call(this, queue)
    .then(() => {
      //generates a correlationId (random uuid) so we know which callback to execute on received response
      var corrId = uuid.v4();
      options.correlationId = corrId;
      //reply to us if you receive this message!
      options.replyTo = amqpRPCQueues[queue].queue;

      publishOrSendToQueue.call(this, queue, msg, options);

      //defered promise that will resolve when response is received
      amqpRPCQueues[queue][corrId] = Promise.defer();
      return amqpRPCQueues[queue][corrId].promise;
    });
  }

  return publishOrSendToQueue.call(this, queue, msg, options);
}

/**
 * Ensure channel exists and send message using `checkRpc`
 * @param  {string} queue   The destination queue on which we want to send a message
 * @param  {any} msg     Anything serializable/bufferable
 * @param  {object} options message options (persistent, durable, rpc, etc.)
 * @return {Promise}         checkRpc response
 */
function produce(queue, msg, options) {
  return this.conn.get()
  .then((_channel) => {
    this.channel = _channel;

    //undefined can't be serialized/buffered :p
    if (!msg) msg = null;

    //default options are persistent and durable because we do not want to miss any outgoing message
    //unless user specify it
    options = options || { persistent: true, durable: true };

    this.conn.config.transport.info('amqp:producer', '[' + queue + '] > ', msg);

    return checkRpc.call(this, queue, parsers.out(msg, options), options);
  })
  .catch((err) => {
    //add timeout between retries because we don't want to overflow the CPU
    this.conn.config.transport.error('amqp:producer', err);
    return utils.timeoutPromise(this.conn.config.timeout)
    .then(() => {
      return produce.call(this, queue, msg, options);
    });
  });
}

module.exports = function(_conn) {
  return {
    conn: _conn,
    produce: produce
  };
};
<|endoftext|>


<commit_before>import Padding from './padding';

export default function Viewport(elementRoutines, buffer, element, viewportController, $rootScope, padding) {
  let topPadding = null;
  let bottomPadding = null;
  const viewport = viewportController && viewportController.viewport ? viewportController.viewport : angular.element(window);
  const container = viewportController && viewportController.container ? viewportController.container : undefined;
  const scope = viewportController && viewportController.scope ? viewportController.scope : $rootScope;

  viewport.css({
    'overflow-anchor': 'none',
    'overflow-y': 'auto',
    'display': 'block'
  });

  function bufferPadding() {
    return viewport.outerHeight() * padding; // some extra space to initiate preload
  }

  angular.extend(viewport, {
    getScope() {
      return scope;
    },

    createPaddingElements(template) {
      topPadding = new Padding(template);
      bottomPadding = new Padding(template);
      element.before(topPadding);
      element.after(bottomPadding);
    },

    applyContainerStyle() {
      if (container && container !== viewport) {
        viewport.css('height', window.getComputedStyle(container[0]).height);
      }
    },

    bottomDataPos() {
      let scrollHeight = viewport[0].scrollHeight;
      scrollHeight = scrollHeight != null ? scrollHeight : viewport[0].document.documentElement.scrollHeight;
      return scrollHeight - bottomPadding.height();
    },

    topDataPos() {
      return topPadding.height();
    },

    bottomVisiblePos() {
      return viewport.scrollTop() + viewport.outerHeight();
    },

    topVisiblePos() {
      return viewport.scrollTop();
    },

    insertElement(e, sibling) {
      return elementRoutines.insertElement(e, sibling || topPadding);
    },

    insertElementAnimated(e, sibling) {
      return elementRoutines.insertElementAnimated(e, sibling || topPadding);
    },

    shouldLoadBottom() {
      return !buffer.eof && viewport.bottomDataPos() < viewport.bottomVisiblePos() + bufferPadding();
    },

    clipBottom() {
      // clip the invisible items off the bottom
      let overage = 0;
      let overageHeight = 0;
      let itemHeight = 0;
      let emptySpaceHeight = viewport.bottomDataPos() - viewport.bottomVisiblePos() - bufferPadding();

      for (let i = buffer.length - 1; i >= 0; i--) {
        itemHeight = buffer[i].element.outerHeight(true);
        if (overageHeight + itemHeight > emptySpaceHeight) {
          break;
        }
        bottomPadding.cache.add(buffer[i]);
        overageHeight += itemHeight;
        overage++;
      }

      if (overage > 0) {
        buffer.eof = false;
        buffer.remove(buffer.length - overage, buffer.length);
        buffer.next -= overage;
        viewport.adjustPaddings();
      }
    },

    shouldLoadTop() {
      return !buffer.bof && (viewport.topDataPos() > viewport.topVisiblePos() - bufferPadding());
    },

    clipTop() {
      // clip the invisible items off the top
      let overage = 0;
      let overageHeight = 0;
      let itemHeight = 0;
      let emptySpaceHeight = viewport.topVisiblePos() - viewport.topDataPos() - bufferPadding();

      for (let i = 0; i < buffer.length; i++) {
        itemHeight = buffer[i].element.outerHeight(true);
        if (overageHeight + itemHeight > emptySpaceHeight) {
          break;
        }
        topPadding.cache.add(buffer[i]);
        overageHeight += itemHeight;
        overage++;
      }

      if (overage > 0) {
        // we need to adjust top padding element before items are removed from top
        // to avoid strange behaviour of scroll bar during remove top items when we are at the very bottom
        topPadding.height(topPadding.height() + overageHeight);
        buffer.bof = false;
        buffer.remove(0, overage);
        buffer.first += overage;
      }
    },

    adjustPaddings() {
      if (!buffer.length) {
        return;
      }

      // precise heights calculation, items that were in buffer once
      let topPaddingHeight = topPadding.cache.reduce((summ, item) => summ + (item.index < buffer.first ? item.height : 0), 0);
      let bottomPaddingHeight = bottomPadding.cache.reduce((summ, item) => summ + (item.index >= buffer.next ? item.height : 0), 0);

      // average item height based on buffer data
      let visibleItemsHeight = buffer.reduce((summ, item) => summ + item.element.outerHeight(true), 0);
      let averageItemHeight = (visibleItemsHeight + topPaddingHeight + bottomPaddingHeight) / (buffer.maxIndex - buffer.minIndex + 1);

      // average heights calculation, items that have never been reached
      let adjustTopPadding = buffer.minIndexUser !== null && buffer.minIndex > buffer.minIndexUser;
      let adjustBottomPadding = buffer.maxIndexUser !== null && buffer.maxIndex < buffer.maxIndexUser;
      let topPaddingHeightAdd = adjustTopPadding ? (buffer.minIndex - buffer.minIndexUser) * averageItemHeight : 0;
      let bottomPaddingHeightAdd = adjustBottomPadding ? (buffer.maxIndexUser - buffer.maxIndex) * averageItemHeight : 0;

      // paddings combine adjustment
      topPadding.height(topPaddingHeight + topPaddingHeightAdd);
      bottomPadding.height(bottomPaddingHeight + bottomPaddingHeightAdd);
    },

    onAfterMinIndexSet(topPaddingHeightOld) {
      // additional scrollTop adjustment in case of datasource.minIndex external set
      if (buffer.minIndexUser !== null && buffer.minIndex > buffer.minIndexUser) {
        let diff = topPadding.height() - topPaddingHeightOld;
        viewport.scrollTop(viewport.scrollTop() + diff);
        diff -= viewport.scrollTop();
        if(diff > 0) {
          bottomPadding.height(bottomPadding.height() + diff);
          viewport.scrollTop(viewport.scrollTop() + diff);
        }
      }
    },

    onAfterPrepend(updates) {
      if (!updates.prepended.length)
        return;
      const height = buffer.effectiveHeight(updates.prepended);
      const paddingHeight = topPadding.height() - height;
      if (paddingHeight >= 0) {
        topPadding.height(paddingHeight);
      }
      else {
        topPadding.height(0);
        viewport.scrollTop(viewport.scrollTop() - paddingHeight);
      }
    },

    resetTopPadding() {
      topPadding.height(0);
      topPadding.cache.clear();
    },

    resetBottomPadding() {
      bottomPadding.height(0);
      bottomPadding.cache.clear();
    },

    removeCacheItem(item, isTop) {
      topPadding.cache.remove(item, isTop);
      bottomPadding.cache.remove(item, isTop);
    },

    removeItem(item) {
      this.removeCacheItem(item);
      return buffer.remove(item);
    }
  });

  return viewport;
}
<commit_msg>average item height calculation refactoring<commit_after>import Padding from './padding';

export default function Viewport(elementRoutines, buffer, element, viewportController, $rootScope, padding) {
  let topPadding = null;
  let bottomPadding = null;
  const viewport = viewportController && viewportController.viewport ? viewportController.viewport : angular.element(window);
  const container = viewportController && viewportController.container ? viewportController.container : undefined;
  const scope = viewportController && viewportController.scope ? viewportController.scope : $rootScope;

  viewport.css({
    'overflow-anchor': 'none',
    'overflow-y': 'auto',
    'display': 'block'
  });

  function bufferPadding() {
    return viewport.outerHeight() * padding; // some extra space to initiate preload
  }

  angular.extend(viewport, {
    getScope() {
      return scope;
    },

    createPaddingElements(template) {
      topPadding = new Padding(template);
      bottomPadding = new Padding(template);
      element.before(topPadding);
      element.after(bottomPadding);
    },

    applyContainerStyle() {
      if (container && container !== viewport) {
        viewport.css('height', window.getComputedStyle(container[0]).height);
      }
    },

    bottomDataPos() {
      let scrollHeight = viewport[0].scrollHeight;
      scrollHeight = scrollHeight != null ? scrollHeight : viewport[0].document.documentElement.scrollHeight;
      return scrollHeight - bottomPadding.height();
    },

    topDataPos() {
      return topPadding.height();
    },

    bottomVisiblePos() {
      return viewport.scrollTop() + viewport.outerHeight();
    },

    topVisiblePos() {
      return viewport.scrollTop();
    },

    insertElement(e, sibling) {
      return elementRoutines.insertElement(e, sibling || topPadding);
    },

    insertElementAnimated(e, sibling) {
      return elementRoutines.insertElementAnimated(e, sibling || topPadding);
    },

    shouldLoadBottom() {
      return !buffer.eof && viewport.bottomDataPos() < viewport.bottomVisiblePos() + bufferPadding();
    },

    clipBottom() {
      // clip the invisible items off the bottom
      let overage = 0;
      let overageHeight = 0;
      let itemHeight = 0;
      let emptySpaceHeight = viewport.bottomDataPos() - viewport.bottomVisiblePos() - bufferPadding();

      for (let i = buffer.length - 1; i >= 0; i--) {
        itemHeight = buffer[i].element.outerHeight(true);
        if (overageHeight + itemHeight > emptySpaceHeight) {
          break;
        }
        bottomPadding.cache.add(buffer[i]);
        overageHeight += itemHeight;
        overage++;
      }

      if (overage > 0) {
        buffer.eof = false;
        buffer.remove(buffer.length - overage, buffer.length);
        buffer.next -= overage;
        viewport.adjustPaddings();
      }
    },

    shouldLoadTop() {
      return !buffer.bof && (viewport.topDataPos() > viewport.topVisiblePos() - bufferPadding());
    },

    clipTop() {
      // clip the invisible items off the top
      let overage = 0;
      let overageHeight = 0;
      let itemHeight = 0;
      let emptySpaceHeight = viewport.topVisiblePos() - viewport.topDataPos() - bufferPadding();

      for (let i = 0; i < buffer.length; i++) {
        itemHeight = buffer[i].element.outerHeight(true);
        if (overageHeight + itemHeight > emptySpaceHeight) {
          break;
        }
        topPadding.cache.add(buffer[i]);
        overageHeight += itemHeight;
        overage++;
      }

      if (overage > 0) {
        // we need to adjust top padding element before items are removed from top
        // to avoid strange behaviour of scroll bar during remove top items when we are at the very bottom
        topPadding.height(topPadding.height() + overageHeight);
        buffer.bof = false;
        buffer.remove(0, overage);
        buffer.first += overage;
      }
    },

    adjustPaddings() {
      if (!buffer.length) {
        return;
      }

      // precise heights calculation based on items that are in buffer or that were in buffer once
      const visibleItemsHeight = buffer.reduce((summ, item) => summ + item.element.outerHeight(true), 0);

      let topPaddingHeight = 0, topCount = 0;
      topPadding.cache.forEach(item => {
        if(item.index < buffer.first) {
          topPaddingHeight += item.height;
          topCount++;
        }
      });

      let bottomPaddingHeight = 0, bottomCount = 0;
      bottomPadding.cache.forEach(item => {
        if(item.index >= buffer.next) {
          bottomPaddingHeight += item.height;
          bottomCount++;
        }
      });

      const totalHeight = visibleItemsHeight + topPaddingHeight + bottomPaddingHeight;
      const averageItemHeight = totalHeight / (topCount + bottomCount + buffer.length);

      // average heights calculation, items that have never been reached
      let adjustTopPadding = buffer.minIndexUser !== null && buffer.minIndex > buffer.minIndexUser;
      let adjustBottomPadding = buffer.maxIndexUser !== null && buffer.maxIndex < buffer.maxIndexUser;
      let topPaddingHeightAdd = adjustTopPadding ? (buffer.minIndex - buffer.minIndexUser) * averageItemHeight : 0;
      let bottomPaddingHeightAdd = adjustBottomPadding ? (buffer.maxIndexUser - buffer.maxIndex) * averageItemHeight : 0;

      // paddings combine adjustment
      topPadding.height(topPaddingHeight + topPaddingHeightAdd);
      bottomPadding.height(bottomPaddingHeight + bottomPaddingHeightAdd);
    },

    onAfterMinIndexSet(topPaddingHeightOld) {
      // additional scrollTop adjustment in case of datasource.minIndex external set
      if (buffer.minIndexUser !== null && buffer.minIndex > buffer.minIndexUser) {
        let diff = topPadding.height() - topPaddingHeightOld;
        viewport.scrollTop(viewport.scrollTop() + diff);
        diff -= viewport.scrollTop();
        if(diff > 0) {
          bottomPadding.height(bottomPadding.height() + diff);
          viewport.scrollTop(viewport.scrollTop() + diff);
        }
      }
    },

    onAfterPrepend(updates) {
      if (!updates.prepended.length)
        return;
      const height = buffer.effectiveHeight(updates.prepended);
      const paddingHeight = topPadding.height() - height;
      if (paddingHeight >= 0) {
        topPadding.height(paddingHeight);
      }
      else {
        topPadding.height(0);
        viewport.scrollTop(viewport.scrollTop() - paddingHeight);
      }
    },

    resetTopPadding() {
      topPadding.height(0);
      topPadding.cache.clear();
    },

    resetBottomPadding() {
      bottomPadding.height(0);
      bottomPadding.cache.clear();
    },

    removeCacheItem(item, isTop) {
      topPadding.cache.remove(item, isTop);
      bottomPadding.cache.remove(item, isTop);
    },

    removeItem(item) {
      this.removeCacheItem(item);
      return buffer.remove(item);
    }
  });

  return viewport;
}
<|endoftext|>


<commit_before>var NBS = function() {
  var _this = {};
  var _internal = 'alphasights';
  var _status = null;
  var _timeout = null;
  var _id_list = [];
  var _g = {
    'recipientWrapActive':'.wO.nr.l1',
    'recipientWrap':'.wO.nr',
    'recipientInput':'textarea.vO',
    'lightboxWrap':'.ah.aiv.aJS',
    'lightboxWrapClass':'ah aiv aJS',
    'contactHighlighted': '.Jd-Je.Je',
    'contactHighlightedClass': 'Jd-Je Je',
    'contact':'.Jd-axF',
    'contactLowerText':'.Sr',
    'contactUpperText':'.am',
    // message page
    'replyActive':'.gA.gt',
    'noReply':'.amn',
    'replyBox': '.fX.aXjCH', // under .gA.gt // check display for activation
    'wrapContact': '.vR', // the contact block when user confirm emails
    'replyBoxPresented':'.oL.aDm.az9',
    // popup page
    'popupNewMessage':'.AD',
    'popupMessageRightTopMinimizeButton': '.Hl', // check data-tooltip = Minimize || Maximize (oposite to status)
    'popupNewMessageMaximized':'', // check display for activation
    'popupReplyBox':'.fX.aXjCH', // under .AD // check display for activation
    'presentReplyBox': '.aoD.hl' // oposite to .fX.aXjCH, check display for activation
  };

  function init () {
    console.log('NBS.init');

    setInterval(function(){
      console.log('setTimeout');
      setupListener();
    }, 5*1000);

    window.onhashchange = onHashChange;
  }

  function onHashChange() {
      console.log('hashchange');
      setupListener();
  }

  function appendNoticBox() {
    console.log('NBS.appendNoticBox');

    $('.aoI').each(function(i, el){
      var $el = $(el);
      if($el.find('.noticebox').length === 0){
        var $popupNewMessage,popupNewMessage,isPopupNotice,noticeClass,$noticebox;
        $popupNewMessage = $(_g.popupNewMessage);
        popupNewMessage = $popupNewMessage.length && $popupNewMessage[0];
        isPopupNotice = $.contains(popupNewMessage, $el[0]);
        noticeClass = isPopupNotice? 'popupNotice' : 'onPageNotice';
        $noticebox =
          $('<div/>', {
            class: ['noticebox','alert','alert-warning',noticeClass].join(' ')
          })
            .hide();

        $el.append( $noticebox );
      }
    });
  }

  function setupListener() {
    console.log('setupListener');

    appendNoticBox();

    $(_g.recipientInput).off().focus(function(e){
      console.log('NBS.focus');
      setTimeout(function(){
        setupListener();
        checkRecipients(e);
      });
    });
    $(_g.recipientInput).off().keydown(function(e){
      console.log('NBS.keypress');
      setTimeout(function(){
        setupListener();
        checkRecipients(e);
      });
    });

    var status = checkStatus();
    if(status.msgPage.isReply && !status.msgPage.isReplyBoxActive ||
       status.popup.isMaximized
      ){

      checkRecipients();
    } else if(status.popup.isReplyBoxActive ||
       status.msgPage.isReplyBoxActive
       ){
      checkRecipients();
    }
  }

  function isElementContrain(parent, children) {
    return $.contains(parent, children);
  }

  function checkRecipients(e, isRemoveEmail) {
    console.log('checkRecipients', e);

    var target = e && $(e.target).parents(_g.recipientWrap) || _g.recipientWrap;
    var $wraps = $(target);

    $wraps.each(function(i, wrap){
      var $wrap, $email_els, $el, email, extenalEmails;
      extenalEmails = [];
      $wrap = $(wrap);
      $email_els = $wrap.find('[email]');

      var $popupNewMessage = $(_g.popupNewMessage);
      var popupNewMessage = $popupNewMessage.length && $popupNewMessage[0];
      var isWrapInPopup = isElementContrain(popupNewMessage, $wrap[0]);

      if($email_els.length){

        $email_els.each(function(i, el){
          $el = $(el);
          email = $el.attr('email');
          if(email.indexOf(_internal) === -1){
            if(extenalEmails.indexOf(email) === -1){
              extenalEmails.push(email);

              $el.find('.vM').off().on('click', function(e){
                console.log('contact-cross.click');
                checkRecipients(e, true);
              });
            }
          }
        });

        if(e && isRemoveEmail){
          var removeEmail = $(e.target).parents('.vN.Y7BVp[email]').attr('email');
          extenalEmails.splice(extenalEmails.indexOf(removeEmail), 1);
        }

        if(extenalEmails.length){
          showAlert({
            email: extenalEmails.join(', '),
            isPopup: isWrapInPopup
          });
        } else {
          hideAlert(isWrapInPopup);
        }
      } else {
        if(e && e.target){
          hideAlert(isWrapInPopup);
        }
      }
    });
  }

  function checkOnPageStatus(hash_arr) {
    var $noReply, $replyBox, isReply, isNoReplyFound, isNoReplyDisplay, isReplyBoxFound, isReplyBoxDisplay, messageID;
    $noReply = $(_g.noReply);
    $replyBox = $(_g.replyBox);
    isNoReplyFound = !!$noReply.length;
    isNoReplyDisplay = $noReply.css('display') !== "none";
    isReplyBoxFound = !!$replyBox.length;
    isReplyBoxDisplay = ($replyBox.css('display') !== "none");
    messageID = hash_arr[2] || ''; // 14aea826eba93d4e
    isReply = (!!messageID && !isNoReplyFound && !!isNoReplyDisplay) || false;

    return {
      id: messageID || '',
      isActive: !!messageID || false,
      isReply: isReply,
      isReplyBoxActive: (isReply && isReplyBoxFound && isReplyBoxDisplay) || false
    };
  }

  function checkPopupStatus(hash_arr){
    var isMaximized, popupStatus_arr, topRightMiniBtn, popupMessageReplyBox, isPopupMessageReplyBoxDisplay, isTopRightMinimizeButton, isPopupMessage, popupMessageID;

    topRightMiniBtn = $(_g.popupMessageRightTopMinimizeButton);
    popupMessageReplyBox = $(_g.popupNewMessage).find(_g.replyBox);
    isPopupMessageReplyBoxDisplay = (popupMessageReplyBox.css('display') !== "none");
    isTopRightMinimizeButton = (topRightMiniBtn.data('tooltip') === "Minimize");
    popupStatus_arr = hash_arr[3] && hash_arr[3].split('=') || [];
    isPopupMessage = (popupStatus_arr[0] === 'compose');
    popupMessageID = popupStatus_arr[1] || '';
    isMaximized = isTopRightMinimizeButton || false;

    return {
      id: popupMessageID || '',
      isActive: isPopupMessage || false,
      isMaximized: isMaximized,
      isReplyBoxActive: isMaximized && popupMessageReplyBox && isPopupMessageReplyBoxDisplay || false
    };
  }

  function checkStatus() {
    // inbox page: https://mail.google.com/mail/u/0/#inbox
    // message page: https://mail.google.com/mail/u/0/#inbox/14aea826eba93d4e
    // popup message: https://mail.google.com/mail/u/0/#inbox/14aea826eba93d4e?compose=new
    // drafts page: https://mail.google.com/mail/u/0/#drafts?compose=14af2e2e6fe7deae
    var hash, hash_arr, page, messageID, popupStatus, popupStatus_arr, status, msgPage, popup;

    hash = window.location.hash;
    hash_arr = hash.split(/#([^?/]+)?\/?([^/?]+)?\??([^&]+)?/);

    page = hash_arr[1]; // #inbox

    msgPage = checkOnPageStatus( hash_arr );
    popup = checkPopupStatus( hash_arr );

    status = {
      hash_arr: hash_arr,
      page: page,
      popupStatus: popupStatus,
      msgPage: msgPage,
      popup: popup
    };

    console.log('status:', status);
    return status;
  }

  function showAlert(data) {
    console.log('noticebox:show');
    var noticebox = data.isPopup? $('.noticebox.popupNotice') : $('.noticebox.onPageNotice');
    noticebox
      .show()
      .text('External Recipients: '+data.email);
  }

  function hideAlert(isPopup) {
    console.log('noticebox:hide');
    var noticebox = isPopup? $('.noticebox.popupNotice') : $('.noticebox.onPageNotice');
    noticebox
      .hide();
  }

  init();

  return _this;
};

$(document).ready(function(){
  window.noticeBeforeSend = new NBS();
});<commit_msg>set Interval to 3sec, handle To, CC and BCC contacts all togther<commit_after>var NBS = function() {
  var _this = {};
  var _internal = 'alphasights';
  var _status = null;
  var _timeout = null;
  var _id_list = [];
  var _g = {
    'recipientWrapActive':'.wO.nr.l1',
    'recipientWrap':'.wO.nr',
    'recipientInput':'textarea.vO',
    'lightboxWrap':'.ah.aiv.aJS',
    'lightboxWrapClass':'ah aiv aJS',
    'contactHighlighted': '.Jd-Je.Je',
    'contactHighlightedClass': 'Jd-Je Je',
    'contact':'.Jd-axF',
    'contactLowerText':'.Sr',
    'contactUpperText':'.am',
    // message page
    'replyActive':'.gA.gt',
    'noReply':'.amn',
    'replyBox': '.fX.aXjCH', // under .gA.gt // check display for activation
    'wrapContact': '.vR', // the contact block when user confirm emails
    'replyBoxPresented':'.oL.aDm.az9',
    // popup page
    'popupNewMessage':'.AD',
    'popupMessageRightTopMinimizeButton': '.Hl', // check data-tooltip = Minimize || Maximize (oposite to status)
    'popupNewMessageMaximized':'', // check display for activation
    'popupReplyBox':'.fX.aXjCH', // under .AD // check display for activation
    'presentReplyBox': '.aoD.hl' // oposite to .fX.aXjCH, check display for activation
  };

  function init () {
    console.log('NBS.init');

    setInterval(function(){
      setupListener();
    }, 3*1000);

    window.onhashchange = onHashChange;
  }

  function onHashChange() {
      console.log('hashchange');
      setupListener();
  }

  function appendNoticBox() {
    console.log('NBS.appendNoticBox');

    $('.aoI').each(function(i, el){
      var $el = $(el);
      if($el.find('.noticebox').length === 0){
        var $popupNewMessage,popupNewMessage,isPopupNotice,noticeClass,$noticebox;
        $popupNewMessage = $(_g.popupNewMessage);
        popupNewMessage = $popupNewMessage.length && $popupNewMessage[0];
        isPopupNotice = $.contains(popupNewMessage, $el[0]);
        noticeClass = isPopupNotice? 'popupNotice' : 'onPageNotice';
        $noticebox =
          $('<div/>', {
            class: ['noticebox','alert','alert-warning',noticeClass].join(' ')
          })
            .hide();

        $el.append( $noticebox );
      }
    });
  }

  function setupListener() {
    console.log('NBS.setupListener');

    appendNoticBox();

    $(_g.recipientInput).off().focus(function(e){
      console.log('recipientInput.focus');
      setTimeout(function(){
        setupListener();
        checkRecipients(e);
      });
    });
    $(_g.recipientInput).off().keydown(function(e){
      console.log('recipientInput.keypress');
      setTimeout(function(){
        setupListener();
        checkRecipients(e);
      });
    });

    var status = checkStatus();
    if(status.msgPage.isReply && !status.msgPage.isReplyBoxActive ||
       status.popup.isMaximized
      ){

      checkRecipients();
    } else if(status.popup.isReplyBoxActive ||
       status.msgPage.isReplyBoxActive
       ){
      checkRecipients();
    }
  }

  function isElementContrain(parent, children) {
    return $.contains(parent, children);
  }

  function checkRecipients(e, isRemoveEmail) {
    console.log('checkRecipients', e);

    var $wraps = $(_g.recipientWrap);
    var extenalEmails = [];

    $wraps.each(function(i, wrap){
      var $wrap, $email_els, $el, email;
      $wrap = $(wrap);
      $email_els = $wrap.find('[email]');

      var $popupNewMessage = $(_g.popupNewMessage);
      var popupNewMessage = $popupNewMessage.length && $popupNewMessage[0];
      var isWrapInPopup = isElementContrain(popupNewMessage, $wrap[0]);

      if($email_els.length){

        $email_els.each(function(i, el){
          $el = $(el);
          email = $el.attr('email');
          if(email.indexOf(_internal) === -1){
            if(extenalEmails.indexOf(email) === -1){
              extenalEmails.push(email);

              $el.find('.vM').off().on('click', function(e){
                console.log('contact-cross.click');
                checkRecipients(e, true);
              });
            }
          }
        });

        if(e && isRemoveEmail){
          var removeEmail = $(e.target).parents('.vN.Y7BVp[email]').attr('email');
          extenalEmails.splice(extenalEmails.indexOf(removeEmail), 1);
        }

      } else {
        if(e && e.target){
          hideAlert(isWrapInPopup);
        }
      }
    });

    if(extenalEmails.length){
      showAlert({
        email: extenalEmails.join(', '),
        isPopup: isWrapInPopup
      });
    } else {
      hideAlert(isWrapInPopup);
    }
  }

  function checkOnPageStatus(hash_arr) {
    var $noReply, $replyBox, isReply, isNoReplyFound, isNoReplyDisplay, isReplyBoxFound, isReplyBoxDisplay, messageID;
    $noReply = $(_g.noReply);
    $replyBox = $(_g.replyBox);
    isNoReplyFound = !!$noReply.length;
    isNoReplyDisplay = $noReply.css('display') !== "none";
    isReplyBoxFound = !!$replyBox.length;
    isReplyBoxDisplay = ($replyBox.css('display') !== "none");
    messageID = hash_arr[2] || ''; // 14aea826eba93d4e
    isReply = (!!messageID && !isNoReplyFound && !!isNoReplyDisplay) || false;

    return {
      id: messageID || '',
      isActive: !!messageID || false,
      isReply: isReply,
      isReplyBoxActive: (isReply && isReplyBoxFound && isReplyBoxDisplay) || false
    };
  }

  function checkPopupStatus(hash_arr){
    var isMaximized, popupStatus_arr, topRightMiniBtn, popupMessageReplyBox, isPopupMessageReplyBoxDisplay, isTopRightMinimizeButton, isPopupMessage, popupMessageID;

    topRightMiniBtn = $(_g.popupMessageRightTopMinimizeButton);
    popupMessageReplyBox = $(_g.popupNewMessage).find(_g.replyBox);
    isPopupMessageReplyBoxDisplay = (popupMessageReplyBox.css('display') !== "none");
    isTopRightMinimizeButton = (topRightMiniBtn.data('tooltip') === "Minimize");
    popupStatus_arr = hash_arr[3] && hash_arr[3].split('=') || [];
    isPopupMessage = (popupStatus_arr[0] === 'compose');
    popupMessageID = popupStatus_arr[1] || '';
    isMaximized = isTopRightMinimizeButton || false;

    return {
      id: popupMessageID || '',
      isActive: isPopupMessage || false,
      isMaximized: isMaximized,
      isReplyBoxActive: isMaximized && popupMessageReplyBox && isPopupMessageReplyBoxDisplay || false
    };
  }

  function checkStatus() {
    // inbox page: https://mail.google.com/mail/u/0/#inbox
    // message page: https://mail.google.com/mail/u/0/#inbox/14aea826eba93d4e
    // popup message: https://mail.google.com/mail/u/0/#inbox/14aea826eba93d4e?compose=new
    // drafts page: https://mail.google.com/mail/u/0/#drafts?compose=14af2e2e6fe7deae
    var hash, hash_arr, page, messageID, popupStatus, popupStatus_arr, status, msgPage, popup;

    hash = window.location.hash;
    hash_arr = hash.split(/#([^?/]+)?\/?([^/?]+)?\??([^&]+)?/);

    page = hash_arr[1]; // #inbox

    msgPage = checkOnPageStatus( hash_arr );
    popup = checkPopupStatus( hash_arr );

    status = {
      hash_arr: hash_arr,
      page: page,
      popupStatus: popupStatus,
      msgPage: msgPage,
      popup: popup
    };

    console.log('status:', status);
    return status;
  }

  function showAlert(data) {
    console.log('noticebox:show');
    var noticebox = data.isPopup? $('.noticebox.popupNotice') : $('.noticebox.onPageNotice');
    noticebox
      .show()
      .text('External Recipients: '+data.email);
  }

  function hideAlert(isPopup) {
    console.log('noticebox:hide');
    var noticebox = isPopup? $('.noticebox.popupNotice') : $('.noticebox.onPageNotice');
    noticebox
      .hide();
  }

  init();

  return _this;
};

$(document).ready(function(){
  window.noticeBeforeSend = new NBS();
});<|endoftext|>


<commit_before>// LICENSE : MIT
"use strict";
import app from 'app';
import BrowserWindow  from 'browser-window';
import path from "path";
import APIServer from "./APIServer";
import WebMessenger from "./WebMessenger";
import {getDictionary, save} from "./textlint/dictionary-store";
import windowStateKeeper from 'electron-window-state';
export default class Application {
    // focus existing running instance window
    restoreWindow(newArgv) {
        var window = this.mainWindow;
        if (window) {
            if (window.isMinimized()) {
                window.restore();
            }
            window.show();
            // restore with command line
            const argv = require('minimist')(newArgv.slice(2));
            const messenger = new WebMessenger(this.mainWindow.webContents);
            if(argv.title || argv.url) {
                messenger.resetField();
            }
            if (argv.title) {
                messenger.updateTitle(argv.title);
            }
            if (argv.url) {
                messenger.updateURL(argv.url);
            }
        }
    }

    launch() {
        // command line
        const argv = require('minimist')(process.argv.slice(2));
        let mainWindowState = windowStateKeeper({
            defaultWidth: 500,
            defaultHeight: 500
        });
        this.mainWindow = new BrowserWindow({
            title: require("../../package.json").name,
            frame: false,
            x: mainWindowState.x,
            y: mainWindowState.y,
            width: mainWindowState.width,
            height: mainWindowState.height
        });
        var index = {
            html: path.join(__dirname, "..", "browser", "index.html")
        };
        this.mainWindow.loadURL('file://' + index.html);
        this.mainWindow.webContents.on('did-finish-load', () => {
            const messenger = new WebMessenger(this.mainWindow.webContents);
            if (argv.title) {
                messenger.updateTitle(argv.title);
            }
            if (argv.url) {
                messenger.updateURL(argv.url);
            }
            //let server = new APIServer(this.mainWindow.webContents);
            //server.start();
        });
        // 辞書の更新
        getDictionary(function (error, result) {
            if (error) {
                return console.error(error);
            }
            console.log("Update: dictionary");
            save(result);
        });

        // Let us register listeners on the window, so we can update the state
        // automatically (the listeners will be removed when the window is closed)
        // and restore the maximized or full screen state
        mainWindowState.manage(this.mainWindow);
        // set top
        this.mainWindow.setAlwaysOnTop(true);
    }
}
<commit_msg>fix(cli): remove reset from cli<commit_after>// LICENSE : MIT
"use strict";
import app from 'app';
import BrowserWindow  from 'browser-window';
import path from "path";
import APIServer from "./APIServer";
import WebMessenger from "./WebMessenger";
import {getDictionary, save} from "./textlint/dictionary-store";
import windowStateKeeper from 'electron-window-state';
export default class Application {
    // focus existing running instance window
    restoreWindow(newArgv) {
        var window = this.mainWindow;
        if (window) {
            if (window.isMinimized()) {
                window.restore();
            }
            window.show();
            // restore with command line
            const argv = require('minimist')(newArgv.slice(2));
            const messenger = new WebMessenger(this.mainWindow.webContents);
            if (argv.title) {
                messenger.updateTitle(argv.title);
            }
            if (argv.url) {
                messenger.updateURL(argv.url);
            }
        }
    }

    launch() {
        // command line
        const argv = require('minimist')(process.argv.slice(2));
        let mainWindowState = windowStateKeeper({
            defaultWidth: 500,
            defaultHeight: 500
        });
        this.mainWindow = new BrowserWindow({
            title: require("../../package.json").name,
            frame: false,
            x: mainWindowState.x,
            y: mainWindowState.y,
            width: mainWindowState.width,
            height: mainWindowState.height
        });
        var index = {
            html: path.join(__dirname, "..", "browser", "index.html")
        };
        this.mainWindow.loadURL('file://' + index.html);
        this.mainWindow.webContents.on('did-finish-load', () => {
            const messenger = new WebMessenger(this.mainWindow.webContents);
            if (argv.title) {
                messenger.updateTitle(argv.title);
            }
            if (argv.url) {
                messenger.updateURL(argv.url);
            }
            //let server = new APIServer(this.mainWindow.webContents);
            //server.start();
        });
        // 辞書の更新
        getDictionary(function (error, result) {
            if (error) {
                return console.error(error);
            }
            console.log("Update: dictionary");
            save(result);
        });

        // Let us register listeners on the window, so we can update the state
        // automatically (the listeners will be removed when the window is closed)
        // and restore the maximized or full screen state
        mainWindowState.manage(this.mainWindow);
        // set top
        this.mainWindow.setAlwaysOnTop(true);
    }
}
<|endoftext|>


<commit_before>goog.provide('og.Extent');

goog.require('og.LonLat');

og.Extent = function (sw, ne) {
    this.southWest = sw || new og.LonLat();
    this.northEast = ne || new og.LonLat();
};

og.Extent.createFromArray = function (arr) {
    return new og.Extent(new og.LonLat(arr[0], arr[1]), new og.LonLat(arr[2], arr[3]));
};

og.Extent.prototype.getWidth = function () {
    return this.northEast.lon - this.southWest.lon;
};

og.Extent.prototype.getHeight = function () {
    return this.northEast.lat - this.southWest.lat
};

og.Extent.prototype.clone = function () {
    return new og.Extent(this.sw, this.ne);
};

og.Extent.prototype.getCenter = function () {
    var sw = this.southWest, ne = this.northEast;
    return new og.LonLat(sw.lon + (ne.lon - sw.lon) * 0.5, sw.lat + (ne.lat - sw.lat) * 0.5);
};

og.Extent.prototype.getNorthWest = function () {
    return new og.LonLat(this.northEast.lon, this.southWest.lat);
};

og.Extent.prototype.getNorthEast = function () {
    return new og.LonLat(this.northEast.lon, this.northEast.lat);
};

og.Extent.prototype.getSouthWest = function () {
    return new og.LonLat(this.southWest.lon, this.southWest.lat);
};

og.Extent.prototype.getSouthEast = function () {
    return new og.LonLat(this.southWest.lon, this.northEast.lat);
};

og.Extent.prototype.getNorth = function () {
    return this.northEast.lat;
};

og.Extent.prototype.getEast = function () {
    return this.northEast.lon;
};

og.Extent.prototype.getWest = function () {
    return this.southWest.lon;
};

og.Extent.prototype.getSouth = function () {
    return this.southWest.lat;
};

og.Extent.fromTile = function (x, y, z) {
    var H = Math.pow(2, zoom),
        W = Math.pow(2, zoom),
        lnSize = 360 / W,
        ltSize = 180.0 / H;

    var left = -180.0 + x * lnSize,
        top = 90 - y * ltSize,
        bottom = top - ltSize,
        right = left + lnSize;

    return new og.Extent(new og.LonLat(left, bottom), new og.LonLat(right, top));
};
<commit_msg>Inside extent point verification function added.<commit_after>goog.provide('og.Extent');

goog.require('og.LonLat');

og.Extent = function (sw, ne) {
    this.southWest = sw || new og.LonLat();
    this.northEast = ne || new og.LonLat();
};

og.Extent.createFromArray = function (arr) {
    return new og.Extent(new og.LonLat(arr[0], arr[1]), new og.LonLat(arr[2], arr[3]));
};

og.Extent.prototype.isInside = function (lonlat) {
    var sw = this.southWest,
        ne = this.northEast;
    return lonlat.lon >= sw.lon && lonlat.lon <= ne.lon &&
           lonlat.lat >= sw.lat && lonlat.lat <= ne.lat;
};

og.Extent.prototype.getWidth = function () {
    return this.northEast.lon - this.southWest.lon;
};

og.Extent.prototype.getHeight = function () {
    return this.northEast.lat - this.southWest.lat
};

og.Extent.prototype.clone = function () {
    return new og.Extent(this.sw, this.ne);
};

og.Extent.prototype.getCenter = function () {
    var sw = this.southWest, ne = this.northEast;
    return new og.LonLat(sw.lon + (ne.lon - sw.lon) * 0.5, sw.lat + (ne.lat - sw.lat) * 0.5);
};

og.Extent.prototype.getNorthWest = function () {
    return new og.LonLat(this.northEast.lon, this.southWest.lat);
};

og.Extent.prototype.getNorthEast = function () {
    return new og.LonLat(this.northEast.lon, this.northEast.lat);
};

og.Extent.prototype.getSouthWest = function () {
    return new og.LonLat(this.southWest.lon, this.southWest.lat);
};

og.Extent.prototype.getSouthEast = function () {
    return new og.LonLat(this.southWest.lon, this.northEast.lat);
};

og.Extent.prototype.getNorth = function () {
    return this.northEast.lat;
};

og.Extent.prototype.getEast = function () {
    return this.northEast.lon;
};

og.Extent.prototype.getWest = function () {
    return this.southWest.lon;
};

og.Extent.prototype.getSouth = function () {
    return this.southWest.lat;
};

og.Extent.fromTile = function (x, y, z) {
    var H = Math.pow(2, zoom),
        W = Math.pow(2, zoom),
        lnSize = 360 / W,
        ltSize = 180.0 / H;

    var left = -180.0 + x * lnSize,
        top = 90 - y * ltSize,
        bottom = top - ltSize,
        right = left + lnSize;

    return new og.Extent(new og.LonLat(left, bottom), new og.LonLat(right, top));
};
<|endoftext|>


<commit_before>goog.provide('ol.geom.Geometry');
goog.provide('ol.geom.GeometryType');

goog.require('goog.asserts');
goog.require('goog.functions');
goog.require('ol.Observable');
goog.require('ol.proj');

/**
 * The geometry type. One of `'Point'`, `'LineString'`, `'LinearRing'`,
 * `'Polygon'`, `'MultiPoint'`, `'MultiLineString'`, `'MultiPolygon'`,
 * `'GeometryCollection'`, `'Circle'`.
 * @enum {string}
 * @api stable
 */
ol.geom.GeometryType = {
  POINT: 'Point',
  LINE_STRING: 'LineString',
  LINEAR_RING: 'LinearRing',
  POLYGON: 'Polygon',
  MULTI_POINT: 'MultiPoint',
  MULTI_LINE_STRING: 'MultiLineString',
  MULTI_POLYGON: 'MultiPolygon',
  GEOMETRY_COLLECTION: 'GeometryCollection',
  CIRCLE: 'Circle'
};

/**
 * The coordinate layout for geometries, indicating whether a 3rd or 4th z ('Z')
 * or measure ('M') coordinate is available. Supported values are `'XY'`,
 * `'XYZ'`, `'XYM'`, `'XYZM'`.
 * @enum {string}
 * @api stable
 */
ol.geom.GeometryLayout = {
  XY: 'XY',
  XYZ: 'XYZ',
  XYM: 'XYM',
  XYZM: 'XYZM'
};

/**
 * @classdesc
 * Abstract base class; normally only used for creating subclasses and not
 * instantiated in apps.
 * Base class for vector geometries.
 *
 * @constructor
 * @extends {ol.Observable}
 * @fires change Triggered when the geometry changes.
 * @api stable
 */
ol.geom.Geometry = function() {

  goog.base(this);

  /**
   * @protected
   * @type {ol.Extent|undefined}
   */
  this.extent = undefined;

  /**
   * @protected
   * @type {number}
   */
  this.extentRevision = -1;

  /**
   * @protected
   * @type {Object.<string, ol.geom.Geometry>}
   */
  this.simplifiedGeometryCache = {};

  /**
   * @protected
   * @type {number}
   */
  this.simplifiedGeometryMaxMinSquaredTolerance = 0;

  /**
   * @protected
   * @type {number}
   */
  this.simplifiedGeometryRevision = 0;

};
goog.inherits(ol.geom.Geometry, ol.Observable);

/**
 * Make a complete copy of the geometry.
 * @function
 * @return {!ol.geom.Geometry} Clone.
 * @api stable
 */
ol.geom.Geometry.prototype.clone = goog.abstractMethod;

/**
 * @param {number} x X.
 * @param {number} y Y.
 * @param {ol.Coordinate} closestPoint Closest point.
 * @param {number} minSquaredDistance Minimum squared distance.
 * @return {number} Minimum squared distance.
 */
ol.geom.Geometry.prototype.closestPointXY = goog.abstractMethod;

/**
 * @param {ol.Coordinate} point Point.
 * @param {ol.Coordinate=} opt_closestPoint Closest point.
 * @return {ol.Coordinate} Closest point.
 * @api stable
 */
ol.geom.Geometry.prototype.getClosestPoint = function(point, opt_closestPoint) {
  var closestPoint = goog.isDef(opt_closestPoint) ?
      opt_closestPoint : [NaN, NaN];
  this.closestPointXY(point[0], point[1], closestPoint, Infinity);
  return closestPoint;
};

/**
 * @param {ol.Coordinate} coordinate Coordinate.
 * @return {boolean} Contains coordinate.
 */
ol.geom.Geometry.prototype.containsCoordinate = function(coordinate) {
  return this.containsXY(coordinate[0], coordinate[1]);
};

/**
 * @param {number} x X.
 * @param {number} y Y.
 * @return {boolean} Contains (x, y).
 */
ol.geom.Geometry.prototype.containsXY = goog.functions.FALSE;

/**
 * Get the extent of the geometry.
 * @function
 * @param {ol.Extent=} opt_extent Extent.
 * @return {ol.Extent} extent Extent.
 * @api stable
 */
ol.geom.Geometry.prototype.getExtent = goog.abstractMethod;

/**
 * Create a simplified version of this geometry using the Douglas Peucker
 * algorithm.
 * @see http://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm
 * @function
 * @param {number} squaredTolerance Squared tolerance.
 * @return {ol.geom.Geometry} Simplified geometry.
 */
ol.geom.Geometry.prototype.getSimplifiedGeometry = goog.abstractMethod;

/**
 * Get the type of this geometry.
 * @function
 * @return {ol.geom.GeometryType} Geometry type.
 * @api stable
 */
ol.geom.Geometry.prototype.getType = goog.abstractMethod;

/**
 * Apply a transform function to each coordinate of the geometry.
 * The geometry is modified in place.
 * If you do not want the geometry modified in place, first clone() it and
 * then use this function on the clone.
 * @function
 * @param {ol.TransformFunction} transformFn Transform.
 * @api stable
 */
ol.geom.Geometry.prototype.applyTransform = goog.abstractMethod;

/**
 * Transform each coordinate of the geometry from one coordinate reference
 * system to another. The geometry is modified in place.
 * For example, a line will be transformed to a line and a circle to a circle.
 * If you do not want the geometry modified in place, first clone() it and
 * then use this function on the clone.
 *
 * @param {ol.proj.ProjectionLike} source The current projection.  Can be a
 *     string identifier or a {@link ol.proj.Projection} object.
 * @param {ol.proj.ProjectionLike} destination The desired projection.  Can be a
 *     string identifier or a {@link ol.proj.Projection} object.
 * @return {ol.geom.Geometry} This geometry.  Note that original geometry is
 *     modified in place.
 * @api stable
 */
ol.geom.Geometry.prototype.transform = function(source, destination) {
  this.applyTransform(ol.proj.getTransform(source, destination));
  return this;
};
<commit_msg>Add ol.geom.Geometry#intersectsExtent (abstract method)<commit_after>goog.provide('ol.geom.Geometry');
goog.provide('ol.geom.GeometryType');

goog.require('goog.asserts');
goog.require('goog.functions');
goog.require('ol.Observable');
goog.require('ol.proj');

/**
 * The geometry type. One of `'Point'`, `'LineString'`, `'LinearRing'`,
 * `'Polygon'`, `'MultiPoint'`, `'MultiLineString'`, `'MultiPolygon'`,
 * `'GeometryCollection'`, `'Circle'`.
 * @enum {string}
 * @api stable
 */
ol.geom.GeometryType = {
  POINT: 'Point',
  LINE_STRING: 'LineString',
  LINEAR_RING: 'LinearRing',
  POLYGON: 'Polygon',
  MULTI_POINT: 'MultiPoint',
  MULTI_LINE_STRING: 'MultiLineString',
  MULTI_POLYGON: 'MultiPolygon',
  GEOMETRY_COLLECTION: 'GeometryCollection',
  CIRCLE: 'Circle'
};

/**
 * The coordinate layout for geometries, indicating whether a 3rd or 4th z ('Z')
 * or measure ('M') coordinate is available. Supported values are `'XY'`,
 * `'XYZ'`, `'XYM'`, `'XYZM'`.
 * @enum {string}
 * @api stable
 */
ol.geom.GeometryLayout = {
  XY: 'XY',
  XYZ: 'XYZ',
  XYM: 'XYM',
  XYZM: 'XYZM'
};

/**
 * @classdesc
 * Abstract base class; normally only used for creating subclasses and not
 * instantiated in apps.
 * Base class for vector geometries.
 *
 * @constructor
 * @extends {ol.Observable}
 * @fires change Triggered when the geometry changes.
 * @api stable
 */
ol.geom.Geometry = function() {

  goog.base(this);

  /**
   * @protected
   * @type {ol.Extent|undefined}
   */
  this.extent = undefined;

  /**
   * @protected
   * @type {number}
   */
  this.extentRevision = -1;

  /**
   * @protected
   * @type {Object.<string, ol.geom.Geometry>}
   */
  this.simplifiedGeometryCache = {};

  /**
   * @protected
   * @type {number}
   */
  this.simplifiedGeometryMaxMinSquaredTolerance = 0;

  /**
   * @protected
   * @type {number}
   */
  this.simplifiedGeometryRevision = 0;

};
goog.inherits(ol.geom.Geometry, ol.Observable);

/**
 * Make a complete copy of the geometry.
 * @function
 * @return {!ol.geom.Geometry} Clone.
 * @api stable
 */
ol.geom.Geometry.prototype.clone = goog.abstractMethod;

/**
 * @param {number} x X.
 * @param {number} y Y.
 * @param {ol.Coordinate} closestPoint Closest point.
 * @param {number} minSquaredDistance Minimum squared distance.
 * @return {number} Minimum squared distance.
 */
ol.geom.Geometry.prototype.closestPointXY = goog.abstractMethod;

/**
 * @param {ol.Coordinate} point Point.
 * @param {ol.Coordinate=} opt_closestPoint Closest point.
 * @return {ol.Coordinate} Closest point.
 * @api stable
 */
ol.geom.Geometry.prototype.getClosestPoint = function(point, opt_closestPoint) {
  var closestPoint = goog.isDef(opt_closestPoint) ?
      opt_closestPoint : [NaN, NaN];
  this.closestPointXY(point[0], point[1], closestPoint, Infinity);
  return closestPoint;
};

/**
 * @param {ol.Coordinate} coordinate Coordinate.
 * @return {boolean} Contains coordinate.
 */
ol.geom.Geometry.prototype.containsCoordinate = function(coordinate) {
  return this.containsXY(coordinate[0], coordinate[1]);
};

/**
 * @param {number} x X.
 * @param {number} y Y.
 * @return {boolean} Contains (x, y).
 */
ol.geom.Geometry.prototype.containsXY = goog.functions.FALSE;

/**
 * Get the extent of the geometry.
 * @function
 * @param {ol.Extent=} opt_extent Extent.
 * @return {ol.Extent} extent Extent.
 * @api stable
 */
ol.geom.Geometry.prototype.getExtent = goog.abstractMethod;

/**
 * Create a simplified version of this geometry using the Douglas Peucker
 * algorithm.
 * @see http://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm
 * @function
 * @param {number} squaredTolerance Squared tolerance.
 * @return {ol.geom.Geometry} Simplified geometry.
 */
ol.geom.Geometry.prototype.getSimplifiedGeometry = goog.abstractMethod;

/**
 * Get the type of this geometry.
 * @function
 * @return {ol.geom.GeometryType} Geometry type.
 * @api stable
 */
ol.geom.Geometry.prototype.getType = goog.abstractMethod;

/**
 * Apply a transform function to each coordinate of the geometry.
 * The geometry is modified in place.
 * If you do not want the geometry modified in place, first clone() it and
 * then use this function on the clone.
 * @function
 * @param {ol.TransformFunction} transformFn Transform.
 * @api stable
 */
ol.geom.Geometry.prototype.applyTransform = goog.abstractMethod;

/**
 * Test if the geometry and the passed extent intersect.
 * @param {ol.Extent} extent Extent.
 * @return {boolean} `true` if the geometry and the extent intersect.
 * @function
 * @api
 */
ol.geom.Geometry.prototype.intersectsExtent = goog.abstractMethod;

/**
 * Transform each coordinate of the geometry from one coordinate reference
 * system to another. The geometry is modified in place.
 * For example, a line will be transformed to a line and a circle to a circle.
 * If you do not want the geometry modified in place, first clone() it and
 * then use this function on the clone.
 *
 * @param {ol.proj.ProjectionLike} source The current projection.  Can be a
 *     string identifier or a {@link ol.proj.Projection} object.
 * @param {ol.proj.ProjectionLike} destination The desired projection.  Can be a
 *     string identifier or a {@link ol.proj.Projection} object.
 * @return {ol.geom.Geometry} This geometry.  Note that original geometry is
 *     modified in place.
 * @api stable
 */
ol.geom.Geometry.prototype.transform = function(source, destination) {
  this.applyTransform(ol.proj.getTransform(source, destination));
  return this;
};
<|endoftext|>


<commit_before>// FIXME bulk inserts

goog.provide('ol.structs.RBush');

goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.object');
goog.require('ol.ext.rbush');

/**
 * Wrapper around the RBush by Vladimir Agafonkin.
 *
 * @constructor
 * @param {number=} opt_maxEntries Max entries.
 * @see https://github.com/mourner/rbush
 * @struct
 * @template T
 */
ol.structs.RBush = function(opt_maxEntries) {

  /**
   * @private
   */
  this.rbush_ = ol.ext.rbush(opt_maxEntries);

  /**
   * A mapping between the objects added to this rbush wrapper
   * and the objects that are actually added to the internal rbush.
   * @private
   * @type {Object.<number, Object>}
   */
  this.items_ = {};

  if (goog.DEBUG) {
    /**
     * @private
     * @type {number}
     */
    this.readers_ = 0;
  }
};

/**
 * Insert a value into the RBush.
 * @param {ol.Extent} extent Extent.
 * @param {T} value Value.
 */
ol.structs.RBush.prototype.insert = function(extent, value) {
  if (goog.DEBUG && this.readers_) {
    throw new Error('Can not insert value while reading');
  }
  var item = [
    extent[0],
    extent[1],
    extent[2],
    extent[3],
    value
  ];
  this.rbush_.insert(item);
  // remember the object that was added to the internal rbush
  goog.object.add(this.items_, goog.getUid(value).toString(), item);
};

/**
 * Bulk-insert values into the RBush.
 * @param {Array.<ol.Extent>} extents Extents.
 * @param {Array.<T>} values Values.
 */
ol.structs.RBush.prototype.load = function(extents, values) {
  if (goog.DEBUG && this.readers_) {
    throw new Error('Can not insert values while reading');
  }
  goog.asserts.assert(extents.length === values.length);

  var items = [];
  for (var i = 0, l = values.length; i < l; i++) {
    var extent = extents[i];
    var value = values[i];

    var item = [
      extent[0],
      extent[1],
      extent[2],
      extent[3],
      value
    ];
    items.push(item);
    goog.object.add(this.items_, goog.getUid(value).toString(), item);
  }
  this.rbush_.load(items);
};

/**
 * Remove a value from the RBush.
 * @param {T} value Value.
 * @return {boolean} Removed.
 */
ol.structs.RBush.prototype.remove = function(value) {
  if (goog.DEBUG && this.readers_) {
    throw new Error('Can not remove value while reading');
  }
  var uid = goog.getUid(value).toString();
  goog.asserts.assert(goog.object.containsKey(this.items_, uid));

  // get the object in which the value was wrapped when adding to the
  // internal rbush. then use that object to do the removal.
  var item = goog.object.get(this.items_, uid);
  goog.object.remove(this.items_, uid);
  return this.rbush_.remove(item) !== null;
};

/**
 * Update the extent of a value in the RBush.
 * @param {ol.Extent} extent Extent.
 * @param {T} value Value.
 */
ol.structs.RBush.prototype.update = function(extent, value) {
  this.remove(value);
  this.insert(extent, value);
};

/**
 * Return all values in the RBush.
 * @return {Array.<T>} All.
 */
ol.structs.RBush.prototype.getAll = function() {
  var items = this.rbush_.all();
  return goog.array.map(items, function(item) {
    return item[4];
  });
};

/**
 * Return all values in the given extent.
 * @param {ol.Extent} extent Extent.
 * @return {Array.<T>} All in extent.
 */
ol.structs.RBush.prototype.getInExtent = function(extent) {
  var items = this.rbush_.search(extent);
  return goog.array.map(items, function(item) {
    return item[4];
  });
};

/**
 * Calls a callback function with each value in the tree.
 * If the callback returns a truthy value, this value is returned without
 * checking the rest of the tree.
 * @param {function(this: S, T): *} callback Callback.
 * @param {S=} opt_this The object to use as `this` in `callback`.
 * @return {*} Callback return value.
 * @template S
 */
ol.structs.RBush.prototype.forEach = function(callback, opt_this) {
  if (goog.DEBUG) {
    ++this.readers_;
    try {
      return this.forEach_(this.getAll(), callback, opt_this);
    } finally {
      --this.readers_;
    }
  } else {
    return this.forEach_(this.getAll(), callback, opt_this);
  }
};

/**
 * Calls a callback function with each value in the provided extent.
 * @param {ol.Extent} extent Extent.
 * @param {function(this: S, T): *} callback Callback.
 * @param {S=} opt_this The object to use as `this` in `callback`.
 * @return {*} Callback return value.
 * @template S
 */
ol.structs.RBush.prototype.forEachInExtent =
    function(extent, callback, opt_this) {
  if (goog.DEBUG) {
    ++this.readers_;
    try {
      return this.forEach_(this.getInExtent(extent), callback, opt_this);
    } finally {
      --this.readers_;
    }
  } else {
    return this.forEach_(this.getInExtent(extent), callback, opt_this);
  }
};

/**
 * @param {Array.<T>} values Values.
 * @param {function(this: S, T): *} callback Callback.
 * @param {S=} opt_this The object to use as `this` in `callback`.
 * @private
 * @return {*} Callback return value.
 * @template S
 */
ol.structs.RBush.prototype.forEach_ = function(values, callback, opt_this) {
  var result;
  for (var i = 0, l = values.length; i < l; i++) {
    result = callback.call(opt_this, values[i]);
    if (result) {
      return result;
    }
  }
  return result;
};

/**
 * @return {boolean} Is empty.
 */
ol.structs.RBush.prototype.isEmpty = function() {
  return goog.object.isEmpty(this.items_);
};

/**
 * Remove all values from the RBush.
 */
ol.structs.RBush.prototype.clear = function() {
  this.rbush_.clear();
  goog.object.clear(this.items_);
};

/**
 * @param {ol.Extent=} opt_extent Extent.
 * @return {ol.Extent} Extent.
 */
ol.structs.RBush.prototype.getExtent = function(opt_extent) {
  // FIXME add getExtent() to rbush
  return this.rbush_.data.bbox;
};
<commit_msg>Remove FIXME in src/ol/structs/rbush.js<commit_after>goog.provide('ol.structs.RBush');

goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.object');
goog.require('ol.ext.rbush');

/**
 * Wrapper around the RBush by Vladimir Agafonkin.
 *
 * @constructor
 * @param {number=} opt_maxEntries Max entries.
 * @see https://github.com/mourner/rbush
 * @struct
 * @template T
 */
ol.structs.RBush = function(opt_maxEntries) {

  /**
   * @private
   */
  this.rbush_ = ol.ext.rbush(opt_maxEntries);

  /**
   * A mapping between the objects added to this rbush wrapper
   * and the objects that are actually added to the internal rbush.
   * @private
   * @type {Object.<number, Object>}
   */
  this.items_ = {};

  if (goog.DEBUG) {
    /**
     * @private
     * @type {number}
     */
    this.readers_ = 0;
  }
};

/**
 * Insert a value into the RBush.
 * @param {ol.Extent} extent Extent.
 * @param {T} value Value.
 */
ol.structs.RBush.prototype.insert = function(extent, value) {
  if (goog.DEBUG && this.readers_) {
    throw new Error('Can not insert value while reading');
  }
  var item = [
    extent[0],
    extent[1],
    extent[2],
    extent[3],
    value
  ];
  this.rbush_.insert(item);
  // remember the object that was added to the internal rbush
  goog.object.add(this.items_, goog.getUid(value).toString(), item);
};

/**
 * Bulk-insert values into the RBush.
 * @param {Array.<ol.Extent>} extents Extents.
 * @param {Array.<T>} values Values.
 */
ol.structs.RBush.prototype.load = function(extents, values) {
  if (goog.DEBUG && this.readers_) {
    throw new Error('Can not insert values while reading');
  }
  goog.asserts.assert(extents.length === values.length);

  var items = [];
  for (var i = 0, l = values.length; i < l; i++) {
    var extent = extents[i];
    var value = values[i];

    var item = [
      extent[0],
      extent[1],
      extent[2],
      extent[3],
      value
    ];
    items.push(item);
    goog.object.add(this.items_, goog.getUid(value).toString(), item);
  }
  this.rbush_.load(items);
};

/**
 * Remove a value from the RBush.
 * @param {T} value Value.
 * @return {boolean} Removed.
 */
ol.structs.RBush.prototype.remove = function(value) {
  if (goog.DEBUG && this.readers_) {
    throw new Error('Can not remove value while reading');
  }
  var uid = goog.getUid(value).toString();
  goog.asserts.assert(goog.object.containsKey(this.items_, uid));

  // get the object in which the value was wrapped when adding to the
  // internal rbush. then use that object to do the removal.
  var item = goog.object.get(this.items_, uid);
  goog.object.remove(this.items_, uid);
  return this.rbush_.remove(item) !== null;
};

/**
 * Update the extent of a value in the RBush.
 * @param {ol.Extent} extent Extent.
 * @param {T} value Value.
 */
ol.structs.RBush.prototype.update = function(extent, value) {
  this.remove(value);
  this.insert(extent, value);
};

/**
 * Return all values in the RBush.
 * @return {Array.<T>} All.
 */
ol.structs.RBush.prototype.getAll = function() {
  var items = this.rbush_.all();
  return goog.array.map(items, function(item) {
    return item[4];
  });
};

/**
 * Return all values in the given extent.
 * @param {ol.Extent} extent Extent.
 * @return {Array.<T>} All in extent.
 */
ol.structs.RBush.prototype.getInExtent = function(extent) {
  var items = this.rbush_.search(extent);
  return goog.array.map(items, function(item) {
    return item[4];
  });
};

/**
 * Calls a callback function with each value in the tree.
 * If the callback returns a truthy value, this value is returned without
 * checking the rest of the tree.
 * @param {function(this: S, T): *} callback Callback.
 * @param {S=} opt_this The object to use as `this` in `callback`.
 * @return {*} Callback return value.
 * @template S
 */
ol.structs.RBush.prototype.forEach = function(callback, opt_this) {
  if (goog.DEBUG) {
    ++this.readers_;
    try {
      return this.forEach_(this.getAll(), callback, opt_this);
    } finally {
      --this.readers_;
    }
  } else {
    return this.forEach_(this.getAll(), callback, opt_this);
  }
};

/**
 * Calls a callback function with each value in the provided extent.
 * @param {ol.Extent} extent Extent.
 * @param {function(this: S, T): *} callback Callback.
 * @param {S=} opt_this The object to use as `this` in `callback`.
 * @return {*} Callback return value.
 * @template S
 */
ol.structs.RBush.prototype.forEachInExtent =
    function(extent, callback, opt_this) {
  if (goog.DEBUG) {
    ++this.readers_;
    try {
      return this.forEach_(this.getInExtent(extent), callback, opt_this);
    } finally {
      --this.readers_;
    }
  } else {
    return this.forEach_(this.getInExtent(extent), callback, opt_this);
  }
};

/**
 * @param {Array.<T>} values Values.
 * @param {function(this: S, T): *} callback Callback.
 * @param {S=} opt_this The object to use as `this` in `callback`.
 * @private
 * @return {*} Callback return value.
 * @template S
 */
ol.structs.RBush.prototype.forEach_ = function(values, callback, opt_this) {
  var result;
  for (var i = 0, l = values.length; i < l; i++) {
    result = callback.call(opt_this, values[i]);
    if (result) {
      return result;
    }
  }
  return result;
};

/**
 * @return {boolean} Is empty.
 */
ol.structs.RBush.prototype.isEmpty = function() {
  return goog.object.isEmpty(this.items_);
};

/**
 * Remove all values from the RBush.
 */
ol.structs.RBush.prototype.clear = function() {
  this.rbush_.clear();
  goog.object.clear(this.items_);
};

/**
 * @param {ol.Extent=} opt_extent Extent.
 * @return {ol.Extent} Extent.
 */
ol.structs.RBush.prototype.getExtent = function(opt_extent) {
  // FIXME add getExtent() to rbush
  return this.rbush_.data.bbox;
};
<|endoftext|>


<commit_before>import React from "react";
import * as S from "../components/Homepage/styles";
import { GlobalStyle } from "../styles/Global";
import Social from "../components/Social/Social";
import Nav from "../components/Nav/Nav";

const ComingSoon = () => {
  return (

      <GlobalStyle />

      <S.Index>
        <S.Title>Coming Soon...</S.Title>
        <Social />
      </S.Index>

  );
};

export default ComingSoon;
<commit_msg>modify coming soon<commit_after>import React from "react";
import * as S from "../components/Homepage/styles";
import { GlobalStyle } from "../styles/Global";
import Footer from "../components/Footer/Footer";
import Nav from "../components/Nav/Nav";

const ComingSoon = () => {
  return (

      <GlobalStyle />

      <S.Index>
        <S.Title>Coming Soon...</S.Title>

      </S.Index>

  );
};

export default ComingSoon;
<|endoftext|>


<commit_before>import React from 'react'
import styled from 'styled-components'
import {
  Heading,
  Box,
  Flex,
  Container,
  Image,
  Text,
  Sheet
} from '@hackclub/design-system'
import { Link } from 'gatsby'
import { Section, SectionTitle, Cols, Quote, theme } from './style'
import { Headline, Subhline, Featline, Lead } from 'components/Content'
import Photo from 'components/Photo'

const BioSheet = styled(Sheet).attrs({ p: 3, bg: theme.colors.darkless })`
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-gap: ${theme.space[3]}px;
  img {
    border-radius: ${theme.radii[2]};
  }
  div {
    align-self: flex-end;
    text-align: left;
  }
  h3,
  span {
    line-height: 1;
  }
  p {
    grid-column: span 2;
  }
`

const Bio = ({ img, name, pronouns, text, ...props }) => (
  <BioSheet mb={0} {...props}>
    <Image src={img} alt={name} />
    <Box>
      <Heading.h3 fontSize={4} mb={1} color="white" children={name} />
      <Text.span
        fontSize={1}
        color="muted"
        align="center"
        children={pronouns}
      />
    </Box>
    <Text fontSize={2} color="muted" children={text} />
  </BioSheet>
)

const Timeline = styled(Flex).attrs({
  flexDirection: 'column',
  mb: [4, 0]
})`
  line-height: 1.125;
  position: relative;
  &:before {
    content: '';
    background-image: linear-gradient(
      to bottom,
      ${theme.colors.dark} 0%,
      ${theme.colors.slate} 15%,
      ${theme.colors.slate} 85%,
      ${theme.colors.dark} 100%
    );
    height: 100%;
    width: 3px;
    margin-left: 4px;
    position: absolute;
    z-index: 0;
  }
`
const TimelineStep = styled(Flex).attrs({
  align: 'center',
  pt: props => (props.first ? 0 : [2, 3])
})`
  line-height: 1.125;
  position: relative;
  z-index: 1;
`
const Circle = styled(Box).attrs({ p: 1 })`
  border-radius: ${theme.pill};
  display: inline-block;
  line-height: 0;
`

Timeline.Step = ({ name, duration, first = false, color = 'red' }) => (
  <TimelineStep first={first}>
    <Circle bg={theme.colors[color]} mr={3} />
    <Box align="left">
      <Text color="muted" fontSize={1} caps children={duration} />
      <Text color="smoke" fontSize={[3, 4]} children={name} />
    </Box>
  </TimelineStep>
)

const Pinboard = styled(Container).attrs({ maxWidth: 72, px: [3, 4] })`
  display: grid;
  grid-gap: ${theme.space[4]}px;
  ${theme.mediaQueries.md} {
    grid-template-columns: repeat(2, 1fr);
    grid-gap: ${theme.space[5]}px;
    align-items: center;
  }
`

const Gallery = styled(Container).attrs({ maxWidth: 84, px: [3, 4] })`
  display: grid;
  grid-gap: ${theme.space[4]}px;
  ${theme.mediaQueries.md} {
    grid-template-columns: repeat(8, 1fr);
    > div {
      grid-column: span 4;
      min-height: 32rem;
      &[data-vertical] {
        grid-column: span 2;
      }
    }
  }
`

export default () => [

    <Container maxWidth={61.25} px={3}>
      <SectionTitle>About Us</SectionTitle>
      <Cols cols="1fr 2fr" mb={[4, 5]}>
        <Subhline>
          Hack Club is a worldwide network of coding clubs.
        </Subhline>
        <Lead>
          We’re{' '}
          <Link style={{ color: theme.colors.red }} to="/">
            Hack Club
          </Link>
          , a global nonprofit network of high school coding clubs (now in 2% of
          US high schools). Hack Camp has been a part of Hack Club since the
          beginning. It’s a great way for us to try out the best ideas from our
          community, develop curriculum, and stay sharp as teachers. We also
          just love doing it!
        </Lead>
      </Cols>
    </Container>
    <Container px={3}>
      <Cols cols="1fr 1fr 1fr">
        <Bio
          img="/camp/fernanda.jpg"
          name="Fernanda Lozano"
          text="Fernanda is a computational neuroscience student, an entrepreneur, and an organizer with years of experience running programs and events for students in Mexico. This summer Fernanda will take charge of Hack Camp’s logistics and serve as your primary point of contact."
          pronouns="she/her"
        />
        <Bio
          img="/camp/mingjie.jpg"
          name="Mingjie Jiang"
          text="Mingjie is a student organizer who has spread his passion for technology to thousands of other students through events like Hack Chicago, CodeDay, and his own Hack Club. This summer he’s working with club leaders around the world to build the ultimate curriculum."
          pronouns="he/him"
        />
        <Bio
          img="/camp/chris.jpg"
          name="Chris Walker"
          text="Chris is an all-around hacker enthusiast passionate about building video games, websites, radios, furniture, rockets, fire sculptures, communities, and more! He will be leading Hack Camp’s workshops, designing hardware projects, and directing the day-to-day experience."
          pronouns="he/him"
        />
      </Cols>
    </Container>
    <Container maxWidth={61.25} px={3}>
      <Subhline mt={[5, 6]} mb={4}>
        A brief history of Hack Camp
      </Subhline>
      <Cols gap={[3, 5]} mt={0} mb={0}>

          <Lead color="muted">
            Hack Camp began as an experiment to discover new ways of teaching
            coding at our clubs around the world.

          </Lead>
          <Lead color="muted" mt={[2, 3]}>

After our first year, something incredible happened—our students
            began running their own camps! They’ve sprung up in a suburb of
            Cincinnati & Southern India.
          </Lead>
          <Lead color="muted" mt={[2, 3]}>
            This was so inspiring to watch that we’re following their lead to
            bring Hack Camp back in 2019.

          </Lead>

        <Timeline>
          <Timeline.Step name="Hack Club is born" duration="2015" first />
          <Timeline.Step name="First Hack Camp in SF" duration="2016" />
          <Timeline.Step name="SF Hack Camp v2" duration="2017" />
          <Timeline.Step
            name="A Camp appears in Mason, OH"
            duration="2017"
            color="cyan"
          />
          <Timeline.Step
            name="Camp runs again in Mason"
            duration="2018"
            color="cyan"
          />
          <Timeline.Step
            name="A Camp appears in Kerala, India"
            duration="2018"
            color="yellow"
          />
          <Timeline.Step name="Hack Camp returns to HQ!" duration="2019" />
        </Timeline>
      </Cols>
    </Container>
    <Pinboard mt={[5, 6]}>
      <Photo
        src="/camp/mason1.jpg"
        alt="A Hack Camp workshop in Mason, Ohio"
        dark
      />
      <Photo src="/camp/sf.jpg" alt="Presenting at the first Hack Camp" dark />
      <Quote
        body="Hack Camp is a chance for young students to discover their ability to build using code. Your youth is the most defining time of your life, and Hack Camp helped us reach out to students around the community to expose them to the most beautiful, empowering parts of technology."
        img="megan.png"
        name="Megan Cui"
        detail="Mason, OH"
        credential="Camp leader, Harvard ’23"
      />
      <Photo
        src="/camp/mason2.jpg"
        alt="Coding at Mason Hack Camp, 2018"
        dark
      />
      <Photo src="/camp/india.jpg" alt="Hack Camp in Kerala, India" dark />
      <Quote
        body="I was worried campers might lose interest since coding was new to them. But when we got them started, they blew us away. They started learning by themselves during the camp and built things we never taught them."
        img="athul.jpg"
        name="Athul Blesson"
        detail="Kerala, India"
        credential="Camp leader, ASIET ’21"
      />
    </Pinboard>

,

    <Container maxWidth={61.25} px={3}>
      <Cols cols="1fr 2fr" mb={[4, 5]}>
        <Subhline mb={0}>Welcome to Hack Club HQ.</Subhline>
        <Lead>
          We’re running Hack Camp right at our office in
          San Francisco (576 Natoma St). Here’s the space.
        </Lead>
      </Cols>
    </Container>
    <Gallery my={5}>
      <Photo
        src="/camp/street.jpg"
        alt="Natoma St, HQ on the left"
        dark
        data-vertical
      />
      <Photo
        src="/camp/neighborhood.jpg"
        alt="Neighborhood, two blocks from HQ"
        dark
      />
      <Photo
        src="/camp/classroom.jpg"
        alt="HQ’s classroom space"
        dark
        data-vertical
      />
      <Photo src="/camp/conference.jpg" alt="HQ’s conference room" dark />
      <Photo src="/camp/library.jpg" alt="HQ’s library" dark />
    </Gallery>

]
<commit_msg>Update Fernanda’s bio<commit_after>import React from 'react'
import styled from 'styled-components'
import {
  Heading,
  Box,
  Flex,
  Container,
  Image,
  Text,
  Sheet
} from '@hackclub/design-system'
import { Link } from 'gatsby'
import { Section, SectionTitle, Cols, Quote, theme } from './style'
import { Headline, Subhline, Featline, Lead } from 'components/Content'
import Photo from 'components/Photo'

const BioSheet = styled(Sheet).attrs({ p: 3, bg: theme.colors.darkless })`
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-gap: ${theme.space[3]}px;
  img {
    border-radius: ${theme.radii[2]};
  }
  div {
    align-self: flex-end;
    text-align: left;
  }
  h3,
  span {
    line-height: 1;
  }
  p {
    grid-column: span 2;
  }
`

const Bio = ({ img, name, pronouns, text, ...props }) => (
  <BioSheet mb={0} {...props}>
    <Image src={img} alt={name} />
    <Box>
      <Heading.h3 fontSize={4} mb={1} color="white" children={name} />
      <Text.span
        fontSize={1}
        color="muted"
        align="center"
        children={pronouns}
      />
    </Box>
    <Text fontSize={2} color="muted" children={text} />
  </BioSheet>
)

const Timeline = styled(Flex).attrs({
  flexDirection: 'column',
  mb: [4, 0]
})`
  line-height: 1.125;
  position: relative;
  &:before {
    content: '';
    background-image: linear-gradient(
      to bottom,
      ${theme.colors.dark} 0%,
      ${theme.colors.slate} 15%,
      ${theme.colors.slate} 85%,
      ${theme.colors.dark} 100%
    );
    height: 100%;
    width: 3px;
    margin-left: 4px;
    position: absolute;
    z-index: 0;
  }
`
const TimelineStep = styled(Flex).attrs({
  align: 'center',
  pt: props => (props.first ? 0 : [2, 3])
})`
  line-height: 1.125;
  position: relative;
  z-index: 1;
`
const Circle = styled(Box).attrs({ p: 1 })`
  border-radius: ${theme.pill};
  display: inline-block;
  line-height: 0;
`

Timeline.Step = ({ name, duration, first = false, color = 'red' }) => (
  <TimelineStep first={first}>
    <Circle bg={theme.colors[color]} mr={3} />
    <Box align="left">
      <Text color="muted" fontSize={1} caps children={duration} />
      <Text color="smoke" fontSize={[3, 4]} children={name} />
    </Box>
  </TimelineStep>
)

const Pinboard = styled(Container).attrs({ maxWidth: 72, px: [3, 4] })`
  display: grid;
  grid-gap: ${theme.space[4]}px;
  ${theme.mediaQueries.md} {
    grid-template-columns: repeat(2, 1fr);
    grid-gap: ${theme.space[5]}px;
    align-items: center;
  }
`

const Gallery = styled(Container).attrs({ maxWidth: 84, px: [3, 4] })`
  display: grid;
  grid-gap: ${theme.space[4]}px;
  ${theme.mediaQueries.md} {
    grid-template-columns: repeat(8, 1fr);
    > div {
      grid-column: span 4;
      min-height: 32rem;
      &[data-vertical] {
        grid-column: span 2;
      }
    }
  }
`

export default () => [

    <Container maxWidth={61.25} px={3}>
      <SectionTitle>About Us</SectionTitle>
      <Cols cols="1fr 2fr" mb={[4, 5]}>
        <Subhline>
          Hack Club is a worldwide network of coding clubs.
        </Subhline>
        <Lead>
          We’re{' '}
          <Link style={{ color: theme.colors.red }} to="/">
            Hack Club
          </Link>
          , a global nonprofit network of high school coding clubs (now in 2% of
          US high schools). Hack Camp has been a part of Hack Club since the
          beginning. It’s a great way for us to try out the best ideas from our
          community, develop curriculum, and stay sharp as teachers. We also
          just love doing it!
        </Lead>
      </Cols>
    </Container>
    <Container px={3}>
      <Cols cols="1fr 1fr 1fr">
        <Bio
          img="/camp/fernanda.jpg"
          name="Fernanda Lozano"
          text="Fernanda is a student of computational neuroscience, entrepreneur, and organizer with years of experience running events and programs like the Entrepreneurial Learning Academy for students in Mexico. This summer, she’ll run Hack Camp’s logistics and be your primary contact."
          pronouns="she/her"
        />
        <Bio
          img="/camp/mingjie.jpg"
          name="Mingjie Jiang"
          text="Mingjie is a student organizer who has spread his passion for technology to thousands of other students through events like Hack Chicago, CodeDay, and his own Hack Club. This summer he’s working with club leaders around the world to build the ultimate curriculum."
          pronouns="he/him"
        />
        <Bio
          img="/camp/chris.jpg"
          name="Chris Walker"
          text="Chris is an all-around hacker enthusiast passionate about building video games, websites, radios, furniture, rockets, fire sculptures, communities, and more! He will be leading Hack Camp’s workshops, designing hardware projects, and directing the day-to-day experience."
          pronouns="he/him"
        />
      </Cols>
    </Container>
    <Container maxWidth={61.25} px={3}>
      <Subhline mt={[5, 6]} mb={4}>
        A brief history of Hack Camp
      </Subhline>
      <Cols gap={[3, 5]} mt={0} mb={0}>

          <Lead color="muted">
            Hack Camp began as an experiment to discover new ways of teaching
            coding at our clubs around the world.

          </Lead>
          <Lead color="muted" mt={[2, 3]}>

After our first year, something incredible happened—our students
            began running their own camps! They’ve sprung up in a suburb of
            Cincinnati & Southern India.
          </Lead>
          <Lead color="muted" mt={[2, 3]}>
            This was so inspiring to watch that we’re following their lead to
            bring Hack Camp back in 2019.

          </Lead>

        <Timeline>
          <Timeline.Step name="Hack Club is born" duration="2015" first />
          <Timeline.Step name="First Hack Camp in SF" duration="2016" />
          <Timeline.Step name="SF Hack Camp v2" duration="2017" />
          <Timeline.Step
            name="A Camp appears in Mason, OH"
            duration="2017"
            color="cyan"
          />
          <Timeline.Step
            name="Camp runs again in Mason"
            duration="2018"
            color="cyan"
          />
          <Timeline.Step
            name="A Camp appears in Kerala, India"
            duration="2018"
            color="yellow"
          />
          <Timeline.Step name="Hack Camp returns to HQ!" duration="2019" />
        </Timeline>
      </Cols>
    </Container>
    <Pinboard mt={[5, 6]}>
      <Photo
        src="/camp/mason1.jpg"
        alt="A Hack Camp workshop in Mason, Ohio"
        dark
      />
      <Photo src="/camp/sf.jpg" alt="Presenting at the first Hack Camp" dark />
      <Quote
        body="Hack Camp is a chance for young students to discover their ability to build using code. Your youth is the most defining time of your life, and Hack Camp helped us reach out to students around the community to expose them to the most beautiful, empowering parts of technology."
        img="megan.png"
        name="Megan Cui"
        detail="Mason, OH"
        credential="Camp leader, Harvard ’23"
      />
      <Photo
        src="/camp/mason2.jpg"
        alt="Coding at Mason Hack Camp, 2018"
        dark
      />
      <Photo src="/camp/india.jpg" alt="Hack Camp in Kerala, India" dark />
      <Quote
        body="I was worried campers might lose interest since coding was new to them. But when we got them started, they blew us away. They started learning by themselves during the camp and built things we never taught them."
        img="athul.jpg"
        name="Athul Blesson"
        detail="Kerala, India"
        credential="Camp leader, ASIET ’21"
      />
    </Pinboard>

,

    <Container maxWidth={61.25} px={3}>
      <Cols cols="1fr 2fr" mb={[4, 5]}>
        <Subhline mb={0}>Welcome to Hack Club HQ.</Subhline>
        <Lead>
          We’re running Hack Camp right at our office in
          San Francisco (576 Natoma St). Here’s the space.
        </Lead>
      </Cols>
    </Container>
    <Gallery my={5}>
      <Photo
        src="/camp/street.jpg"
        alt="Natoma St, HQ on the left"
        dark
        data-vertical
      />
      <Photo
        src="/camp/neighborhood.jpg"
        alt="Neighborhood, two blocks from HQ"
        dark
      />
      <Photo
        src="/camp/classroom.jpg"
        alt="HQ’s classroom space"
        dark
        data-vertical
      />
      <Photo src="/camp/conference.jpg" alt="HQ’s conference room" dark />
      <Photo src="/camp/library.jpg" alt="HQ’s library" dark />
    </Gallery>

]
<|endoftext|>