<commit_before>module.exports = Server

var bencode = require('bencode')
var debug = require('debug')('bittorrent-tracker')
var dgram = require('dgram')
var EventEmitter = require('events').EventEmitter
var http = require('http')
var inherits = require('inherits')
var portfinder = require('portfinder')
var series = require('run-series')
var string2compact = require('string2compact')

var common = require('./lib/common')
var Swarm = require('./lib/swarm')
var parseHttpRequest = require('./lib/parse_http')
var parseUdpRequest = require('./lib/parse_udp')

// Use random port above 1024
portfinder.basePort = Math.floor(Math.random() * 60000) + 1025

inherits(Server, EventEmitter)

/**
 * A BitTorrent tracker server.
 *
 * A "BitTorrent tracker" is an HTTP service which responds to GET requests from
 * BitTorrent clients. The requests include metrics from clients that help the tracker
 * keep overall statistics about the torrent. The response includes a peer list that
 * helps the client participate in the torrent.
 *
 * @param {Object}  opts            options
 * @param {Number}  opts.interval   interval in ms that clients should announce on
 * @param {Number}  opts.trustProxy Trust 'x-forwarded-for' header from reverse proxy
 * @param {boolean} opts.http       Start an http server? (default: true)
 * @param {boolean} opts.udp        Start a udp server? (default: true)
 */
function Server (opts) {
  var self = this
  if (!(self instanceof Server)) return new Server(opts)
  EventEmitter.call(self)
  opts = opts || {}

  self._intervalMs = opts.interval
    ? opts.interval / 1000
    : 10 * 60 // 10 min (in secs)

  self._trustProxy = !!opts.trustProxy

  self.listening = false
  self.port = null
  self.torrents = {}

  // default to starting an http server unless the user explictly says no
  if (opts.http !== false) {
    self._httpServer = http.createServer()
    self._httpServer.on('request', self.onHttpRequest.bind(self))
    self._httpServer.on('error', self._onError.bind(self))
    self._httpServer.on('listening', onListening)
  }

  // default to starting a udp server unless the user explicitly says no
  if (opts.udp !== false) {
    self._udpSocket = dgram.createSocket('udp4')
    self._udpSocket.on('message', self.onUdpRequest.bind(self))
    self._udpSocket.on('error', self._onError.bind(self))
    self._udpSocket.on('listening', onListening)
  }

  var num = !!self._httpServer + !!self._udpSocket
  function onListening () {
    num -= 1
    if (num === 0) {
      self.listening = true
      self.emit('listening', self.port)
    }
  }
}

Server.prototype._onError = function (err) {
  var self = this
  self.emit('error', err)
}

Server.prototype.listen = function (port, onlistening) {
  var self = this
  if (typeof port === 'function') {
    onlistening = port
    port = undefined
  }
  if (self.listening) throw new Error('server already listening')
  if (onlistening) self.once('listening', onlistening)

  function onPort (err, port) {
    if (err) return self.emit('error', err)
    self.port = port
    // ATTENTION:
    // binding to :: only receives IPv4 connections if the bindv6only
    // sysctl is set 0, which is the default on many operating systems.
    self._httpServer && self._httpServer.listen(port.http || port, '::')
    self._udpSocket && self._udpSocket.bind(port.udp || port)
  }

  if (port) onPort(null, port)
  else portfinder.getPort(onPort)
}

Server.prototype.close = function (cb) {
  var self = this
  cb = cb || function () {}
  if (self._udpSocket) {
    self._udpSocket.close()
  }
  if (self._httpServer) {
    self._httpServer.close(cb)
  } else {
    cb(null)
  }
}

Server.prototype.getSwarm = function (infoHash) {
  var self = this
  if (Buffer.isBuffer(infoHash)) infoHash = infoHash.toString('hex')
  var swarm = self.torrents[infoHash]
  if (!swarm) swarm = self.torrents[infoHash] = new Swarm(infoHash, this)
  return swarm
}

Server.prototype.onHttpRequest = function (req, res) {
  var self = this

  var params
  try {
    params = parseHttpRequest(req, { trustProxy: self._trustProxy })
  } catch (err) {
    debug('sent error %s', err.message)
    res.end(bencode.encode({
      'failure reason': err.message
    }))

    // even though it's an error for the client, it's just a warning for the server.
    // don't crash the server because a client sent bad data :)
    self.emit('warning', err)

    return
  }

  this._onRequest(params, function (err, response) {
    if (err) {
      self.emit('warning', err)
      response = {
        'failure reason': err.message
      }
    }

    delete response.action  // only needed for UDP encoding
    res.end(bencode.encode(response))
  })
}

Server.prototype.onUdpRequest = function (msg, rinfo) {
  var self = this

  var params
  try {
    params = parseUdpRequest(msg, rinfo)
  } catch (err) {
    self.emit('warning', err)
    // Do not reply for parsing errors
    return
  }

  // Handle
  this._onRequest(params, function (err, response) {
    if (err) {
      self.emit('warning', err)
      response = {
        action: common.ACTIONS.ERRROR,
        'failure reason': err.message
      }
    }

    response.transactionId = params.transactionId
    response.connectionId = params.connectionId
    var buf = makeUdpPacket(response)
    self._udpSocket.send(buf, 0, buf.length, rinfo.port, rinfo.address, function () {
      try {
        socket.close()
      } catch (err) {}
    })
  })
}

Server.prototype._onRequest = function (params, cb) {
  if (params && params.action === common.ACTIONS.CONNECT) {
    cb(null, { action: common.ACTIONS.CONNECT })
  } else if (params && params.action === common.ACTIONS.ANNOUNCE) {
    this._onAnnounce(params, cb)
  } else if (params && params.action === common.ACTIONS.SCRAPE) {
    this._onScrape(params, cb)
  } else {
    cb(new Error('Invalid action'))
  }
}

Server.prototype._onAnnounce = function (params, cb) {
  var self = this
  var swarm = self.getSwarm(params.info_hash)
  swarm.announce(params, function (err, response) {
    if (response) {
      if (!response.action) response.action = common.ACTIONS.ANNOUNCE
      if (!response.intervalMs) response.intervalMs = self._intervalMs

      if (params.compact === 1) {
        var peers = response.peers
        // Find IPv4 peers
        response.peers = string2compact(peers.filter(function (peer) {
          return common.IPV4_RE.test(peer.ip)
        }).map(function (peer) {
          return peer.ip + ':' + peer.port
        }))
        // Find IPv6 peers
        response.peers6 = string2compact(peers.filter(function (peer) {
          return common.IPV6_RE.test(peer.ip)
        }).map(function (peer) {
          return '[' + peer.ip + ']:' + peer.port
        }))
      }
      // IPv6 peers are not separate for non-compact responses
    }
    cb(err, response)
  })
}

Server.prototype._onScrape = function (params, cb) {
  var self = this

  if (params.info_hash == null) {
    // if info_hash param is omitted, stats for all torrents are returned
    // TODO: make this configurable!
    params.info_hash = Object.keys(self.torrents)
  }

  series(params.info_hash.map(function (infoHash) {
    var swarm = self.getSwarm(infoHash)
    return function (cb) {
      swarm.scrape(params, function (err, scrapeInfo) {
        cb(err, scrapeInfo && {
          infoHash: infoHash,
          complete: scrapeInfo.complete || 0,
          incomplete: scrapeInfo.incomplete || 0
        })
      })
    }
  }), function (err, results) {
    if (err) return cb(err)

    var response = {
      action: common.ACTIONS.SCRAPE,
      files: {},
      flags: { min_request_interval: self._intervalMs }
    }

    results.forEach(function (result) {
      response.files[common.hexToBinary(result.infoHash)] = {
        complete: result.complete,
        incomplete: result.incomplete,
        downloaded: result.complete // TODO: this only provides a lower-bound
      }
    })

    cb(null, response)
  })
}

function makeUdpPacket (params) {
  switch (params.action) {
    case common.ACTIONS.CONNECT:
      return Buffer.concat([
        common.toUInt32(common.ACTIONS.CONNECT),
        common.toUInt32(params.transactionId),
        params.connectionId
      ])
    case common.ACTIONS.ANNOUNCE:
      return Buffer.concat([
        common.toUInt32(common.ACTIONS.ANNOUNCE),
        common.toUInt32(params.transactionId),
        common.toUInt32(params.intervalMs),
        common.toUInt32(params.incomplete),
        common.toUInt32(params.complete),
        params.peers
      ])
    case common.ACTIONS.SCRAPE:
      var firstInfoHash = Object.keys(params.files)[0]
      var scrapeInfo = firstInfoHash ? {
        complete: params.files[firstInfoHash].complete,
        incomplete: params.files[firstInfoHash].incomplete,
        completed: params.files[firstInfoHash].complete // TODO: this only provides a lower-bound
      } : {}
      return Buffer.concat([
        common.toUInt32(common.ACTIONS.SCRAPE),
        common.toUInt32(params.transactionId),
        common.toUInt32(scrapeInfo.complete),
        common.toUInt32(scrapeInfo.completed),
        common.toUInt32(scrapeInfo.incomplete)
      ])
    case common.ACTIONS.ERROR:
      return Buffer.concat([
        common.toUInt32(common.ACTIONS.ERROR),
        common.toUInt32(params.transactionId || 0),
        new Buffer(params.message, 'utf8')
      ])
  default:
    throw new Error('Action not implemented: ' + params.action)
  }
}
<commit_msg>server: fix interval unit<commit_after>module.exports = Server

var bencode = require('bencode')
var debug = require('debug')('bittorrent-tracker')
var dgram = require('dgram')
var EventEmitter = require('events').EventEmitter
var http = require('http')
var inherits = require('inherits')
var portfinder = require('portfinder')
var series = require('run-series')
var string2compact = require('string2compact')

var common = require('./lib/common')
var Swarm = require('./lib/swarm')
var parseHttpRequest = require('./lib/parse_http')
var parseUdpRequest = require('./lib/parse_udp')

// Use random port above 1024
portfinder.basePort = Math.floor(Math.random() * 60000) + 1025

inherits(Server, EventEmitter)

/**
 * A BitTorrent tracker server.
 *
 * A "BitTorrent tracker" is an HTTP service which responds to GET requests from
 * BitTorrent clients. The requests include metrics from clients that help the tracker
 * keep overall statistics about the torrent. The response includes a peer list that
 * helps the client participate in the torrent.
 *
 * @param {Object}  opts            options
 * @param {Number}  opts.interval   interval in ms that clients should announce on
 * @param {Number}  opts.trustProxy Trust 'x-forwarded-for' header from reverse proxy
 * @param {boolean} opts.http       Start an http server? (default: true)
 * @param {boolean} opts.udp        Start a udp server? (default: true)
 */
