<commit_before>var EventEmitter = require('events').EventEmitter
var gzipMaybe = require('http-gzip-maybe')
var gzipSize = require('gzip-size')
var assert = require('assert')
var path = require('path')
var pump = require('pump')
var send = require('send')

var Router = require('./lib/regex-router')
var ui = require('./lib/ui')
var bankai = require('./')

var files = [
  'assets',
  'documents',
  'scripts',
  'manifest',
  'styles',
  'service-worker'
]

module.exports = start

function start (entry, opts) {
  opts = opts || {}

  assert.equal(typeof entry, 'string', 'bankai/http: entry should be type string')
  assert.equal(typeof opts, 'object', 'bankai/http: opts should be type object')

  var quiet = !!opts.quiet
  opts = Object.assign({ reload: true }, opts)
  var compiler = bankai(entry, opts)
  var router = new Router()
  var emitter = new EventEmitter()
  var id = 0
  var state = {
    count: compiler.metadata.count,
    files: {},
    sse: 0,
    size: 0
  }

  files.forEach(function (filename) {
    state.files[filename] = {
      name: filename,
      progress: 0,
      timestamp: '        ',
      size: 0,
      status: 'pending',
      done: false
    }
  })

  if (!quiet) var render = ui(state)
  compiler.on('error', function (topic, sub, err) {
    if (err.pretty) state.error = err.pretty
    else state.error = `${topic}:${sub} ${err.message}\n${err.stack}`
    if (!quiet) render()
  })

  compiler.on('progress', function () {
    state.error = null
    if (!quiet) render()
  })

  compiler.on('ssr', function (result) {
    state.ssr = result
  })

  compiler.on('change', function (nodeName, edgeName, nodeState) {
    var node = nodeState[nodeName][edgeName]
    var name = nodeName + ':' + edgeName
    var data = {
      name: nodeName,
      progress: 100,
      timestamp: time(),
      size: 0,
      status: 'done',
      done: true
    }
    state.files[nodeName] = data

    if (name === 'documents:index.html') emitter.emit('documents:index.html', node)
    if (name === 'styles:bundle') emitter.emit('styles:bundle', node)

    // Only calculate the gzip size if there's a buffer. Apparently zipping
    // an empty file means it'll pop out with a 20B base size.
    if (node.buffer.length) {
      gzipSize(node.buffer, function (err, size) {
        if (err) data.size = node.buffer.length
        else data.size = size
        if (!quiet) render()
      })
    }
    if (!quiet) render()
  })

  router.route(/^\/manifest.json$/, function (req, res, params) {
    compiler.manifest(function (err, node) {
      if (err) {
        res.statusCode = 404
        return res.end(err.message)
      }
      res.setHeader('content-type', 'application/json')
      gzip(node.buffer, req, res)
    })
  })

  router.route(/\/(service-worker\.js)|(\/sw\.js)$/, function (req, res, params) {
    compiler.serviceWorker(function (err, node) {
      if (err) {
        res.statusCode = 404
        return res.end(err.message)
      }
      res.setHeader('content-type', 'application/javascript')
      gzip(node.buffer, req, res)
    })
  })

  router.route(/\/([a-zA-Z0-9-_.]+)\.js\?{0,1}[\w&=]*$/, function (req, res, params) {
    var name = params[1]
    compiler.scripts(name, function (err, node) {
      if (err) {
        res.statusCode = 404
        return res.end(err.message)
      }
      res.setHeader('content-type', 'application/javascript')
      gzip(node.buffer, req, res)
    })
  })

  router.route(/\/([a-zA-Z0-9-_.]+)\.css\?{0,1}[\w&=]*$/, function (req, res, params) {
    var name = params[1]
    compiler.styles(name, function (err, node) {
      if (err) {
        res.statusCode = 404
        return res.end(err.message)
      }
      res.setHeader('content-type', 'text/css')
      gzip(node.buffer, req, res)
    })
  })

  // Source maps. Each source map is stored as 'foo.js.map' within their
  // respective node. So in order to figure out the right source map we must
  // derive figure out where the extension comes from.
  router.route(/\/([a-zA-Z0-9-_.]+)\.map$/, function (req, res, params) {
    var source = params[1]
    var ext = path.extname(source.replace(/\.map$/, ''))
    var type = source === 'bankai-reload.js'
      ? 'reload'
      : source === 'bankai-service-worker.js'
        ? 'service-worker'
        : ext === '.js'
          ? 'scripts'
          : 'unknown'
    compiler.sourceMaps(type, source, function (err, node) {
      if (err) {
        res.statusCode = 404
        return res.end(err.message)
      }
      res.setHeader('content-type', 'application/json')
      gzip(node.buffer, req, res)
    })
  })

  router.route(/^\/assets\/([a-zA-Z0-9-_.]*)\?{0,1}[\w&=]*$/, function (req, res, params) {
    var prefix = 'assets' // TODO: also accept 'content'
    var name = prefix + '/' + params[1]
    compiler.assets(name, function (err, filename) {
      if (err) {
        res.statusCode = 404
        return res.end(err.message)
      }
      pump(send(req, filename), res)
    })
  })

  router.route(/\/reload/, function sse (req, res) {
    var connected = true
    emitter.on('documents:index.html', reloadScript)
    emitter.on('styles:bundle', reloadStyle)
    state.sse += 1
    if (!quiet) render()

    res.writeHead(200, {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache'
    })
    res.write('retry: 10000\n')

    var interval = setInterval(function () {
      if (res.finished) return // prevent writes after stream has closed
      res.write(`id:${id++}\ndata:{ "type:": "heartbeat" }\n\n`)
    }, 4000)

    req.on('error', disconnect)
    res.on('error', disconnect)
    res.on('close', disconnect)
    res.on('finish', disconnect)

    function disconnect () {
      clearInterval(interval)
      if (connected) {
        emitter.removeListener('documents:index.html', reloadScript)
        emitter.removeListener('styles:bundle', reloadStyle)
        connected = false
        state.sse -= 1
        if (!quiet) render()
      }
    }

    function reloadScript (node) {
      var msg = JSON.stringify({ type: 'scripts' })
      res.write(`id:${id++}\ndata:${msg}\n\n`)
    }

    function reloadStyle (node) {
      var msg = JSON.stringify({
        type: 'styles',
        bundle: node.buffer.toString()
      })
      res.write(`id:${id++}\ndata:${msg}\n\n`)
    }
  })

  router.default(function (req, res, next) {
    var url = req.url

    if (state.ssr && state.ssr.renderRoute) {
      state.ssr.renderRoute(url, function (err, buffer) {
        if (err) {
          state.ssr.success = false
          state.ssr.error = err
          return sendDocument(url, req, res, next)
        }

        res.setHeader('content-type', 'text/html')
        gzip(buffer, req, res)
      })
    } else {
      return sendDocument(url, req, res, next)
    }
  })

  function sendDocument (url, req, res, next) {
    compiler.documents(url, function (err, node) {
      if (err) {
        return compiler.documents('/404', function (err, node) {
          if (err) return next() // No matches found, call next
          res.statusCode = 404
          res.setHeader('content-type', 'text/html')
          gzip(node.buffer, req, res)
        })
      }
      res.setHeader('content-type', 'text/html')
      gzip(node.buffer, req, res)
    })
  }

  // TODO: move all UI code out of this file
  handler.state = state
  return handler

  // Return a handler to listen.
  function handler (req, res, next) {
    router.match(req, res, next)
  }
}

function gzip (buffer, req, res) {
  var zipper = gzipMaybe(req, res)
  pump(zipper, res)
  zipper.end(buffer)
}

function time () {
  var date = new Date()
  var hours = numPad(date.getHours())
  var minutes = numPad(date.getMinutes())
  var seconds = numPad(date.getSeconds())
  return `${hours}:${minutes}:${seconds}`
}

function numPad (num) {
  if (num < 10) num = '0' + num
  return num
}
<commit_msg>Add X-Accel-Buffering: no to /reload's header (#389)<commit_after>var EventEmitter = require('events').EventEmitter
var gzipMaybe = require('http-gzip-maybe')
var gzipSize = require('gzip-size')
var assert = require('assert')
var path = require('path')
var pump = require('pump')
var send = require('send')

var Router = require('./lib/regex-router')
var ui = require('./lib/ui')
var bankai = require('./')

var files = [
  'assets',
  'documents',
  'scripts',
  'manifest',
  'styles',
  'service-worker'
]

module.exports = start

