<commit_before>import React, {PropTypes} from 'react';
import {catalogShape} from '../CatalogPropTypes';
import Radium from 'radium';
import Frame from '../components/Frame/Frame';
import Hint from '../specimens/Hint';
import Specimen from '../components/Specimen/Specimen';
import HighlightedCode from '../components/HighlightedCode/HighlightedCode';
import ResponsiveTabs from '../components/ResponsiveTabs/ResponsiveTabs';
import runscript from '../utils/runscript';
import validateSizes from '../utils/validateSizes';

const PADDING = 3;
const SIZE = 20;

function getStyle(theme) {
  return {
    container: {
      border: '1px solid #eee',
      borderRadius: '2px',
      boxSizing: 'border-box',
      position: 'relative',
      flexBasis: '100%',
      marginTop: '40px',
      fontFamily: theme.fontFamily
    },
    toggle: {
      border: PADDING + 'px solid transparent',
      color: theme.lightColor,
      cursor: 'pointer',
      display: 'inline-block',
      fontFamily: theme.fontMono,
      fontSize: '16px',
      fontStyle: 'normal',
      fontWeight: 700,
      height: SIZE + 'px',
      lineHeight: SIZE + 'px',
      padding: PADDING + 'px',
      position: 'absolute',
      right: -PADDING + 'px',
      top: -(SIZE + 2 * PADDING) + 'px',
      userSelect: 'none',
      ':hover': {
        color: theme.textColor
      }
    },
    source: {
      borderTop: '1px solid #eee',
      boxSizing: 'border-box',
      width: '100%',
      height: 'auto'
    },
    content: {
      background: `url(${theme.checkerboardPatternLight})`,
      boxSizing: 'border-box',
      display: 'block',
      padding: 20,
      position: 'relative',
      width: '100%'
    },
    light: {
      background: `url(${theme.checkerboardPatternLight})`
    },
    dark: {
      background: `url(${theme.checkerboardPatternDark})`
    },
    plain: {
      background: 'transparent',
      padding: 0
    },
    plain_light: {
      background: theme.bgLight,
      padding: '20px'
    },
    plain_dark: {
      background: theme.bgDark,
      padding: '20px'
    },
    responsive: {
      background: `url(${theme.checkerboardPatternLight})`,
      boxSizing: 'border-box',
      overflow: 'hidden',
      padding: '15px',
      textAlign: 'center'
    }
  };
}

class Html extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      viewSource: false,
      parentWidth: 0,
      activeScreenSize: validateSizes(props.responsive, props.catalog.responsiveSizes)[0] || null
    };
    this.setSize = this.setSize.bind(this);
    this.updateParentWidth = this.updateParentWidth.bind(this);
  }

  componentDidMount() {
    const {runScript} = this.props;
    runScript && Array.from(this.specimen.querySelectorAll('script')).forEach(runscript);

    if (this.state.activeScreenSize) {
      window.addEventListener('resize', this.updateParentWidth);
      setTimeout(this.updateParentWidth);
    }
  }

  componentWillUnmount() {
    if (this.state.activeScreenSize) {
      window.removeEventListener('resize', this.updateParentWidth);
    }
  }

  setElementState(nextState) {
    if (typeof nextState === 'function') {
      this.setState(({elementState}) => ({elementState: {...elementState, ...nextState(elementState)}}));
    } else {
      this.setState({elementState: {...this.state.elementState, ...nextState}});
    }
  }

  updateParentWidth() {
    const nextParentWidth = this.specimen.getBoundingClientRect().width - 30;
    if (nextParentWidth !== this.state.parentWidth) {
      this.setState({parentWidth: nextParentWidth});
    }
  }

  setSize(activeScreenSize) {
    this.setState({activeScreenSize: activeScreenSize});
  }

  toggleSource() {
    this.setState(({viewSource}) => ({viewSource: !viewSource}));
  }

  render() {
    const {catalog: {theme, responsiveSizes}, children, frame, ...options} = this.props;
    const {activeScreenSize, parentWidth, viewSource} = this.state;
    const styles = getStyle(theme);
    const validSizes = validateSizes(options.responsive, responsiveSizes);

    const exampleStyles = {
      ...(options.plain ? styles.plain : null),
      ...(options.light ? styles.light : null),
      ...(options.dark ? styles.dark : null),
      ...(options.plain && options.light ? styles.plain_light : null),
      ...(options.plain && options.dark ? styles.plain_dark : null),
      ...(options.responsive ? styles.responsive : null)
    };

    const source = viewSource
      ?
<HighlightedCode language='markup' code={children} theme={theme} />

      : null;

    const toggle = !options.noSource
      ?
<>

      : null;

    // eslint-disable-next-line
    const content =
;

    if (options.responsive && !validSizes) {
      return <Hint warning>Please check that the responsive parameters match an existing entry.</Hint>;
    }

    return (

 {this.specimen = el;}}>
        {toggle}
        {options.responsive && parentWidth && activeScreenSize &&
          <ResponsiveTabs theme={theme} sizes={validSizes} action={this.setSize} activeSize={activeScreenSize} parentWidth={parentWidth}/>
        }
        {(!options.responsive || parentWidth) &&

            {frame || activeScreenSize
              ? <Frame width={activeScreenSize && activeScreenSize.width} parentWidth={parentWidth ? parentWidth : '100%'} height={activeScreenSize && activeScreenSize.height}>
                  {content}
                </Frame>
              : content
            }

        }
        {source}

    );
  }
}

Html.propTypes = {
  children: PropTypes.string.isRequired,
  catalog: catalogShape.isRequired,
  responsive: PropTypes.oneOfType([PropTypes.bool, PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
  runScript: PropTypes.bool,
  plain: PropTypes.bool,
  light: PropTypes.bool,
  dark: PropTypes.bool,
  noSource: PropTypes.bool,
  frame: PropTypes.bool
};

export default Specimen(undefined, undefined, {withChildren: true})(Radium(Html));
<commit_msg>Fix #279 by setting width:100% (#282)<commit_after>import React, {PropTypes} from 'react';
import {catalogShape} from '../CatalogPropTypes';
import Radium from 'radium';
import Frame from '../components/Frame/Frame';
import Hint from '../specimens/Hint';
import Specimen from '../components/Specimen/Specimen';
import HighlightedCode from '../components/HighlightedCode/HighlightedCode';
import ResponsiveTabs from '../components/ResponsiveTabs/ResponsiveTabs';
import runscript from '../utils/runscript';
import validateSizes from '../utils/validateSizes';

const PADDING = 3;
const SIZE = 20;

function getStyle(theme) {
  return {
    container: {
      border: '1px solid #eee',
      borderRadius: '2px',
      boxSizing: 'border-box',
      position: 'relative',
      flexBasis: '100%',
      width: '100%',
      marginTop: '40px',
      fontFamily: theme.fontFamily
    },
    toggle: {
      border: PADDING + 'px solid transparent',
      color: theme.lightColor,
      cursor: 'pointer',
      display: 'inline-block',
      fontFamily: theme.fontMono,
      fontSize: '16px',
      fontStyle: 'normal',
      fontWeight: 700,
      height: SIZE + 'px',
      lineHeight: SIZE + 'px',
      padding: PADDING + 'px',
      position: 'absolute',
      right: -PADDING + 'px',
      top: -(SIZE + 2 * PADDING) + 'px',
      userSelect: 'none',
      ':hover': {
        color: theme.textColor
      }
    },
    source: {
      borderTop: '1px solid #eee',
      boxSizing: 'border-box',
      width: '100%',
      height: 'auto'
    },
    content: {
      background: `url(${theme.checkerboardPatternLight})`,
      boxSizing: 'border-box',
      display: 'block',
      padding: 20,
      position: 'relative',
      width: '100%'
    },
    light: {
      background: `url(${theme.checkerboardPatternLight})`
    },
    dark: {
      background: `url(${theme.checkerboardPatternDark})`
    },
    plain: {
      background: 'transparent',
      padding: 0
    },
    plain_light: {
      background: theme.bgLight,
      padding: '20px'
    },
    plain_dark: {
      background: theme.bgDark,
      padding: '20px'
    },
    responsive: {
      background: `url(${theme.checkerboardPatternLight})`,
      boxSizing: 'border-box',
      overflow: 'hidden',
      padding: '15px',
      textAlign: 'center'
    }
  };
}

class Html extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      viewSource: false,
      parentWidth: 0,
      activeScreenSize: validateSizes(props.responsive, props.catalog.responsiveSizes)[0] || null
    };
    this.setSize = this.setSize.bind(this);
    this.updateParentWidth = this.updateParentWidth.bind(this);
  }

  componentDidMount() {
    const {runScript} = this.props;
    runScript && Array.from(this.specimen.querySelectorAll('script')).forEach(runscript);

    if (this.state.activeScreenSize) {
      window.addEventListener('resize', this.updateParentWidth);
      setTimeout(this.updateParentWidth);
    }
  }

  componentWillUnmount() {
    if (this.state.activeScreenSize) {
      window.removeEventListener('resize', this.updateParentWidth);
    }
  }

  setElementState(nextState) {
    if (typeof nextState === 'function') {
      this.setState(({elementState}) => ({elementState: {...elementState, ...nextState(elementState)}}));
    } else {
      this.setState({elementState: {...this.state.elementState, ...nextState}});
    }
  }

  updateParentWidth() {
    const nextParentWidth = this.specimen.getBoundingClientRect().width - 30;
    if (nextParentWidth !== this.state.parentWidth) {
      this.setState({parentWidth: nextParentWidth});
    }
  }

  setSize(activeScreenSize) {
    this.setState({activeScreenSize: activeScreenSize});
  }

  toggleSource() {
    this.setState(({viewSource}) => ({viewSource: !viewSource}));
  }

  render() {
    const {catalog: {theme, responsiveSizes}, children, frame, ...options} = this.props;
    const {activeScreenSize, parentWidth, viewSource} = this.state;
    const styles = getStyle(theme);
    const validSizes = validateSizes(options.responsive, responsiveSizes);

    const exampleStyles = {
      ...(options.plain ? styles.plain : null),
      ...(options.light ? styles.light : null),
      ...(options.dark ? styles.dark : null),
      ...(options.plain && options.light ? styles.plain_light : null),
      ...(options.plain && options.dark ? styles.plain_dark : null),
      ...(options.responsive ? styles.responsive : null)
    };

    const source = viewSource
      ?
<HighlightedCode language='markup' code={children} theme={theme} />

      : null;

    const toggle = !options.noSource
      ?
<>

      : null;

    // eslint-disable-next-line
    const content =
;

    if (options.responsive && !validSizes) {
      return <Hint warning>Please check that the responsive parameters match an existing entry.</Hint>;
    }

    return (

 {this.specimen = el;}}>
        {toggle}
        {options.responsive && parentWidth && activeScreenSize &&
          <ResponsiveTabs theme={theme} sizes={validSizes} action={this.setSize} activeSize={activeScreenSize} parentWidth={parentWidth}/>
        }
        {(!options.responsive || parentWidth) &&

            {frame || activeScreenSize
              ? <Frame width={activeScreenSize && activeScreenSize.width} parentWidth={parentWidth ? parentWidth : '100%'} height={activeScreenSize && activeScreenSize.height}>
                  {content}
                </Frame>
              : content
            }

        }
        {source}

    );
  }
}