function Server (opts) {
  var self = this
  if (!(self instanceof Server)) return new Server(opts)
  EventEmitter.call(self)
  opts = opts || {}

  self._intervalMs = opts.interval
    ? opts.interval
    : 10 * 60 * 1000 // 10 min

  self._trustProxy = !!opts.trustProxy

  self.listening = false
  self.port = null
  self.torrents = {}

  // default to starting an http server unless the user explictly says no
  if (opts.http !== false) {
    self._httpServer = http.createServer()
    self._httpServer.on('request', self.onHttpRequest.bind(self))
    self._httpServer.on('error', self._onError.bind(self))
    self._httpServer.on('listening', onListening)
  }

  // default to starting a udp server unless the user explicitly says no
  if (opts.udp !== false) {
    self._udpSocket = dgram.createSocket('udp4')
    self._udpSocket.on('message', self.onUdpRequest.bind(self))
    self._udpSocket.on('error', self._onError.bind(self))
    self._udpSocket.on('listening', onListening)
  }

  var num = !!self._httpServer + !!self._udpSocket
  function onListening () {
    num -= 1
    if (num === 0) {
      self.listening = true
      self.emit('listening', self.port)
    }
  }
}

Server.prototype._onError = function (err) {
  var self = this
  self.emit('error', err)
}

Server.prototype.listen = function (port, onlistening) {
  var self = this
  if (typeof port === 'function') {
    onlistening = port
    port = undefined
  }
  if (self.listening) throw new Error('server already listening')
  if (onlistening) self.once('listening', onlistening)

  function onPort (err, port) {
    if (err) return self.emit('error', err)
    self.port = port
    // ATTENTION:
    // binding to :: only receives IPv4 connections if the bindv6only
    // sysctl is set 0, which is the default on many operating systems.
    self._httpServer && self._httpServer.listen(port.http || port, '::')
    self._udpSocket && self._udpSocket.bind(port.udp || port)
  }

  if (port) onPort(null, port)
  else portfinder.getPort(onPort)
}

Server.prototype.close = function (cb) {
  var self = this
  cb = cb || function () {}
  if (self._udpSocket) {
    self._udpSocket.close()
  }
  if (self._httpServer) {
    self._httpServer.close(cb)
  } else {
    cb(null)
  }
}

Server.prototype.getSwarm = function (infoHash) {
  var self = this
  if (Buffer.isBuffer(infoHash)) infoHash = infoHash.toString('hex')
  var swarm = self.torrents[infoHash]
  if (!swarm) swarm = self.torrents[infoHash] = new Swarm(infoHash, this)
  return swarm
}

Server.prototype.onHttpRequest = function (req, res) {
  var self = this

  var params
  try {
    params = parseHttpRequest(req, { trustProxy: self._trustProxy })
  } catch (err) {
    debug('sent error %s', err.message)
    res.end(bencode.encode({
      'failure reason': err.message
    }))

    // even though it's an error for the client, it's just a warning for the server.
    // don't crash the server because a client sent bad data :)
    self.emit('warning', err)

    return
  }

  this._onRequest(params, function (err, response) {
    if (err) {
      self.emit('warning', err)
      response = {
        'failure reason': err.message
      }
    }

    delete response.action  // only needed for UDP encoding
    res.end(bencode.encode(response))
  })
}

Server.prototype.onUdpRequest = function (msg, rinfo) {
  var self = this

  var params
  try {
    params = parseUdpRequest(msg, rinfo)
  } catch (err) {
    self.emit('warning', err)
    // Do not reply for parsing errors
    return
  }

  // Handle
  this._onRequest(params, function (err, response) {
    if (err) {
      self.emit('warning', err)
      response = {
        action: common.ACTIONS.ERRROR,
        'failure reason': err.message
      }
    }

    response.transactionId = params.transactionId
    response.connectionId = params.connectionId
    var buf = makeUdpPacket(response)
    self._udpSocket.send(buf, 0, buf.length, rinfo.port, rinfo.address, function () {
      try {
        socket.close()
      } catch (err) {}
    })
  })
}

Server.prototype._onRequest = function (params, cb) {
  if (params && params.action === common.ACTIONS.CONNECT) {
    cb(null, { action: common.ACTIONS.CONNECT })
  } else if (params && params.action === common.ACTIONS.ANNOUNCE) {
    this._onAnnounce(params, cb)
  } else if (params && params.action === common.ACTIONS.SCRAPE) {
    this._onScrape(params, cb)
  } else {
    cb(new Error('Invalid action'))
  }
}

Server.prototype._onAnnounce = function (params, cb) {
  var self = this
  var swarm = self.getSwarm(params.info_hash)
  swarm.announce(params, function (err, response) {
    if (response) {
      if (!response.action) response.action = common.ACTIONS.ANNOUNCE
      if (!response.interval) response.interval = Math.ceil(self._intervalMs / 1000)

      if (params.compact === 1) {
        var peers = response.peers
        // Find IPv4 peers
        response.peers = string2compact(peers.filter(function (peer) {
          return common.IPV4_RE.test(peer.ip)
        }).map(function (peer) {
          return peer.ip + ':' + peer.port
        }))
        // Find IPv6 peers
        response.peers6 = string2compact(peers.filter(function (peer) {
          return common.IPV6_RE.test(peer.ip)
        }).map(function (peer) {
          return '[' + peer.ip + ']:' + peer.port
        }))
      }
      // IPv6 peers are not separate for non-compact responses
    }
    cb(err, response)
  })
}

Server.prototype._onScrape = function (params, cb) {
  var self = this

  if (params.info_hash == null) {
    // if info_hash param is omitted, stats for all torrents are returned
    // TODO: make this configurable!
    params.info_hash = Object.keys(self.torrents)
  }

  series(params.info_hash.map(function (infoHash) {
    var swarm = self.getSwarm(infoHash)
    return function (cb) {
      swarm.scrape(params, function (err, scrapeInfo) {
        cb(err, scrapeInfo && {
          infoHash: infoHash,
          complete: scrapeInfo.complete || 0,
          incomplete: scrapeInfo.incomplete || 0
        })
      })
    }
  }), function (err, results) {
    if (err) return cb(err)

    var response = {
      action: common.ACTIONS.SCRAPE,
      files: {},
      flags: { min_request_interval: Math.ceil(self._intervalMs / 1000) }
    }

    results.forEach(function (result) {
      response.files[common.hexToBinary(result.infoHash)] = {
        complete: result.complete,
        incomplete: result.incomplete,
        downloaded: result.complete // TODO: this only provides a lower-bound
      }
    })

    cb(null, response)
  })
}

function makeUdpPacket (params) {
  switch (params.action) {
    case common.ACTIONS.CONNECT:
      return Buffer.concat([
        common.toUInt32(common.ACTIONS.CONNECT),
        common.toUInt32(params.transactionId),
        params.connectionId
      ])
    case common.ACTIONS.ANNOUNCE:
      return Buffer.concat([
        common.toUInt32(common.ACTIONS.ANNOUNCE),
        common.toUInt32(params.transactionId),
        common.toUInt32(params.interval),
        common.toUInt32(params.incomplete),
        common.toUInt32(params.complete),
        params.peers
      ])
    case common.ACTIONS.SCRAPE:
      var firstInfoHash = Object.keys(params.files)[0]
      var scrapeInfo = firstInfoHash ? {
        complete: params.files[firstInfoHash].complete,
        incomplete: params.files[firstInfoHash].incomplete,
        completed: params.files[firstInfoHash].complete // TODO: this only provides a lower-bound
      } : {}
      return Buffer.concat([
        common.toUInt32(common.ACTIONS.SCRAPE),
        common.toUInt32(params.transactionId),
        common.toUInt32(scrapeInfo.complete),
        common.toUInt32(scrapeInfo.completed),
        common.toUInt32(scrapeInfo.incomplete)
      ])
    case common.ACTIONS.ERROR:
      return Buffer.concat([
        common.toUInt32(common.ACTIONS.ERROR),
        common.toUInt32(params.transactionId || 0),
        new Buffer(params.message, 'utf8')
      ])
  default:
    throw new Error('Action not implemented: ' + params.action)
  }
}
<|endoftext|>


<commit_before>var http = require('http'),
  _ = require("../underscore_ext");

/**
 * Class responsible for tunnelling requests
 */
class Proxy {
  constructor(config) {
    _.bindAll(this, '_handleRequest');

    this._configure.call(this, config);
  }

  /**
   * Listen to port
   */
  listen() {
    this._createServer();
    this.server.listen(this.config.port);
  }

  /**
   * Stops listening
   */
 stop() {
   this.server.close();
  }

  /**
   * Configure redirecter
   */
  _configure(config) {
    let redirecter = this;

    redirecter.config = _.extend({
      port:3330,
      proxy: {
        host: "localhost",
        port: 80
      },
      before:[]
    }, config);

    redirecter.before = _.asArray(config.before);
  }

  /**
   * Initiate server
   */
  _createServer() {
    let redirecter = this;

    redirecter.server = http.createServer(this._handleRequest);
  }

  /**
   * Handles each request piping it to the proxied server
   */
  _handleRequest(request, response){
    if (this._applyBefore(request, response)) {
      this._pipeRequest(request, response);
    }
  }

  _pipeRequest(request, response) {
    request.pipe(this._proxyRequest(request, response));
  }

  _proxyRequest(request, response) {
    var options = {
      headers:  request.headers,
      hostname: this.config.proxy.host,
      port:     this.config.proxy.port,
      method:   request.method,
      path:     request.url
    };

    return http.request(options, function (res) {
      response.writeHead(res.statusCode, res.headers);
      res.pipe(response, {
        end: true
      });
    });
  }

  /**
   * Run before scripts on request
   */
  _applyBefore(request, response){
    let redirecter = this;

    for (var i = 0; i < redirecter.before.length; i++){
      if (! redirecter.before[i].call(redirecter, request, response))
        return false;
    }
    return true;
  }
}

module.exports = function(config){
  redirecter = new Proxy(config);
  return redirecter;
};

module.exports.fn = Proxy.prototype;
<commit_msg>Use singlequote<commit_after>var http = require('http'),
  _ = require('../underscore_ext');

/**
 * Class responsible for tunnelling requests
 */
class Proxy {
  constructor(config) {
    _.bindAll(this, '_handleRequest');

    this._configure.call(this, config);
  }

  /**
   * Listen to port
   */
  listen() {
    this._createServer();
    this.server.listen(this.config.port);
  }

  /**
   * Stops listening
   */
 stop() {
   this.server.close();
  }