function start (entry, opts) {
  opts = opts || {}

  assert.equal(typeof entry, 'string', 'bankai/http: entry should be type string')
  assert.equal(typeof opts, 'object', 'bankai/http: opts should be type object')

  var quiet = !!opts.quiet
  opts = Object.assign({ reload: true }, opts)
  var compiler = bankai(entry, opts)
  var router = new Router()
  var emitter = new EventEmitter()
  var id = 0
  var state = {
    count: compiler.metadata.count,
    files: {},
    sse: 0,
    size: 0
  }

  files.forEach(function (filename) {
    state.files[filename] = {
      name: filename,
      progress: 0,
      timestamp: '        ',
      size: 0,
      status: 'pending',
      done: false
    }
  })

  if (!quiet) var render = ui(state)
  compiler.on('error', function (topic, sub, err) {
    if (err.pretty) state.error = err.pretty
    else state.error = `${topic}:${sub} ${err.message}\n${err.stack}`
    if (!quiet) render()
  })

  compiler.on('progress', function () {
    state.error = null
    if (!quiet) render()
  })

  compiler.on('ssr', function (result) {
    state.ssr = result
  })

  compiler.on('change', function (nodeName, edgeName, nodeState) {
    var node = nodeState[nodeName][edgeName]
    var name = nodeName + ':' + edgeName
    var data = {
      name: nodeName,
      progress: 100,
      timestamp: time(),
      size: 0,
      status: 'done',
      done: true
    }
    state.files[nodeName] = data

    if (name === 'documents:index.html') emitter.emit('documents:index.html', node)
    if (name === 'styles:bundle') emitter.emit('styles:bundle', node)

    // Only calculate the gzip size if there's a buffer. Apparently zipping
    // an empty file means it'll pop out with a 20B base size.
    if (node.buffer.length) {
      gzipSize(node.buffer, function (err, size) {
        if (err) data.size = node.buffer.length
        else data.size = size
        if (!quiet) render()
      })
    }
    if (!quiet) render()
  })

  router.route(/^\/manifest.json$/, function (req, res, params) {
    compiler.manifest(function (err, node) {
      if (err) {
        res.statusCode = 404
        return res.end(err.message)
      }
      res.setHeader('content-type', 'application/json')
      gzip(node.buffer, req, res)
    })
  })

  router.route(/\/(service-worker\.js)|(\/sw\.js)$/, function (req, res, params) {
    compiler.serviceWorker(function (err, node) {
      if (err) {
        res.statusCode = 404
        return res.end(err.message)
      }
      res.setHeader('content-type', 'application/javascript')
      gzip(node.buffer, req, res)
    })
  })

  router.route(/\/([a-zA-Z0-9-_.]+)\.js\?{0,1}[\w&=]*$/, function (req, res, params) {
    var name = params[1]
    compiler.scripts(name, function (err, node) {
      if (err) {
        res.statusCode = 404
        return res.end(err.message)
      }
      res.setHeader('content-type', 'application/javascript')
      gzip(node.buffer, req, res)
    })
  })

  router.route(/\/([a-zA-Z0-9-_.]+)\.css\?{0,1}[\w&=]*$/, function (req, res, params) {
    var name = params[1]
    compiler.styles(name, function (err, node) {
      if (err) {
        res.statusCode = 404
        return res.end(err.message)
      }
      res.setHeader('content-type', 'text/css')
      gzip(node.buffer, req, res)
    })
  })

  // Source maps. Each source map is stored as 'foo.js.map' within their
  // respective node. So in order to figure out the right source map we must
  // derive figure out where the extension comes from.
  router.route(/\/([a-zA-Z0-9-_.]+)\.map$/, function (req, res, params) {
    var source = params[1]
    var ext = path.extname(source.replace(/\.map$/, ''))
    var type = source === 'bankai-reload.js'
      ? 'reload'
      : source === 'bankai-service-worker.js'
        ? 'service-worker'
        : ext === '.js'
          ? 'scripts'
          : 'unknown'
    compiler.sourceMaps(type, source, function (err, node) {
      if (err) {
        res.statusCode = 404
        return res.end(err.message)
      }
      res.setHeader('content-type', 'application/json')
      gzip(node.buffer, req, res)
    })
  })

  router.route(/^\/assets\/([a-zA-Z0-9-_.]*)\?{0,1}[\w&=]*$/, function (req, res, params) {
    var prefix = 'assets' // TODO: also accept 'content'
    var name = prefix + '/' + params[1]
    compiler.assets(name, function (err, filename) {
      if (err) {
        res.statusCode = 404
        return res.end(err.message)
      }
      pump(send(req, filename), res)
    })
  })

  router.route(/\/reload/, function sse (req, res) {
    var connected = true
    emitter.on('documents:index.html', reloadScript)
    emitter.on('styles:bundle', reloadStyle)
    state.sse += 1
    if (!quiet) render()

    res.writeHead(200, {
      'Content-Type': 'text/event-stream',
      'X-Accel-Buffering': 'no',
      'Cache-Control': 'no-cache'
    })
    res.write('retry: 10000\n')

    var interval = setInterval(function () {
      if (res.finished) return // prevent writes after stream has closed
      res.write(`id:${id++}\ndata:{ "type:": "heartbeat" }\n\n`)
    }, 4000)

    req.on('error', disconnect)
    res.on('error', disconnect)
    res.on('close', disconnect)
    res.on('finish', disconnect)

    function disconnect () {
      clearInterval(interval)
      if (connected) {
        emitter.removeListener('documents:index.html', reloadScript)
        emitter.removeListener('styles:bundle', reloadStyle)
        connected = false
        state.sse -= 1
        if (!quiet) render()
      }
    }

    function reloadScript (node) {
      var msg = JSON.stringify({ type: 'scripts' })
      res.write(`id:${id++}\ndata:${msg}\n\n`)
    }

    function reloadStyle (node) {
      var msg = JSON.stringify({
        type: 'styles',
        bundle: node.buffer.toString()
      })
      res.write(`id:${id++}\ndata:${msg}\n\n`)
    }
  })

  router.default(function (req, res, next) {
    var url = req.url

    if (state.ssr && state.ssr.renderRoute) {
      state.ssr.renderRoute(url, function (err, buffer) {
        if (err) {
          state.ssr.success = false
          state.ssr.error = err
          return sendDocument(url, req, res, next)
        }

        res.setHeader('content-type', 'text/html')
        gzip(buffer, req, res)
      })
    } else {
      return sendDocument(url, req, res, next)
    }
  })

  function sendDocument (url, req, res, next) {
    compiler.documents(url, function (err, node) {
      if (err) {
        return compiler.documents('/404', function (err, node) {
          if (err) return next() // No matches found, call next
          res.statusCode = 404
          res.setHeader('content-type', 'text/html')
          gzip(node.buffer, req, res)
        })
      }
      res.setHeader('content-type', 'text/html')
      gzip(node.buffer, req, res)
    })
  }

  // TODO: move all UI code out of this file
  handler.state = state
  return handler

  // Return a handler to listen.
  function handler (req, res, next) {
    router.match(req, res, next)
  }
}

function gzip (buffer, req, res) {
  var zipper = gzipMaybe(req, res)
  pump(zipper, res)
  zipper.end(buffer)
}

function time () {
  var date = new Date()
  var hours = numPad(date.getHours())
  var minutes = numPad(date.getMinutes())
  var seconds = numPad(date.getSeconds())
  return `${hours}:${minutes}:${seconds}`
}

function numPad (num) {
  if (num < 10) num = '0' + num
  return num
}
<|endoftext|>


<commit_before>/**
 * toggle-switch-react-native
 * Toggle Switch component for react native, it works on iOS and Android
 * https://github.com/aminebenkeroum/toggle-switch-react-native
 * Email:amine.benkeroum@gmail.com
 * Blog: https://medium.com/@aminebenkeroum/
 * @benkeroumamine
 */

import React from 'react';
import {
  StyleSheet,
  Text,
  View,
  TouchableOpacity,
  Animated,
} from 'react-native';

import PropTypes from 'prop-types'

export default class ToggleSwitch extends React.Component {
  static calculateDimensions(size) {
    switch (size) {
      case 'small':
        return ({
          width: 50, padding: 10, cercleWidth: 15, cercleHeight: 15, translateX: 22,
        });
      case 'large':
        return ({
          width: 100, padding: 20, cercleWidth: 30, cercleHeight: 30, translateX: 38,
        });
      default:
        return ({
          width: 60, padding: 12, cercleWidth: 18, cercleHeight: 18, translateX: 26,
        });
    }
  }

  static propTypes = {
    isOn: PropTypes.bool.isRequired,
    label: PropTypes.string,
    onColor: PropTypes.string.isRequired,
    offColor: PropTypes.string.isRequired,
    size: PropTypes.string,
    labelStyle: PropTypes.object,
    onToggle: PropTypes.func.isRequired
  }

  static defaultProps = {
    isOn : false,
    onColor: '#634fc9',
    offColor: '#ecf0f1',
    size: 'medium',
    labelStyle: {}
  }

  offsetX = new Animated.Value(0);
  dimensions = ToggleSwitch.calculateDimensions(this.props.size);

  createToggleSwitchStyle = () => ({
    justifyContent: 'center',
    width: this.dimensions.width,
    borderRadius: 20,
    padding: this.dimensions.padding,
    backgroundColor: (this.props.isOn) ? this.props.onColor : this.props.offColor,
  })

  createInsideCercleStyle = () => ({
    margin: 4,
    position: 'absolute',
    backgroundColor: 'white',
    transform: [{ translateX: this.offsetX }],
    width: this.dimensions.cercleWidth,
    height: this.dimensions.cercleHeight,
    borderRadius: (this.dimensions.cercleWidth / 2),
  });

  render() {
    const toValue = this.props.isOn
      ? this.dimensions.width - this.dimensions.translateX
      : 0;

    Animated.timing(
      this.offsetX,
      {
        toValue,
        duration: 300,
      },
    ).start();

    return (
      <View style={styles.container}>
        {(this.props.label)
          ? <Text style={[styles.labelStyle, this.props.labelStyle]}>{this.props.label}</Text>
          : null
        }
        <TouchableOpacity
          style={this.createToggleSwitchStyle()}
          activeOpacity={0.8}
          onPress={() => {
            this.props.onToggle(!this.props.isOn);
          }}
        >
          <Animated.View style={this.createInsideCercleStyle()} />
        </TouchableOpacity>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  labelStyle: {
    marginHorizontal: 10,
  },
});
<commit_msg>Fix: Typo for `circle`<commit_after>/**
 * toggle-switch-react-native
 * Toggle Switch component for react native, it works on iOS and Android
 * https://github.com/aminebenkeroum/toggle-switch-react-native
 * Email:amine.benkeroum@gmail.com
 * Blog: https://medium.com/@aminebenkeroum/
 * @benkeroumamine
 */

import React from 'react';
import {
  StyleSheet,
  Text,
  View,
  TouchableOpacity,
  Animated,
} from 'react-native';

import PropTypes from 'prop-types'

export default class ToggleSwitch extends React.Component {
  static calculateDimensions(size) {
    switch (size) {
      case 'small':
        return ({
          width: 50, padding: 10, circleWidth: 15, circleHeight: 15, translateX: 22,
        });
      case 'large':
        return ({
          width: 100, padding: 20, circleWidth: 30, circleHeight: 30, translateX: 38,
        });
      default:
        return ({
          width: 60, padding: 12, circleWidth: 18, circleHeight: 18, translateX: 26,
        });
    }
  }

  static propTypes = {
    isOn: PropTypes.bool.isRequired,
    label: PropTypes.string,
    onColor: PropTypes.string.isRequired,
    offColor: PropTypes.string.isRequired,
    size: PropTypes.string,
    labelStyle: PropTypes.object,
    onToggle: PropTypes.func.isRequired
  }

  static defaultProps = {
    isOn : false,
    onColor: '#634fc9',
    offColor: '#ecf0f1',
    size: 'medium',
    labelStyle: {}
  }

  offsetX = new Animated.Value(0);
  dimensions = ToggleSwitch.calculateDimensions(this.props.size);

  createToggleSwitchStyle = () => ({
    justifyContent: 'center',
    width: this.dimensions.width,
    borderRadius: 20,
    padding: this.dimensions.padding,
    backgroundColor: (this.props.isOn) ? this.props.onColor : this.props.offColor,
  })

  createInsideCircleStyle = () => ({
    margin: 4,
    position: 'absolute',
    backgroundColor: 'white',
    transform: [{ translateX: this.offsetX }],
    width: this.dimensions.circleWidth,
    height: this.dimensions.circleHeight,
    borderRadius: (this.dimensions.circleWidth / 2),
  });