Html.propTypes = {
  children: PropTypes.string.isRequired,
  catalog: catalogShape.isRequired,
  responsive: PropTypes.oneOfType([PropTypes.bool, PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
  runScript: PropTypes.bool,
  plain: PropTypes.bool,
  light: PropTypes.bool,
  dark: PropTypes.bool,
  noSource: PropTypes.bool,
  frame: PropTypes.bool
};

export default Specimen(undefined, undefined, {withChildren: true})(Radium(Html));
<|endoftext|>


<commit_before>const LosslessJSON = require('lossless-json')
const Decimal = require('decimal.js')
const _ = require('lodash')
const DECIMAL_REGEX = /^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$/

const _reviver = (key, value) => {
  if (value && value.isLosslessNumber) {
    return new Decimal(value.toString())
  }
  return value
}

const _replacer = (key, value) => {
  if (_.isString(value) && DECIMAL_REGEX.test(value) && !isNaN(value) && parseFloat(value, 10) > Number.MAX_SAFE_INTEGER) {
    return new LosslessJSON.LosslessNumber(value.replace(/^\+/, ''))
  } else if (value instanceof Decimal) {
    return new LosslessJSON.LosslessNumber(value.toString())
  } else {
    return value
  }
}

const parse = (str, configs) => {
  let result
  try {
    result = _.get(configs, 'options.support-big-int') ? LosslessJSON.parse(str, _reviver) : JSON.parse(str)
  } catch (e) {
    throw new Error('failed to parse json (message: "' + e.message + '") - source: ' + JSON.stringify(str))
  }

  return result
}

const stringify = (json, configs) => _.get(configs, 'options.support-big-int') ? LosslessJSON.stringify(json, _replacer) : JSON.stringify(json)

module.exports = {
  parse,
  stringify
}
<commit_msg>clean up jsonparser.js<commit_after>const LosslessJSON = require('lossless-json')
const Decimal = require('decimal.js')
const _ = require('lodash')
const DECIMAL_REGEX = /^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$/

const _reviver = (key, value) => {
  if (value && value.isLosslessNumber) {
    return new Decimal(value.toString())
  }
  return value
}

const _replacer = (key, value) => {
  if (_.isString(value) && DECIMAL_REGEX.test(value) &&
    !isNaN(value) && parseFloat(value) > Number.MAX_SAFE_INTEGER) {
    return new LosslessJSON.LosslessNumber(value.replace(/^\+/, ''))
  } else if (value instanceof Decimal) {
    return new LosslessJSON.LosslessNumber(value.toString())
  } else {
    return value
  }
}

const parse = (str, configs) => {
  let result
  try {
    result = _.get(configs, 'options.support-big-int')
      ? LosslessJSON.parse(str, _reviver)
      : JSON.parse(str)
  } catch (e) {
    throw new Error(`failed to parse json (message: "${e.message}") - source: ${JSON.stringify(str)}`)
  }

  return result
}

const stringify = (json, configs) => _.get(configs, 'options.support-big-int')
  ? LosslessJSON.stringify(json, _replacer)
  : JSON.stringify(json)

module.exports = {
  parse,
  stringify
}
<|endoftext|>


<commit_before>var crypto = require('crypto')

var async = require('async')
  , kafka = require('kafka-node')
  , protocol = require('../node_modules/kafka-node/lib/protocol')

module.exports =
{ producerPayload:  producerPayload
, outgoingMessage:  outgoingMessage
, consumer:         consumer
}

var compose = function () {
  var fns = arguments

  return function (result) {
    for (var i = fns.length - 1; i > -1; i--) {
      result = fns[i].call(this, result)
    }

    return result
  }
}

var catchErr = function (left, right) {
  return function (err) {
    return err
            ? left(err)
            : right.apply(null, Array.prototype.slice.call(arguments, 1))
  }
}

// A "face" is what you show the world and is a representation of who
// you think you are. Make sure you put on makeup first cause you ugly.

function producerPayload(topic, message, nPartitions, key) {
  var face = {}

  face.get = function () {
    return  [ { topic: topic
              , partition: message.mapToPartition(nPartitions, key)
              , messages: message.toKafkaMessage()
              }
            ]
  }

  return face
}

// nInstances is the number of processes running this code globally
// instanceId is an int 0,1,2,3...
function consumerPayloads(topic, fetchMaxBytes, instanceId, nInstances, nPartitions) {
  var partitions = []
    , payloads = []
    , face = {}

  for (var k=0; k < nPartitions; k++) {
    if ((k + instanceId) % nInstances === 0) partitions.push(k)
  }

  payloads = partitions.map(function (p) {
    return  { topic: topic
            , partition: p
            , maxBytes: fetchMaxBytes
            }
  })

  var toMap = function (results) {
    return results.reduce(function (acc, result) {
      var topic = Object.keys(result)[0]
        , partition = Object.keys(result[topic])[0]
        , offset = result[topic][partition]

      acc[partition] = offset < 0 ? 0 : offset

      return acc
    }, {})
  }

  face.getPartitionOffsetMap = function (client, group, cb) {
    var _payloads = payloads.map(function (payload) { return [payload] })

    async.map(_payloads,
              client.sendOffsetFetchRequest.bind(client, group),
              catchErr(cb, compose(cb.bind(null, null), toMap)))
  }

  face.getPartitions = function () { return partitions }

  face.get = function (partitionToOffsetMap) {
    return payloads.map(function (payload) {
      payload.offset = partitionToOffsetMap[payload.partition]

      return payload
    })
  }

  return face
}

function outgoingMessage(task) {
  var face = {}

  function _getKeyVal(key) {
    var arr = key.split('.')
      , mutator = task

    while (arr.length) { mutator = mutator[arr.shift()] }

    return mutator
  }

  // Takes a key in dot notation to access a field in "task"
  // Hashes that field to obtain number between 0.. nPartitions-1
  face.mapToPartition = function (nPartitions, key) {
    function __mapHash(key, nPartitions) {
      return parseInt(crypto.createHash('sha1')
                            .update(JSON.stringify(_getKeyVal(key)))
                            .digest('hex')
                            .slice(0,6), 16) % nPartitions
    }

    // If key is undefined, map to a random partition
    return (key !== undefined ? __mapHash(key, nPartitions)
                              : Math.floor(Math.random() * nPartitions))
  }

  face.toKafkaMessage = function () {
    return JSON.stringify(task)
  }

  return face
}

function incomingMessage(message) {
  var face = {}

  face.get = function (field) { return message[field] }

  face.toTask = function () {
    return JSON.parse(message.value)
  }

  return face
}

function consumer(client, topic, group, options) {
  var face = {}
    , noop = function () {}

    // OMFG WATCH OUT FOR STATE o_0
    // Consumer has a lot of ferking state
    , shuttingDown = false
    , reading = false
    , offsets = {} // partition to offset map
    , ops = { data:   function () { throw new Error('No data handler supplied') }
            , error:  function (err) { throw new Error(err) }
            , end:    noop
            }

    , fetchMaxWaitMs = options.fetch_max_wait_ms
    , fetchMinBytes = options.fetch_min_bytes

    , payloads = consumerPayloads(topic,
                                  options.fetch_max_bytes,
                                  options.instance_id,
                                  options.num_instances,
                                  options.num_partitions)

  var read = function () {
    if (shuttingDown || reading) { return }

    reading = true

    var retryDueToError = false
      , mbs = messageBins(payloads.getPartitions())
      , encoder = protocol.encodeFetchRequest(fetchMaxWaitMs, fetchMinBytes)
      , decoder = protocol
                    .decodeFetchResponse(
                        catchErr( compose(ops.error, _setRetry),
                                  _decoderCb))

      , _send = client.send.bind( client,
                                  payloads.get(offsets),
                                  encoder,
                                  decoder,
                                  catchErr(_onSenderErr, noop))

    if (client.ready) {
      _send()
    } else {
      client.on('ready', _send)
    }

    function _onSenderErr(err) { return (reading = false) && ops.error(err) }

    function _setRetry(err) {
      retryDueToError = true
      ready = false
      return err
    }

    function _decoderCb(type, value) {
      if (shuttingDown || retryDueToError) { return }

      if (type === "message") {
        mbs.enqueue(incomingMessage(value))

      } else {
        mbs.process(_processMsg, _fin)

      }
    }

    function _processMsg(message, next) {
      if (shuttingDown) { return next() }

      ops.data(message, catchErr( next,
                                  compose(next,
                                          _updateOffsets.bind(null, message))))
    }

    function _updateOffsets(message) {
      var partition = message.get('partition')
        , offset = message.get('offset')

      return (offsets[partition] = offset + 1) && null
    }

    var _fin = compose(
        catchErr(ops.error, face.read),
        function (err) { return (reading = false) && err })
  }

  var ensureOffsets = function (next) {
    if (Object.keys(offsets).length) { return next() }

    payloads
      .getPartitionOffsetMap(
          client,
          group,
          catchErr( ops.error,
                    function(map) { (offsets = map) && next() }))
  }

  face.read = ensureOffsets.bind(null, read)

  face.on = function (evt, cb) {
    cb && (ops[evt] = cb)
  }

  face.commit = function (partition, offset, next) {
    return client.sendOffsetCommitRequest(group,
        [ { topic: topic
          , partition: partition
          , offset: offset + 1
          , metadata: 'm'
          }
        ], next)
  }

  face.close = function (next) {
    shuttingDown = true

    ops.end()

    return setImmediate(client.close.bind(client, next))
  }

  return face
}

// creates a queue for each partition in partitions
// messages from these queues are concurrently processed
function messageBins(partitions) {
  var qs = []
    , face = {}

  // Set up the buffer queues
  for (var k = 0; k < partitions.length; k++) {
    qs.push([])
  }

  face.enqueue = function (message) {
    return qs[partitions.indexOf(message.get('partition'))].push(message)
  }

  face.process = function (handler, done) {
    return async.each(qs, function (q, cb) {
      async.eachSeries(q, handler, cb)
    }, done)
  }

  return face
}
<commit_msg>fix small bug<commit_after>var crypto = require('crypto')

var async = require('async')
  , kafka = require('kafka-node')
  , protocol = require('../node_modules/kafka-node/lib/protocol')

module.exports =
{ producerPayload:  producerPayload
, outgoingMessage:  outgoingMessage
, consumer:         consumer
}

var compose = function () {
  var fns = arguments

  return function (result) {
    for (var i = fns.length - 1; i > -1; i--) {
      result = fns[i].call(this, result)
    }

    return result
  }
}

var catchErr = function (left, right) {
  return function (err) {
    return err
            ? left(err)
            : right.apply(null, Array.prototype.slice.call(arguments, 1))
  }
}

// A "face" is what you show the world and is a representation of who
// you think you are. Make sure you put on makeup first cause you ugly.

function producerPayload(topic, message, nPartitions, key) {
  var face = {}

  face.get = function () {
    return  [ { topic: topic
              , partition: message.mapToPartition(nPartitions, key)
              , messages: message.toKafkaMessage()
              }
            ]
  }

  return face
}

// nInstances is the number of processes running this code globally
// instanceId is an int 0,1,2,3...
function consumerPayloads(topic, fetchMaxBytes, instanceId, nInstances, nPartitions) {
  var partitions = []
    , payloads = []
    , face = {}

  for (var k=0; k < nPartitions; k++) {
    if ((k + instanceId) % nInstances === 0) partitions.push(k)
  }

  payloads = partitions.map(function (p) {
    return  { topic: topic
            , partition: p
            , maxBytes: fetchMaxBytes
            }
  })

  var toMap = function (results) {
    return results.reduce(function (acc, result) {
      var topic = Object.keys(result)[0]
        , partition = Object.keys(result[topic])[0]
        , offset = result[topic][partition]

      acc[partition] = offset < 0 ? 0 : offset

      return acc
    }, {})
  }

  face.getPartitionOffsetMap = function (client, group, cb) {
    var _payloads = payloads.map(function (payload) { return [payload] })

    async.map(_payloads,
              client.sendOffsetFetchRequest.bind(client, group),
              catchErr(cb, compose(cb.bind(null, null), toMap)))
  }

  face.getPartitions = function () { return partitions }

  face.get = function (partitionToOffsetMap) {
    return payloads.map(function (payload) {
      payload.offset = partitionToOffsetMap[payload.partition]

      return payload
    })
  }

  return face
}

function outgoingMessage(task) {
  var face = {}

  function _getKeyVal(key) {
    var arr = key.split('.')
      , mutator = task

    while (arr.length) { mutator = mutator[arr.shift()] }

    return mutator
  }

  // Takes a key in dot notation to access a field in "task"
  // Hashes that field to obtain number between 0.. nPartitions-1
  face.mapToPartition = function (nPartitions, key) {
    function __mapHash(key, nPartitions) {
      return parseInt(crypto.createHash('sha1')
                            .update(JSON.stringify(_getKeyVal(key)))
                            .digest('hex')
                            .slice(0,6), 16) % nPartitions
    }

    // If key is undefined, map to a random partition
    return (key !== undefined ? __mapHash(key, nPartitions)
                              : Math.floor(Math.random() * nPartitions))
  }

  face.toKafkaMessage = function () {
    return JSON.stringify(task)
  }

  return face
}

function incomingMessage(message) {
  var face = {}

  face.get = function (field) { return message[field] }

  face.toTask = function () {
    return JSON.parse(message.value)
  }

  return face
}

function consumer(client, topic, group, options) {
  var face = {}
    , noop = function () {}

    // OMFG WATCH OUT FOR STATE o_0
    // Consumer has a lot of ferking state
    , shuttingDown = false
    , reading = false
    , offsets = {} // partition to offset map
    , ops = { data:   function () { throw new Error('No data handler supplied') }
            , error:  function (err) { throw new Error(err) }
            , end:    noop
            }

    , fetchMaxWaitMs = options.fetch_max_wait_ms
    , fetchMinBytes = options.fetch_min_bytes

    , payloads = consumerPayloads(topic,
                                  options.fetch_max_bytes,
                                  options.instance_id,
                                  options.num_instances,
                                  options.num_partitions)

  var read = function () {
    if (shuttingDown || reading) { return }

    reading = true

    var retryDueToError = false
      , mbs = messageBins(payloads.getPartitions())
      , encoder = protocol.encodeFetchRequest(fetchMaxWaitMs, fetchMinBytes)
      , decoder = protocol
                    .decodeFetchResponse(
                        catchErr( compose(ops.error, _setRetry),
                                  _decoderCb))

      , _send = client.send.bind( client,
                                  payloads.get(offsets),
                                  encoder,
                                  decoder,
                                  catchErr(_onSenderErr, noop))

    if (client.ready) {
      _send()
    } else {
      client.on('ready', _send)
    }

    function _onSenderErr(err) { return (reading = false) && ops.error(err) }

    function _setRetry(err) {
      retryDueToError = true
      reading = false
      return err
    }

    function _decoderCb(type, value) {
      if (shuttingDown || retryDueToError) { return }

      if (type === "message") {
        mbs.enqueue(incomingMessage(value))

      } else {
        mbs.process(_processMsg, _fin)

      }
    }

    function _processMsg(message, next) {
      if (shuttingDown) { return next() }

      ops.data(message, catchErr( next,
                                  compose(next,
                                          _updateOffsets.bind(null, message))))
    }

    function _updateOffsets(message) {
      var partition = message.get('partition')
        , offset = message.get('offset')

      return (offsets[partition] = offset + 1) && null
    }

    var _fin = compose(
        catchErr(ops.error, face.read),
        function (err) { return (reading = false) && err })
  }

  var ensureOffsets = function (next) {
    if (Object.keys(offsets).length) { return next() }

    payloads
      .getPartitionOffsetMap(
          client,
          group,
          catchErr( ops.error,
                    function(map) { (offsets = map) && next() }))
  }

  face.read = ensureOffsets.bind(null, read)

  face.on = function (evt, cb) {
    cb && (ops[evt] = cb)
  }

  face.commit = function (partition, offset, next) {
    return client.sendOffsetCommitRequest(group,
        [ { topic: topic
          , partition: partition
          , offset: offset + 1
          , metadata: 'm'
          }
        ], next)
  }

  face.close = function (next) {
    shuttingDown = true

    ops.end()

    return setImmediate(client.close.bind(client, next))
  }

  return face
}

// creates a queue for each partition in partitions
// messages from these queues are concurrently processed
function messageBins(partitions) {
  var qs = []
    , face = {}

  // Set up the buffer queues
  for (var k = 0; k < partitions.length; k++) {
    qs.push([])
  }

  face.enqueue = function (message) {
    return qs[partitions.indexOf(message.get('partition'))].push(message)
  }

  face.process = function (handler, done) {
    return async.each(qs, function (q, cb) {
      async.eachSeries(q, handler, cb)
    }, done)
  }

  return face
}
<|endoftext|>


<commit_before>var fs = require("fs");
var path = require("path");
var stream = require("stream");
var crypto = require("crypto");
var HTMLProcessor = require("../lib/htmlprocessor");

function readFileSync(file) {
    return fs.readFileSync(file).toString();
}

function concat(a, b) {
    return a + b;
}

function combineCss(sources) {
    var cleanCSS = require("clean-css");

    console.log("Concatenating CSS");
    var concatenatedCss = sources.map(readFileSync).reduce(concat, "");

    console.log("Minifying CSS");
    return cleanCSS.process(concatenatedCss);
}

function combineJs(sources) {
    var uglify = require("uglify-js");

    console.log("Minifying JS");
    var uglified = uglify.minify(sources, {compress: false});
    return uglified.code;
}

function hashFilename(filename, content) {
    console.log("Getting hash of file");
    var hash = crypto.createHash("md5").update(content).digest("hex");
    return path.join(path.dirname(filename), hash.substr(0, 8) + "." + path.basename(filename));
}

function processBlock(proc) {
    return function (block) {
        console.log("-----");
        console.log("Processing block for " + block.dest);
        var fileContents;

        try {
            fileContents = (block.type === "css")
                ? combineCss(block.src)
                : combineJs(block.src);
        }
        catch (error) {
            console.log("ERROR while minifying " + block.type.toUpperCase() + ": ");
            console.log(error);
            return;
        }

        try {
            var revPath = hashFilename(block.dest, fileContents);

            console.log("Creating copy with hashed filename");
            fs.writeFileSync(revPath, fileContents);
        }
        catch (error) {
            console.log("ERROR while hashing: ");
            console.log(error);
            return;
        }

        try {
            var blockLine = block.raw.join(proc.linefeed);
            var replacement = proc.replaceWith(block);
            replacement = replacement.replace(path.basename(block.relativeDest), path.basename(revPath));
            console.log("New reference: " + replacement);

            return {
                source: blockLine,
                dest: replacement
            };
        }
        catch (error) {
            console.log("ERROR while creating new reference: ");
            console.log(error);
            return;
        }
    };
}

function processHtml(sourceHtml, basePath) {
    var processedHtml = new HTMLProcessor(basePath, null, sourceHtml);
    var replacements = processedHtml.blocks.map(processBlock(processedHtml));
    return replacements.reduce(replace, sourceHtml);
}

function replace(string, replacement) {
    return string.replace(replacement.source, replacement.dest);
}

var hashcatify = function (options) {
    var inputFile = path.join(process.cwd(), options.htmlFile);
    var outputFile = path.join(process.cwd(), options.outputHtmlFile);

    begin(inputFile, outputFile);
};

var begin = function (inputFile, outputFile) {
    var sourceHtml = readFileSync(inputFile);

    if (sourceHtml.length <= 0) {
        console.log("ERROR reading " + inputFile + ", it appears to be empty");
        return;
    }

    var basePath = path.dirname(inputFile);
    var destHtml = processHtml(sourceHtml, basePath);

    console.log("Writing to HTML source file");
    fs.writeFileSync(outputFile, destHtml, "utf8");
    console.log("Hashcat complete");
};

exports.hashcatify = hashcatify;
<commit_msg>Don't swallow exceptions<commit_after>var fs = require("fs");
var path = require("path");
var crypto = require("crypto");
var HTMLProcessor = require("../lib/htmlprocessor");

function readFileSync(file) {
    return fs.readFileSync(file).toString();
}

function concat(a, b) {
    return a + b;
}

function combineCss(sources) {
    var cleanCSS = require("clean-css");

    console.log("Concatenating CSS");
    var concatenatedCss = sources.map(readFileSync).reduce(concat, "");

    console.log("Minifying CSS");
    return cleanCSS.process(concatenatedCss);
}

function combineJs(sources) {
    var uglify = require("uglify-js");

    console.log("Minifying JS");
    var uglified = uglify.minify(sources, {compress: false});
    return uglified.code;
}

function hashFilename(filename, content) {
    console.log("Getting hash of file");
    var hash = crypto.createHash("md5").update(content).digest("hex");
    return path.join(path.dirname(filename), hash.substr(0, 8) + "." + path.basename(filename));
}

function processBlock(proc) {
    return function (block) {
        console.log("-----");
        console.log("Processing block for " + block.dest);

        var fileContents = (block.type === "css")
                ? combineCss(block.src)
                : combineJs(block.src);

        console.log("Creating copy with hashed filename");
        var revPath = hashFilename(block.dest, fileContents);
        fs.writeFileSync(revPath, fileContents);

        var blockLine = block.raw.join(proc.linefeed);
        var replacement = proc.replaceWith(block);
        replacement = replacement.replace(path.basename(block.relativeDest), path.basename(revPath));
        console.log("New reference: " + replacement);

        return {
            source: blockLine,
            dest: replacement
        };
    };
}

function processHtml(sourceHtml, basePath) {
    var processedHtml = new HTMLProcessor(basePath, null, sourceHtml);
    var replacements = processedHtml.blocks.map(processBlock(processedHtml));
    return replacements.reduce(replace, sourceHtml);
}

function replace(string, replacement) {
    return string.replace(replacement.source, replacement.dest);
}

var hashcatify = function (options) {
    var inputFile = path.join(process.cwd(), options.htmlFile);
    var outputFile = path.join(process.cwd(), options.outputHtmlFile);

    begin(inputFile, outputFile);
};

var begin = function (inputFile, outputFile) {
    var sourceHtml = readFileSync(inputFile);

    if (sourceHtml.length <= 0) {
        throw new Error("ERROR reading " + inputFile + ", it appears to be empty");
    }

    var basePath = path.dirname(inputFile);
    var destHtml = processHtml(sourceHtml, basePath);

    console.log("Writing to HTML source file");
    fs.writeFileSync(outputFile, destHtml, "utf8");
    console.log("Hashcat complete");
};

exports.hashcatify = hashcatify;
<|endoftext|>


<commit_before>'use strict';

/**
   Log events to console.error

   @example
   var react = require('react');
   react.logEvents(); // log all task and flow events on all react functions
   react.logEvents('task.*'); // log all task events on all react functions
   react.logEvents(flowFn); // log all task and flow events on flowFn only
   react.logEvents(flowFn, 'flow.*'); // log all flow events on flowFn only
  */

var util = require('util'); // TODO replace inspect with something portable to browser

var react = require('../'); // require('react');
react.trackTasks(); // enable task and flow tracking

var ALL_FLOW_EVENTS = 'flow.*';
var ALL_TASK_EVENTS = 'task.*';
var FLOW_RE = /^flow\./;

function flowLog(obj) {
  /*jshint validthis: true */
  var time = new Date();
  time.setTime(obj.time);
  var argsNoCb = obj.args.filter(function (a) { return (typeof(a) !== 'function'); });
  var eventTimeStr = time.toISOString();
  if (this.event === 'flow.complete') {
    var env = obj;
    console.error('%s: %s \tmsecs: %s \n\targs: %s \n\tresults: %s\n',
                  this.event, env.name, env.elapsedTime, util.inspect(argsNoCb), util.inspect(env.results));
  } else {
    var name = obj.name;
    var args = obj.args;
    console.error('%s: %s \n\targs: %s\n', this.event, name, util.inspect(argsNoCb));
  }
}

function taskLog(obj) {
  /*jshint validthis: true */
  var time = new Date();
  time.setTime(obj.time);
  var argsNoCb = obj.args.filter(function (a) { return (typeof(a) !== 'function'); });
  var eventTimeStr = time.toISOString();
  if (this.event === 'task.complete') {
    var task = obj;
    console.error('%s: %s \tmsecs: %s \n\targs: %s \n\tresults: %s\n',
                  this.event, task.name, task.elapsedTime, util.inspect(argsNoCb), util.inspect(task.results));
  } else {
    var name = obj.name;
    var args = obj.args;
    console.error('%s: %s \n\targs: %s\n', this.event, name, util.inspect(argsNoCb));
  }

}

/**
   Log flow and task events for a flowFn or all of react.
   If called multiple times, remove previous listener (if any) before
   adding.

   @example
   var react = require('react');
   react.logEvents(flowFn, eventWildcard); //log events on flowfn matching wildcard

   @param flowFn Flow function or global react object
   @param eventWildcard wildcarded event type, if not provided use flow.* and task.*
  */
function logEvents(flowFn, eventWildcard) {
  if (!flowFn) flowFn = react; // use global
  if (eventWildcard && eventWildcard !== '*') {
    var logFn = (FLOW_RE.test(eventWildcard)) ? flowLog : taskLog;
    flowFn.events.removeListener(eventWildcard, logFn);
    flowFn.events.on(eventWildcard, logFn);
  } else { // none provided, use flow.* and task.*
    //output events as tasks start and complete
    flowFn.events.removeListener(ALL_FLOW_EVENTS, flowLog);
    flowFn.events.on(ALL_FLOW_EVENTS, flowLog);
    flowFn.events.removeListener(ALL_TASK_EVENTS, taskLog);
    flowFn.events.on(ALL_TASK_EVENTS, taskLog);
  }
}

module.exports = react;
module.exports.logEvents = logEvents;<commit_msg>Prepend flow name to task name on task.* event log entries<commit_after>'use strict';

/**
   Log events to console.error

   @example
   var react = require('react');
   react.logEvents(); // log all task and flow events on all react functions
   react.logEvents('task.*'); // log all task events on all react functions
   react.logEvents(flowFn); // log all task and flow events on flowFn only
   react.logEvents(flowFn, 'flow.*'); // log all flow events on flowFn only
  */

var util = require('util'); // TODO replace inspect with something portable to browser

var react = require('../'); // require('react');
react.trackTasks(); // enable task and flow tracking

var ALL_FLOW_EVENTS = 'flow.*';
var ALL_TASK_EVENTS = 'task.*';
var FLOW_RE = /^flow\./;

function flowLog(obj) {
  /*jshint validthis: true */
  var time = new Date();
  time.setTime(obj.time);
  var argsNoCb = obj.args.filter(function (a) { return (typeof(a) !== 'function'); });
  var eventTimeStr = time.toISOString();
  if (this.event === 'flow.complete') {
    var env = obj;
    console.error('%s: %s \tmsecs: %s \n\targs: %s \n\tresults: %s\n',
                  this.event, env.name, env.elapsedTime, util.inspect(argsNoCb), util.inspect(env.results));
  } else {
    var name = obj.name;
    var args = obj.args;
    console.error('%s: %s \n\targs: %s\n', this.event, name, util.inspect(argsNoCb));
  }
}

function taskLog(obj) {
  /*jshint validthis: true */
  var time = new Date();
  time.setTime(obj.time);
  var argsNoCb = obj.args.filter(function (a) { return (typeof(a) !== 'function'); });
  var eventTimeStr = time.toISOString();
  if (this.event === 'task.complete') {
    var task = obj;
    console.error('%s: %s:%s \tmsecs: %s \n\targs: %s \n\tresults: %s\n',
                  this.event, task.env.name, task.name, task.elapsedTime, util.inspect(argsNoCb), util.inspect(task.results));
  } else {
    var name = obj.name;
    var args = obj.args;
    console.error('%s: %s:%s \n\targs: %s\n', this.event, obj.env.name, obj.name, util.inspect(argsNoCb));
  }

}

/**
   Log flow and task events for a flowFn or all of react.
   If called multiple times, remove previous listener (if any) before
   adding.

   @example
   var react = require('react');
   react.logEvents(flowFn, eventWildcard); //log events on flowfn matching wildcard

   @param flowFn Flow function or global react object
   @param eventWildcard wildcarded event type, if not provided use flow.* and task.*
  */
function logEvents(flowFn, eventWildcard) {
  if (!flowFn) flowFn = react; // use global
  if (eventWildcard && eventWildcard !== '*') {
    var logFn = (FLOW_RE.test(eventWildcard)) ? flowLog : taskLog;
    flowFn.events.removeListener(eventWildcard, logFn);
    flowFn.events.on(eventWildcard, logFn);
  } else { // none provided, use flow.* and task.*
    //output events as tasks start and complete
    flowFn.events.removeListener(ALL_FLOW_EVENTS, flowLog);
    flowFn.events.on(ALL_FLOW_EVENTS, flowLog);
    flowFn.events.removeListener(ALL_TASK_EVENTS, taskLog);
    flowFn.events.on(ALL_TASK_EVENTS, taskLog);
  }
}

module.exports = react;
module.exports.logEvents = logEvents;<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013, Yahoo! Inc.  All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */

/*jslint node:true, nomen: true */

/**
The `express-middleware` exports few middlewares that provide some basic
features to attach information into the `res.locals` object
that could be used to boot `YUI` in the client runtime.

@module express-middleware
**/

'use strict';

var utils = require('./utils'),
    debug = require('debug')('express:yui'),
    middleware = require('modown-static'),

    NODE_ENV   = process.env.NODE_ENV || 'development',
    FILTERS_MAP = {
        raw: '',
        min: '-min',
        debug: '-debug'
    },
    DEFAULT_FILTER = '-min';

/**
The `express-middleware` exports few middlewares that provide some basic
features to attach information into the `res.locals` object
that could be used to boot `YUI` in the client runtime.

    var app = express();
    app.yui.applyConfig({ fetchCSS: false });
    app.use(yui.expose());

@class middleware
@static
@uses utils, debug
@extensionfor yui
*/
module.exports = {

    /**
    Exposes `res.locals.yui_config` string with the serialized
    configuration computed based on all the calls to `app.yui.*`
    methods. This middleware will be invoked by `yui.expose` middleware
    automatically, which means you should not call it directly.

    @method exposeConfig
    @protected
    @return {function} express middleware
    **/
    exposeConfig: function () {

        var configCache;

        function composeConfigBlob(yui) {
            var config = yui.config(),
                blob = 'YUI.applyConfig(' + utils.serialize(config) + ');';
            if (config.extendedCore) {
                blob = 'YUI.Env.core.push.apply(YUI.Env.core,' +
                    utils.serialize(config.extendedCore) + ');' + blob;
            }
            return '(function(){' + blob + '}())';
        }

        return function (req, res, next) {

            var yui_config = configCache;

            // if app.yui exists, we can expose the configuration
            if (!yui_config && req.app && req.app.yui) {
                // one time operation to compute the initial configuration
                // and caching the serialized version of it
                yui_config = configCache = composeConfigBlob(req.app.yui);
            }

            // exposing the serialized version of the config
            res.locals.yui_config = yui_config;

            next();

        };

    },

    /**
    Expose the seed information to the client.
    Usually, `yui.expose()` will take care of calling
    `yui.exposeSeed()`, although you can do it directly.

    This method will expose an array through
    `res.locals.yui_seed` with the following format:

        [
            {src: "path/to/yui.js"},
            {src: "path/to/another.js"}
        ]

    In your template (assuming using handlebars):

        {{#yui_seed}}
        <script src="{{{src}}}"></script>
        {{/yui_seed}}

    Adjust the format if using a different template engine.

    @method exposeSeed
    @protected
    @return {function} express middleware
    **/
    exposeSeed: function () {

        var seedCache;

        function composeSeedList(yui) {
            // getting static config
            var config = yui.config(),
                modules = config.seed || yui.getDefaultSeed(),
                seedCache = [],
                groups = config.groups || {},
                prevGroup,
                stack = [],
                groupName,
                groupConfig,
                path,
                filter,
                i,
                m,
                moduleName;

            function flush(newGroup) {
                if (stack.length > 0) {
                    seedCache.push({
                        src: prevGroup.comboBase + stack.join(prevGroup.comboSep)
                    });
                }
                stack = [];
            }

            function isSimilarGroup(newGroup) {
                return newGroup && newGroup.combine && prevGroup && prevGroup.combine &&
                    newGroup.comboBase === prevGroup.comboBase &&
                    newGroup.comboSep === prevGroup.comboSep;
            }

            // producing an array of objects with the src
            // for each file in the seed.
            for (i = 0; i < modules.length; i += 1) {
                // a module in the list might have a suffix with the group name denotated as @<groupname>
                m = modules[i].split('@');
                moduleName  = m[0];
                if (m[1]) {
                    groupName   = m[1];
                    groupConfig = groups[groupName]; // group config
                } else {
                    groupName   = 'yui';
                    groupConfig = config; // core config
                }

                // computing the default filter for yui core modules
                // default is always -min
                filter = groupConfig.filter || config.filter; // inheriting from yui config
                filter = filter && FILTERS_MAP.hasOwnProperty(filter) ?
                        FILTERS_MAP[filter] : DEFAULT_FILTER;

                // just build the url as loader will do at the client side.
                path = moduleName + '/' + moduleName + filter + '.js';

                if (groupConfig) {

                    if (!isSimilarGroup(groupConfig)) {
                        flush(groupConfig);
                    }
                    if (groupConfig.combine) {
                        stack.push(groupConfig.root + path);
                    } else {
                        seedCache.push({
                            src: groupConfig.base + path
                        });
                    }
                    prevGroup = groupConfig;

                } else {

                    debug('Skipping module [' + moduleName + '] form ' +
                        'seed due to invalid group resolution.');

                }

            }

            // flushing any remaining piece in stack
            flush();

            return seedCache;
        }

        return function (req, res, next) {

            var yui_seed = seedCache;

            if (!yui_seed && req.app && req.app.yui) {
                yui_seed = seedCache = composeSeedList(req.app.yui);
            }

            res.locals.yui_seed = yui_seed;

            next();

        };

    },

    /**
    Exposes different data structures thru `res.locals.*`,
    all of them will be prefixed with `yui_` to avoid collitions.
    E.g: `res.locals.yui_seed` and `res.locals.yui_config`.
    Each of these structures could be string, array or object.

    @method expose
    @public
    @return {function[]} express middleware collection
    **/
    expose: function () {

        return [this.exposeConfig(), this.exposeSeed()];

    },

    /**
    Serves YUI Modules as static assets. All registered groups and core will be
    served if they have the proper configuration to be used from app origin.

        app.use(yui.static());

    @method static
    @public
    @param {Object} options express static handler options
    @return {Function} express middleware
    **/
    'static': function (options) {

        var staticCache;

        options = options || {};

        // Disable HTTP caching when in dev and no maxAge option is set
        if (!options.maxAge && NODE_ENV === "development") {
            options.maxAge = 0;
        }

        function composeStaticHandlers(yui) {
            var config = yui.config(),
                groups = config.groups || {},
                group,
                handlers = [],
                localGroupConfig;

            // first, yui core if it is marked as local
            if (config.local) {
                handlers.push(middleware.folder('yui', yui.path, options));
                localGroupConfig = config.combine || config;
            }

            // second, each group might be marked as local, and should be included
            for (group in groups) {
                if (groups.hasOwnProperty(group) && groups[group].local && yui._groupFolderMap && yui._groupFolderMap[group]) {
                    handlers.push(middleware.folder(group, yui._groupFolderMap[group], utils.extend({}, options)));
                    localGroupConfig = localGroupConfig || (groups[group].combine && groups[group]);
                }
            }

            // only if there is a group with local && combine, we enable the combo
            // and we will pick the comboSep & comboBase from one of those groups
            // as the basic setting for the `combine` handler.
            if (localGroupConfig) {
                handlers.push(middleware.combine(utils.extend({}, options, {
                    comboSep: localGroupConfig.comboSep,
                    comboBase: localGroupConfig.comboBase
                })));
            }

            return handlers;
        }

        return function (req, res, next) {

            var handlers = staticCache;

            function run(index) {
                if (handlers && index < handlers.length) {
                    handlers[index](req, res, function (err) {
                        if (err) {
                            return next(err);
                        }
                        index += 1;
                        run(index);
                    });
                } else {
                    next();
                }
            }

            if (!handlers && req.app && req.app.yui) {
                handlers = staticCache = composeStaticHandlers(req.app.yui);
            }

            run(0);
        };

    }

};
<commit_msg>some extra guarding<commit_after>/*
 * Copyright (c) 2013, Yahoo! Inc.  All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */

/*jslint node:true, nomen: true */

/**
The `express-middleware` exports few middlewares that provide some basic
features to attach information into the `res.locals` object
that could be used to boot `YUI` in the client runtime.

@module express-middleware
**/

'use strict';

var utils = require('./utils'),
    debug = require('debug')('express:yui'),
    middleware = require('modown-static'),

    NODE_ENV   = process.env.NODE_ENV || 'development',
    FILTERS_MAP = {
        raw: '',
        min: '-min',
        debug: '-debug'
    },
    DEFAULT_FILTER = '-min';

/**
The `express-middleware` exports few middlewares that provide some basic
features to attach information into the `res.locals` object
that could be used to boot `YUI` in the client runtime.

    var app = express();
    app.yui.applyConfig({ fetchCSS: false });
    app.use(yui.expose());

@class middleware
@static
@uses utils, debug
@extensionfor yui
*/
module.exports = {

    /**
    Exposes `res.locals.yui_config` string with the serialized
    configuration computed based on all the calls to `app.yui.*`
    methods. This middleware will be invoked by `yui.expose` middleware
    automatically, which means you should not call it directly.

    @method exposeConfig
    @protected
    @return {function} express middleware
    **/
    exposeConfig: function () {

        var configCache;

        function composeConfigBlob(yui) {
            var config = yui.config(),
                blob = 'YUI.applyConfig(' + utils.serialize(config) + ');';
            if (config.extendedCore) {
                blob = 'YUI.Env.core.push.apply(YUI.Env.core,' +
                    utils.serialize(config.extendedCore) + ');' + blob;
            }
            return '(function(){' + blob + '}())';
        }

        return function (req, res, next) {

            var yui_config = configCache;

            // if app.yui exists, we can expose the configuration
            if (!yui_config && req.app && req.app.yui) {
                // one time operation to compute the initial configuration
                // and caching the serialized version of it
                yui_config = configCache = composeConfigBlob(req.app.yui);
            }

            // exposing the serialized version of the config
            res.locals.yui_config = yui_config;

            next();

        };

    },

    /**
    Expose the seed information to the client.
    Usually, `yui.expose()` will take care of calling
    `yui.exposeSeed()`, although you can do it directly.

    This method will expose an array through
    `res.locals.yui_seed` with the following format:

        [
            {src: "path/to/yui.js"},
            {src: "path/to/another.js"}
        ]

    In your template (assuming using handlebars):

        {{#yui_seed}}
        <script src="{{{src}}}"></script>
        {{/yui_seed}}

    Adjust the format if using a different template engine.

    @method exposeSeed
    @protected
    @return {function} express middleware
    **/
    exposeSeed: function () {

        var seedCache;

        function composeSeedList(yui) {
            // getting static config
            var config = yui.config(),
                modules = config.seed || yui.getDefaultSeed(),
                seedCache = [],
                groups = config.groups || {},
                prevGroup,
                stack = [],
                groupName,
                groupConfig,
                path,
                filter,
                i,
                m,
                moduleName;

            function flush(newGroup) {
                if (stack.length > 0) {
                    seedCache.push({
                        src: prevGroup.comboBase + stack.join(prevGroup.comboSep)
                    });
                }
                stack = [];
            }

            function isSimilarGroup(newGroup) {
                return newGroup && newGroup.combine && prevGroup && prevGroup.combine &&
                    newGroup.comboBase === prevGroup.comboBase &&
                    newGroup.comboSep === prevGroup.comboSep;
            }

            // producing an array of objects with the src
            // for each file in the seed.
            for (i = 0; i < modules.length; i += 1) {
                // a module in the list might have a suffix with the group name denotated as @<groupname>
                m = modules[i].split('@');
                moduleName  = m[0];
                if (m[1]) {
                    groupName   = m[1];
                    groupConfig = groups[groupName]; // group config
                } else {
                    groupName   = 'yui';
                    groupConfig = config; // core config
                }

                // computing the default filter for yui core modules
                // default is always -min
                filter = groupConfig.filter || config.filter; // inheriting from yui config
                filter = filter && FILTERS_MAP.hasOwnProperty(filter) ?
                        FILTERS_MAP[filter] : DEFAULT_FILTER;

                // just build the url as loader will do at the client side.
                path = moduleName + '/' + moduleName + filter + '.js';

                if (groupConfig) {

                    if (!isSimilarGroup(groupConfig)) {
                        flush(groupConfig);
                    }
                    if (groupConfig.combine) {
                        stack.push(groupConfig.root + path);
                    } else {
                        seedCache.push({
                            src: groupConfig.base + path
                        });
                    }
                    prevGroup = groupConfig;

                } else {

                    debug('Skipping module [' + moduleName + '] form ' +
                        'seed due to invalid group resolution.');

                }

            }

            // flushing any remaining piece in stack
            flush();

            return seedCache;
        }

        return function (req, res, next) {

            var yui_seed = seedCache;

            if (!yui_seed && req.app && req.app.yui) {
                yui_seed = seedCache = composeSeedList(req.app.yui);
            }

            res.locals.yui_seed = yui_seed;

            next();

        };

    },

    /**
    Exposes different data structures thru `res.locals.*`,
    all of them will be prefixed with `yui_` to avoid collitions.
    E.g: `res.locals.yui_seed` and `res.locals.yui_config`.
    Each of these structures could be string, array or object.

    @method expose
    @public
    @return {function[]} express middleware collection
    **/
    expose: function () {

        return [this.exposeConfig(), this.exposeSeed()];

    },

    /**
    Serves YUI Modules as static assets. All registered groups and core will be
    served if they have the proper configuration to be used from app origin.

        app.use(yui.static());

    @method static
    @public
    @param {Object} options express static handler options
    @return {Function} express middleware
    **/
    'static': function (options) {

        var staticCache;

        options = options || {};

        // Disable HTTP caching when in dev and no maxAge option is set
        if (!options.maxAge && NODE_ENV === "development") {
            options.maxAge = 0;
        }

        function composeStaticHandlers(yui) {
            var config = yui.config(),
                groups = config.groups || {},
                group,
                handlers = [],
                localGroupConfig;

            // first, yui core if it is marked as local
            if (config.local) {
                handlers.push(middleware.folder('yui', yui.path, options));
                localGroupConfig = config.combine && config;
            }

            // second, each group might be marked as local, and should be included
            for (group in groups) {
                if (groups.hasOwnProperty(group) && groups[group].local && yui._groupFolderMap && yui._groupFolderMap[group]) {
                    handlers.push(middleware.folder(group, yui._groupFolderMap[group], utils.extend({}, options)));
                    localGroupConfig = localGroupConfig || (groups[group].combine && groups[group]);
                }
            }

            // only if there is a group with local && combine, we enable the combo
            // and we will pick the comboSep & comboBase from one of those groups
            // as the basic setting for the `combine` handler.
            if (localGroupConfig && localGroupConfig.comboSep && localGroupConfig.comboBase) {
                handlers.push(middleware.combine(utils.extend({}, options, {
                    comboSep: localGroupConfig.comboSep,
                    comboBase: localGroupConfig.comboBase
                })));
            }

            return handlers;
        }

        return function (req, res, next) {

            var handlers = staticCache;

            function run(index) {
                if (handlers && index < handlers.length) {
                    handlers[index](req, res, function (err) {
                        if (err) {
                            return next(err);
                        }
                        index += 1;
                        run(index);
                    });
                } else {
                    next();
                }
            }

            if (!handlers && req.app && req.app.yui) {
                handlers = staticCache = composeStaticHandlers(req.app.yui);
            }

            run(0);
        };

    }

};
<|endoftext|>


<commit_before>/**
 * This is manager that a provides storage
 * and transmitting updates for middleware
 *
 * @module telekit/middleware
 * @author Denis Maslennikov <mrdenniska@gmail.com> (nofach.com)
 * @license MIT
 */

/** Dependencies */
const isArrow = require('isarrow');
const isClass = require('isclass');
const debug = require('debug')('telekit:middleware');

/**
 * Implementation
 * @public
 */
class Middleware {
    constructor(kit) {
        this.kit = kit;
        this.store = [];
    }

    transmit(type, ...params) {
        let next = true;
        let fn = () => next = true;

        debug('transmits %s into middleware', type);
        for (let handle of this.store) {
            if (!next) break;
            if (handle && handle[type]) {
                next = false;
                handle[type](...params, fn);
                continue;
            }

            next = false;
        }
    }

    /**
     * Register middleware into stack
     *
     * @param  {Class|Function} value - The middleware
     * @return {Middleware}
     */
    use(value, ...others) {
        let handle = value;

        /** Value is empty */
        if (!value) return this.kit;

        /** Value is array */
        if (Array.isArray(handle)) {
            handle.forEach((item) => this.use(item, ...others));
            return this.kit;
        }

        debug('use %s', value.name || '_');

        /** Value is function */
        if (typeof(value) == 'function') {
            /** Value is Class */
            if (isClass(value) && !isArrow(value)) {
                handle = new handle(this.kit, ...others);
            } else {
                handle = handle(this.kit, ...others);
            }
        }

        /** Add handle into stack if it there's */
        if (handle) {
            debug('added %s into stack', value.name || '_');
            this.store.push(handle);
        }

        return this.kit;
    }
}

/** Methods */
module.exports = Middleware;
<commit_msg>HOTBUG(@pinkinice it's for you! 💁)<commit_after>/**
 * This is manager that a provides storage
 * and transmitting updates for middleware
 *
 * @module telekit/middleware
 * @author Denis Maslennikov <mrdenniska@gmail.com> (nofach.com)
 * @license MIT
 */

/** Dependencies */
const isArrow = require('isarrow');
const isClass = require('isclass');
const debug = require('debug')('telekit:middleware');

/**
 * Implementation
 * @public
 */
class Middleware {
    constructor(kit) {
        this.kit = kit;
        this.store = [];
    }

    transmit(type, ...params) {
        let next = true;
        let fn = () => next = true;

        debug('transmits %s into middleware', type);
        for (let handle of this.store) {
            if (!next) break;
            if (handle && handle[type]) {
                next = false;
                handle[type](...params, fn);
                continue;
            }

            next = true;
        }
    }

    /**
     * Register middleware into stack
     *
     * @param  {Class|Function} value - The middleware
     * @return {Middleware}
     */
    use(value, ...others) {
        let handle = value;

        /** Value is empty */
        if (!value) return this.kit;

        /** Value is array */
        if (Array.isArray(handle)) {
            handle.forEach((item) => this.use(item, ...others));
            return this.kit;
        }

        debug('use %s', value.name || '_');

        /** Value is function */
        if (typeof(value) == 'function') {
            /** Value is Class */
            if (isClass(value) && !isArrow(value)) {
                handle = new handle(this.kit, ...others);
            } else {
                handle = handle(this.kit, ...others);
            }
        }

        /** Add handle into stack if it there's */
        if (handle) {
            debug('added %s into stack', value.name || '_');
            this.store.push(handle);
        }

        return this.kit;
    }
}

/** Methods */
module.exports = Middleware;
<|endoftext|>


<commit_before>/*
 * middleware: Loads custom and npm middleware.
 */

var path = require('path'),
    fs = require('fs'),
    console = require('./utils');

module.exports = function(app, express){
  var config = iora.config;

  // Check and set defaults
  if (typeof config.base !== 'object') config.base = {};

  var base = config.base.middleware;
  if (typeof base !== 'string') {
    base = path.join(iora.dir, 'middleware');
  } else {
    base = path.resolve(iora.dir, base);
  }

  var middleware = config.middleware;
  if (!Array.isArray(middleware)) middleware = null;

  // Loader:
  var load = function(path){
    try {
      return require.apply(require, arguments);
    } catch (e) {
      iora.warn('Failed to load ' + path);
      return function(){};
    }
  };

  // Load npm middleware
  if (middleware) {
    middleware.forEach(function(name){
      load(name.replace(/^@/, 'iora-'))(app, config, iora, express);
    });
  }

  // Load base folder middleware
  if (base) {
    fs.readdir(base, function(err, files){
      if (!err) {
        files.forEach(function(file){
          load(path.resolve(path.join(base, file)))(app, config, iora, express);
        });
      }
    });
  }
};
<commit_msg>Fixed loading of npm modules.<commit_after>/*
 * middleware: Loads custom and npm middleware.
 */

var path = require('path'),
    fs = require('fs'),
    console = require('./utils');

module.exports = function(app, express){
  var config = iora.config;

  // Check and set defaults
  if (typeof config.base !== 'object') config.base = {};

  var base = config.base.middleware;
  if (typeof base !== 'string') {
    base = path.join(iora.dir, 'middleware');
  } else {
    base = path.resolve(iora.dir, base);
  }

  var middleware = config.middleware;
  if (!Array.isArray(middleware)) middleware = null;

  // Loader:
  var load = function(path){
    try {
      return require(path);
    } catch (e) {
      iora.warn('Failed to load ' + path);
      return function(){};
    }
  };

  // Load npm middleware
  if (middleware) {
    middleware.forEach(function(name){
      load(path.join(iora.dir, 'node_modules', name))(app, config, iora, express);
    });
  }

  // Load base folder middleware
  if (base) {
    fs.readdir(base, function(err, files){
      if (!err) {
        files.forEach(function(file){
          load(path.resolve(path.join(base, file)))(app, config, iora, express);
        });
      }
    });
  }
};
<|endoftext|>


<commit_before>"use strict";

/*!
 * Less - middleware (adapted from the stylus middleware)
 *
 * Copyright(c) 2014 Randy Merrill <Zoramite+github@gmail.com>
 * MIT Licensed
 */

var extend = require('node.extend');
var fs = require('fs');
var less = require('less');
var mkdirp = require('mkdirp');
var path = require('path');
var url = require('url');
var utilities = require('./utilities');

// Import mapping with mtimes
var lessFiles = {};

/**
 * Return Connect middleware with the given `options`.
 */
module.exports = less.middleware = function(source, options){
  // Source dir is required.
  if (!source) {
    throw new Error('less.middleware() requires `source` directory');
  }

  // Override the defaults for the middleware.
  options = extend(true, {
    debug: false,
    dest: source,
    force: false,
    once: false,
    pathRoot: null,
    postprocess: {
      css: function(css, req) { return css; },
      sourcemap: function(sourcemap, req) { return sourcemap; }
    },
    preprocess: {
      less: function(src, req) { return src; },
      path: function(pathname, req) { return pathname; }
    },
    render: {
      compress: 'auto',
      yuicompress: false
    },
    storeCss: function(pathname, css, req, next) {
      mkdirp(path.dirname(pathname), 511 /* 0777 */, function(err){
        if (err) return next(err);

        fs.writeFile(pathname, css, 'utf8', next);
      });
    },
    storeSourcemap: function(pathname, sourcemap, req) {
      mkdirp(path.dirname(pathname), 511 /* 0777 */, function(err){
        if (err) {
          utilities.lessError(err);
          return;
        }

        fs.writeFile(pathname, sourcemap, 'utf8');
      });
    }
  }, options || {});

  // The log function is determined by the debug option.
  var log = (options.debug ? utilities.logDebug : utilities.log);

  // Actual middleware.
  return function(req, res, next) {
    if ('GET' != req.method.toUpperCase() && 'HEAD' != req.method.toUpperCase()) { return next(); }

    var pathname = url.parse(req.url).pathname;

    // Only handle the matching files in this middleware.
    if (utilities.isValidPath(pathname)) {
      var isSourceMap = utilities.isSourceMap(pathname);

      // Translate source maps to a normal .css request which will update the associated source-map.
      if( isSourceMap ){
        pathname = pathname.replace( /\.map$/, '' );
      }
      var lessPath = path.join(source, utilities.maybeCompressedSource(pathname));
      var cssPath = path.join(options.dest, pathname);

      if (options.pathRoot) {
        pathname = pathname.replace(options.dest, '');
        cssPath = path.join(options.pathRoot, options.dest, pathname);
        lessPath = path.join(options.pathRoot, source, utilities.maybeCompressedSource(pathname));
      }

      var sourcemapPath = cssPath + '.map';

      // Allow for preprocessing the source filename.
      lessPath = options.preprocess.path(lessPath, req);

      log('pathname', pathname);
      log('source', lessPath);
      log('destination', cssPath);

      // Ignore ENOENT to fall through as 404.
      var error = function(err) {
        return next('ENOENT' == err.code ? null : err);
      };

      var compile = function() {
        fs.readFile(lessPath, 'utf8', function(err, lessSrc){
          if (err) {
            return error(err);
          }

          delete lessFiles[lessPath];

          try {
            lessSrc = options.preprocess.less(lessSrc, req);
            options.render.filename = lessPath;
            less.render(lessSrc, options.render, function(err, output){
              if (err) {
                utilities.lessError(err);
                return next(err);
              }

              // Store the less paths for simple cache invalidation.
              lessFiles[lessPath] = {
                mtime: Date.now()
              };

              if(output.map) {
                // Postprocessing on the sourcemap.
                var map = options.postprocess.sourcemap(output.map, req);

                // Custom sourcemap storage.
                options.storeSourcemap(sourcemapPath, map, req);
              }

              // Postprocessing on the css.
              var css = options.postprocess.css(output.css, req);

              // Custom css storage.
              options.storeCss(cssPath, css, req, next);
            });
          } catch (err) {
            utilities.lessError(err);
            return next(err);
          }
        });
      };

      // Force recompile of all files.
      if (options.force) {
        return compile();
      }

      // Only compile once, disregarding the file changes.
      if (options.once && lessFiles[lessPath]) {
        return next();
      }

      // Compile on server restart and new files.
      if (!lessFiles[lessPath]) {
        return compile();
      }

      // Compare mtimes to determine if changed.
      fs.stat(lessPath, function(err, lessStats){
        if (err) {
          return error(err);
        }

        fs.stat(cssPath, function(err, cssStats){
          // CSS has not been compiled, compile it!
          if (err) {
            if ('ENOENT' == err.code) {
              log('not found', cssPath);

              // No CSS file found in dest
              return compile();
            }

            return next(err);
          }

          if (lessStats.mtime > cssStats.mtime) {
            // Source has changed, compile it
            log('modified', cssPath);

            return compile();
          } else if (lessStats.mtime > lessFiles[lessPath].mtime) {
            // This can happen if lessFiles[lessPath] was copied from
            // cachedLessFiles above, but the cache file was out of date (which
            // can happen e.g. if node is killed and we were unable to write out
            // lessFiles on exit). Since imports might have changed, we need to
            // recompile.
            log('cache file out of date for', lessPath);

            return compile();
          } else {
            return next();
          }
        });
      });
    } else {
      return next();
    }
  };
};
<commit_msg>Bringing back the ability to monitor the imports for changes to trigger recompile.<commit_after>"use strict";

/*!
 * Less - middleware (adapted from the stylus middleware)
 *
 * Copyright(c) 2014 Randy Merrill <Zoramite+github@gmail.com>
 * MIT Licensed
 */

var extend = require('node.extend');
var fs = require('fs');
var less = require('less');
var mkdirp = require('mkdirp');
var path = require('path');
var url = require('url');
var utilities = require('./utilities');

// Import mapping with mtimes
var lessFiles = {};

// Check imports for changes.
var checkImports = function(path, next) {
  var nodes = lessFiles[path].imports;

  if (!nodes || !nodes.length) {
    return next();
  }

  var pending = nodes.length;
  var changed = [];

  nodes.forEach(function(imported){
    fs.stat(imported.path, function(err, stat) {
      // error or newer mtime
      if (err || !imported.mtime || stat.mtime > imported.mtime) {
        changed.push(imported.path);
      }

      --pending || next(changed);
    });
  });
};

/**
 * Return Connect middleware with the given `options`.
 */
module.exports = less.middleware = function(source, options){
  // Source dir is required.
  if (!source) {
    throw new Error('less.middleware() requires `source` directory');
  }

  // Override the defaults for the middleware.
  options = extend(true, {
    debug: false,
    dest: source,
    force: false,
    once: false,
    pathRoot: null,
    postprocess: {
      css: function(css, req) { return css; },
      sourcemap: function(sourcemap, req) { return sourcemap; }
    },
    preprocess: {
      less: function(src, req) { return src; },
      path: function(pathname, req) { return pathname; }
    },
    render: {
      compress: 'auto',
      yuicompress: false
    },
    storeCss: function(pathname, css, req, next) {
      mkdirp(path.dirname(pathname), 511 /* 0777 */, function(err){
        if (err) return next(err);

        fs.writeFile(pathname, css, 'utf8', next);
      });
    },
    storeSourcemap: function(pathname, sourcemap, req) {
      mkdirp(path.dirname(pathname), 511 /* 0777 */, function(err){
        if (err) {
          utilities.lessError(err);
          return;
        }

        fs.writeFile(pathname, sourcemap, 'utf8');
      });
    }
  }, options || {});

  // The log function is determined by the debug option.
  var log = (options.debug ? utilities.logDebug : utilities.log);

  // Actual middleware.
  return function(req, res, next) {
    if ('GET' != req.method.toUpperCase() && 'HEAD' != req.method.toUpperCase()) { return next(); }

    var pathname = url.parse(req.url).pathname;

    // Only handle the matching files in this middleware.
    if (utilities.isValidPath(pathname)) {
      var isSourceMap = utilities.isSourceMap(pathname);

      // Translate source maps to a normal .css request which will update the associated source-map.
      if( isSourceMap ){
        pathname = pathname.replace( /\.map$/, '' );
      }
      var lessPath = path.join(source, utilities.maybeCompressedSource(pathname));
      var cssPath = path.join(options.dest, pathname);

      if (options.pathRoot) {
        pathname = pathname.replace(options.dest, '');
        cssPath = path.join(options.pathRoot, options.dest, pathname);
        lessPath = path.join(options.pathRoot, source, utilities.maybeCompressedSource(pathname));
      }

      var sourcemapPath = cssPath + '.map';

      // Allow for preprocessing the source filename.
      lessPath = options.preprocess.path(lessPath, req);

      log('pathname', pathname);
      log('source', lessPath);
      log('destination', cssPath);

      // Ignore ENOENT to fall through as 404.
      var error = function(err) {
        return next('ENOENT' == err.code ? null : err);
      };

      var compile = function() {
        fs.readFile(lessPath, 'utf8', function(err, lessSrc){
          if (err) {
            return error(err);
          }

          delete lessFiles[lessPath];

          try {
            lessSrc = options.preprocess.less(lessSrc, req);
            options.render.filename = lessPath;
            less.render(lessSrc, options.render, function(err, output){
              if (err) {
                utilities.lessError(err);
                return next(err);
              }

              // Store the less paths for simple cache invalidation.
              lessFiles[lessPath] = {
                mtime: Date.now(),
                imports: output.imports
              };

              if(output.map) {
                // Postprocessing on the sourcemap.
                var map = options.postprocess.sourcemap(output.map, req);

                // Custom sourcemap storage.
                options.storeSourcemap(sourcemapPath, map, req);
              }

              // Postprocessing on the css.
              var css = options.postprocess.css(output.css, req);

              // Custom css storage.
              options.storeCss(cssPath, css, req, next);
            });
          } catch (err) {
            utilities.lessError(err);
            return next(err);
          }
        });
      };

      // Force recompile of all files.
      if (options.force) {
        return compile();
      }

      // Only compile once, disregarding the file changes.
      if (options.once && lessFiles[lessPath]) {
        return next();
      }

      // Compile on server restart and new files.
      if (!lessFiles[lessPath]) {
        return compile();
      }

      // Compare mtimes to determine if changed.
      fs.stat(lessPath, function(err, lessStats){
        if (err) {
          return error(err);
        }

        fs.stat(cssPath, function(err, cssStats){
          // CSS has not been compiled, compile it!
          if (err) {
            if ('ENOENT' == err.code) {
              log('not found', cssPath);

              // No CSS file found in dest
              return compile();
            }

            return next(err);
          }

          if (lessStats.mtime > cssStats.mtime) {
            // Source has changed, compile it
            log('modified', cssPath);

            return compile();
          } else if (lessStats.mtime > lessFiles[lessPath].mtime) {
            // This can happen if lessFiles[lessPath] was copied from
            // cachedLessFiles above, but the cache file was out of date (which
            // can happen e.g. if node is killed and we were unable to write out
            // lessFiles on exit). Since imports might have changed, we need to
            // recompile.
            log('cache file out of date for', lessPath);

            return compile();
          } else {
            // Check if any of the less imports were changed
            checkImports(lessPath, function(changed){
              if(typeof changed != "undefined" && changed.length) {
                log('modified import', changed);

                return compile();
              }

              return next();
            });
          }
        });
      });
    } else {
      return next();
    }
  };
};
<|endoftext|>