  /**
   * Configure redirecter
   */
  _configure(config) {
    let redirecter = this;

    redirecter.config = _.extend({
      port:3330,
      proxy: {
        host: 'localhost',
        port: 80
      },
      before:[]
    }, config);

    redirecter.before = _.asArray(config.before);
  }

  /**
   * Initiate server
   */
  _createServer() {
    let redirecter = this;

    redirecter.server = http.createServer(this._handleRequest);
  }

  /**
   * Handles each request piping it to the proxied server
   */
  _handleRequest(request, response){
    if (this._applyBefore(request, response)) {
      this._pipeRequest(request, response);
    }
  }

  _pipeRequest(request, response) {
    request.pipe(this._proxyRequest(request, response));
  }

  _proxyRequest(request, response) {
    var options = {
      headers:  request.headers,
      hostname: this.config.proxy.host,
      port:     this.config.proxy.port,
      method:   request.method,
      path:     request.url
    };

    return http.request(options, function (res) {
      response.writeHead(res.statusCode, res.headers);
      res.pipe(response, {
        end: true
      });
    });
  }

  /**
   * Run before scripts on request
   */
  _applyBefore(request, response){
    let redirecter = this;

    for (var i = 0; i < redirecter.before.length; i++){
      if (! redirecter.before[i].call(redirecter, request, response))
        return false;
    }
    return true;
  }
}

module.exports = function(config){
  redirecter = new Proxy(config);
  return redirecter;
};

module.exports.fn = Proxy.prototype;
<|endoftext|>


<commit_before>const React = require('react');
const _throttle = require('lodash/throttle');

const NotifyOnScrollThreshold = React.createClass({
  propTypes: {
    children: React.PropTypes.func.isRequired,
    threshold: React.PropTypes.number // Number between 0 and 1 representing 0 to 100%
  },

  getDefaultProps () {
    return {
      threshold: 0.9
    };
  },

  getInitialState () {
    return {
      scrollHeight: 0,
      scrollPosition: 0,
      thresholdMet: false
    };
  },

  componentDidMount () {
    this._handleScroll = _throttle(this._handleScroll, 200);

    this.container.parentElement.addEventListener('scroll', this._handleScroll);

    if (this.container.parentElement.scrollHeight <= this.container.parentElement.clientHeight) {
      this.setState({
        scrollHeight: this.container.parentElement.scrollHeight,
        thresholdMet: true
      });
    }
  },

  componentWillUnmount () {
    this.container.parentElement.removeEventListener('scroll', this._handleScroll);
  },

  _handleScroll (evt) {
    const element = evt.target;
    const heightDifference = element.scrollHeight - element.clientHeight;
    const position = element.scrollTop / heightDifference;
    const scrollHeightIsLessThanElementHeight = element.scrollHeight <= element.clientHeight;
    const thresholdMet = position >= this.props.threshold || scrollHeightIsLessThanElementHeight;

    if (this.state.thresholdMet !== thresholdMet) {
      this.setState({
        scrollHeight: element.scrollHeight,
        scrollPosition: element.scrollTop,
        thresholdMet
      });
    }
  },

  render () {
    return (

 this.container = ref}>
        {this.props.children(this.state.thresholdMet, this.state.scrollPosition, this.state.scrollHeight)}

    );
  }
});

module.exports = NotifyOnScrollThreshold;<commit_msg>Adds onThresholdMet prop to component<commit_after>const React = require('react');
const _throttle = require('lodash/throttle');

const NotifyOnScrollThreshold = React.createClass({
  propTypes: {
    children: React.PropTypes.func.isRequired,
    onThresholdMet: React.PropTypes.func,
    threshold: React.PropTypes.number // Number between 0 and 1 representing 0 to 100%
  },

  getDefaultProps () {
    return {
      onThresholdMet: () => {},
      threshold: 0.9
    };
  },

  getInitialState () {
    return {
      scrollHeight: 0,
      scrollPosition: 0,
      thresholdMet: false
    };
  },

  componentDidMount () {
    this._handleScroll = _throttle(this._handleScroll, 200);

    this.container.parentElement.addEventListener('scroll', this._handleScroll);

    if (this.container.parentElement.scrollHeight <= this.container.parentElement.clientHeight) {
      this.setState({
        scrollHeight: this.container.parentElement.scrollHeight,
        thresholdMet: true
      });
    }
  },

  componentWillUnmount () {
    this.container.parentElement.removeEventListener('scroll', this._handleScroll);
  },

  _handleScroll (evt) {
    const element = evt.target;
    const heightDifference = element.scrollHeight - element.clientHeight;
    const position = element.scrollTop / heightDifference;
    const scrollHeightIsLessThanElementHeight = element.scrollHeight <= element.clientHeight;
    const thresholdMet = position >= this.props.threshold || scrollHeightIsLessThanElementHeight;

    if (this.state.thresholdMet !== thresholdMet) {
      this.setState({
        scrollHeight: element.scrollHeight,
        scrollPosition: element.scrollTop,
        thresholdMet
      }, this.props.onThresholdMet);
    }
  },

  render () {
    return (

 this.container = ref}>
        {this.props.children(this.state.thresholdMet, this.state.scrollPosition, this.state.scrollHeight)}

    );
  }
});

module.exports = NotifyOnScrollThreshold;<|endoftext|>


<commit_before>var mercury = require('../../../index.js');
var backbone = require('backbone');
var h = mercury.h;

var toObserv = require('./observ-backbone.js')

var Item = backbone.Model.extend({
    defaults: {
        name: '',
        value: '',
        color: ''
    }
});

var Items = backbone.Collection.extend({
    model: Item
});

var AppState = backbone.Model.extend({
    defaults: {
        description: '',
        events: {},
        items: []
    }
})

var events = mercury.input(['add'])

var state = new AppState({
    description: 'app state description',
    events: events,
    items: new Items([
        { name: 'one', value: 'first', color: 'red' },
        { name: 'two', value: 'second', color: 'blue' }
    ])
})

events.add(function (data) {
    console.log('wtf', data);
    state.get('items').add(data)
})

window.state = state;

mercury.app(document.body, toObserv(state), render)

function render(state) {
    return h('div', [
        h('h2', state.description),
        h('ul', state.items.map(function (item) {
            return h('li', {
                key: item.cid,
                style: { color: item.color }
            }, [
                h('span', item.name),
                h('input', { value: item.value })
            ])
        })),
        h('div', {
            'data-event': mercury.submitEvent(state.events.add)
        }, [
            h('input', {
                name: 'name',
                placeholder: 'name'
            }),
            h('input', {
                name: 'value',
                placeholder: 'value'
            }),
            h('input', {
                name: 'color',
                placeholder: 'color'
            }),
            h('button', 'add')
        ])
    ])
}
<commit_msg>remove wtf<commit_after>var mercury = require('../../../index.js');
var backbone = require('backbone');
var h = mercury.h;

var toObserv = require('./observ-backbone.js')

var Item = backbone.Model.extend({
    defaults: {
        name: '',
        value: '',
        color: ''
    }
});

var Items = backbone.Collection.extend({
    model: Item
});

var AppState = backbone.Model.extend({
    defaults: {
        description: '',
        events: {},
        items: []
    }
})

var events = mercury.input(['add'])

var state = new AppState({
    description: 'app state description',
    events: events,
    items: new Items([
        { name: 'one', value: 'first', color: 'red' },
        { name: 'two', value: 'second', color: 'blue' }
    ])
})

events.add(function (data) {
    state.get('items').add(data)
})

window.state = state;

mercury.app(document.body, toObserv(state), render)

function render(state) {
    return h('div', [
        h('h2', state.description),
        h('ul', state.items.map(function (item) {
            return h('li', {
                key: item.cid,
                style: { color: item.color }
            }, [
                h('span', item.name),
                h('input', { value: item.value })
            ])
        })),
        h('div', {
            'data-event': mercury.submitEvent(state.events.add)
        }, [
            h('input', {
                name: 'name',
                placeholder: 'name'
            }),
            h('input', {
                name: 'value',
                placeholder: 'value'
            }),
            h('input', {
                name: 'color',
                placeholder: 'color'
            }),
            h('button', 'add')
        ])
    ])
}
<|endoftext|>


<commit_before>'use strict';

angular.module('myApp.homePage', ['ngRoute', 'ui.calendar'])

    .config(['$routeProvider', function ($routeProvider) {
        $routeProvider.when('/homePage', {
            templateUrl: 'homePage/homePage.html',
            controller: 'homePageCtrl'
        });
    }])

    .controller('homePageCtrl', ['$scope', 'homePageFactory', 'announcementFactory', function ($scope, homePageFactory, announcementFactory) {
        $scope.duties;
        $scope.calendarEvents = [];

        announcementFactory.getAnnouncements().then(function (response) {
            $scope.announces = response.data;

            angular.forEach($scope.announces, function (value, key) {
                var temp_object = {
                    title: value.desc,
                    start: value.eventDate
                };
                this.push(temp_object);
            }, $scope.calendarEvents);
        });

        homePageFactory.getDuties().then(function (response) {
            $scope.duties = response.data;
            angular.forEach($scope.duties, function (value, key) {
                var temp_object = {
                    title: value.title,
                    start: value.deadline
                };
                this.push(temp_object);
            }, $scope.calendarEvents);

            //custom filter
            $scope.afterToday = function () {
                return function (item) {
                    return item.start >= new moment().format("YYYY-MM-DD");
                }
            }

            $scope.humanizeTime = function (date) {
                return moment(date, "YYYY-MM-DD").fromNow();
            }
        });

        $scope.eventSources = [{
            events: $scope.calendarEvents
        }
        ];

        $scope.uiConfig = {
            calendar: {
                height: 450,
                header: {
                    left: 'prev,next today',
                    center: 'title',
                    right: 'year month basicWeek'
                },
                dayClick: $scope.alertEventOnClick,
                eventResize: $scope.alertOnResize
            }
        };
    }])

    .factory('homePageFactory', ['$http', function ($http) {
        var service = {};

        service.getDuties = function () {
            return $http.get('accomplish/accomplishData.json');
        };

        return service;
    }])

<commit_msg>fix issue with dissapearing events<commit_after>'use strict';