  render() {
    const toValue = this.props.isOn
      ? this.dimensions.width - this.dimensions.translateX
      : 0;

    Animated.timing(
      this.offsetX,
      {
        toValue,
        duration: 300,
      },
    ).start();

    return (
      <View style={styles.container}>
        {(this.props.label)
          ? <Text style={[styles.labelStyle, this.props.labelStyle]}>{this.props.label}</Text>
          : null
        }
        <TouchableOpacity
          style={this.createToggleSwitchStyle()}
          activeOpacity={0.8}
          onPress={() => {
            this.props.onToggle(!this.props.isOn);
          }}
        >
          <Animated.View style={this.createInsideCircleStyle()} />
        </TouchableOpacity>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  labelStyle: {
    marginHorizontal: 10,
  },
});
<|endoftext|>


<commit_before>(function(root) {
    var get   = typeof require == 'function' && require('request')
    var hyve  = typeof exports != 'undefined'?  exports : root.hyve = { }

    // ECMA-262 compatible Array#forEach polyfills
    Array.prototype.forEach = Array.prototype.forEach
    || function(fn, ctx) {
           var len = this.length >>> 0
           for (var i = 0; i < len; ++i)
               if (i in this) fn.call(ctx, this[i], i, this)
       }

    // Fills a template with data from an object
    function format(string, data) {
        return string.replace( /{{(?:#(.+?)#)?\s*(.+?)\s*}}/g
                             , function(m, cond, id) {
                                 var rv = data[id]
                                 return rv? (cond || '') + rv
                                          :  cond? m : '' })
    }

    // Pulls data from several streams and handle all them with the given
    // callback
    function stream(query, callback, custom_services) {
        var services
        services = custom_services || Object.keys(hyve.feeds)
        services.forEach(function(service){
            var options = hyve.feeds[service.toLowerCase()]
            var feed_url = format( options.feed_url,
                                     { query:  query
                                     , apikey: options.api_key })
                fetch(feed_url, service, callback)
            setInterval(function(){
                fetch(feed_url, service, callback)
            }, options.interval)
        })
    }

    // Fetches a JSON stream
    var fetch = function() {
        var counter   = 0
        var callbacks = { }
        var head      = !get && document.getElementsByTagName('head')[0]

        // Returns a qualified identifier pointing to a callback
        function get_callback() {
            return format('hyve.callbacks.f{{id}}', { id: ++counter })
        }

        // Requires an URI using JSONP
        function jsonp(url, callback) {
            hyve.callbacks['f' + counter] = callback
            var s = document.createElement('script')
            s.setAttribute('src', url)
            head.appendChild(s)
        }

        // Requires an URI using Node.js's request library
        function request(url, callback) {
            get({uri: url}, function(error, res, data) {
                try {
                    callback(JSON.parse(data))
                }
                catch(e){
                    callback({ }, e)
                }
            })
        }

        // Abstracts fetching URIs.
        function fetch(url, service, callback) {
            var fn = pass(service, callback)
            var cb = !get && get_callback()
            url    = format(url, { callback: cb })

            var fetcher = get? request : jsonp
            fetcher(url, fn)
        }

        // Higher-order function to process the fetched data
        function pass(service, callback) {
            return function(data) {
                hyve.feeds[service].parse(data, callback)
            }
        }

        // Export the `fetch` function
        return fetch
    }()

    // Exports data to the outside world
    hyve.stream    = stream
    hyve.callbacks = []
    hyve.feeds     = {
            twitter: {
                interval : 2000,
                feed_url :'http://search.twitter.com/search.json?q={{query}}{{#&callback=#callback}}',
                parse : function(data,callback){
                    if (data.refresh_url != null){
                        this.feed_url = 'http://search.twitter.com/search.json'
                                      + data.refresh_url
                                      + '{{#&callback=#callback}}'
                    }
                    data.results.forEach(function(item){
                        callback({
                            'service' : 'twitter',
                            'user' : {
                                'id' : item.from_user_id_str,
                                'name' : item.from_user,
                                'avatar' : item.profile_image_url
                            },
                            'id' : item.id_str,
                            'date' : item.created_at, //TODO: normalize
                            'text' : item.text,
                            'source' : item.source
                        })
                    })
                }
            },
            identica: {
                interval : 6000,
                feed_url :'http://identi.ca/api/search.json?q={{query}}{{#&callback=#callback}}',
                parse : function(data,callback){
                    if (data.refresh_url != null){
                        this.feed_url = 'http://identi.ca/api/search.json' + data.refresh_url+ '{{#&callback=#callback}}'
                    }
                    data.results.forEach(function(item){
                        callback({
                            'service' : 'identica',
                            'user' : {
                                'id' : item.from_user_id_str,
                                'name' : item.from_user,
                                'avatar' : item.profile_image_url
                            },
                            'id' : item.id_str,
                            'date' : item.created_at, //TODO: normalize
                            'text' : item.text,
                            'source' : item.source
                        })
                    })
                }
            },
            buzz: {
                interval : 5000,
                api_key: '',
                feed_url :'https://www.googleapis.com/buzz/v1/activities/search?q={{query}}&alt=json&orderby=published{{#&callback=#callback}}{{#&key=#apikey}}',
                parse : function(data,callback){
                    if (this.orig_url == null){
                        this.orig_url = this.feed_url
                    }
                    if (data.data != null){
                        var last_date = data.data.items[0].updated.split('.')[0]
                        this.feed_url = this.orig_url.replace('{{query}}','{{query}}%20AND%20date%3E' + last_date)
                        data.data.items.forEach(function(item){
                            if (item.title != '-'){
                                callback({
                                    'service' : 'buzz',
                                    'user' : {
                                        'id' : item.actor.name,
                                        'name' : item.actor.name,
                                        'avatar' : item.actor.thumbnailUrl,
                                        'source' : item.actor.profileUrl
                                    },
                                    'id' : item.id.split(':')[3],
                                    'date' : item.published, //TODO normalize
                                    'text' : item.title,
                                    'source' : item.object.links.alternate[0].href
                                })
                            }
                        })
                    }
                }
            },
            facebook: {
                interval : 3000,
                feed_url : 'https://graph.facebook.com/search?q={{query}}&type=post{{#&callback=#callback}}',
                parse : function(data,callback){
                    if (data.data != null){
                        if (data.paging != null) {
                            this.feed_url = data.paging.previous + '{{#&callback=#callback}}'
                        }
                        data.data.forEach(function(item){
                            if (item.message != null){
                                callback({
                                    'service' : 'facebook',
                                    'user' : {
                                        'id' : item.from.id,
                                        'name' : item.from.name,
                                        'avatar' : 'http://graph.facebook.com/'+item.from.id+'/picture'
                                    },
                                    'id' : item.id,
                                    'date' : item.created_time, //TODO: normalize
                                    'text' : item.message,
                                    'source' : 'http://facebook.com/'+item.from.id
                                })
                            }
                        })
                    }
                }
            },
            reddit: {
                interval : 5000,
                feed_url : 'http://www.reddit.com/search.json?q={{query}}&sort=new{{#&jsonp=#callback}}',
                parse : function(data,callback){
                    if (data.data.children[0]){
                        if (this.orig_url == null){
                            this.orig_url = this.feed_url
                        }
                        var before = data.data.children[0].data.name
                        if (before != null){
                            this.feed_url = this.orig_url + '&before=' + before
                        }
                        data.data.children.forEach(function(item){
                            item = item.data
                            callback({
                                'service' : 'reddit',
                                'user' : {
                                    'id' : '',
                                    'name' : '',
                                    'avatar' : ''
                                },
                                'id' : item.id,
                                'date' : item.created_utc, //TODO: normalize
                                'text' : item.title,
                                'source' : item.url,
                                'thumbnail':'http://reddit.com' + item.thumbnail
                            })
                        })
                    }
                }
            },
            flickr: {
                interval : 10000,
                api_key : '',
                feed_url : 'http://api.flickr.com/services/feeds/photos_public.gne?format=json&tagmode=all&tags={{query}}{{#&jsoncallback=#callback}}&extras=date_upload,date_taken,owner_name,geo,tags,views',
                parse : function(data,callback){
                    if (this.items_seen == null){
                        this.items_seen = {};
                    }
                    data.items && data.items.forEach(function(item){
                        if (this.items_seen[item.media.m] == null){
                            this.items_seen[item.media.m] = true
                            callback({
                                'service' : 'flickr',
                                'user' : {
                                    'id' : '',
                                    'name' : '',
                                    'avatar' : ''
                                },
                                'id' : '',
                                'date' : '', //TODO: normalize
                                'text' : item.description,
                                'source' : '',
                                'thumbnail':''
                            })
                        }
                    }, this)
                }
            },
            youtube: {
                interval : 8000,
                feed_url : 'http://gdata.youtube.com/feeds/api/videos?q={{query}}&time=today&orderby=published&format=5&max-results=20&v=2&alt=jsonc{{#&callback=#callback}}',
                parse : function(data,callback){
                    if (this.items_seen == null){
                        this.items_seen = {};
                    }
                    if (data.data != null){
                        data.data.items.forEach(function(item){
                            if (this.items_seen[item.id] == null){
                                this.items_seen[item.id] = true
                                callback({
                                    'service' : 'youtube',
                                    'user' : {
                                        'id' : item.uploader,
                                        'name' : item.uploader,
                                        'profile' : 'http://youtube.com/' + item.uploader,
                                        'avatar' : ''
                                    },
                                    'id' : item.id,
                                    'date' : '', //TODO: normalize
                                    'text' : item.title,
                                    'source' : 'http://youtu.be/'+ item.id,
                                    'thumbnail':'http://i.ytimg.com/vi/' + item.id + '/hqdefault.jpg'
                                })
                            }
                        }, this)
                    }
                }
            },
            wordpress: {
                interval : 10000,
                feed_url : 'http://pipes.yahoo.com/pipes/pipe.run?_id=332d9216d8910ba39e6c2577fd321a6a&_render=json&u=http%3A%2F%2Fen.search.wordpress.com%2F%3Fq%3D{{query}}%26s%3Ddate%26f%3Djson{{#&_callback=#callback}}',
                parse : function(data,callback){
                    if (this.items_seen == null){
                        this.items_seen = {};
                    }
                    if (data != null){
                        data.value.items.forEach(function(item){
                            if (this.items_seen[item.guid] == null){
                                this.items_seen[item.guid] = true
                                callback({
                                    'service' : 'wordpress',
                                    'user' : {
                                        'id' : item.author,
                                        'name' : item.author,
                                        'profile' :'',
                                        'avatar' : ''
                                    },
                                    'id' : item.id,
                                    'date' : '', //TODO: normalize
                                    'text' : item.title,
                                    'description':item.content,
                                    'source' : item.guid,
                                })
                            }
                        }, this)
                    }
                }
            }
        }
})(this);

/*
$.getJSON('http://pipes.yahoo.com/pipes/pipe.run?_id=332d9216d8910ba39e6c2577fd321a6a&_render=json&u=http%3A%2F%2Fen.search.wordpress.com%2F%3Fq%3D' + query + '%26f%3Djson&_callback=?', function(data){                                  $('
Wordpress

').appendTo($('body')).show('slow')
    $.each(data.value.items, function(i,item) {
        $('
'+ item.author + ' : ' + item.title + '
').hide().appendTo($('body')).show('slow')
    });
});
});*/
<commit_msg>flickr usmf / fix feed_url refreshing<commit_after>(function(root) {
    var get   = typeof require == 'function' && require('request')
    var hyve  = typeof exports != 'undefined'?  exports : root.hyve = { }

    // ECMA-262 compatible Array#forEach polyfills
    Array.prototype.forEach = Array.prototype.forEach
    || function(fn, ctx) {
           var len = this.length >>> 0
           for (var i = 0; i < len; ++i)
               if (i in this) fn.call(ctx, this[i], i, this)
       }

    // Fills a template with data from an object
    function format(string, data) {
        return string.replace( /{{(?:#(.+?)#)?\s*(.+?)\s*}}/g
                             , function(m, cond, id) {
                                 var rv = data[id]
                                 return rv? (cond || '') + rv
                                          :  cond? m : '' })
    }

    // Pulls data from several streams and handle all them with the given
    // callback
    function stream(query, callback, custom_services) {
        var services
        services = custom_services || Object.keys(hyve.feeds)
        services.forEach(function(service){
            var options = hyve.feeds[service.toLowerCase()]
            var feed_url = format( options.feed_url,
                                     { query:  query
                                     , apikey: options.api_key })
                fetch(feed_url, service, callback)
            setInterval(function(){
                var feed_url = format( options.feed_url,
                                     { query:  query
                                     , apikey: options.api_key })
                fetch(feed_url, service, callback)
            }, options.interval)
        })
    }

    // Fetches a JSON stream
    var fetch = function() {
        var counter   = 0
        var callbacks = { }
        var head      = !get && document.getElementsByTagName('head')[0]

        // Returns a qualified identifier pointing to a callback
        function get_callback() {
            return format('hyve.callbacks.f{{id}}', { id: ++counter })
        }

        // Requires an URI using JSONP
        function jsonp(url, callback) {
            hyve.callbacks['f' + counter] = callback
            var s = document.createElement('script')
            s.setAttribute('src', url)
            head.appendChild(s)
        }

        // Requires an URI using Node.js's request library
        function request(url, callback) {
            get({uri: url}, function(error, res, data) {
                try {
                    callback(JSON.parse(data))
                }
                catch(e){
                    callback({ }, e)
                }
            })
        }

        // Abstracts fetching URIs.
        function fetch(url, service, callback) {
            var fn = pass(service, callback)
            var cb = !get && get_callback()
            url    = format(url, { callback: cb })

            var fetcher = get? request : jsonp
            fetcher(url, fn)
        }

        // Higher-order function to process the fetched data
        function pass(service, callback) {
            return function(data) {
                hyve.feeds[service].parse(data, callback)
            }
        }

        // Export the `fetch` function
        return fetch
    }()

    // Exports data to the outside world
    hyve.stream    = stream
    hyve.callbacks = []
    hyve.feeds     = {
            twitter: {
                interval : 2000,
                feed_url :'http://search.twitter.com/search.json?q={{query}}{{#&callback=#callback}}',
                parse : function(data,callback){
                    if (data.refresh_url != null){
                        this.feed_url = 'http://search.twitter.com/search.json'
                                      + data.refresh_url
                                      + '{{#&callback=#callback}}'
                    }
                    data.results.forEach(function(item){
                        callback({
                            'service' : 'twitter',
                            'user' : {
                                'id' : item.from_user_id_str,
                                'name' : item.from_user,
                                'avatar' : item.profile_image_url
                            },
                            'id' : item.id_str,
                            'date' : item.created_at, //TODO: normalize
                            'text' : item.text,
                            'source' : item.source
                        })
                    })
                }
            },
            identica: {
                interval : 6000,
                feed_url :'http://identi.ca/api/search.json?q={{query}}{{#&callback=#callback}}',
                parse : function(data,callback){
                    if (data.refresh_url != null){
                        this.feed_url = 'http://identi.ca/api/search.json' + data.refresh_url+ '{{#&callback=#callback}}'
                    }
                    data.results.forEach(function(item){
                        callback({
                            'service' : 'identica',
                            'user' : {
                                'id' : item.from_user_id_str,
                                'name' : item.from_user,
                                'avatar' : item.profile_image_url
                            },
                            'id' : item.id_str,
                            'date' : item.created_at, //TODO: normalize
                            'text' : item.text,
                            'source' : item.source
                        })
                    })
                }
            },
            buzz: {
                interval : 5000,
                api_key: '',
                feed_url :'https://www.googleapis.com/buzz/v1/activities/search?q={{query}}&alt=json&orderby=published{{#&callback=#callback}}{{#&key=#apikey}}',
                parse : function(data,callback){
                    if (this.orig_url == null){
                        this.orig_url = this.feed_url
                    }
                    if (data.data != null){
                        var last_date = data.data.items[0].updated.split('.')[0]
                        this.feed_url = this.orig_url.replace('{{query}}','{{query}}%20AND%20date%3E' + last_date)
                        data.data.items.forEach(function(item){
                            if (item.title != '-'){
                                callback({
                                    'service' : 'buzz',
                                    'user' : {
                                        'id' : item.actor.name,
                                        'name' : item.actor.name,
                                        'avatar' : item.actor.thumbnailUrl,
                                        'source' : item.actor.profileUrl
                                    },
                                    'id' : item.id.split(':')[3],
                                    'date' : item.published, //TODO normalize
                                    'text' : item.title,
                                    'source' : item.object.links.alternate[0].href
                                })
                            }
                        })
                    }
                }
            },
            facebook: {
                interval : 3000,
                feed_url : 'https://graph.facebook.com/search?q={{query}}&type=post{{#&callback=#callback}}',
                parse : function(data,callback){
                    if (data.data != null){
                        if (data.paging != null) {
                            this.feed_url = data.paging.previous + '{{#&callback=#callback}}'
                        }
                        data.data.forEach(function(item){
                            if (item.message != null){
                                callback({
                                    'service' : 'facebook',
                                    'user' : {
                                        'id' : item.from.id,
                                        'name' : item.from.name,
                                        'avatar' : 'http://graph.facebook.com/'+item.from.id+'/picture'
                                    },
                                    'id' : item.id,
                                    'date' : item.created_time, //TODO: normalize
                                    'text' : item.message,
                                    'source' : 'http://facebook.com/'+item.from.id
                                })
                            }
                        })
                    }
                }
            },
            reddit: {
                interval : 5000,
                feed_url : 'http://www.reddit.com/search.json?q={{query}}&sort=new{{#&jsonp=#callback}}',
                parse : function(data,callback){
                    if (data.data.children[0]){
                        if (this.orig_url == null){
                            this.orig_url = this.feed_url
                        }
                        var before = data.data.children[0].data.name
                        if (before != null){
                            this.feed_url = this.orig_url + '&before=' + before
                        }
                        data.data.children.forEach(function(item){
                            item = item.data
                            callback({
                                'service' : 'reddit',
                                'user' : {
                                    'id' : '',
                                    'name' : '',
                                    'avatar' : ''
                                },
                                'id' : item.id,
                                'date' : item.created_utc, //TODO: normalize
                                'text' : item.title,
                                'source' : item.url,
                                'thumbnail':'http://reddit.com' + item.thumbnail
                            })
                        })
                    }
                }
            },
            flickr: {
                interval : 10000,
                api_key : '',
                feed_url : 'http://api.flickr.com/services/feeds/photos_public.gne?format=json&tagmode=all&tags={{query}}{{#&jsoncallback=#callback}}&extras=date_upload,date_taken,owner_name,geo,tags,views',
                parse : function(data,callback){
                    if (this.items_seen == null){
                        this.items_seen = {};
                    }
                    data.items && data.items.forEach(function(item){
                        if (this.items_seen[item.media.m] == null){
                            this.items_seen[item.media.m] = true
                            console.log(item)
                            callback({
                                'service' : 'flickr',
                                'user' : {
                                    'id' : item.author_id,
                                    'name' : item.author,
                                    'avatar' : ''
                                },
                                'id' : '',
                                'date' : item.published, //TODO: normalize
                                'text' : item.description,
                                'source' : item.link,
                                'thumbnail':item.media.m
                            })
                        }
                    }, this)
                }
            },
            youtube: {
                interval : 8000,
                feed_url : 'http://gdata.youtube.com/feeds/api/videos?q={{query}}&time=today&orderby=published&format=5&max-results=20&v=2&alt=jsonc{{#&callback=#callback}}',
                parse : function(data,callback){
                    if (this.items_seen == null){
                        this.items_seen = {};
                    }
                    if (data.data != null){
                        data.data.items.forEach(function(item){
                            if (this.items_seen[item.id] == null){
                                this.items_seen[item.id] = true
                                callback({
                                    'service' : 'youtube',
                                    'user' : {
                                        'id' : item.uploader,
                                        'name' : item.uploader,
                                        'profile' : 'http://youtube.com/' + item.uploader,
                                        'avatar' : ''
                                    },
                                    'id' : item.id,
                                    'date' : '', //TODO: normalize
                                    'text' : item.title,
                                    'source' : 'http://youtu.be/'+ item.id,
                                    'thumbnail':'http://i.ytimg.com/vi/' + item.id + '/hqdefault.jpg'
                                })
                            }
                        }, this)
                    }
                }
            },
            wordpress: {
                interval : 10000,
                feed_url : 'http://pipes.yahoo.com/pipes/pipe.run?_id=332d9216d8910ba39e6c2577fd321a6a&_render=json&u=http%3A%2F%2Fen.search.wordpress.com%2F%3Fq%3D{{query}}%26s%3Ddate%26f%3Djson{{#&_callback=#callback}}',
                parse : function(data,callback){
                    if (this.items_seen == null){
                        this.items_seen = {};
                    }
                    if (data != null){
                        data.value.items.forEach(function(item){
                            if (this.items_seen[item.guid] == null){
                                this.items_seen[item.guid] = true
                                callback({
                                    'service' : 'wordpress',
                                    'user' : {
                                        'id' : item.author,
                                        'name' : item.author,
                                        'profile' :'',
                                        'avatar' : ''
                                    },
                                    'id' : item.id,
                                    'date' : '', //TODO: normalize
                                    'text' : item.title,
                                    'description':item.content,
                                    'source' : item.guid,
                                })
                            }
                        }, this)
                    }
                }
            }
        }
})(this);

/*
$.getJSON('http://pipes.yahoo.com/pipes/pipe.run?_id=332d9216d8910ba39e6c2577fd321a6a&_render=json&u=http%3A%2F%2Fen.search.wordpress.com%2F%3Fq%3D' + query + '%26f%3Djson&_callback=?', function(data){                                  $('
Wordpress

').appendTo($('body')).show('slow')
    $.each(data.value.items, function(i,item) {
        $('
'+ item.author + ' : ' + item.title + '
').hide().appendTo($('body')).show('slow')
    });
});
});*/
<|endoftext|>


<commit_before>/**
 * @author  John Resig <jeresig@gmail.com>
 * @author  Originally by Marcus Spiegel <marcus.spiegel@gmail.com>
 * @link    https://github.com/jeresig/i18n-node
 * @license http://opensource.org/licenses/MIT
 *
 * @version 0.4.6
 */

// dependencies
var vsprintf = require("sprintf").vsprintf,
	fs = require("fs"),
	path = require("path");

var i18n = module.exports = function(opt) {
	var self = this;

	// Put into dev or production mode
	this.devMode = process.env.NODE_ENV !== "production";

	// Copy over options
	for (var prop in opt) {
		this[prop] = opt[prop];
	}

	// you may register helpers in global scope, up to you
	if (typeof this.register === "object") {
		i18n.resMethods.forEach(function(method) {
			self.register[method] = self[method].bind(self);
		});
	}

	// implicitly read all locales
	// if it's an array of locale names, read in the data
	if (opt.locales && opt.locales.forEach) {
		this.locales = {};

		opt.locales.forEach(function(locale) {
			self.readFile(locale);
		});

		this.defaultLocale = opt.locales[0];
	}

	// Set the locale to the default locale
	this.setLocale(this.defaultLocale);

	// Check the defaultLocale
	if (!this.locales[this.defaultLocale]) {
		console.error("Not a valid default locale.");
	}

	if (this.request) {
		if (this.subdomain) {
			this.setLocaleFromSubdomain(this.request);
		}

		if (this.query !== false) {
			this.setLocaleFromQuery(this.request);
		}

		this.prefLocale = this.preferredLocale();
	}
};

i18n.version = "0.4.6";

i18n.localeCache = {};
i18n.resMethods = ["__", "__n", "getLocale", "isPreferredLocale"];

i18n.expressBind = function(app, opt) {
	if (!app) {
		return;
	}

	app.use(function(req, res, next) {
		opt.request = req;
		req.i18n = new i18n(opt);

		// Express 3
		if (res.locals) {
			i18n.registerMethods(res.locals, req)
		}

		next();
	});

	// Express 2
	if (app.dynamicHelpers) {
		app.dynamicHelpers(i18n.registerMethods({}));
	}
};

i18n.registerMethods = function(helpers, req) {
	i18n.resMethods.forEach(function(method) {
		if (req) {
			helpers[method]	= req.i18n[method].bind(req.i18n);
		} else {
			helpers[method] = function(req) {
				return req.i18n[method].bind(req.i18n);
			};
		}

	});

	return helpers;
};

i18n.prototype = {
	defaultLocale: "en",
	extension: ".js",
	directory: "./locales",
	cookieName: "lang",

	__: function() {
		var msg = this.translate(this.locale, arguments[0]);

		if (arguments.length > 1) {
			msg = vsprintf(msg, Array.prototype.slice.call(arguments, 1));
		}

		return msg;
	},

	__n: function(singular, plural, count) {
		var msg = this.translate(this.locale, singular, plural);

		msg = vsprintf(parseInt(count, 10) > 1 ? msg.other : msg.one, [count]);

		if (arguments.length > 3) {
			msg = vsprintf(msg, Array.prototype.slice.call(arguments, 3));
		}

		return msg;
	},

	setLocale: function(locale) {

		if (!locale) return;

		if (!this.locales[locale]) {
			if (this.devMode) {
				console.warn("Locale (" + locale + ") not found.");
			}

			locale = this.defaultLocale;
		}

		return (this.locale = locale);
	},

	getLocale: function() {
		return this.locale;
	},

	isPreferredLocale: function() {
		return !this.prefLocale ||
			this.prefLocale === this.getLocale();
	},

	setLocaleFromQuery: function(req) {
		req = req || this.request;

		if (!req || !req.query || !req.query.lang) {
			return;
		}

		var locale = req.query.lang.toLowerCase();

		if (this.locales[locale]) {
			if (this.devMode) {
				console.log("Overriding locale from query: " + locale);
			}

			this.setLocale(locale);
		}
	},

	setLocaleFromSubdomain: function(req) {
		req = req || this.request;

		if (!req || !req.headers || !req.headers.host) {
			return;
		}

		if (/^([^.]+)/.test(req.headers.host) && this.locales[RegExp.$1]) {
			if (this.devMode) {
				console.log("Overriding locale from host: " + RegExp.$1);
			}

			this.setLocale(RegExp.$1);
		}
	},

	setLocaleFromCookie: function(req) {
		req = req || this.request;

		if (!req || !req.cookies || !this.cookieName || !req.cookies[this.cookieName]) {
			return;
		}

		var locale = req.cookies[this.cookieName].toLowerCase();

		if (this.locales[locale]) {
			if (this.devMode) {
				console.log("Overriding locale from cookie: " + locale);
			}

			this.setLocale(locale);
		}
	},

	preferredLocale: function(req) {
		req = req || this.request;

		if (!req || !req.headers) {
			return;
		}

		var accept = req.headers["accept-language"] || "",
			regExp = /(^|,\s*)([a-z-]+)/gi,
			self = this,
			prefLocale;

		while ((match = regExp.exec(accept))){
			var locale = match[2];
			var parts = locale.split("-");

			if (!prefLocale) {
				if (self.locales[locale]) {
					prefLocale = locale;
				} else if (parts.length > 1 && self.locales[parts[0]]) {
					prefLocale = parts[0];
				}
			}
		}

		return prefLocale || this.defaultLocale;
	},

	// read locale file, translate a msg and write to fs if new
	translate: function(locale, singular, plural) {
		if (!locale || !this.locales[locale]) {
			if (this.devMode) {
				console.warn("WARN: No locale found. Using the default (" +
					this.defaultLocale + ") as current locale");
			}

			locale = this.defaultLocale;

			this.initLocale(locale, {});
		}

		if (!this.locales[locale][singular]) {
			this.locales[locale][singular] = plural ?
				{ one: singular, other: plural } :
				singular;

			if (this.devMode) {
				this.writeFile(locale);
			}
		}

		return this.locales[locale][singular];
	},

	// try reading a file
	readFile: function(locale) {
		var file = this.locateFile(locale);

		if (!this.devMode && i18n.localeCache[file]) {
			this.initLocale(locale, i18n.localeCache[file]);
			return;
		}

		try {
			var localeFile = fs.readFileSync(file);

			try {
				// parsing filecontents to locales[locale]
				this.initLocale(locale, JSON.parse(localeFile));

			} catch (e) {
				console.error('unable to parse locales from file (maybe ' + file +
					' is empty or invalid json?): ', e);
			}

		} catch (e) {
			// unable to read, so intialize that file
			// locales[locale] are already set in memory, so no extra read required
			// or locales[locale] are empty, which initializes an empty locale.json file
			this.writeFile(locale);
		}
	},

	// try writing a file in a created directory
	writeFile: function(locale) {
		// don't write new locale information to disk if we're not in dev mode
		if (!this.devMode) {
			// Initialize the locale if didn't exist already
			this.initLocale(locale, {});
		}

		// creating directory if necessary
		try {
			fs.lstatSync(this.directory);

		} catch (e) {
			if (this.devMode) {
				console.log('creating locales dir in: ' + this.directory);
			}

			fs.mkdirSync(this.directory, 0755);
		}

		// Initialize the locale if didn't exist already
		this.initLocale(locale, {});

		// writing to tmp and rename on success
		try {
			var target = this.locateFile(locale),
				tmp = target + ".tmp";

			fs.writeFileSync(tmp, JSON.stringify(
				this.locales[locale], null, "\t"), "utf8");

			if (fs.statSync(tmp).isFile()) {
				fs.renameSync(tmp, target);

			} else {
				console.error('unable to write locales to file (either ' + tmp +
					' or ' + target + ' are not writeable?): ');
			}

		} catch (e) {
			console.error('unexpected error writing files (either ' + tmp +
				' or ' + target + ' are not writeable?): ', e);
		}
	},

	// basic normalization of filepath
	locateFile: function(locale) {
		return path.normalize(this.directory + '/' + locale + this.extension);
	},

	initLocale: function(locale, data) {
		if (!this.locales[locale]) {
			this.locales[locale] = data;

			// Only cache the files when we're not in dev mode
			if (!this.devMode) {
			    var file = this.locateFile(locale);
				if ( !i18n.localeCache[file] ) {
			    	i18n.localeCache[file] = data;
				}
			}
		}
	}
};
<commit_msg>Fixed https://github.com/jeresig/i18n-node-2/pull/51<commit_after>/**
 * @author  John Resig <jeresig@gmail.com>
 * @author  Originally by Marcus Spiegel <marcus.spiegel@gmail.com>
 * @link    https://github.com/jeresig/i18n-node
 * @license http://opensource.org/licenses/MIT
 *
 * @version 0.4.6
 */

// dependencies
var vsprintf = require("sprintf").vsprintf,
	fs = require("fs"),
	path = require("path");

var i18n = module.exports = function(opt) {
	var self = this;

	// Put into dev or production mode
	this.devMode = process.env.NODE_ENV !== "production";

	// Copy over options
	for (var prop in opt) {
		this[prop] = opt[prop];
	}

	// you may register helpers in global scope, up to you
	if (typeof this.register === "object") {
		i18n.resMethods.forEach(function(method) {
			self.register[method] = self[method].bind(self);
		});
	}

	// implicitly read all locales
	// if it's an array of locale names, read in the data
	if (opt.locales && opt.locales.forEach) {
		this.locales = {};

		opt.locales.forEach(function(locale) {
			self.readFile(locale);
		});

		this.defaultLocale = opt.locales[0];
	}

	// Set the locale to the default locale
	this.setLocale(this.defaultLocale);

	// Check the defaultLocale
	if (!this.locales[this.defaultLocale]) {
		console.error("Not a valid default locale.");
	}

	if (this.request) {
		if (this.subdomain) {
			this.setLocaleFromSubdomain(this.request);
		}

		if (this.query !== false) {
			this.setLocaleFromQuery(this.request);
		}

		this.prefLocale = this.preferredLocale();
	}
};

i18n.version = "0.4.6";

i18n.localeCache = {};
i18n.resMethods = ["__", "__n", "getLocale", "isPreferredLocale"];

i18n.expressBind = function(app, opt) {
	if (!app) {
		return;
	}

	app.use(function(req, res, next) {
		opt.request = req;
		req.i18n = new i18n(opt);

		// Express 3
		if (res.locals) {
			i18n.registerMethods(res.locals, req)
		}

		next();
	});

	// Express 2
	if (app.dynamicHelpers) {
		app.dynamicHelpers(i18n.registerMethods({}));
	}
};

i18n.registerMethods = function(helpers, req) {
	i18n.resMethods.forEach(function(method) {
		if (req) {
			helpers[method]	= req.i18n[method].bind(req.i18n);
		} else {
			helpers[method] = function(req) {
				return req.i18n[method].bind(req.i18n);
			};
		}

	});

	return helpers;
};

i18n.prototype = {
	defaultLocale: "en",
	extension: ".js",
	directory: "./locales",
	cookieName: "lang",

	__: function() {
		var msg = this.translate(this.locale, arguments[0]);

		if (arguments.length > 1) {
			msg = vsprintf(msg, Array.prototype.slice.call(arguments, 1));
		}

		return msg;
	},

	__n: function(singular, plural, count) {
		var msg = this.translate(this.locale, singular, plural);

		msg = vsprintf(parseInt(count, 10) === 1 ? msg.one : msg.other, [count]);

		if (arguments.length > 3) {
			msg = vsprintf(msg, Array.prototype.slice.call(arguments, 3));
		}

		return msg;
	},

	setLocale: function(locale) {

		if (!locale) return;

		if (!this.locales[locale]) {
			if (this.devMode) {
				console.warn("Locale (" + locale + ") not found.");
			}

			locale = this.defaultLocale;
		}

		return (this.locale = locale);
	},

	getLocale: function() {
		return this.locale;
	},

	isPreferredLocale: function() {
		return !this.prefLocale ||
			this.prefLocale === this.getLocale();
	},

	setLocaleFromQuery: function(req) {
		req = req || this.request;

		if (!req || !req.query || !req.query.lang) {
			return;
		}

		var locale = req.query.lang.toLowerCase();

		if (this.locales[locale]) {
			if (this.devMode) {
				console.log("Overriding locale from query: " + locale);
			}

			this.setLocale(locale);
		}
	},

	setLocaleFromSubdomain: function(req) {
		req = req || this.request;

		if (!req || !req.headers || !req.headers.host) {
			return;
		}

		if (/^([^.]+)/.test(req.headers.host) && this.locales[RegExp.$1]) {
			if (this.devMode) {
				console.log("Overriding locale from host: " + RegExp.$1);
			}

			this.setLocale(RegExp.$1);
		}
	},

	setLocaleFromCookie: function(req) {
		req = req || this.request;

		if (!req || !req.cookies || !this.cookieName || !req.cookies[this.cookieName]) {
			return;
		}

		var locale = req.cookies[this.cookieName].toLowerCase();

		if (this.locales[locale]) {
			if (this.devMode) {
				console.log("Overriding locale from cookie: " + locale);
			}

			this.setLocale(locale);
		}
	},

	preferredLocale: function(req) {
		req = req || this.request;

		if (!req || !req.headers) {
			return;
		}

		var accept = req.headers["accept-language"] || "",
			regExp = /(^|,\s*)([a-z-]+)/gi,
			self = this,
			prefLocale;

		while ((match = regExp.exec(accept))){
			var locale = match[2];
			var parts = locale.split("-");

			if (!prefLocale) {
				if (self.locales[locale]) {
					prefLocale = locale;
				} else if (parts.length > 1 && self.locales[parts[0]]) {
					prefLocale = parts[0];
				}
			}
		}

		return prefLocale || this.defaultLocale;
	},

	// read locale file, translate a msg and write to fs if new
	translate: function(locale, singular, plural) {
		if (!locale || !this.locales[locale]) {
			if (this.devMode) {
				console.warn("WARN: No locale found. Using the default (" +
					this.defaultLocale + ") as current locale");
			}

			locale = this.defaultLocale;

			this.initLocale(locale, {});
		}

		if (!this.locales[locale][singular]) {
			this.locales[locale][singular] = plural ?
				{ one: singular, other: plural } :
				singular;

			if (this.devMode) {
				this.writeFile(locale);
			}
		}

		return this.locales[locale][singular];
	},

	// try reading a file
	readFile: function(locale) {
		var file = this.locateFile(locale);

		if (!this.devMode && i18n.localeCache[file]) {
			this.initLocale(locale, i18n.localeCache[file]);
			return;
		}

		try {
			var localeFile = fs.readFileSync(file);

			try {
				// parsing filecontents to locales[locale]
				this.initLocale(locale, JSON.parse(localeFile));

			} catch (e) {
				console.error('unable to parse locales from file (maybe ' + file +
					' is empty or invalid json?): ', e);
			}

		} catch (e) {
			// unable to read, so intialize that file
			// locales[locale] are already set in memory, so no extra read required
			// or locales[locale] are empty, which initializes an empty locale.json file
			this.writeFile(locale);
		}
	},

	// try writing a file in a created directory
	writeFile: function(locale) {
		// don't write new locale information to disk if we're not in dev mode
		if (!this.devMode) {
			// Initialize the locale if didn't exist already
			this.initLocale(locale, {});
		}

		// creating directory if necessary
		try {
			fs.lstatSync(this.directory);

		} catch (e) {
			if (this.devMode) {
				console.log('creating locales dir in: ' + this.directory);
			}

			fs.mkdirSync(this.directory, 0755);
		}

		// Initialize the locale if didn't exist already
		this.initLocale(locale, {});

		// writing to tmp and rename on success
		try {
			var target = this.locateFile(locale),
				tmp = target + ".tmp";

			fs.writeFileSync(tmp, JSON.stringify(
				this.locales[locale], null, "\t"), "utf8");

			if (fs.statSync(tmp).isFile()) {
				fs.renameSync(tmp, target);

			} else {
				console.error('unable to write locales to file (either ' + tmp +
					' or ' + target + ' are not writeable?): ');
			}

		} catch (e) {
			console.error('unexpected error writing files (either ' + tmp +
				' or ' + target + ' are not writeable?): ', e);
		}
	},

	// basic normalization of filepath
	locateFile: function(locale) {
		return path.normalize(this.directory + '/' + locale + this.extension);
	},

	initLocale: function(locale, data) {
		if (!this.locales[locale]) {
			this.locales[locale] = data;

			// Only cache the files when we're not in dev mode
			if (!this.devMode) {
			    var file = this.locateFile(locale);
				if ( !i18n.localeCache[file] ) {
			    	i18n.localeCache[file] = data;
				}
			}
		}
	}
};
<|endoftext|>


<commit_before>import './polyfills.js';

export { WebGLRenderTargetCube } from './renderers/WebGLRenderTargetCube.js';
export { WebGLRenderTarget } from './renderers/WebGLRenderTarget.js';
export { WebGLRenderer } from './renderers/WebGLRenderer.js';
export { WebGL2Renderer } from './renderers/WebGL2Renderer.js';
export { ShaderLib } from './renderers/shaders/ShaderLib.js';
export { UniformsLib } from './renderers/shaders/UniformsLib.js';
export { ShaderChunk } from './renderers/shaders/ShaderChunk.js';
export { FogExp2 } from './scenes/FogExp2.js';
export { Fog } from './scenes/Fog.js';
export { Scene } from './scenes/Scene.js';
export { LensFlare } from './objects/LensFlare.js';
export { Sprite } from './objects/Sprite.js';
export { LOD } from './objects/LOD.js';
export { SkinnedMesh } from './objects/SkinnedMesh.js';
export { Skeleton } from './objects/Skeleton.js';
export { Bone } from './objects/Bone.js';
export { Mesh } from './objects/Mesh.js';
export { LineSegments } from './objects/LineSegments.js';
export { Line } from './objects/Line.js';
export { Points } from './objects/Points.js';
export { Group } from './objects/Group.js';
export { VideoTexture } from './textures/VideoTexture.js';
export { DataTexture } from './textures/DataTexture.js';
export { CompressedTexture } from './textures/CompressedTexture.js';
export { CubeTexture } from './textures/CubeTexture.js';
export { CanvasTexture } from './textures/CanvasTexture.js';
export { DepthTexture } from './textures/DepthTexture.js';
export { TextureIdCount, Texture } from './textures/Texture.js';
export * from './geometries/Geometries.js';
export * from './materials/Materials.js';
export { MaterialIdCount } from './materials/Material.js';
export { CompressedTextureLoader } from './loaders/CompressedTextureLoader.js';
export { BinaryTextureLoader, DataTextureLoader } from './loaders/BinaryTextureLoader.js';
export { CubeTextureLoader } from './loaders/CubeTextureLoader.js';
export { TextureLoader } from './loaders/TextureLoader.js';
export { ObjectLoader } from './loaders/ObjectLoader.js';
export { MaterialLoader } from './loaders/MaterialLoader.js';
export { BufferGeometryLoader } from './loaders/BufferGeometryLoader.js';
export { DefaultLoadingManager, LoadingManager } from './loaders/LoadingManager.js';
export { JSONLoader } from './loaders/JSONLoader.js';
export { ImageLoader } from './loaders/ImageLoader.js';
export { FontLoader } from './loaders/FontLoader.js';
export { FileLoader } from './loaders/FileLoader.js';
export { Loader } from './loaders/Loader.js';
export { Cache } from './loaders/Cache.js';
export { AudioLoader } from './loaders/AudioLoader.js';
export { SpotLightShadow } from './lights/SpotLightShadow.js';
export { SpotLight } from './lights/SpotLight.js';
export { PointLight } from './lights/PointLight.js';
export { RectAreaLight } from './lights/RectAreaLight.js';
export { HemisphereLight } from './lights/HemisphereLight.js';
export { DirectionalLightShadow } from './lights/DirectionalLightShadow.js';
export { DirectionalLight } from './lights/DirectionalLight.js';
export { AmbientLight } from './lights/AmbientLight.js';
export { LightShadow } from './lights/LightShadow.js';
export { Light } from './lights/Light.js';
export { StereoCamera } from './cameras/StereoCamera.js';
export { PerspectiveCamera } from './cameras/PerspectiveCamera.js';
export { OrthographicCamera } from './cameras/OrthographicCamera.js';
export { CubeCamera } from './cameras/CubeCamera.js';
export { Camera } from './cameras/Camera.js';
export { AudioListener } from './audio/AudioListener.js';
export { PositionalAudio } from './audio/PositionalAudio.js';
export { AudioContext } from './audio/AudioContext.js';
export { AudioAnalyser } from './audio/AudioAnalyser.js';
export { Audio } from './audio/Audio.js';
export { VectorKeyframeTrack } from './animation/tracks/VectorKeyframeTrack.js';
export { StringKeyframeTrack } from './animation/tracks/StringKeyframeTrack.js';
export { QuaternionKeyframeTrack } from './animation/tracks/QuaternionKeyframeTrack.js';
export { NumberKeyframeTrack } from './animation/tracks/NumberKeyframeTrack.js';
export { ColorKeyframeTrack } from './animation/tracks/ColorKeyframeTrack.js';
export { BooleanKeyframeTrack } from './animation/tracks/BooleanKeyframeTrack.js';
export { PropertyMixer } from './animation/PropertyMixer.js';
export { PropertyBinding } from './animation/PropertyBinding.js';
export { KeyframeTrack } from './animation/KeyframeTrack.js';
export { AnimationUtils } from './animation/AnimationUtils.js';
export { AnimationObjectGroup } from './animation/AnimationObjectGroup.js';
export { AnimationMixer } from './animation/AnimationMixer.js';
export { AnimationClip } from './animation/AnimationClip.js';
export { Uniform } from './core/Uniform.js';
export { InstancedBufferGeometry } from './core/InstancedBufferGeometry.js';
export { BufferGeometry } from './core/BufferGeometry.js';
export { GeometryIdCount, Geometry } from './core/Geometry.js';
export { InterleavedBufferAttribute } from './core/InterleavedBufferAttribute.js';
export { InstancedInterleavedBuffer } from './core/InstancedInterleavedBuffer.js';
export { InterleavedBuffer } from './core/InterleavedBuffer.js';
export { InstancedBufferAttribute } from './core/InstancedBufferAttribute.js';
export {
	Float64BufferAttribute,
	Float32BufferAttribute,
	Uint32BufferAttribute,
	Int32BufferAttribute,
	Uint16BufferAttribute,
	Int16BufferAttribute,
	Uint8ClampedBufferAttribute,
	Uint8BufferAttribute,
	Int8BufferAttribute,
	BufferAttribute
} from './core/BufferAttribute.js';
export { Face3 } from './core/Face3.js';
export { Object3DIdCount, Object3D } from './core/Object3D.js';
export { Raycaster } from './core/Raycaster.js';
export { Layers } from './core/Layers.js';
export { EventDispatcher } from './core/EventDispatcher.js';
export { Clock } from './core/Clock.js';
export { QuaternionLinearInterpolant } from './math/interpolants/QuaternionLinearInterpolant.js';
export { LinearInterpolant } from './math/interpolants/LinearInterpolant.js';
export { DiscreteInterpolant } from './math/interpolants/DiscreteInterpolant.js';
export { CubicInterpolant } from './math/interpolants/CubicInterpolant.js';
export { Interpolant } from './math/Interpolant.js';
export { Triangle } from './math/Triangle.js';
export { Spline } from './math/Spline.js';
export { _Math as Math } from './math/Math.js';
export { Spherical } from './math/Spherical.js';
export { Plane } from './math/Plane.js';
export { Frustum } from './math/Frustum.js';
export { Sphere } from './math/Sphere.js';
export { Ray } from './math/Ray.js';
export { Matrix4 } from './math/Matrix4.js';
export { Matrix3 } from './math/Matrix3.js';
export { Box3 } from './math/Box3.js';
export { Box2 } from './math/Box2.js';
export { Line3 } from './math/Line3.js';
export { Euler } from './math/Euler.js';
export { Vector4 } from './math/Vector4.js';
export { Vector3 } from './math/Vector3.js';
export { Vector2 } from './math/Vector2.js';
export { Quaternion } from './math/Quaternion.js';
export { Color } from './math/Color.js';
export { MorphBlendMesh } from './extras/objects/MorphBlendMesh.js';
export { ImmediateRenderObject } from './extras/objects/ImmediateRenderObject.js';
export { VertexNormalsHelper } from './extras/helpers/VertexNormalsHelper.js';
export { SpotLightHelper } from './extras/helpers/SpotLightHelper.js';
export { SkeletonHelper } from './extras/helpers/SkeletonHelper.js';
export { PointLightHelper } from './extras/helpers/PointLightHelper.js';
export { RectAreaLightHelper } from './extras/helpers/RectAreaLightHelper.js';
export { HemisphereLightHelper } from './extras/helpers/HemisphereLightHelper.js';
export { GridHelper } from './extras/helpers/GridHelper.js';
export { FaceNormalsHelper } from './extras/helpers/FaceNormalsHelper.js';
export { DirectionalLightHelper } from './extras/helpers/DirectionalLightHelper.js';
export { CameraHelper } from './extras/helpers/CameraHelper.js';
export { BoundingBoxHelper } from './extras/helpers/BoundingBoxHelper.js';
export { BoxHelper } from './extras/helpers/BoxHelper.js';
export { ArrowHelper } from './extras/helpers/ArrowHelper.js';
export { AxisHelper } from './extras/helpers/AxisHelper.js';
// export { ClosedSplineCurve3 } from './extras/curves/ClosedSplineCurve3.js';
export { CatmullRomCurve3 } from './extras/curves/CatmullRomCurve3.js';
export { SplineCurve3 } from './extras/curves/SplineCurve3.js';
export { CubicBezierCurve3 } from './extras/curves/CubicBezierCurve3.js';
export { QuadraticBezierCurve3 } from './extras/curves/QuadraticBezierCurve3.js';
export { LineCurve3 } from './extras/curves/LineCurve3.js';
export { ArcCurve } from './extras/curves/ArcCurve.js';
export { EllipseCurve } from './extras/curves/EllipseCurve.js';
export { SplineCurve } from './extras/curves/SplineCurve.js';
export { CubicBezierCurve } from './extras/curves/CubicBezierCurve.js';
export { QuadraticBezierCurve } from './extras/curves/QuadraticBezierCurve.js';
export { LineCurve } from './extras/curves/LineCurve.js';
export { Shape } from './extras/core/Shape.js';
export { ShapePath, Path } from './extras/core/Path.js';
export { Font } from './extras/core/Font.js';
export { CurvePath } from './extras/core/CurvePath.js';
export { Curve } from './extras/core/Curve.js';
export { ShapeUtils } from './extras/ShapeUtils.js';
export { SceneUtils } from './extras/SceneUtils.js';
export { CurveUtils } from './extras/CurveUtils.js';
export * from './constants.js';
export * from './Three.Legacy.js';
<commit_msg>Removed export { ClosedSplineCurve3 }<commit_after>import './polyfills.js';

export { WebGLRenderTargetCube } from './renderers/WebGLRenderTargetCube.js';
export { WebGLRenderTarget } from './renderers/WebGLRenderTarget.js';
export { WebGLRenderer } from './renderers/WebGLRenderer.js';
export { WebGL2Renderer } from './renderers/WebGL2Renderer.js';
export { ShaderLib } from './renderers/shaders/ShaderLib.js';
export { UniformsLib } from './renderers/shaders/UniformsLib.js';
export { ShaderChunk } from './renderers/shaders/ShaderChunk.js';
export { FogExp2 } from './scenes/FogExp2.js';
export { Fog } from './scenes/Fog.js';
export { Scene } from './scenes/Scene.js';
export { LensFlare } from './objects/LensFlare.js';
export { Sprite } from './objects/Sprite.js';
export { LOD } from './objects/LOD.js';
export { SkinnedMesh } from './objects/SkinnedMesh.js';
export { Skeleton } from './objects/Skeleton.js';
export { Bone } from './objects/Bone.js';
export { Mesh } from './objects/Mesh.js';
export { LineSegments } from './objects/LineSegments.js';
export { Line } from './objects/Line.js';
export { Points } from './objects/Points.js';
export { Group } from './objects/Group.js';
export { VideoTexture } from './textures/VideoTexture.js';
export { DataTexture } from './textures/DataTexture.js';
export { CompressedTexture } from './textures/CompressedTexture.js';
export { CubeTexture } from './textures/CubeTexture.js';
export { CanvasTexture } from './textures/CanvasTexture.js';
export { DepthTexture } from './textures/DepthTexture.js';
export { TextureIdCount, Texture } from './textures/Texture.js';
export * from './geometries/Geometries.js';
export * from './materials/Materials.js';
export { MaterialIdCount } from './materials/Material.js';
export { CompressedTextureLoader } from './loaders/CompressedTextureLoader.js';
export { BinaryTextureLoader, DataTextureLoader } from './loaders/BinaryTextureLoader.js';
export { CubeTextureLoader } from './loaders/CubeTextureLoader.js';
export { TextureLoader } from './loaders/TextureLoader.js';
export { ObjectLoader } from './loaders/ObjectLoader.js';
export { MaterialLoader } from './loaders/MaterialLoader.js';
export { BufferGeometryLoader } from './loaders/BufferGeometryLoader.js';
export { DefaultLoadingManager, LoadingManager } from './loaders/LoadingManager.js';
export { JSONLoader } from './loaders/JSONLoader.js';
export { ImageLoader } from './loaders/ImageLoader.js';
export { FontLoader } from './loaders/FontLoader.js';
export { FileLoader } from './loaders/FileLoader.js';
export { Loader } from './loaders/Loader.js';
export { Cache } from './loaders/Cache.js';
export { AudioLoader } from './loaders/AudioLoader.js';
export { SpotLightShadow } from './lights/SpotLightShadow.js';
export { SpotLight } from './lights/SpotLight.js';
export { PointLight } from './lights/PointLight.js';
export { RectAreaLight } from './lights/RectAreaLight.js';
export { HemisphereLight } from './lights/HemisphereLight.js';
export { DirectionalLightShadow } from './lights/DirectionalLightShadow.js';
export { DirectionalLight } from './lights/DirectionalLight.js';
export { AmbientLight } from './lights/AmbientLight.js';
export { LightShadow } from './lights/LightShadow.js';
export { Light } from './lights/Light.js';
export { StereoCamera } from './cameras/StereoCamera.js';
export { PerspectiveCamera } from './cameras/PerspectiveCamera.js';
export { OrthographicCamera } from './cameras/OrthographicCamera.js';
export { CubeCamera } from './cameras/CubeCamera.js';
export { Camera } from './cameras/Camera.js';
export { AudioListener } from './audio/AudioListener.js';
export { PositionalAudio } from './audio/PositionalAudio.js';
export { AudioContext } from './audio/AudioContext.js';
export { AudioAnalyser } from './audio/AudioAnalyser.js';
export { Audio } from './audio/Audio.js';
export { VectorKeyframeTrack } from './animation/tracks/VectorKeyframeTrack.js';
export { StringKeyframeTrack } from './animation/tracks/StringKeyframeTrack.js';
export { QuaternionKeyframeTrack } from './animation/tracks/QuaternionKeyframeTrack.js';
export { NumberKeyframeTrack } from './animation/tracks/NumberKeyframeTrack.js';
export { ColorKeyframeTrack } from './animation/tracks/ColorKeyframeTrack.js';
export { BooleanKeyframeTrack } from './animation/tracks/BooleanKeyframeTrack.js';
export { PropertyMixer } from './animation/PropertyMixer.js';
export { PropertyBinding } from './animation/PropertyBinding.js';
export { KeyframeTrack } from './animation/KeyframeTrack.js';
export { AnimationUtils } from './animation/AnimationUtils.js';
export { AnimationObjectGroup } from './animation/AnimationObjectGroup.js';
export { AnimationMixer } from './animation/AnimationMixer.js';
export { AnimationClip } from './animation/AnimationClip.js';
export { Uniform } from './core/Uniform.js';
export { InstancedBufferGeometry } from './core/InstancedBufferGeometry.js';
export { BufferGeometry } from './core/BufferGeometry.js';
export { GeometryIdCount, Geometry } from './core/Geometry.js';
export { InterleavedBufferAttribute } from './core/InterleavedBufferAttribute.js';
export { InstancedInterleavedBuffer } from './core/InstancedInterleavedBuffer.js';
export { InterleavedBuffer } from './core/InterleavedBuffer.js';
export { InstancedBufferAttribute } from './core/InstancedBufferAttribute.js';
export {
	Float64BufferAttribute,
	Float32BufferAttribute,
	Uint32BufferAttribute,
	Int32BufferAttribute,
	Uint16BufferAttribute,
	Int16BufferAttribute,
	Uint8ClampedBufferAttribute,
	Uint8BufferAttribute,
	Int8BufferAttribute,
	BufferAttribute
} from './core/BufferAttribute.js';
export { Face3 } from './core/Face3.js';
export { Object3DIdCount, Object3D } from './core/Object3D.js';
export { Raycaster } from './core/Raycaster.js';
export { Layers } from './core/Layers.js';
export { EventDispatcher } from './core/EventDispatcher.js';
export { Clock } from './core/Clock.js';
export { QuaternionLinearInterpolant } from './math/interpolants/QuaternionLinearInterpolant.js';
export { LinearInterpolant } from './math/interpolants/LinearInterpolant.js';
export { DiscreteInterpolant } from './math/interpolants/DiscreteInterpolant.js';
export { CubicInterpolant } from './math/interpolants/CubicInterpolant.js';
export { Interpolant } from './math/Interpolant.js';
export { Triangle } from './math/Triangle.js';
export { Spline } from './math/Spline.js';
export { _Math as Math } from './math/Math.js';
export { Spherical } from './math/Spherical.js';
export { Plane } from './math/Plane.js';
export { Frustum } from './math/Frustum.js';
export { Sphere } from './math/Sphere.js';
export { Ray } from './math/Ray.js';
export { Matrix4 } from './math/Matrix4.js';
export { Matrix3 } from './math/Matrix3.js';
export { Box3 } from './math/Box3.js';
export { Box2 } from './math/Box2.js';
export { Line3 } from './math/Line3.js';
export { Euler } from './math/Euler.js';
export { Vector4 } from './math/Vector4.js';
export { Vector3 } from './math/Vector3.js';
export { Vector2 } from './math/Vector2.js';
export { Quaternion } from './math/Quaternion.js';
export { Color } from './math/Color.js';
export { MorphBlendMesh } from './extras/objects/MorphBlendMesh.js';
export { ImmediateRenderObject } from './extras/objects/ImmediateRenderObject.js';
export { VertexNormalsHelper } from './extras/helpers/VertexNormalsHelper.js';
export { SpotLightHelper } from './extras/helpers/SpotLightHelper.js';
export { SkeletonHelper } from './extras/helpers/SkeletonHelper.js';
export { PointLightHelper } from './extras/helpers/PointLightHelper.js';
export { RectAreaLightHelper } from './extras/helpers/RectAreaLightHelper.js';
export { HemisphereLightHelper } from './extras/helpers/HemisphereLightHelper.js';
export { GridHelper } from './extras/helpers/GridHelper.js';
export { FaceNormalsHelper } from './extras/helpers/FaceNormalsHelper.js';
export { DirectionalLightHelper } from './extras/helpers/DirectionalLightHelper.js';
export { CameraHelper } from './extras/helpers/CameraHelper.js';
export { BoundingBoxHelper } from './extras/helpers/BoundingBoxHelper.js';
export { BoxHelper } from './extras/helpers/BoxHelper.js';
export { ArrowHelper } from './extras/helpers/ArrowHelper.js';
export { AxisHelper } from './extras/helpers/AxisHelper.js';
export { CatmullRomCurve3 } from './extras/curves/CatmullRomCurve3.js';
export { SplineCurve3 } from './extras/curves/SplineCurve3.js';
export { CubicBezierCurve3 } from './extras/curves/CubicBezierCurve3.js';
export { QuadraticBezierCurve3 } from './extras/curves/QuadraticBezierCurve3.js';
export { LineCurve3 } from './extras/curves/LineCurve3.js';
export { ArcCurve } from './extras/curves/ArcCurve.js';
export { EllipseCurve } from './extras/curves/EllipseCurve.js';
export { SplineCurve } from './extras/curves/SplineCurve.js';
export { CubicBezierCurve } from './extras/curves/CubicBezierCurve.js';
export { QuadraticBezierCurve } from './extras/curves/QuadraticBezierCurve.js';
export { LineCurve } from './extras/curves/LineCurve.js';
export { Shape } from './extras/core/Shape.js';
export { ShapePath, Path } from './extras/core/Path.js';
export { Font } from './extras/core/Font.js';
export { CurvePath } from './extras/core/CurvePath.js';
export { Curve } from './extras/core/Curve.js';
export { ShapeUtils } from './extras/ShapeUtils.js';
export { SceneUtils } from './extras/SceneUtils.js';
export { CurveUtils } from './extras/CurveUtils.js';
export * from './constants.js';
export * from './Three.Legacy.js';
<|endoftext|>


<commit_before>import Ember from 'ember';
import { test, moduleFor, moduleForComponent } from 'ember-qunit';
import startApp from '../../helpers/start-app';
import { contains } from '../../helpers/sl/synchronous';

var App;

moduleForComponent( 'sl-tab-panel', 'Unit - component:sl-tab-panel', {
    needs: [ 'component:sl-tab-pane' ],

    setup: function() {
        App = startApp();
    },

    teardown: function() {
        Ember.run( App, App.destroy );
    }
});

test( 'Expected default classes are applied', function() {
    var $component = this.append();

    contains( $component.prop( 'class' ), [ 'sl-tab-panel', 'sl-align-tabs-left' ], 'Default classes are not correctly applied' );
});

test( 'setupTabs() does so correctly', function() {
    expect(5);
    stop();

    var component  = this.subject({
            template: Ember.Handlebars.compile(
                '{{#sl-tab-pane label="A" name="a"}}A content{{/sl-tab-pane}}' +
                '{{#sl-tab-pane label="B" name="b"}}B content{{/sl-tab-pane}}' +
                '{{#sl-tab-pane label="C" name="c"}}C content{{/sl-tab-pane}}'
            )
        });

    this.append();

    component.paneFor( 'a' ).queue( function() {
        // All tabs are rendered
        equal( $('.tab[data-tab-name]' ).length, 3 );

        // Tab content is rendered
        equal( $('.sl-tab-pane[data-tab-name]').length, 3 );
        equal( $.trim( $('.sl-tab-pane[data-tab-name="b"]').text() ), 'B content' );

        // First tab is active
        equal( $('.tab.active[data-tab-name="a"]').length, 1 );
        equal( $('.sl-tab-pane.active[data-tab-name="a"]').length, 1 );

        start();
    });
});

test( 'ARIA roles are implemented', function() {
    var component  = this.subject({
            template : Ember.Handlebars.compile(
                '{{#sl-tab-pane label="A" name="a"}}A content{{/sl-tab-pane}}' +
                '{{#sl-tab-pane label="B" name="b"}}B content{{/sl-tab-pane}}' +
                '{{#sl-tab-pane label="C" name="c"}}C content{{/sl-tab-pane}}'
            )
        });

    this.append();

    equal( $('.nav-tabs[role="tablist"]').length, 1 );
    equal( $('.tab a[role="tab"]').length, 3 );
});

test( '"initialTabName" property is respected', function() {
    expect(2);
    stop();

    var component  = this.subject({
            initialTabName : 'b',
            template       : Ember.Handlebars.compile(
                '{{#sl-tab-pane label="A" name="a"}}A content{{/sl-tab-pane}}' +
                '{{#sl-tab-pane label="B" name="b"}}B content{{/sl-tab-pane}}' +
                '{{#sl-tab-pane label="C" name="c"}}C content{{/sl-tab-pane}}'
            )
        });

    this.append();

    component.paneFor( 'b' ).queue( function() {

        equal( $('.tab.active[data-tab-name="b"]').length, 1 );
        equal( $('.sl-tab-pane.active[data-tab-name="b"]').length, 1 );

        start();
    });
});

test( '"alignTabs" property is respected', function() {
    var component  = this.subject({
            alignTabs : 'right'
        }),
        $component = this.append();

    contains( $component.prop( 'class' ), 'sl-align-tabs-right', 'Tab alignment class not applied' );
});

test( 'Tabs display in expected order when "alignTabs" property is not specified', function() {
    var component  = this.subject({
            template: Ember.Handlebars.compile(
                '{{#sl-tab-pane label="A" name="a"}}A content{{/sl-tab-pane}}' +
                '{{#sl-tab-pane label="B" name="b"}}B content{{/sl-tab-pane}}' +
                '{{#sl-tab-pane label="C" name="c"}}C content{{/sl-tab-pane}}'
            )
        }),
        $component = this.append(),
        labels     = [];

    $('.tab[data-tab-name]').each( function() {
        labels.push( $( this ).attr('data-tab-name') );
    });

    deepEqual( labels, [ 'a', 'b', 'c' ] );
});

test( 'Clicking tab changes active tab', function() {
    expect(2);
    stop();

    var component  = this.subject({
            template : Ember.Handlebars.compile(
                '{{#sl-tab-pane label="A" name="a"}}A content{{/sl-tab-pane}}' +
                '{{#sl-tab-pane label="B" name="b"}}B content{{/sl-tab-pane}}' +
                '{{#sl-tab-pane label="C" name="c"}}C content{{/sl-tab-pane}}'
            )
        });

    this.append();

    click( $('.tab[data-tab-name="b"] a') );

    component.paneFor( 'a' ).queue( function() {
        component.paneFor( 'b' ).queue( function() {
            equal( $('.tab.active[data-tab-name="b"]').length, 1 );
            equal( $('.sl-tab-pane.active[data-tab-name="b"]').length, 1 );

            start();
        });
    });
});

test( 'Tab content height is adjusted after new tab selection', function() {
    expect(1);
    stop();

    var component  = this.subject({
            template : Ember.Handlebars.compile(
                '{{#sl-tab-pane label="A" name="a"}}A content{{/sl-tab-pane}}' +
                '{{#sl-tab-pane label="B" name="b"}}B content

Taller content{{/sl-tab-pane}}' +
                '{{#sl-tab-pane label="C" name="c"}}C content{{/sl-tab-pane}}'
            )
        }),
        initialHeight;

    this.append();

    click( $('.tab[data-tab-name="b"] a') );

    component.paneFor( 'a' ).queue( function() {
        initialHeight = $('.tab-content').height();

        component.paneFor( 'b' ).queue( function() {
            notEqual( initialHeight, $('.tab-content').height() );

            start();
        });
    });
});

test( '"activatePane" animates as expected', function() {
});

// @TODO - fadeOut is not firing (in test environment)
test( '"deactivatePane" animates as expected', function() {
});

// @TODO - fadeOut is not firing (in test environment)
test( '"deactivatePane" calls specified callback', function() {
});
<commit_msg>Fix "activatePane animates as expected" test<commit_after>import Ember from 'ember';
import { test, moduleFor, moduleForComponent } from 'ember-qunit';
import startApp from '../../helpers/start-app';
import { contains } from '../../helpers/sl/synchronous';

var App;

moduleForComponent( 'sl-tab-panel', 'Unit - component:sl-tab-panel', {
    needs: [ 'component:sl-tab-pane' ],

    setup: function() {
        App = startApp();
    },

    teardown: function() {
        Ember.run( App, App.destroy );
    }
});

test( 'Expected default classes are applied', function() {
    var $component = this.append();

    contains( $component.prop( 'class' ), [ 'sl-tab-panel', 'sl-align-tabs-left' ], 'Default classes are not correctly applied' );
});

test( 'setupTabs() does so correctly', function() {
    expect(5);
    stop();

    var component  = this.subject({
            template: Ember.Handlebars.compile(
                '{{#sl-tab-pane label="A" name="a"}}A content{{/sl-tab-pane}}' +
                '{{#sl-tab-pane label="B" name="b"}}B content{{/sl-tab-pane}}' +
                '{{#sl-tab-pane label="C" name="c"}}C content{{/sl-tab-pane}}'
            )
        });

    this.append();

    component.paneFor( 'a' ).queue( function() {
        // All tabs are rendered
        equal( $('.tab[data-tab-name]' ).length, 3 );

        // Tab content is rendered
        equal( $('.sl-tab-pane[data-tab-name]').length, 3 );
        equal( $.trim( $('.sl-tab-pane[data-tab-name="b"]').text() ), 'B content' );

        // First tab is active
        equal( $('.tab.active[data-tab-name="a"]').length, 1 );
        equal( $('.sl-tab-pane.active[data-tab-name="a"]').length, 1 );

        start();
    });
});

test( 'ARIA roles are implemented', function() {
    var component  = this.subject({
            template : Ember.Handlebars.compile(
                '{{#sl-tab-pane label="A" name="a"}}A content{{/sl-tab-pane}}' +
                '{{#sl-tab-pane label="B" name="b"}}B content{{/sl-tab-pane}}' +
                '{{#sl-tab-pane label="C" name="c"}}C content{{/sl-tab-pane}}'
            )
        });

    this.append();

    equal( $('.nav-tabs[role="tablist"]').length, 1 );
    equal( $('.tab a[role="tab"]').length, 3 );
});

test( '"initialTabName" property is respected', function() {
    expect(2);
    stop();

    var component  = this.subject({
            initialTabName : 'b',
            template       : Ember.Handlebars.compile(
                '{{#sl-tab-pane label="A" name="a"}}A content{{/sl-tab-pane}}' +
                '{{#sl-tab-pane label="B" name="b"}}B content{{/sl-tab-pane}}' +
                '{{#sl-tab-pane label="C" name="c"}}C content{{/sl-tab-pane}}'
            )
        });

    this.append();

    component.paneFor( 'b' ).queue( function() {

        equal( $('.tab.active[data-tab-name="b"]').length, 1 );
        equal( $('.sl-tab-pane.active[data-tab-name="b"]').length, 1 );

        start();
    });
});

test( '"alignTabs" property is respected', function() {
    var component  = this.subject({
            alignTabs : 'right'
        }),
        $component = this.append();

    contains( $component.prop( 'class' ), 'sl-align-tabs-right', 'Tab alignment class not applied' );
});

test( 'Tabs display in expected order when "alignTabs" property is not specified', function() {
    var component  = this.subject({
            template: Ember.Handlebars.compile(
                '{{#sl-tab-pane label="A" name="a"}}A content{{/sl-tab-pane}}' +
                '{{#sl-tab-pane label="B" name="b"}}B content{{/sl-tab-pane}}' +
                '{{#sl-tab-pane label="C" name="c"}}C content{{/sl-tab-pane}}'
            )
        }),
        $component = this.append(),
        labels     = [];

    $('.tab[data-tab-name]').each( function() {
        labels.push( $( this ).attr('data-tab-name') );
    });

    deepEqual( labels, [ 'a', 'b', 'c' ] );
});

test( 'Clicking tab changes active tab', function() {
    expect(2);
    stop();

    var component  = this.subject({
            template : Ember.Handlebars.compile(
                '{{#sl-tab-pane label="A" name="a"}}A content{{/sl-tab-pane}}' +
                '{{#sl-tab-pane label="B" name="b"}}B content{{/sl-tab-pane}}' +
                '{{#sl-tab-pane label="C" name="c"}}C content{{/sl-tab-pane}}'
            )
        });

    this.append();

    click( $('.tab[data-tab-name="b"] a') );

    component.paneFor( 'a' ).queue( function() {
        component.paneFor( 'b' ).queue( function() {
            equal( $('.tab.active[data-tab-name="b"]').length, 1 );
            equal( $('.sl-tab-pane.active[data-tab-name="b"]').length, 1 );

            start();
        });
    });
});

test( 'Tab content height is adjusted after new tab selection', function() {
    expect(1);
    stop();

    var component  = this.subject({
            template : Ember.Handlebars.compile(
                '{{#sl-tab-pane label="A" name="a"}}A content{{/sl-tab-pane}}' +
                '{{#sl-tab-pane label="B" name="b"}}B content

Taller content{{/sl-tab-pane}}' +
                '{{#sl-tab-pane label="C" name="c"}}C content{{/sl-tab-pane}}'
            )
        }),
        initialHeight;

    this.append();

    click( $('.tab[data-tab-name="b"] a') );

    component.paneFor( 'a' ).queue( function() {
        initialHeight = $('.tab-content').height();

        component.paneFor( 'b' ).queue( function() {
            notEqual( initialHeight, $('.tab-content').height() );

            start();
        });
    });
});

test( '"activatePane" animates as expected', function() {
    expect(1);
    stop();

    var component = this.subject({
            template : Ember.Handlebars.compile(
                '{{#sl-tab-pane label="A" name="a"}}A content{{/sl-tab-pane}}' +
                '{{#sl-tab-pane label="B" name="b"}}B content{{/sl-tab-pane}}'
            )
        }),
        spy = sinon.spy( $.prototype, 'fadeIn' );

    this.append();

    component.paneFor( 'a' ).queue( function() {
        equal( spy.calledOnce, true );
        start();
    });
});

// @TODO - fadeOut is not firing (in test environment)
test( '"deactivatePane" animates as expected', function() {

});

// @TODO - fadeOut is not firing (in test environment)
test( '"deactivatePane" calls specified callback', function() {
});
<|endoftext|>