angular.module('myApp.homePage', ['ngRoute', 'ui.calendar'])

    .config(['$routeProvider', function ($routeProvider) {
        $routeProvider.when('/homePage', {
            templateUrl: 'homePage/homePage.html',
            controller: 'homePageCtrl'
        });
    }])

    .controller('homePageCtrl', ['$scope', 'homePageFactory', 'announcementFactory', function ($scope, homePageFactory, announcementFactory) {
        $scope.duties;
        $scope.calendarEvents = [];

        announcementFactory.getAnnouncements().then(function (response) {
            $scope.announces = response.data;

            angular.forEach($scope.announces, function (value, key) {
                var temp_object = {
                    title: value.desc,
                    start: value.eventDate,
                    stick: true
                };
                this.push(temp_object);
            }, $scope.calendarEvents);
        });

        homePageFactory.getDuties().then(function (response) {
            $scope.duties = response.data;
            angular.forEach($scope.duties, function (value, key) {
                var temp_object = {
                    title: value.title,
                    start: value.deadline,
                    stick: true
                };
                this.push(temp_object);
            }, $scope.calendarEvents);

            //custom filter
            $scope.afterToday = function () {
                return function (item) {
                    return item.start >= new moment().format("YYYY-MM-DD");
                }
            }

            $scope.humanizeTime = function (date) {
                return moment(date, "YYYY-MM-DD").fromNow();
            }
        });

        $scope.eventSources = [{
            events: $scope.calendarEvents
        }
        ];

        $scope.uiConfig = {
            calendar: {
                height: 450,
                header: {
                    left: 'prev,next today',
                    center: 'title',
                    right: 'year month basicWeek'
                },
                dayClick: $scope.alertEventOnClick,
                eventResize: $scope.alertOnResize
            }
        };
    }])

    .factory('homePageFactory', ['$http', function ($http) {
        var service = {};

        service.getDuties = function () {
            return $http.get('accomplish/accomplishData.json');
        };

        return service;
    }])

<|endoftext|>


<commit_before>/* Dashboard plugin for jQuery */
(function($) {
  var _server = null;
  var _url = null;

  function query_data_view(data_view_name, data_view_arguments, callback) {
    _server.query_data_view(callback, data_view_name, data_view_arguments);
  }

  var methods = {
    init: function(url, callback) {
      if (_server == null) {
        _url = url;
        _server = $.rpc(url, "xml", callback, "2.0");
      }
      return _server;
    },

    graph: function(options) {
      return this.each(function() {
        var $this = $(this);
        var plot_data = {
          options: options,
          series: []
        };
        $this.data('dashboard', plot_data);
        $.plot($this, plot_data.series, plot_data.options);
      });
    },

    add_series: function(query) {
      return this.each(function() {
        var $this = $(this);
        var plot_data = $this.data('dashboard');
        if (!plot_data) {
          plot_data = {
            options: {},
            series: []
          };
          $this.data('dashboard', plot_data);
        }
        query_data_view(query.data_view.name, query.data_view.args, function(response) {
          plot_data.series.push({
            data: response.result.rows,
            label: query.label
          });
          $.plot($this, plot_data.series, plot_data.options);
        });
      });
    },

    render_table: function(dataset, options) {
      var html = "
";
      if (options.caption != undefined) {
        html += "
" + options.caption + "
";
      }
      html += "
";
      $.each(dataset.columns, function (index, column) {
        html += "" + column.name + "	";
      });
      html += "
";
      $.each(dataset.rows, function (index, row) {
        html += "
";
        $.each(row, function (index, cell) {
          var column = dataset.columns[index];
          var cell_html = undefined;
          var cell_link = null;
          if (cell_html == undefined) {
            cell_html = cell;
          }
          if (column.name == "UUID") {
            /* This is a bit hacky but will work for now */
            cell_link = _url + ".." + "/test-runs/" + cell + "/";
          }
          html += "";
          if (cell_link) {
            html += ""
            html += cell_html;
            html += "";
          } else {
            html += cell_html;
          }
          html += "	";
        });
        html += "
";
      });
      html += "
";
      this.html(html);
    },

    render_to_table: function(data_view_name, data_view_arguments, options) {
      var outer = this;
      _server.query_data_view(function (response) {
        if (response.result) {
          outer.dashboard("render_table", response.result, options);
        } else {
          outer.html("Error code:" + response.error.faultCode + ", message: " + response.error.faultString);
        }
      }, data_view_name, data_view_arguments);
    }

  };

  $.fn.dashboard = function(method) {
    if (methods[method]) {
      return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
    } else if (typeof method == "object" || !method) {
      return methods.init.apply(this, arguments);
    } else {
      $.error("Method " + method + "does not exist on jQuery.dashboard");
    }
  };
})(jQuery);
<commit_msg>Minor style change<commit_after>/* Dashboard plugin for jQuery */
(function($) {
  var _server = null;
  var _url = null;

  function query_data_view(data_view_name, data_view_arguments, callback) {
    _server.query_data_view(callback, data_view_name, data_view_arguments);
  }

  var methods = {
    init: function(url, callback) {
      if (_server == null) {
        _url = url;
        _server = $.rpc(url, "xml", callback, "2.0");
      }
      return _server;
    },

    graph: function(options) {
      return this.each(function() {
        var $this = $(this);
        var plot_data = {
          options: options,
          series: []
        };
        $this.data('dashboard', plot_data);
        $.plot($this, plot_data.series, plot_data.options);
      });
    },

    add_series: function(query) {
      return this.each(function() {
        var $this = $(this);
        var plot_data = $this.data('dashboard');
        if (!plot_data) {
          plot_data = {
            options: {},
            series: []
          };
          $this.data('dashboard', plot_data);
        }
        query_data_view(query.data_view.name, query.data_view.args, function(response) {
          plot_data.series.push({
            data: response.result.rows,
            label: query.label
          });
          $.plot($this, plot_data.series, plot_data.options);
        });
      });
    },

    render_table: function(dataset, options) {
      var html = "
";
      if (options.caption != undefined) {
        html += "
" + options.caption + "
";
      }
      html += "
";
      $.each(dataset.columns, function (index, column) {
        html += "" + column.name + "	";
      });
      html += "
";
      $.each(dataset.rows, function (index, row) {
        html += "
";
        $.each(row, function (index, cell) {
          var column = dataset.columns[index];
          var cell_html = undefined;
          var cell_link = null;
          if (cell_html == undefined) {
            cell_html = cell;
          }
          if (column.name == "UUID") {
            /* This is a bit hacky but will work for now */
            cell_link = _url + ".." + "/test-runs/" + cell + "/";
          }
          html += "";
          if (cell_link) {
            html += ""
            html += cell_html;
            html += "";
          } else {
            html += cell_html;
          }
          html += "	";
        });
        html += "
";
      });
      html += "
";
      this.html(html);
    },

    render_to_table: function(data_view_name, data_view_arguments, options) {
      var $this = $(this);
      _server.query_data_view(function (response) {
        if (response.result) {
          $this.dashboard("render_table", response.result, options);
        } else {
          $this.html("Error code:" + response.error.faultCode + ", message: " + response.error.faultString);
        }
      }, data_view_name, data_view_arguments);
    }

  };

  $.fn.dashboard = function(method) {
    if (methods[method]) {
      return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
    } else if (typeof method == "object" || !method) {
      return methods.init.apply(this, arguments);
    } else {
      $.error("Method " + method + "does not exist on jQuery.dashboard");
    }
  };
})(jQuery);
<|endoftext|>


<commit_before>/**
* Parent for the AJAX requests, provides default success and error handlers
*/
enyo.kind({
  name: 'AJAX.Parent'
  , kind: 'enyo.Ajax'
  , handleAs: "json"
  , dataType: "json"
  , contentType:"application/json"
  , url: ''
  , callback: '?'
  , cacheBust: false
  , data: {}
  ,crossDomain: true
  , headers: [{'Access-Control-Allow-Credentials':true}]
  , beforeSend: function(xhr){
       xhr.withCredentials = true;
  }
  , xhrFields: {withCredentials : true}
  , published: {
     owner: null
     , fireEvent: null
  }
  , constructor: function (props) {
      this.inherited(arguments);
      // properties mapped to published attributes get set
      console.log("AJAX.Parent " + this.fireEvent)
  }
  , makeRequest: function (params) {
      console.log('AJAX.Parent makeRequest ' + JSON.stringify(params));
      this.url = this.buildBaseURL() + this.rest;

      // attach responders to the transaction object
      this.response(this, "processResponse");
      this.error(this, "processError");

      // send parameters the remote service using the 'go()' method
      if (this.method == 'GET') {
        this.data = params;
      } else {
        this.postBody = JSON.stringify(params);
      }
      this.go(this.data);
  }
  , buildBaseURL: function() {
    return mvcApp.getAjaxBaseURL() + ':' + mvcApp.getAjaxBasePort();
  }
});
<commit_msg>User signup working, still need to figure out CORS issue with server<commit_after>/**
* Parent for the AJAX requests, provides default success and error handlers
*/
enyo.kind({
  name: 'AJAX.Parent'
  , kind: 'enyo.Ajax'
  , handleAs: "json"
  , dataType: "json"
  , contentType:"application/json"
  , url: ''
  , callback: '?'
  , cacheBust: false
  , data: {}
//  , crossDomain: true
//  , headers: [{'Access-Control-Allow-Credentials':true}]
//  , beforeSend: function(xhr){
//       xhr.withCredentials = true;
//  }
  , xhrFields: {withCredentials : true}
  , published: {
     owner: null
     , fireEvent: null
  }
  , constructor: function (props) {
      this.inherited(arguments);
      // properties mapped to published attributes get set
      console.log("AJAX.Parent " + this.fireEvent)
  }
  , makeRequest: function (params) {
      console.log('AJAX.Parent makeRequest ' + JSON.stringify(params));
      this.url = this.buildBaseURL() + this.rest;

      // attach responders to the transaction object
      this.response(this, "processResponse");
      this.error(this, "processError");

      // send parameters the remote service using the 'go()' method
      if (this.method == 'GET') {
        this.data = params;
      } else {
        this.postBody = JSON.stringify(params);
      }
      this.go(this.data);
  }
  , buildBaseURL: function() {
    return mvcApp.getAjaxBaseURL() + ':' + mvcApp.getAjaxBasePort();
  }
});
<|endoftext|>


<commit_before>
var os = require('os');

var agent = require('cast-agent/entry');
var norris = require('norris');
var http = require('services/http');
var httputil = require('util/http');
var version = require('util/version');

var route = http.route;

function info(req, res) {
  var date_started = agent.date_started;
  var current_date = new Date();
  var uptime = (current_date.getTime() / 1000) - (date_started.getTime() / 1000);

  norris.get(function(facts) {
    var info = {
      'agent_version': version.toString(),
      'node_version': process.version,
      'api_version': http.CURRENT_API_VERSION,
      'hostname': facts.hostname,
      'architecture': facts.arch,
      'os': os.release(),
      'memory': os.totalmem(),
      'os_uptime': os.uptime(),
      'agent_uptime': uptime
    };

    httputil.return_json(res, 200, info);
  });
}

exports.urls = route([
   ['GET /$', '1.0', info]
]);
<commit_msg>Add missing license header.<commit_after>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var os = require('os');

var agent = require('cast-agent/entry');
var norris = require('norris');
var http = require('services/http');
var httputil = require('util/http');
var version = require('util/version');

var route = http.route;

function info(req, res) {
  var date_started = agent.date_started;
  var current_date = new Date();
  var uptime = (current_date.getTime() / 1000) - (date_started.getTime() / 1000);

  norris.get(function(facts) {
    var info = {
      'agent_version': version.toString(),
      'node_version': process.version,
      'api_version': http.CURRENT_API_VERSION,
      'hostname': facts.hostname,
      'architecture': facts.arch,
      'os': os.release(),
      'memory': os.totalmem(),
      'os_uptime': os.uptime(),
      'agent_uptime': uptime
    };

    httputil.return_json(res, 200, info);
  });
}

exports.urls = route([
   ['GET /$', '1.0', info]
]);
<|endoftext|>


<commit_before>/**
 * jquery.tinymce.js
 *
 * Copyright 2009, Moxiecode Systems AB
 * Released under LGPL License.
 *
 * License: http://tinymce.moxiecode.com/license
 * Contributing: http://tinymce.moxiecode.com/contributing
 */

(function($) {
	var undefined,
		lazyLoading,
		delayedInits = [],
		win = window;

	$.fn.tinymce = function(settings) {
		var self = this, url, ed, base, pos, lang, query = "", suffix = "";

		// No match then just ignore the call
		if (!self.length)
			return;

		// Get editor instance
		if (!settings)
			return tinyMCE.get(self[0].id);

		function init() {
			var editors = [], initCount = 0;

			// Apply patches to the jQuery object, only once
			if (applyPatch) {
				applyPatch();
				applyPatch = null;
			}

			// Create an editor instance for each matched node
			self.each(function(i, node) {
				var ed, id = node.id, oninit = settings.oninit;

				// Generate unique id for target element if needed
				if (!id)
					node.id = id = tinymce.DOM.uniqueId();

				// Create editor instance and render it
				ed = new tinymce.Editor(id, settings);
				editors.push(ed);

				// Add onInit event listener if the oninit setting is defined
				// this logic will fire the oninit callback ones each
				// matched editor instance is initialized
				if (oninit) {
					ed.onInit.add(function() {
						var scope, func = oninit;

						// Fire the oninit event ones each editor instance is initialized
						if (++initCount == editors.length) {
							if (tinymce.is(func, "string")) {
								scope = (func.indexOf(".") === -1) ? null : tinymce.resolve(func.replace(/\.\w+$/, ""));
								func = tinymce.resolve(func);
							}

							// Call the oninit function with the object
							func.apply(scope || tinymce, editors);
						}
					});
				}
			});

			// Render the editor instances in a separate loop since we
			// need to have the full editors array used in the onInit calls
			$.each(editors, function(i, ed) {
				ed.render();
			});
		}

		// Load TinyMCE on demand, if we need to
		if (!win["tinymce"] && !lazyLoading && (url = settings.script_url)) {
			lazyLoading = 1;
			base = url.substring(0, url.lastIndexOf("/"));

			// Check if it's a dev/src version they want to load then
			// make sure that all plugins, themes etc are loaded in source mode aswell
			if (/_(src|dev)\.js/g.test(url))
				suffix = "_src";

			// Parse out query part, this will be appended to all scripts, css etc to clear browser cache
			pos = url.lastIndexOf("?");
			if (pos != -1)
				query = url.substring(pos + 1);

			// Setup tinyMCEPreInit object this will later be used by the TinyMCE
			// core script to locate other resources like CSS files, dialogs etc
			win.tinyMCEPreInit = {
				base : base,
				suffix : suffix,
				query : query
			};

			// url contains gzip then we assume it's a compressor
			if (url.indexOf('gzip') != -1) {
				lang = settings.language || "en";
				url = url + (/\?/.test(url) ? '&' : '?') + "js=true&core=true&suffix=" + escape(suffix) + "&themes=" + escape(settings.theme) + "&plugins=" + escape(settings.plugins) + "&languages=" + lang;

				// Check if compressor script is already loaded otherwise setup a basic one
				if (!win["tinyMCE_GZ"]) {
					tinyMCE_GZ = {
						start : function() {
							tinymce.suffix = suffix;

							function load(url) {
								tinymce.ScriptLoader.markDone(tinyMCE.baseURI.toAbsolute(url));
							}

							// Add core languages
							load("langs/" + lang + ".js");

							// Add themes with languages
							load("themes/" + settings.theme + "/editor_template" + suffix + ".js");
							load("themes/" + settings.theme + "/langs/" + lang + ".js");

							// Add plugins with languages
							$.each(settings.plugins.split(","), function(i, name) {
								if (name) {
									load("plugins/" + name + "/editor_plugin" + suffix + ".js");
									load("plugins/" + name + "/langs/" + lang + ".js");
								}
							});
						},

						end : function() {
						}
					}
				}
			}

			// Load the script cached and execute the inits once it's done
			$.ajax({
				type : "GET",
				url : url,
				dataType : "script",
				cache : true,
				success : function() {
					tinymce.dom.Event.domLoaded = 1;
					lazyLoading = 2;
					init();

					$.each(delayedInits, function(i, init) {
						init();
					});
				}
			});
		} else {
			// Delay the init call until tinymce is loaded
			if (lazyLoading === 1)
				delayedInits.push(init);
			else
				init();
		}
	};

	// Add :tinymce psuedo selector this will select elements that has been converted into editor instances
	// it's now possible to use things like $('*:tinymce') to get all TinyMCE bound elements.
	$.extend($.expr[":"], {
		tinymce : function(e) {
			return e.id && !!tinyMCE.get(e.id);
		}
	});

	// This function patches internal jQuery functions so that if
	// you for example remove an div element containing an editor it's
	// automatically destroyed by the TinyMCE API
	function applyPatch() {
		// Removes any child editor instances by looking for editor wrapper elements
		function removeEditors() {
			this.find("span.mceEditor,div.mceEditor").each(function(i, node) {
				var ed = tinyMCE.get(node.id.replace(/_parent$/, ""));

				if (ed)
					ed.remove();
			});
		}

		// Loads or saves contents from/to textarea if the value
		// argument is defined it will set the TinyMCE internal contents
		function loadOrSave(value) {
			var self = this, ed;

			// Handle set value
			if (value !== undefined) {
				removeEditors.call(self);

				// Saves the contents before get/set value of textarea/div
				self.each(function(i, node) {
					var ed;

					if (ed = tinyMCE.get(node.id))
						ed.setContent(value);
				});
			} else if (self.length > 0) {
				// Handle get value
				if (ed = tinyMCE.get(self[0].id))
					return ed.getContent();
			}
		}

		// Returns tinymce instance for the specified element or null if it wasn't found
		function tinyMCEInstance(element) {
			var ed = null;

			(element) && (element.id) && (win["tinymce"]) && (ed = tinyMCE.get(element.id));

			return ed;
		}

		// Checks if the specified set contains tinymce instances
		function containsTinyMCE(matchedSet) {
			return !!((matchedSet) && (matchedSet.length) && (win["tinymce"]) && (matchedSet.is(":tinymce")));
		}

		// Patch various jQuery functions
		var jQueryFn = {};

		// Patch some setter/getter functions these will
		// now be able to set/get the contents of editor instances for
		// example $('#editorid').html('Content'); will update the TinyMCE iframe instance
		$.each(["text", "html", "val"], function(i, name) {
			var origFn = jQueryFn[name] = $.fn[name],
				textProc = (name === "text");

			 $.fn[name] = function(value) {
				var self = this;

				if (!containsTinyMCE(self))
					return origFn.call(self, value);

				if (value !== undefined) {
					loadOrSave.call(self.filter(":tinymce"), value);
					origFn.call(self.not(":tinymce"), value);

					return self; // return original set for chaining
				} else {
					var ret = "";

					(textProc ? self : self.eq(0)).each(function(i, node) {
						var ed = tinyMCEInstance(node);

						ret += ed ? (textProc ? ed.getContent().replace(/<(?:"[^"]*"|'[^']*'|[^'">])*>/g, "") : ed.getContent()) : origFn.call($(node), value);
					});

					return ret;
				}
			 };
		});

		// Makes it possible to use $('#id').append("content"); to append contents to the TinyMCE editor iframe
		$.each(["append", "prepend"], function(i, name) {
			var origFn = jQueryFn[name] = $.fn[name],
				prepend = (name === "prepend");

			 $.fn[name] = function(value) {
				var self = this;

				if (!containsTinyMCE(self))
					return origFn.call(self, value);

				if (value !== undefined) {
					self.filter(":tinymce").each(function(i, node) {
						var ed = tinyMCEInstance(node);

						ed && ed.setContent(prepend ? value + ed.getContent() : ed.getContent() + value);
					});

					origFn.call(self.not(":tinymce"), value);

					return self; // return original set for chaining
				}
			 };
		});

		// Makes sure that the editor instance gets properly destroyed when the parent element is removed
		$.each(["remove", "replaceWith", "replaceAll", "empty"], function(i, name) {
			var origFn = jQueryFn[name] = $.fn[name];

			$.fn[name] = function() {
				removeEditors.apply(this);

				return origFn.apply(this, arguments);
			};
		});

		jQueryFn.attr = $.fn.attr;

		// Makes sure that $('#tinymce_id').attr('value') gets the editors current HTML contents
		$.fn.attr = function(name, value, type) {
			var self = this;

			if ((!name) || (name !== "value") || (!containsTinyMCE(self)))
				return jQueryFn.attr.call(self, name, value, type);

			if (value !== undefined) {
				loadOrSave.call(self.filter(":tinymce"), value);
				jQueryFn.attr.call(self.not(":tinymce"), name, value, type);

				return self; // return original set for chaining
			} else {
				var node = self[0], ed = tinyMCEInstance(node);

				return ed ? ed.getContent() : jQueryFn.attr.call($(node), name, value, type);
			}
		};
	}
})(jQuery);<commit_msg>Fixed so the tinymce instance is removed when the textarea is removed by jQuery.<commit_after>/**
 * jquery.tinymce.js
 *
 * Copyright 2009, Moxiecode Systems AB
 * Released under LGPL License.
 *
 * License: http://tinymce.moxiecode.com/license
 * Contributing: http://tinymce.moxiecode.com/contributing
 */

(function($) {
	var undefined,
		lazyLoading,
		delayedInits = [],
		win = window;

	$.fn.tinymce = function(settings) {
		var self = this, url, ed, base, pos, lang, query = "", suffix = "";

		// No match then just ignore the call
		if (!self.length)
			return;

		// Get editor instance
		if (!settings)
			return tinyMCE.get(self[0].id);

		function init() {
			var editors = [], initCount = 0;

			// Apply patches to the jQuery object, only once
			if (applyPatch) {
				applyPatch();
				applyPatch = null;
			}

			// Create an editor instance for each matched node
			self.each(function(i, node) {
				var ed, id = node.id, oninit = settings.oninit;

				// Generate unique id for target element if needed
				if (!id)
					node.id = id = tinymce.DOM.uniqueId();

				// Create editor instance and render it
				ed = new tinymce.Editor(id, settings);
				editors.push(ed);

				// Add onInit event listener if the oninit setting is defined
				// this logic will fire the oninit callback ones each
				// matched editor instance is initialized
				if (oninit) {
					ed.onInit.add(function() {
						var scope, func = oninit;

						// Fire the oninit event ones each editor instance is initialized
						if (++initCount == editors.length) {
							if (tinymce.is(func, "string")) {
								scope = (func.indexOf(".") === -1) ? null : tinymce.resolve(func.replace(/\.\w+$/, ""));
								func = tinymce.resolve(func);
							}

							// Call the oninit function with the object
							func.apply(scope || tinymce, editors);
						}
					});
				}
			});

			// Render the editor instances in a separate loop since we
			// need to have the full editors array used in the onInit calls
			$.each(editors, function(i, ed) {
				ed.render();
			});
		}

		// Load TinyMCE on demand, if we need to
		if (!win["tinymce"] && !lazyLoading && (url = settings.script_url)) {
			lazyLoading = 1;
			base = url.substring(0, url.lastIndexOf("/"));

			// Check if it's a dev/src version they want to load then
			// make sure that all plugins, themes etc are loaded in source mode aswell
			if (/_(src|dev)\.js/g.test(url))
				suffix = "_src";

			// Parse out query part, this will be appended to all scripts, css etc to clear browser cache
			pos = url.lastIndexOf("?");
			if (pos != -1)
				query = url.substring(pos + 1);

			// Setup tinyMCEPreInit object this will later be used by the TinyMCE
			// core script to locate other resources like CSS files, dialogs etc
			win.tinyMCEPreInit = {
				base : base,
				suffix : suffix,
				query : query
			};

			// url contains gzip then we assume it's a compressor
			if (url.indexOf('gzip') != -1) {
				lang = settings.language || "en";
				url = url + (/\?/.test(url) ? '&' : '?') + "js=true&core=true&suffix=" + escape(suffix) + "&themes=" + escape(settings.theme) + "&plugins=" + escape(settings.plugins) + "&languages=" + lang;

				// Check if compressor script is already loaded otherwise setup a basic one
				if (!win["tinyMCE_GZ"]) {
					tinyMCE_GZ = {
						start : function() {
							tinymce.suffix = suffix;

							function load(url) {
								tinymce.ScriptLoader.markDone(tinyMCE.baseURI.toAbsolute(url));
							}

							// Add core languages
							load("langs/" + lang + ".js");

							// Add themes with languages
							load("themes/" + settings.theme + "/editor_template" + suffix + ".js");
							load("themes/" + settings.theme + "/langs/" + lang + ".js");

							// Add plugins with languages
							$.each(settings.plugins.split(","), function(i, name) {
								if (name) {
									load("plugins/" + name + "/editor_plugin" + suffix + ".js");
									load("plugins/" + name + "/langs/" + lang + ".js");
								}
							});
						},

						end : function() {
						}
					}
				}
			}

			// Load the script cached and execute the inits once it's done
			$.ajax({
				type : "GET",
				url : url,
				dataType : "script",
				cache : true,
				success : function() {
					tinymce.dom.Event.domLoaded = 1;
					lazyLoading = 2;
					init();

					$.each(delayedInits, function(i, init) {
						init();
					});
				}
			});
		} else {
			// Delay the init call until tinymce is loaded
			if (lazyLoading === 1)
				delayedInits.push(init);
			else
				init();
		}
	};

	// Add :tinymce psuedo selector this will select elements that has been converted into editor instances
	// it's now possible to use things like $('*:tinymce') to get all TinyMCE bound elements.
	$.extend($.expr[":"], {
		tinymce : function(e) {
			return e.id && !!tinyMCE.get(e.id);
		}
	});

	// This function patches internal jQuery functions so that if
	// you for example remove an div element containing an editor it's
	// automatically destroyed by the TinyMCE API
	function applyPatch() {
		// Removes any child editor instances by looking for editor wrapper elements
		function removeEditors(remove) {
			// If the function is remove
			if (remove) {
				this.each(function(i, node) {
					var ed = tinyMCEInstance(node);

					if (ed)
						ed.remove();
				});
			}

			this.find("span.mceEditor,div.mceEditor").each(function(i, node) {
				var ed = tinyMCE.get(node.id.replace(/_parent$/, ""));

				if (ed)
					ed.remove();
			});
		}

		// Loads or saves contents from/to textarea if the value
		// argument is defined it will set the TinyMCE internal contents
		function loadOrSave(value) {
			var self = this, ed;

			// Handle set value
			if (value !== undefined) {
				removeEditors.call(self);

				// Saves the contents before get/set value of textarea/div
				self.each(function(i, node) {
					var ed;

					if (ed = tinyMCE.get(node.id))
						ed.setContent(value);
				});
			} else if (self.length > 0) {
				// Handle get value
				if (ed = tinyMCE.get(self[0].id))
					return ed.getContent();
			}
		}

		// Returns tinymce instance for the specified element or null if it wasn't found
		function tinyMCEInstance(element) {
			var ed = null;

			(element) && (element.id) && (win["tinymce"]) && (ed = tinyMCE.get(element.id));

			return ed;
		}

		// Checks if the specified set contains tinymce instances
		function containsTinyMCE(matchedSet) {
			return !!((matchedSet) && (matchedSet.length) && (win["tinymce"]) && (matchedSet.is(":tinymce")));
		}

		// Patch various jQuery functions
		var jQueryFn = {};

		// Patch some setter/getter functions these will
		// now be able to set/get the contents of editor instances for
		// example $('#editorid').html('Content'); will update the TinyMCE iframe instance
		$.each(["text", "html", "val"], function(i, name) {
			var origFn = jQueryFn[name] = $.fn[name],
				textProc = (name === "text");

			 $.fn[name] = function(value) {
				var self = this;

				if (!containsTinyMCE(self))
					return origFn.call(self, value);

				if (value !== undefined) {
					loadOrSave.call(self.filter(":tinymce"), value);
					origFn.call(self.not(":tinymce"), value);

					return self; // return original set for chaining
				} else {
					var ret = "";

					(textProc ? self : self.eq(0)).each(function(i, node) {
						var ed = tinyMCEInstance(node);

						ret += ed ? (textProc ? ed.getContent().replace(/<(?:"[^"]*"|'[^']*'|[^'">])*>/g, "") : ed.getContent()) : origFn.call($(node), value);
					});

					return ret;
				}
			 };
		});

		// Makes it possible to use $('#id').append("content"); to append contents to the TinyMCE editor iframe
		$.each(["append", "prepend"], function(i, name) {
			var origFn = jQueryFn[name] = $.fn[name],
				prepend = (name === "prepend");

			 $.fn[name] = function(value) {
				var self = this;

				if (!containsTinyMCE(self))
					return origFn.call(self, value);

				if (value !== undefined) {
					self.filter(":tinymce").each(function(i, node) {
						var ed = tinyMCEInstance(node);

						ed && ed.setContent(prepend ? value + ed.getContent() : ed.getContent() + value);
					});

					origFn.call(self.not(":tinymce"), value);

					return self; // return original set for chaining
				}
			 };
		});

		// Makes sure that the editor instance gets properly destroyed when the parent element is removed
		$.each(["remove", "replaceWith", "replaceAll", "empty"], function(i, name) {
			var origFn = jQueryFn[name] = $.fn[name];

			$.fn[name] = function() {
				removeEditors.apply(this, name === "remove");

				return origFn.apply(this, arguments);
			};
		});

		jQueryFn.attr = $.fn.attr;

		// Makes sure that $('#tinymce_id').attr('value') gets the editors current HTML contents
		$.fn.attr = function(name, value, type) {
			var self = this;

			if ((!name) || (name !== "value") || (!containsTinyMCE(self)))
				return jQueryFn.attr.call(self, name, value, type);

			if (value !== undefined) {
				loadOrSave.call(self.filter(":tinymce"), value);
				jQueryFn.attr.call(self.not(":tinymce"), name, value, type);

				return self; // return original set for chaining
			} else {
				var node = self[0], ed = tinyMCEInstance(node);

				return ed ? ed.getContent() : jQueryFn.attr.call($(node), name, value, type);
			}
		};
	}
})(jQuery);<|endoftext|>


<commit_before>Package.describe({
  summary: "Make HTTP calls to remote servers",
  version: '1.4.3-beta200.9'
});

Npm.depends({
  request: "2.88.0"
});

Package.onUse(function (api) {
  api.use([
    'url',
    // This package intentionally does not depend on ecmascript, so that
    // ecmascript and its dependencies can depend on http without creating
    // package dependency cycles.
    'modules',
    'logging' // For deprecation message
  ]);

  api.mainModule('httpcall_client.js', 'client');
  api.mainModule('httpcall_server.js', 'server');

  api.export('HTTP');
  api.export('HTTPInternals', 'server');
});

Package.onTest(function (api) {
  api.use('ecmascript');
  api.use('webapp', 'server');
  api.use('underscore');
  api.use('random');
  api.use('http', ['client', 'server']);
  api.use('tinytest');
  api.use('test-helpers', ['client', 'server']);

  api.addFiles('test_responder.js', 'server');
  api.addFiles('httpcall_tests.js', ['client', 'server']);

  api.addAssets('test_static.serveme', 'client');
});
<commit_msg>publishes http@1.4.3, this package is deprecated now and so it does not need to be released as part of a Meteor release<commit_after>Package.describe({
  summary: "Make HTTP calls to remote servers",
  version: '1.4.3'
});

Npm.depends({
  request: "2.88.0"
});

Package.onUse(function (api) {
  api.versionsFrom('1.12.1');
  api.use([
    'url',
    // This package intentionally does not depend on ecmascript, so that
    // ecmascript and its dependencies can depend on http without creating
    // package dependency cycles.
    'modules',
    'logging' // For deprecation message
  ]);

  api.mainModule('httpcall_client.js', 'client');
  api.mainModule('httpcall_server.js', 'server');

  api.export('HTTP');
  api.export('HTTPInternals', 'server');
});

Package.onTest(function (api) {
  api.use('ecmascript');
  api.use('webapp', 'server');
  api.use('underscore');
  api.use('random');
  api.use('http', ['client', 'server']);
  api.use('tinytest');
  api.use('test-helpers', ['client', 'server']);

  api.addFiles('test_responder.js', 'server');
  api.addFiles('httpcall_tests.js', ['client', 'server']);

  api.addAssets('test_static.serveme', 'client');
});
<|endoftext|>


<commit_before>var mumuki = mumuki || {};

(function (mumuki) {
    $(function () {
        var token = new mumuki.CsrfToken();
        // setInterval(function () {
        //   if ($('.badge-comments').length == 0) {
        //     return;
        //   }
        //   $.ajax(token.newRequest({
        //       url: '/comments',
        //       type: 'GET'
        //     })).
        //     done(function (res) {
        //       $('.badge-comments').html(res.comments_count);
        //       $('.comments-box').toggleClass('comments-box-empty', !res.has_comments);
        //     }).
        //     fail(function (_error) {
        //       //ignoring error, not important
        //     });
        // }, 60000);
    });
}(mumuki));
<commit_msg>Revert "Comment comments ajax"<commit_after>var mumuki = mumuki || {};

(function (mumuki) {
  $(function () {
    var token = new mumuki.CsrfToken();
    setInterval(function () {
      if ($('.badge-comments').length == 0) {
        return;
      }
      $.ajax(token.newRequest({
          url: '/comments',
          type: 'GET'
        })).
        done(function (res) {
          $('.badge-comments').html(res.comments_count);
          $('.comments-box').toggleClass('comments-box-empty', !res.has_comments);
        }).
        fail(function (_error) {
          //ignoring error, not important
        });
    }, 60000);
  });
}(mumuki));
<|endoftext|>


<commit_before>/* document.getElementsBySelector(selector)
   - returns an array of element objects from the current document
     matching the CSS selector. Selectors can contain element names,
     class names and ids and can be nested. For example:

       elements = document.getElementsBySelect('div#main p a.external')

     Will return an array of all 'a' elements with 'external' in their
     class attribute that are contained inside 'p' elements that are
     contained inside the 'div' element which has id="main"

   New in version 0.4: Support for CSS2 and CSS3 attribute selectors:
   See http://www.w3.org/TR/css3-selectors/#attribute-selectors

   Version 0.4 - Simon Willison, March 25th 2003
   -- Works in Phoenix 0.5, Mozilla 1.3, Opera 7, Internet Explorer 6, Internet Explorer 5 on Windows
   -- Opera 7 fails
*/

function getAllChildren(e) {
  // Returns all children of element. Workaround required for IE5/Windows. Ugh.
  return e.all ? e.all : e.getElementsByTagName('*');
}

document.getElementsBySelector = function(selector) {
  // Attempt to fail gracefully in lesser browsers
  if (!document.getElementsByTagName) {
    return new Array();
  }
  // Split selector in to tokens
  var tokens = selector.split(' ');
  var currentContext = new Array(document);
  for (var i = 0; i < tokens.length; i++) {
    token = tokens[i].replace(/^\s+/,'').replace(/\s+$/,'');;
    if (token.indexOf('#') > -1) {
      // Token is an ID selector
      var bits = token.split('#');
      var tagName = bits[0];
      var id = bits[1];
      var element = document.getElementById(id);
      //if (tagName && element.nodeName.toLowerCase() != tagName) {
      if (!element || (tagName && element.nodeName.toLowerCase() != tagName))
        // tag with that ID not found, return false
        return new Array();
      }
      // Set currentContext to contain just this element
      currentContext = new Array(element);
      continue; // Skip to next token
    }
    if (token.indexOf('.') > -1) {
      // Token contains a class selector
      var bits = token.split('.');
      var tagName = bits[0];
      var className = bits[1];
      if (!tagName) {
        tagName = '*';
      }
      // Get elements matching tag, filter them for class selector
      var found = new Array;
      var foundCount = 0;
      for (var h = 0; h < currentContext.length; h++) {
        var elements;
        if (tagName == '*') {
            elements = getAllChildren(currentContext[h]);
        } else {
            try {
                elements = currentContext[h].getElementsByTagName(tagName);
            }
            catch(e) {
                elements = [];
            }
        }
        for (var j = 0; j < elements.length; j++) {
          found[foundCount++] = elements[j];
        }
      }
      currentContext = new Array;
      var currentContextIndex = 0;
      for (var k = 0; k < found.length; k++) {
        if (found[k].className && found[k].className.match(new RegExp('\\b'+className+'\\b'))) {
          currentContext[currentContextIndex++] = found[k];
        }
      }
      continue; // Skip to next token
    }
    // Code to deal with attribute selectors
    if (token.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) {
      var tagName = RegExp.$1;
      var attrName = RegExp.$2;
      var attrOperator = RegExp.$3;
      var attrValue = RegExp.$4;
      if (!tagName) {
        tagName = '*';
      }
      // Grab all of the tagName elements within current context
      var found = new Array;
      var foundCount = 0;
      for (var h = 0; h < currentContext.length; h++) {
        var elements;
        if (tagName == '*') {
            elements = getAllChildren(currentContext[h]);
        } else {
            elements = currentContext[h].getElementsByTagName(tagName);
        }
        for (var j = 0; j < elements.length; j++) {
          found[foundCount++] = elements[j];
        }
      }
      currentContext = new Array;
      var currentContextIndex = 0;
      var checkFunction; // This function will be used to filter the elements
      switch (attrOperator) {
        case '=': // Equality
          checkFunction = function(e) { return (e.getAttribute(attrName) == attrValue); };
          break;
        case '~': // Match one of space seperated words
          checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('\\b'+attrValue+'\\b'))); };
          break;
        case '|': // Match start with value followed by optional hyphen
          checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('^'+attrValue+'-?'))); };
          break;
        case '^': // Match starts with value
          checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) == 0); };
          break;
        case '$': // Match ends with value - fails with "Warning" in Opera 7
          checkFunction = function(e) { return (e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length); };
          break;
        case '*': // Match ends with value
          checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) > -1); };
          break;
        default :
          // Just test for existence of attribute
          checkFunction = function(e) { return e.getAttribute(attrName); };
      }
      currentContext = new Array;
      var currentContextIndex = 0;
      for (var k = 0; k < found.length; k++) {
        if (checkFunction(found[k])) {
          currentContext[currentContextIndex++] = found[k];
        }
      }
      // alert('Attribute Selector: '+tagName+' '+attrName+' '+attrOperator+' '+attrValue);
      continue; // Skip to next token
    }
    // If we get here, token is JUST an element (not a class or ID selector)
    tagName = token;
    var found = new Array;
    var foundCount = 0;
    for (var h = 0; h < currentContext.length; h++) {
      var elements = currentContext[h].getElementsByTagName(tagName);
      for (var j = 0; j < elements.length; j++) {
        found[foundCount++] = elements[j];
      }
    }
    currentContext = found;
  }
  return currentContext;
}

/* That revolting regular expression explained
/^(\w+)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/
  \---/  \---/\-------------/    \-------/
    |      |         |               |
    |      |         |           The value
    |      |    ~,|,^,$,* or =
    |   Attribute
   Tag
*/
<commit_msg>fixes issue 186<commit_after>/* document.getElementsBySelector(selector)
   - returns an array of element objects from the current document
     matching the CSS selector. Selectors can contain element names,
     class names and ids and can be nested. For example:

       elements = document.getElementsBySelect('div#main p a.external')

     Will return an array of all 'a' elements with 'external' in their
     class attribute that are contained inside 'p' elements that are
     contained inside the 'div' element which has id="main"

   New in version 0.4: Support for CSS2 and CSS3 attribute selectors:
   See http://www.w3.org/TR/css3-selectors/#attribute-selectors

   Version 0.4 - Simon Willison, March 25th 2003
   -- Works in Phoenix 0.5, Mozilla 1.3, Opera 7, Internet Explorer 6, Internet Explorer 5 on Windows
   -- Opera 7 fails
*/

function getAllChildren(e) {
  // Returns all children of element. Workaround required for IE5/Windows. Ugh.
  return e.all ? e.all : e.getElementsByTagName('*');
}

document.getElementsBySelector = function(selector) {
  // Attempt to fail gracefully in lesser browsers
  if (!document.getElementsByTagName) {
    return new Array();
  }
  // Split selector in to tokens
  var tokens = selector.split(' ');
  var currentContext = new Array(document);
  for (var i = 0; i < tokens.length; i++) {
    token = tokens[i].replace(/^\s+/,'').replace(/\s+$/,'');;
    if (token.indexOf('#') > -1) {
      // Token is an ID selector
      var bits = token.split('#');
      var tagName = bits[0];
      var id = bits[1];
      var element = document.getElementById(id);
      //if (tagName && element.nodeName.toLowerCase() != tagName) {
      if (!element || (tagName && element.nodeName.toLowerCase() != tagName)) {
        // tag with that ID not found, return false
        return new Array();
      }
      // Set currentContext to contain just this element
      currentContext = new Array(element);
      continue; // Skip to next token
    }
    if (token.indexOf('.') > -1) {
      // Token contains a class selector
      var bits = token.split('.');
      var tagName = bits[0];
      var className = bits[1];
      if (!tagName) {
        tagName = '*';
      }
      // Get elements matching tag, filter them for class selector
      var found = new Array;
      var foundCount = 0;
      for (var h = 0; h < currentContext.length; h++) {
        var elements;
        if (tagName == '*') {
            elements = getAllChildren(currentContext[h]);
        } else {
            try {
                elements = currentContext[h].getElementsByTagName(tagName);
            }
            catch(e) {
                elements = [];
            }
        }
        for (var j = 0; j < elements.length; j++) {
          found[foundCount++] = elements[j];
        }
      }
      currentContext = new Array;
      var currentContextIndex = 0;
      for (var k = 0; k < found.length; k++) {
        if (found[k].className && found[k].className.match(new RegExp('\\b'+className+'\\b'))) {
          currentContext[currentContextIndex++] = found[k];
        }
      }
      continue; // Skip to next token
    }
    // Code to deal with attribute selectors
    if (token.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) {
      var tagName = RegExp.$1;
      var attrName = RegExp.$2;
      var attrOperator = RegExp.$3;
      var attrValue = RegExp.$4;
      if (!tagName) {
        tagName = '*';
      }
      // Grab all of the tagName elements within current context
      var found = new Array;
      var foundCount = 0;
      for (var h = 0; h < currentContext.length; h++) {
        var elements;
        if (tagName == '*') {
            elements = getAllChildren(currentContext[h]);
        } else {
            elements = currentContext[h].getElementsByTagName(tagName);
        }
        for (var j = 0; j < elements.length; j++) {
          found[foundCount++] = elements[j];
        }
      }
      currentContext = new Array;
      var currentContextIndex = 0;
      var checkFunction; // This function will be used to filter the elements
      switch (attrOperator) {
        case '=': // Equality
          checkFunction = function(e) { return (e.getAttribute(attrName) == attrValue); };
          break;
        case '~': // Match one of space seperated words
          checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('\\b'+attrValue+'\\b'))); };
          break;
        case '|': // Match start with value followed by optional hyphen
          checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('^'+attrValue+'-?'))); };
          break;
        case '^': // Match starts with value
          checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) == 0); };
          break;
        case '$': // Match ends with value - fails with "Warning" in Opera 7
          checkFunction = function(e) { return (e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length); };
          break;
        case '*': // Match ends with value
          checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) > -1); };
          break;
        default :
          // Just test for existence of attribute
          checkFunction = function(e) { return e.getAttribute(attrName); };
      }
      currentContext = new Array;
      var currentContextIndex = 0;
      for (var k = 0; k < found.length; k++) {
        if (checkFunction(found[k])) {
          currentContext[currentContextIndex++] = found[k];
        }
      }
      // alert('Attribute Selector: '+tagName+' '+attrName+' '+attrOperator+' '+attrValue);
      continue; // Skip to next token
    }
    // If we get here, token is JUST an element (not a class or ID selector)
    tagName = token;
    var found = new Array;
    var foundCount = 0;
    for (var h = 0; h < currentContext.length; h++) {
      var elements = currentContext[h].getElementsByTagName(tagName);
      for (var j = 0; j < elements.length; j++) {
        found[foundCount++] = elements[j];
      }
    }
    currentContext = found;
  }
  return currentContext;
}

/* That revolting regular expression explained
/^(\w+)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/
  \---/  \---/\-------------/    \-------/
    |      |         |               |
    |      |         |           The value
    |      |    ~,|,^,$,* or =
    |   Attribute
   Tag
*/
<|endoftext|>


<commit_before>import Head from "next/head";
import Link from "next/link";
import { useRouter } from "next/router";
import { useState } from "react";
import classnames from "classnames";
import { join } from "path";
import { getDocs, formatDate, buildPageTree, getPage } from "../../lib/lib";
import Markdown from "../../components/Markdown";
import ContentArea from "../../components/ContentArea";
import Sidebar from "../../components/Sidebar";
import markdownStyles from "../../styles/markdown.module.css";
import { decode } from "html-entities";

const breadcrumbs = (posts, paths) => {
  const results = [
    <Link href="/">Urbit</Link>,
    /,
    <Link href="/docs">Documentation</Link>,
  ];
  let thisLink = "/docs";
  for (const path of paths) {
    posts = posts.children[path];
    thisLink = join(thisLink, path);
    results.push(
      /,
      <Link href={thisLink}>{posts.title}</Link>
    );
  }
  return results;
};

const childPages = (thisLink, children, level = 0) => (

    {Object.entries(children).map(([childSlug, child]) => (

{pageTree(join(thisLink, childSlug), child, level)}

    ))}

);

const pageTree = (thisLink, tree, level = 0) => {
  const router = useRouter();
  const firstCrumb = "/" + router.asPath.split("/").slice(1, -1).join("/");

  const includesThisPage = firstCrumb.includes(thisLink);
  const isThisPage = router.asPath === thisLink;
  const [isOpen, toggleTree] = useState(includesThisPage);

  const activeClasses = classnames({
    hidden: !isOpen,
  });

  const headingItemClasses = classnames({
    "pl-0 text-black text-base font-semibold hover:text-green leading-relaxed":
      level === 0,
    "pl-4 text-black text-base font-semibold hover:text-green": level === 1,
    "pl-8 text-black text-base hover:text-green": level === 2,
  });

  const pageItemClasses = classnames({
    "pl-4 text-black text-base hover:text-green": level === 0,
    "pl-8 text-black text-base hover:text-green": level === 1,
    "pl-12 text-black text-base hover:text-green": level === 2,
    dot: isThisPage,
  });

  return (
    <>
       toggleTree(!isOpen)}>
        <p className={`${headingItemClasses} cursor-pointer`}>{tree.title}

          {tree.pages.map(({ title, slug }) => {
            const href = join(thisLink, slug);
            const isSelected = router.asPath === href;
            const selectedClasses = classnames({
              dot: isSelected,
              "text-green": isSelected,
            });
            return (

                <Link href={href}>
                  <a
                    className={`relative ${pageItemClasses} ${selectedClasses}`}
                  >
                    {title}

                </Link>

            );
          })}

        {childPages(thisLink, tree.children, level + 1)}

    </>
  );
};

export default function DocsLayout({ posts, data, params, search, markdown }) {
  const [isOpen, toggleTray] = useState(false);

  return (
    <>

        <title>{data.title} • Documentation • urbit.org</title>

        <Sidebar search={search}>{childPages("/docs", posts.children)}</Sidebar>

        <ContentArea
          breadcrumbs={breadcrumbs(posts, params.slug?.slice(0, -1) || "")}
          title={data.title}
          search={search}
          section="Urbit Documentation"
        >

        </ContentArea>

    </>
  );
}

export async function getStaticProps({ params }) {
  const posts = buildPageTree(join(process.cwd(), "content/docs"), "weight");

  const { data, content } = getPage(
    join(process.cwd(), "content/docs", params.slug?.join("/") || "/")
  );

  const markdown = await Markdown({ post: { content: content } });

  return { props: { posts, data, markdown, params } };
}

export async function getStaticPaths() {
  const posts = buildPageTree(join(process.cwd(), "content/docs"), "weight");
  const slugs = [];

  const allHrefs = (thisLink, tree) => {
    slugs.push(thisLink, ...tree.pages.map((e) => join(thisLink, e.slug)));
    allHrefsChildren(thisLink, tree.children);
  };

  const allHrefsChildren = (thisLink, children) => {
    Object.entries(children).map(([childSlug, child]) => {
      allHrefs(join(thisLink, childSlug), child);
    });
  };

  allHrefs("/docs", posts);

  return {
    paths: slugs,
    fallback: false,
  };
}
<commit_msg>docs: they demand the root<commit_after>import Head from "next/head";
import Link from "next/link";
import { useRouter } from "next/router";
import { useState } from "react";
import classnames from "classnames";
import { join } from "path";
import { getDocs, formatDate, buildPageTree, getPage } from "../../lib/lib";
import Markdown from "../../components/Markdown";
import ContentArea from "../../components/ContentArea";
import Sidebar from "../../components/Sidebar";
import markdownStyles from "../../styles/markdown.module.css";
import { decode } from "html-entities";

const breadcrumbs = (posts, paths) => {
  const results = [
    <Link href="/">Urbit</Link>,
    /,
    <Link href="/docs">Documentation</Link>,
  ];
  let thisLink = "/docs";
  for (const path of paths) {
    posts = posts.children[path];
    thisLink = join(thisLink, path);
    results.push(
      /,
      <Link href={thisLink}>{posts.title}</Link>
    );
  }
  return results;
};

const childPages = (thisLink, children, level = 0) => (

    {Object.entries(children).map(([childSlug, child]) => (

{pageTree(join(thisLink, childSlug), child, level)}

    ))}

);

const pageTree = (thisLink, tree, level = 0) => {
  const router = useRouter();
  const firstCrumb = "/" + router.asPath.split("/").slice(1, -1).join("/");

  const includesThisPage = firstCrumb.includes(thisLink);
  const isThisPage = router.asPath === thisLink;
  const [isOpen, toggleTree] = useState(includesThisPage);

  const activeClasses = classnames({
    hidden: !isOpen,
  });

  const headingItemClasses = classnames({
    "pl-0 text-black text-base font-semibold hover:text-green leading-relaxed":
      level === 0,
    "pl-4 text-black text-base font-semibold hover:text-green": level === 1,
    "pl-8 text-black text-base hover:text-green": level === 2,
  });

  const pageItemClasses = classnames({
    "pl-4 text-black text-base hover:text-green": level === 0,
    "pl-8 text-black text-base hover:text-green": level === 1,
    "pl-12 text-black text-base hover:text-green": level === 2,
    dot: isThisPage,
  });

  return (
    <>
       toggleTree(!isOpen)}>
        <p className={`${headingItemClasses} cursor-pointer`}>{tree.title}

          {tree.pages.map(({ title, slug }) => {
            const href = join(thisLink, slug);
            const isSelected = router.asPath === href;
            const selectedClasses = classnames({
              dot: isSelected,
              "text-green": isSelected,
            });
            return (

                <Link href={href}>
                  <a
                    className={`relative ${pageItemClasses} ${selectedClasses}`}
                  >
                    {title}

                </Link>

            );
          })}

        {childPages(thisLink, tree.children, level + 1)}

    </>
  );
};

export default function DocsLayout({ posts, data, params, search, markdown }) {
  const router = useRouter();
  const isSelected = "/docs".includes(router.asPath);
  const selectedClasses = classnames({
    dot: isSelected,
    "text-green": isSelected,
    "text-black": !isSelected,
  });
  const rootClasses = "pl-0 text-base hover:text-green";
  return (
    <>

        <title>{data.title} • Documentation • urbit.org</title>

        <Sidebar search={search}>

              <Link href="/docs">
                <a className={`relative ${selectedClasses} ${rootClasses}`}>
                  Developer Documentation

              </Link>

          {childPages("/docs", posts.children)}
        </Sidebar>
        <ContentArea
          breadcrumbs={breadcrumbs(posts, params.slug?.slice(0, -1) || "")}
          title={data.title}
          search={search}
          section="Urbit Documentation"
        >

        </ContentArea>

    </>
  );
}

export async function getStaticProps({ params }) {
  const posts = buildPageTree(join(process.cwd(), "content/docs"), "weight");

  const { data, content } = getPage(
    join(process.cwd(), "content/docs", params.slug?.join("/") || "/")
  );

  const markdown = await Markdown({ post: { content: content } });

  return { props: { posts, data, markdown, params } };
}

export async function getStaticPaths() {
  const posts = buildPageTree(join(process.cwd(), "content/docs"), "weight");
  const slugs = [];

  const allHrefs = (thisLink, tree) => {
    slugs.push(thisLink, ...tree.pages.map((e) => join(thisLink, e.slug)));
    allHrefsChildren(thisLink, tree.children);
  };

  const allHrefsChildren = (thisLink, children) => {
    Object.entries(children).map(([childSlug, child]) => {
      allHrefs(join(thisLink, childSlug), child);
    });
  };

  allHrefs("/docs", posts);

  return {
    paths: slugs,
    fallback: false,
  };
}
<|endoftext|>