<commit_before>var BasePlugin = require('ember-cli-deploy-plugin');
var Rsync = require('rsync');

module.exports = {
  name: 'ember-cli-deploy-scp',

  createDeployPlugin: function(options) {
    var DeployPlugin = BasePlugin.extend({
      name: options.name,

      defaultConfig: {
        port: '22',
        directory: 'tmp/deploy-dist/.',
        exclude: false,
        flags: 'rtvu',
        displayCommands: false,
        options: {},
        beforeBuild: function() {},
        beforeUpload: function() {}
      },

      requiredConfig: ['username', 'path', 'host'],

      willBuild: function(context) {
        this.readConfig('beforeBuild');
      },

      willUpload: function(context) {
        this.readConfig('beforeUpload');
      },

      build: function(context) {
      },

      rsync: function (destination) {
        var _this = this;
        var rsync = new Rsync()
          .shell('ssh -p ' + this.readConfig('port'))
          .flags(this.readConfig('flags'))
          .source(this.readConfig('directory'))
          .destination(destination);

        Object.keys(this.readConfig('options')).forEach(function(key) {
          rsync.set(key, _this.readConfig('options')[key]);
        });

        if (this.readConfig('exclude')){
          rsync.exclude(this.readConfig('exclude'));
        }

        if (this.readConfig('displayCommands')) {
          this.log(rsync.command())
        } else {
          _this.log(rsync.command(), { verbose: true });
        }

        return new Promise(function(resolve, reject) {
          rsync.execute(function(error, code, cmd) {
              if (error) {
                _this.log(error);
                reject(error);
              } else {
                _this.log('Done !');
                resolve();
              }
          });
        });
      },

      revisionKey(context) {
        if (context.revisionData && context.revisionData.revisionKey) {
          return context.revisionData.revisionKey;
        }

        // An ISO8601 string without separators (not allowed in directory names),
        // so something like 20160327T0701, which is equivalent to 2016-03-27T07:01
        return (new Date()).toISOString().replace(/[-:\.]/g, '').slice(0, 13);
      },

      upload: function(context) {
        var generatedPath = this.readConfig('username') + '@' + this.readConfig('host') + ':' + this.readConfig('path'),
            parentPath = generatedPath.substr(0, generatedPath.lastIndexOf("/"));

        return this.rsync(parentPath + '/' + this.revisionKey(context)).then(() => {
          return this.rsync(generatedPath);
        });
      }
    });

    return new DeployPlugin();
  }
};
<commit_msg>Support deploying to multiple nodes<commit_after>var BasePlugin = require('ember-cli-deploy-plugin');
var Rsync = require('rsync');

var DEFAULT_PORT = 22;

// takes an array of functions, each returning a promise when invoked
var sequentially = function(iterable) {
  return iterable.reduce((sum, func) => {
    return sum.then(() => func());
  }, Promise.resolve());
};

module.exports = {
  name: 'ember-cli-deploy-scp',

  createDeployPlugin: function(options) {
    var DeployPlugin = BasePlugin.extend({
      name: options.name,

      defaultConfig: {
        port: DEFAULT_PORT,
        directory: 'tmp/deploy-dist/.',
        exclude: false,
        flags: 'rtvu',
        displayCommands: false,
        options: {},
        beforeBuild: function() {},
        beforeUpload: function() {},
      },

      willBuild: function(context) {
        this.readConfig('beforeBuild');
      },

      willUpload: function(context) {
        this.readConfig('beforeUpload');
      },

      build: function(context) {
      },

      rsync: function (destination, port) {
        var _this = this;
        var rsync = new Rsync()
          .shell('ssh -p ' + port)
          .flags(this.readConfig('flags'))
          .source(this.readConfig('directory'))
          .destination(destination);

        Object.keys(this.readConfig('options')).forEach(function(key) {
          rsync.set(key, _this.readConfig('options')[key]);
        });

        if (this.readConfig('exclude')){
          rsync.exclude(this.readConfig('exclude'));
        }

        if (this.readConfig('displayCommands')) {
          this.log(rsync.command())
        } else {
          _this.log(rsync.command(), { verbose: true });
        }

        return new Promise(function(resolve, reject) {
          rsync.execute(function(error, code, cmd) {
              if (error) {
                _this.log(error);
                reject(error);
              } else {
                _this.log('Done !');
                resolve();
              }
          });
        });
      },

      revisionKey(context) {
        if (context.revisionData && context.revisionData.revisionKey) {
          return context.revisionData.revisionKey;
        }

        // An ISO8601 string without separators (not allowed in directory names),
        // so something like 20160327T0701, which is equivalent to 2016-03-27T07:01
        return (new Date()).toISOString().replace(/[-:\.]/g, '').slice(0, 13);
      },

      upload: function(context) {
        var revisionKey = this.revisionKey(context);
        var nodes = this.readConfig('nodes');

        if (this.readConfig('username')) {
          var username    = this.readConfig('username');
          var host        = this.readConfig('host');
          var path        = this.readConfig('path');
          var port        = this.readConfig('port');

          return _upload(username, host, port, path, revisionKey);
        } else if (nodes) {
          return sequentially(nodes.map((n) => {
            var username    = n.username;
            var host        = n.host;
            var path        = n.path;
            var port        = n.port || DEFAULT_PORT;

            return () => { return this._upload(username, host, port, path, revisionKey); }
          }));
        }
      },

      _upload: function(username, host, port, path, revisionKey) {
        var targetPath = username + '@' + host + ':' + path;
        return this._uploadFiles(targetPath, revisionKey, port);
      },

      _uploadFiles: function(targetPath, revisionKey, port) {
        this.log('Beginning upload to ' + targetPath, { verbose: true });
        var parentPath = targetPath.substr(0, targetPath.lastIndexOf('/'));

        return this.rsync(parentPath + '/' + revisionKey, port).then(() => {
          return this.rsync(targetPath, port);
        }).then((res) => {
          this.log('Upload completed', { verbose: true });
          return res;
        });
      },
    });

    return new DeployPlugin();
  }
};
<|endoftext|>


<commit_before>// Use Hilbert curve point generation to map 2D data to 1D space and vice-versa.
// Will later expand to allow `n` dimensions.

function Point(x, y, z) {
    this.x = Math.round(x) || 0
    this.y = Math.round(y) || 0
    if (z) {
        this.z = Math.round(z) || 0
        this.d = 3
    } else {
        this.z = null
        this.d = 2
    }

    this.n = function () {
        return 4 * this.z + 2 * this.y  + this.x
    }
}

Point.prototype.rotateLeft = function (n) {
    if (n % 3 == 0) return this
    if (n % 3 == 1) return new Point(this.y, this.z, this.x)
    return new Point(this.z, this.x, this.y)
}

Point.prototype.rotateRight = function (n) {
    if (n % 3 == 0) return this
    if (n % 3 == 1) return new Point(this.z, this.x, this.y)
    return new Point(this.y, this.z, this.x)
}

Point.prototype.toArray = function () {
        if (this.d == 3) { return [this.x, this.y, this.z] }
        return [this.x, this.y]
}

// Accepts the height or width of a square/graph, and the coordinates to
// convert.
function convert2dPointToDistance (height, p) { // :: Int -> Int -> Int -> Int
    var xbit, ybit, level, d = 0
    if (height < 2) {
        height = 2
    }

    // For each Hilbert level, we want to add an amount to
    // `d` based on which region we are in
    for (level = height / 2; level > 0; level /= 2) {
        // Determine what region we're in
        xbit = (p.x & level) > 0
        ybit = (p.y & level) > 0
        // increase distance based on region
        d += level * level * ((3 * xbit) ^ ybit)
        // rotate so that we'll be in sync with the next
        // region.
        var temp = rotate2d(height, p.x, p.y, xbit, ybit)
        p.x = temp[0]
        p.y = temp[1]
    }

    return d
}

// height and coordinates.
function convert3dPointToDistance (height, x, y, z) { // :: Int -> Int -> Int -> Int -> Int
    var s = 1, level = 0, max = Math.max.apply(Math, [x, y, z]), p = new Point(x, y, z)
    for (; 2 * s <= max; s *= 2) {
        level = (level + 1) % 3
    }
}

// Accepts height or width of a square/graph and distance
function convertDistanceTo2dPoint (height, distance) { // :: Int -> Int -> [Int, Int]
    distance = Math.floor(distance)
    var xbit, ybit, level
    var p = new Point(0, 0)
    if (height < 2) {
        height = 2
    }

    for (level = 1; level < height || distance > 0; level *= 2) {
        ybit = 1 & (distance / 2)
        xbit = 1 & (ybit ^ distance)

        var temp = rotate2d(level, x, y, xbit, ybit)
        p.x = temp[0]
        p.y = temp[1]
        p.x += level * xbit
        p.y += level * ybit
        distance = Math.floor(distance / 4)
    }

    return p
}

// height/width of a square/graph and distance
function convertDistanceTo3dPoint (height, distance) { // Int -> Int -> [Int, Int, Int]
    distance = Math.floor(distance)
    var xbit, ybit, zbit, level
    var x = 0, y = 0, z = 0
    if (height < 2) {
        height = 2
    }
    var parity = height % 3;

    for (level = 1; level < height || distance > 0; level *=2) {
        xbit = distance & 1;
        ybit = (ditance / 2) & 1;
        zbit = (distance / 4) & 1;

        var temp = rotate3d(level - 1, xbit ^ ybit, ybit ^ zbit, zbit)
        x = temp[0] * level + level - 1
        y = temp[1] * level + level - 1
        z = temp[2] * level + level - 1

        distance = Math.floor(distance / 8)
    }
}

// Rotate the coordinate plane and (x,y)
function rotate2d (n, x, y, xbit, ybit) { // :: Int -> Int -> Int -> Int -> Int -> [Int, Int]
    if (ybit === 0  ) {
        if (xbit === 1) {
            x = n - 1 - x
            y = n - 1 - y
        }

        var temp = x
        x = y
        y = temp
    }

    return [x, y]
}

// Rotate the coordinate plane and (x,y, z)
function rotate3d(level, x, y, z) { // :: Int -> Int -> Int -> Int -> [Int, Int, Int]
    index = 4 * z + 2 * y + x
    if (index == 0) {
        return [z, x, y]
    } else if (index == 1 || index == 3) {
        return [y, z, x]
    } else if (index == 2 || index == 6) {
        return [level - x, level - y, z]
    } else if (index == 5 || index == 7) {
        return [y, level - z, level - x]
    } else {
        return [level - z, x, level - y]
    }
}

exports.p2d = function (height, x, y) {
    return convert2dPointToDistance(height, new Point(x, y))
}
exports.d2p = convertDistanceTo2dPoint
<commit_msg>Point.n().<commit_after>// Use Hilbert curve point generation to map 2D data to 1D space and vice-versa.
// Will later expand to allow `n` dimensions.

function Point(x, y, z) {
    this.x = Math.round(x) || 0
    this.y = Math.round(y) || 0
    if (z) {
        this.z = Math.round(z) || 0
        this.d = 3
    } else {
        this.z = null
        this.d = 2
    }

}

Point.prototype.rotateLeft = function (n) {
    if (n % 3 == 0) return this
    if (n % 3 == 1) return new Point(this.y, this.z, this.x)
    return new Point(this.z, this.x, this.y)
}

Point.prototype.rotateRight = function (n) {
    if (n % 3 == 0) return this
    if (n % 3 == 1) return new Point(this.z, this.x, this.y)
    return new Point(this.y, this.z, this.x)
}

Point.prototype.toArray = function () {
        if (this.d == 3) { return [this.x, this.y, this.z] }
        return [this.x, this.y]
}

Point.prototype.n = function () {
        return 4 * this.z + 2 * this.y  + this.x
}

// Accepts the height or width of a square/graph, and the coordinates to
// convert.
function convert2dPointToDistance (height, p) { // :: Int -> Int -> Int -> Int
    var xbit, ybit, level, d = 0
    if (height < 2) {
        height = 2
    }

    // For each Hilbert level, we want to add an amount to
    // `d` based on which region we are in
    for (level = height / 2; level > 0; level /= 2) {
        // Determine what region we're in
        xbit = (p.x & level) > 0
        ybit = (p.y & level) > 0
        // increase distance based on region
        d += level * level * ((3 * xbit) ^ ybit)
        // rotate so that we'll be in sync with the next
        // region.
        var temp = rotate2d(height, p.x, p.y, xbit, ybit)
        p.x = temp[0]
        p.y = temp[1]
    }

    return d
}

// height and coordinates.
function convert3dPointToDistance (height, x, y, z) { // :: Int -> Int -> Int -> Int -> Int
    var s = 1, level = 0, max = Math.max.apply(Math, [x, y, z]), p = new Point(x, y, z)
    for (; 2 * s <= max; s *= 2) {
        level = (level + 1) % 3
    }
}

// Accepts height or width of a square/graph and distance
function convertDistanceTo2dPoint (height, distance) { // :: Int -> Int -> [Int, Int]
    distance = Math.floor(distance)
    var xbit, ybit, level
    var p = new Point(0, 0)
    if (height < 2) {
        height = 2
    }

    for (level = 1; level < height || distance > 0; level *= 2) {
        ybit = 1 & (distance / 2)
        xbit = 1 & (ybit ^ distance)

        var temp = rotate2d(level, x, y, xbit, ybit)
        p.x = temp[0]
        p.y = temp[1]
        p.x += level * xbit
        p.y += level * ybit
        distance = Math.floor(distance / 4)
    }

    return p
}

// height/width of a square/graph and distance
function convertDistanceTo3dPoint (height, distance) { // Int -> Int -> [Int, Int, Int]
    distance = Math.floor(distance)
    var xbit, ybit, zbit, level
    var x = 0, y = 0, z = 0
    if (height < 2) {
        height = 2
    }
    var parity = height % 3;

    for (level = 1; level < height || distance > 0; level *=2) {
        xbit = distance & 1;
        ybit = (ditance / 2) & 1;
        zbit = (distance / 4) & 1;

        var temp = rotate3d(level - 1, xbit ^ ybit, ybit ^ zbit, zbit)
        x = temp[0] * level + level - 1
        y = temp[1] * level + level - 1
        z = temp[2] * level + level - 1

        distance = Math.floor(distance / 8)
    }
}

// Rotate the coordinate plane and (x,y)
function rotate2d (n, x, y, xbit, ybit) { // :: Int -> Int -> Int -> Int -> Int -> [Int, Int]
    if (ybit === 0  ) {
        if (xbit === 1) {
            x = n - 1 - x
            y = n - 1 - y
        }

        var temp = x
        x = y
        y = temp
    }

    return [x, y]
}

// Rotate the coordinate plane and (x,y, z)
function rotate3d(level, x, y, z) { // :: Int -> Int -> Int -> Int -> [Int, Int, Int]
    index = 4 * z + 2 * y + x
    if (index == 0) {
        return [z, x, y]
    } else if (index == 1 || index == 3) {
        return [y, z, x]
    } else if (index == 2 || index == 6) {
        return [level - x, level - y, z]
    } else if (index == 5 || index == 7) {
        return [y, level - z, level - x]
    } else {
        return [level - z, x, level - y]
    }
}

exports.p2d = function (height, x, y) {
    return convert2dPointToDistance(height, new Point(x, y))
}
exports.d2p = convertDistanceTo2dPoint
<|endoftext|>


<commit_before>const React = require('react');
const {
  PropTypes,
  Component,
} = React;
const { ViewPropTypes } = ReactNative = require('react-native');
const {
  Dimensions,
  View,
  Animated,
  ScrollView,
  StyleSheet,
  InteractionManager,
  Platform,
} = ReactNative;
const TimerMixin = require('react-timer-mixin');

const SceneComponent = require('./SceneComponent');
const DefaultTabBar = require('./DefaultTabBar');
const ScrollableTabBar = require('./ScrollableTabBar');

const ScrollableTabView = React.createClass({
  mixins: [TimerMixin, ],
  statics: {
    DefaultTabBar,
    ScrollableTabBar,
  },

  propTypes: {
    tabBarPosition: PropTypes.oneOf(['top', 'bottom', 'overlayTop', 'overlayBottom', ]),
    initialPage: PropTypes.number,
    page: PropTypes.number,
    onChangeTab: PropTypes.func,
    onScroll: PropTypes.func,
    renderTabBar: PropTypes.any,
    style: ViewPropTypes.style,
    contentProps: PropTypes.object,
    scrollWithoutAnimation: PropTypes.bool,
    locked: PropTypes.bool,
    prerenderingSiblingsNumber: PropTypes.number,
  },

  getDefaultProps() {
    return {
      tabBarPosition: 'top',
      initialPage: 0,
      page: -1,
      onChangeTab: () => {},
      onScroll: () => {},
      contentProps: {},
      scrollWithoutAnimation: false,
      locked: false,
      prerenderingSiblingsNumber: 0,
    };
  },

  getInitialState() {
    const width = Dimensions.get('window').width;
    return {
      currentPage: this.props.initialPage,
      scrollX: new Animated.Value(this.props.initialPage * width),
      scrollValue: new Animated.Value(this.props.initialPage),
      containerWidth: width,
      sceneKeys: this.newSceneKeys({ currentPage: this.props.initialPage, }),
    };
  },

  componentDidMount() {
    this.setTimeout(() => {
      InteractionManager.runAfterInteractions(() => {
        if (Platform.OS === 'android') {
          this.goToPage(this.props.initialPage, false);
        }
      });
    }, 0);

    this.state.scrollX.addListener(({ value, }) => {
      const scrollValue = value / this.state.containerWidth;
      this.state.scrollValue.setValue(scrollValue);
      this.props.onScroll(scrollValue);
    });
  },

  componentWillReceiveProps(props) {
    if (props.children !== this.props.children) {
      this.updateSceneKeys({ page: this.state.currentPage, children: props.children, });
    }

    if (props.page >= 0 && props.page !== this.state.currentPage) {
      this.goToPage(props.page);
    }
  },

  goToPage(pageNumber, animated = !this.props.scrollWithoutAnimation) {
    const offset = pageNumber * this.state.containerWidth;
    if (this.scrollView && this.scrollView._component && this.scrollView._component.scrollTo) {
      this.scrollView._component.scrollTo({x: offset, y: 0, animated, });
    }

    const currentPage = this.state.currentPage;
    this.updateSceneKeys({
      page: pageNumber,
      callback: this._onChangeTab.bind(this, currentPage, pageNumber),
    });
  },

  renderTabBar(props) {
    if (this.props.renderTabBar === false) {
      return null;
    } else if (this.props.renderTabBar) {
      return React.cloneElement(this.props.renderTabBar(props), props);
    } else {
      return <DefaultTabBar {...props} />;
    }
  },

  updateSceneKeys({ page, children = this.props.children, callback = () => {}, }) {
    let newKeys = this.newSceneKeys({ previousKeys: this.state.sceneKeys, currentPage: page, children, });
    this.setState({currentPage: page, sceneKeys: newKeys, }, callback);
  },

  newSceneKeys({ previousKeys = [], currentPage = 0, children = this.props.children, }) {
    let newKeys = [];
    this._children(children).forEach((child, idx) => {
      let key = this._makeSceneKey(child, idx);
      if (this._keyExists(previousKeys, key) ||
        this._shouldRenderSceneKey(idx, currentPage)) {
        newKeys.push(key);
      }
    });
    return newKeys;
  },

  _shouldRenderSceneKey(idx, currentPageKey) {
    let numOfSibling = this.props.prerenderingSiblingsNumber;
    return (idx < (currentPageKey + numOfSibling + 1) &&
      idx > (currentPageKey - numOfSibling - 1));
  },

  _keyExists(sceneKeys, key) {
    return sceneKeys.find((sceneKey) => key === sceneKey);
  },

  _makeSceneKey(child, idx) {
    return child.props.tabLabel + '_' + idx;
  },

  renderScrollableContent() {
    const scenes = this._composeScenes();
    return <Animated.ScrollView
      horizontal
      pagingEnabled
      automaticallyAdjustContentInsets={false}
      contentOffset={{ x: this.props.initialPage * this.state.containerWidth, }}
      ref={(scrollView) => { this.scrollView = scrollView; }}
      onScroll={
        Animated.event([{
              nativeEvent: { contentOffset: { x: this.state.scrollX } }
            }], {
              useNativeDriver: true,
            })
      }
      onMomentumScrollBegin={this._onMomentumScrollBeginAndEnd}
      onMomentumScrollEnd={this._onMomentumScrollBeginAndEnd}
      scrollEventThrottle={16}
      scrollsToTop={false}
      showsHorizontalScrollIndicator={false}
      scrollEnabled={!this.props.locked}
      directionalLockEnabled
      alwaysBounceVertical={false}
      keyboardDismissMode="on-drag"
      {...this.props.contentProps}
      >
      {scenes}
    </Animated.ScrollView>;
  },

  _composeScenes() {
    return this._children().map((child, idx) => {
      let key = this._makeSceneKey(child, idx);
      return <SceneComponent
        key={child.key}
        shouldUpdated={this._shouldRenderSceneKey(idx, this.state.currentPage)}
        style={{width: this.state.containerWidth, }}
      >
        {this._keyExists(this.state.sceneKeys, key) ? child : <View tabLabel={child.props.tabLabel}/>}
      </SceneComponent>;
    });
  },

  _onMomentumScrollBeginAndEnd(e) {
    const offsetX = e.nativeEvent.contentOffset.x;
    const page = Math.round(offsetX / this.state.containerWidth);
    if (this.state.currentPage !== page) {
      this._updateSelectedPage(page);
    }
  },

  _updateSelectedPage(nextPage) {
    let localNextPage = nextPage;
    if (typeof localNextPage === 'object') {
      localNextPage = nextPage.nativeEvent.position;
    }

    const currentPage = this.state.currentPage;
    this.updateSceneKeys({
      page: localNextPage,
      callback: this._onChangeTab.bind(this, currentPage, localNextPage),
    });
  },

  _onChangeTab(prevPage, currentPage) {
    this.props.onChangeTab({
      i: currentPage,
      ref: this._children()[currentPage],
      from: prevPage,
    });
  },

  _handleLayout(e) {
    const { width, } = e.nativeEvent.layout;

    if (Math.round(width) !== Math.round(this.state.containerWidth)) {
      this.setState({ containerWidth: width, });
      this.requestAnimationFrame(() => {
        this.goToPage(this.state.currentPage);
      });
    }
  },

  _children(children = this.props.children) {
    return React.Children.map(children, (child) => child);
  },

  render() {
    let overlayTabs = (this.props.tabBarPosition === 'overlayTop' || this.props.tabBarPosition === 'overlayBottom');
    let tabBarProps = {
      goToPage: this.goToPage,
      tabs: this._children().map((child) => child.props.tabLabel),
      activeTab: this.state.currentPage,
      scrollX: this.state.scrollX,
      scrollValue: this.state.scrollValue,
      containerWidth: this.state.containerWidth,
    };

    if (this.props.tabBarBackgroundColor) {
      tabBarProps.backgroundColor = this.props.tabBarBackgroundColor;
    }
    if (this.props.tabBarActiveTextColor) {
      tabBarProps.activeTextColor = this.props.tabBarActiveTextColor;
    }
    if (this.props.tabBarInactiveTextColor) {
      tabBarProps.inactiveTextColor = this.props.tabBarInactiveTextColor;
    }
    if (this.props.tabBarTextStyle) {
      tabBarProps.textStyle = this.props.tabBarTextStyle;
    }
    if (this.props.tabBarUnderlineStyle) {
      tabBarProps.underlineStyle = this.props.tabBarUnderlineStyle;
    }
    if (overlayTabs) {
      tabBarProps.style = {
        position: 'absolute',
        left: 0,
        right: 0,
        [this.props.tabBarPosition === 'overlayTop' ? 'top' : 'bottom']: 0,
      };
    }

    return <View style={[styles.container, this.props.style, ]} onLayout={this._handleLayout}>
      {this.props.tabBarPosition === 'top' && this.renderTabBar(tabBarProps)}
      {this.renderScrollableContent()}
      {(this.props.tabBarPosition === 'bottom' || overlayTabs) && this.renderTabBar(tabBarProps)}
    </View>;
  },
});

module.exports = ScrollableTabView;

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  scrollableContentAndroid: {
    flex: 1,
  },
});
<commit_msg>WIP tab props<commit_after>const React = require('react');
const {
  PropTypes,
  Component,
} = React;
const { ViewPropTypes } = ReactNative = require('react-native');
const {
  Dimensions,
  View,
  Animated,
  ScrollView,
  StyleSheet,
  InteractionManager,
  Platform,
} = ReactNative;
const TimerMixin = require('react-timer-mixin');

const SceneComponent = require('./SceneComponent');
const DefaultTabBar = require('./DefaultTabBar');
const ScrollableTabBar = require('./ScrollableTabBar');

const ScrollableTabView = React.createClass({
  mixins: [TimerMixin, ],
  statics: {
    DefaultTabBar,
    ScrollableTabBar,
  },

  propTypes: {
    tabBarPosition: PropTypes.oneOf(['top', 'bottom', 'overlayTop', 'overlayBottom', ]),
    initialPage: PropTypes.number,
    page: PropTypes.number,
    onChangeTab: PropTypes.func,
    onScroll: PropTypes.func,
    renderTabBar: PropTypes.any,
    style: ViewPropTypes.style,
    contentProps: PropTypes.object,
    scrollWithoutAnimation: PropTypes.bool,
    locked: PropTypes.bool,
    prerenderingSiblingsNumber: PropTypes.number,
  },

  getDefaultProps() {
    return {
      tabBarPosition: 'top',
      initialPage: 0,
      page: -1,
      onChangeTab: () => {},
      onScroll: () => {},
      contentProps: {},
      scrollWithoutAnimation: false,
      locked: false,
      prerenderingSiblingsNumber: 0,
    };
  },

  getInitialState() {
    const width = Dimensions.get('window').width;
    return {
      currentPage: this.props.initialPage,
      scrollX: new Animated.Value(this.props.initialPage * width),
      scrollValue: new Animated.Value(this.props.initialPage),
      containerWidth: width,
      sceneKeys: this.newSceneKeys({ currentPage: this.props.initialPage, }),
    };
  },

  componentDidMount() {
    this.setTimeout(() => {
      InteractionManager.runAfterInteractions(() => {
        if (Platform.OS === 'android') {
          this.goToPage(this.props.initialPage, false);
        }
      });
    }, 0);

    this.state.scrollX.addListener(({ value, }) => {
      const scrollValue = value / this.state.containerWidth;
      this.state.scrollValue.setValue(scrollValue);
      this.props.onScroll(scrollValue);
    });
  },

  componentWillReceiveProps(props) {
    if (props.children !== this.props.children) {
      this.updateSceneKeys({ page: this.state.currentPage, children: props.children, });
    }

    if (props.page >= 0 && props.page !== this.state.currentPage) {
      this.goToPage(props.page);
    }
  },

  goToPage(pageNumber, animated = !this.props.scrollWithoutAnimation) {
    const offset = pageNumber * this.state.containerWidth;
    if (this.scrollView && this.scrollView._component && this.scrollView._component.scrollTo) {
      this.scrollView._component.scrollTo({x: offset, y: 0, animated, });
    }

    const currentPage = this.state.currentPage;
    this.updateSceneKeys({
      page: pageNumber,
      callback: this._onChangeTab.bind(this, currentPage, pageNumber),
    });
  },

  renderTabBar(props) {
    if (this.props.renderTabBar === false) {
      return null;
    } else if (this.props.renderTabBar) {
      return React.cloneElement(this.props.renderTabBar(props), props);
    } else {
      return <DefaultTabBar {...props} />;
    }
  },

  updateSceneKeys({ page, children = this.props.children, callback = () => {}, }) {
    let newKeys = this.newSceneKeys({ previousKeys: this.state.sceneKeys, currentPage: page, children, });
    this.setState({currentPage: page, sceneKeys: newKeys, }, callback);
  },

  newSceneKeys({ previousKeys = [], currentPage = 0, children = this.props.children, }) {
    let newKeys = [];
    this._children(children).forEach((child, idx) => {
      let key = this._makeSceneKey(child, idx);
      if (this._keyExists(previousKeys, key) ||
        this._shouldRenderSceneKey(idx, currentPage)) {
        newKeys.push(key);
      }
    });
    return newKeys;
  },

  _shouldRenderSceneKey(idx, currentPageKey) {
    let numOfSibling = this.props.prerenderingSiblingsNumber;
    return (idx < (currentPageKey + numOfSibling + 1) &&
      idx > (currentPageKey - numOfSibling - 1));
  },

  _keyExists(sceneKeys, key) {
    return sceneKeys.find((sceneKey) => key === sceneKey);
  },

  _makeSceneKey(child, idx) {
    return child.props.tab.name + '_' + idx;
  },

  renderScrollableContent() {
    const scenes = this._composeScenes();
    return <Animated.ScrollView
      horizontal
      pagingEnabled
      automaticallyAdjustContentInsets={false}
      contentOffset={{ x: this.props.initialPage * this.state.containerWidth, }}
      ref={(scrollView) => { this.scrollView = scrollView; }}
      onScroll={
        Animated.event([{
              nativeEvent: { contentOffset: { x: this.state.scrollX } }
            }], {
              useNativeDriver: true,
            })
      }
      onMomentumScrollBegin={this._onMomentumScrollBeginAndEnd}
      onMomentumScrollEnd={this._onMomentumScrollBeginAndEnd}
      scrollEventThrottle={16}
      scrollsToTop={false}
      showsHorizontalScrollIndicator={false}
      scrollEnabled={!this.props.locked}
      directionalLockEnabled
      alwaysBounceVertical={false}
      keyboardDismissMode="on-drag"
      {...this.props.contentProps}
      >
      {scenes}
    </Animated.ScrollView>;
  },

  _composeScenes() {
    return this._children().map((child, idx) => {
      let key = this._makeSceneKey(child, idx);
      return <SceneComponent
        key={child.key}
        shouldUpdated={this._shouldRenderSceneKey(idx, this.state.currentPage)}
        style={{width: this.state.containerWidth, }}
      >
        {this._keyExists(this.state.sceneKeys, key) ? child : <View tab={child.props.tab}/>}
      </SceneComponent>;
    });
  },

  _onMomentumScrollBeginAndEnd(e) {
    const offsetX = e.nativeEvent.contentOffset.x;
    const page = Math.round(offsetX / this.state.containerWidth);
    if (this.state.currentPage !== page) {
      this._updateSelectedPage(page);
    }
  },

  _updateSelectedPage(nextPage) {
    let localNextPage = nextPage;
    if (typeof localNextPage === 'object') {
      localNextPage = nextPage.nativeEvent.position;
    }

    const currentPage = this.state.currentPage;
    this.updateSceneKeys({
      page: localNextPage,
      callback: this._onChangeTab.bind(this, currentPage, localNextPage),
    });
  },

  _onChangeTab(prevPage, currentPage) {
    this.props.onChangeTab({
      i: currentPage,
      ref: this._children()[currentPage],
      from: prevPage,
    });
  },

  _handleLayout(e) {
    const { width, } = e.nativeEvent.layout;

    if (Math.round(width) !== Math.round(this.state.containerWidth)) {
      this.setState({ containerWidth: width, });
      this.requestAnimationFrame(() => {
        this.goToPage(this.state.currentPage);
      });
    }
  },

  _children(children = this.props.children) {
    return React.Children.map(children, (child) => child);
  },

  render() {
    let overlayTabs = (this.props.tabBarPosition === 'overlayTop' || this.props.tabBarPosition === 'overlayBottom');
    let tabBarProps = {
      goToPage: this.goToPage,
      tabs: this._children().map((child) => child.props.tab),
      activeTab: this.state.currentPage,
      scrollX: this.state.scrollX,
      scrollValue: this.state.scrollValue,
      containerWidth: this.state.containerWidth,
    };

    if (this.props.tabBarBackgroundColor) {
      tabBarProps.backgroundColor = this.props.tabBarBackgroundColor;
    }
    if (this.props.tabBarActiveTextColor) {
      tabBarProps.activeTextColor = this.props.tabBarActiveTextColor;
    }
    if (this.props.tabBarInactiveTextColor) {
      tabBarProps.inactiveTextColor = this.props.tabBarInactiveTextColor;
    }
    if (this.props.tabBarTextStyle) {
      tabBarProps.textStyle = this.props.tabBarTextStyle;
    }
    if (this.props.tabBarUnderlineStyle) {
      tabBarProps.underlineStyle = this.props.tabBarUnderlineStyle;
    }
    if (overlayTabs) {
      tabBarProps.style = {
        position: 'absolute',
        left: 0,
        right: 0,
        [this.props.tabBarPosition === 'overlayTop' ? 'top' : 'bottom']: 0,
      };
    }

    return <View style={[styles.container, this.props.style, ]} onLayout={this._handleLayout}>
      {this.props.tabBarPosition === 'top' && this.renderTabBar(tabBarProps)}
      {this.renderScrollableContent()}
      {(this.props.tabBarPosition === 'bottom' || overlayTabs) && this.renderTabBar(tabBarProps)}
    </View>;
  },
});

module.exports = ScrollableTabView;

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  scrollableContentAndroid: {
    flex: 1,
  },
});
<|endoftext|>


<commit_before>var containercss = {
  position : "relative",
  // "margin" : "20px 0 0 0",
  // "background" : "gray",
  overflow : "hidden"
};

var canvascss = {
  position : "absolute",
  left : 0,
  top : 0,
  "z-index" : 100,
  cursor : "move"
};

function Annotation() {
  this.pts = [{x:0,y:0}, {x:0,y:0}];
  this.type = "rect";
};

var att = new Annotation();

// Canvas re-draw op
var repaint = function(g, $img) {
  var w = $img.width();
  var h = $img.height();

  // Drop shadow
  g.shadowColor = "#555";
  g.shadowBlur = 40;

  // Draw the image
  g.drawImage($img[0], -w/2, -h/2);

  // Annotation
  drawAtt(g);
};

// Annotation draw op
var drawAtt = function(g) {
  g.shadowBlur = 10;
  g.strokeStyle = "white";
  g.lineWidth = 2 / curScale;

  // Box drawing (2-point)
  if (att.type == "rect") {
    var x0 = att.pts[0].x;
    var y0 = att.pts[0].y;
    var x1 = att.pts[1].x;
    var y1 = att.pts[1].y;

    var dx = Math.abs(x1-x0);
    var dy = Math.abs(y1-y0);
    var x = Math.min(x0, x1);
    var y = Math.min(y0, y1);

    g.strokeRect(x, y, dx, dy);
  }
  // Polygon drawing (n-point)
  else if (att.type == "poly") {
    // TODO (!)
  }
}

// Transform info
var curScale = 0.9;
var xOffs = 0;
var yOffs = 0;

// General transform op
var doTransform = function(g, $img) {
  var w = $img.width();
  var h = $img.height();

  // Reset xform & clear
  g.setTransform(1,0,0,1,0,0);
  g.clearRect(0, 0, w, h);

  // To draw in position with scaling,
  // move to position (translate), then
  // scale before drawing at (0, 0)
  g.translate(w/2 + xOffs, h/2 + yOffs);
  g.scale(curScale, curScale);

  repaint(g, $img);
};

// Zoom op
var zoom = function(g, $img, scale) {
  // New scaling level
  curScale *= scale;

  if (curScale < 0.9) {
    curScale = 0.9;
  }

  doTransform(g, $img);
};

// Pan op
var pan = function(g, $img, x, y) {
  // New offset
  xOffs += x;
  yOffs += y;
  doTransform(g, $img);
};

// Util - canvas to image space
var ptToImg = function($img, x, y) {
  var out = {
    x : 0, y : 0
  }

  out.x = (x-$img.width()/2-xOffs)/curScale;
  out.y = (y-$img.height()/2-yOffs)/curScale;

  return out;
};

(function( $ ) {
  // The annotator function - appplicable to any jQuery object collection
  $.fn.annotator = function(src, width, height) {
    return this.each(function() {
      var $zoomin, $zoomout, $pan, $annotate,
          $container, $img, $canvas, $type, g;

      // Check for annotator class
      $parent = $(this);

      // Update if we're passed an existing annotator
      if ($parent.hasClass("annotator")) {
        // Retrieve controls
        $zoomin     = $parent.find("#zoomin");
        $zoomout    = $parent.find("#zoomin");
        $pan        = $parent.find("#pan");
        $annotate   = $parent.find("#annot");

        $type       = $parent.find("#typesel");

        // Retrieve/resize container
        $container = $parent.find("div").width(width).height(height);

        // Reload the image
        $img = $parent.find("img").attr("src", src).width(width).height(height);

        // Retrieve canvas
        $canvas = $parent.find("canvas");

        // Reset pan/zoom
        curScale = 0.9;
        xOffs = 0;
        yOffs = 0;

        // Reset annotation
        att = new Annotation();
      }
      else {
        // Register and generate annotator components
        $parent.addClass("annotator");

        // Controls
    	  $zoomin    = $('<button id="zoomin">+</button>').appendTo($parent);
        $zoomout   = $('<button id="zoomout">-</button>').appendTo($parent);
        $pan       = $('<button id="pan">Pan</button>').appendTo($parent);
        $annotate  = $('<button id="annot">Annotate</button>').appendTo($parent);

        $type      = $('<select id="typesel"></select>')
                      .html('<option>Rect</option><option>Polygon</option>')
                      .appendTo($parent);

        // Canvas container
        $container = $('

')
                    .css(containercss)
                    .width(width)
                    .height(width)
                    .appendTo($parent);

        // Load the image
        $img = $('')
                    .width(width)
                    .height(height)
                    .hide()
                    .appendTo($parent);

        // The drawing canvas
        $canvas = $('<canvas>Unsupported browser.</canvas>')
                    .css(canvascss)
                    .appendTo($container);

        if (typeof G_vmlCanvasManager != 'undefined') {
          console.log("um");
          canvas = G_vmlCanvasManager.initElement(canvas);
        }

        // Zoom control
        $zoomin.click(function(){zoom(g, $img, 1.25 );});
        $zoomout.click(function(){zoom(g, $img, 0.8  );});

        // Canvas operations
        var x0, x1;
        var y0, y1;
        var op = "pan";
        var active = false;

        // Operation selection
        $pan.click(function(){
          op = "pan";
          $canvas.css("cursor", "move");
        });
        $annotate.click(function(){
          op = "annotate";
          $canvas.css("cursor", "crosshair");
        });

        // Mouse down - start drawing or panning
        $canvas.mousedown(function(e){
          if (!active) {
            var offset = $canvas.offset();
            x1 = x0 = e.pageX - offset.left;
            y1 = y0 = e.pageY - offset.top;
            active = true;
          }
        });

        // Movement continues draw/pan as long as the mouse button is held
        $canvas.mousemove(function(e){
          if (!active) return;

          var offset = $canvas.offset();
          x1 = e.pageX - offset.left;
          y1 = e.pageY - offset.top;

          var dx = x1 - x0;
          var dy = y1 - y0;

          if (op == "pan") {
            // Panning the image
            pan(g, $img, dx, dy);
            x0 = x1;
            y0 = y1;
          }
          else if (op == "annotate") {
            // Annotation - in image space
            if (att.type == "rect") {
              var pt1 = ptToImg($img, x0, y0);
              att.pts[0] = pt1;

              var pt2 = ptToImg($img, x1, y1);
              att.pts[1] = pt2;
            }

            // Redraw
            doTransform(g, $img);
          }
        });

        // Operation end
        $canvas.mouseup(function(){
          // End ONLY if dragged
          if (op == "annotate") {
            if (x0 != x1 && y0 != y1) {
              active = false;
            }
          }
          else {
            active = false;
          }
        });
      } // end of conditional update

      // Scale the canvas to the original image
      $canvas[0].width = width;
      $canvas[0].height = height;

      // 'g' is the graphics context for rendering
      g = $canvas[0].getContext("2d");

      // We have to wait for the image to load before we can use it
      $img.load(function(){
        doTransform(g, $img);
      });
    });
  };
}(jQuery));
<commit_msg>[broken] working on poly drawing<commit_after>var containercss = {
  position : "relative",
  // "margin" : "20px 0 0 0",
  // "background" : "gray",
  overflow : "hidden"
};

var canvascss = {
  position : "absolute",
  left : 0,
  top : 0,
  "z-index" : 100,
  cursor : "move"
};

function Annotation() {
  this.pts = [{x:0,y:0}, {x:0,y:0}];
  this.type = "rect";
};

var att = new Annotation();

// Canvas re-draw op
function repaint(g, $img) {
  var w = $img.width();
  var h = $img.height();

  // Drop shadow
  g.shadowColor = "#555";
  g.shadowBlur = 40;

  // Draw the image
  g.drawImage($img[0], -w/2, -h/2);

  // Annotation
  drawAtt(g);
};

// Annotation draw op
function drawAtt(g) {
  g.shadowBlur = 10;
  g.strokeStyle = "white";
  g.lineWidth = 2 / curScale;

  // Box drawing (2-point)
  if (att.type == "rect") {
    var x0 = att.pts[0].x;
    var y0 = att.pts[0].y;
    var x1 = att.pts[1].x;
    var y1 = att.pts[1].y;

    var dx = Math.abs(x1-x0);
    var dy = Math.abs(y1-y0);
    var x = Math.min(x0, x1);
    var y = Math.min(y0, y1);

    g.strokeRect(x, y, dx, dy);
  }
  // Polygon drawing (n-point)
  else if (att.type == "poly") {
    g.beginPath();
    g.moveTo(att.pts[0].x, att.pts[0].y);

    for (var i = 1; i < att.pts.length; i++) {
      g.lineTo(att.pts[i].x, att.pts[i].y);
    }

    g.stroke();
  }
}

// Transform info
var curScale = 0.9;
var xOffs = 0;
var yOffs = 0;

// General transform op
function doTransform(g, $img) {
  var w = $img.width();
  var h = $img.height();

  // Reset xform & clear
  g.setTransform(1,0,0,1,0,0);
  g.clearRect(0, 0, w, h);

  // To draw in position with scaling,
  // move to position (translate), then
  // scale before drawing at (0, 0)
  g.translate(w/2 + xOffs, h/2 + yOffs);
  g.scale(curScale, curScale);

  repaint(g, $img);
};

// Zoom op
function zoom(g, $img, scale) {
  // New scaling level
  curScale *= scale;

  if (curScale < 0.9) {
    curScale = 0.9;
  }

  doTransform(g, $img);
};

// Pan op
function pan(g, $img, x, y) {
  // New offset
  xOffs += x;
  yOffs += y;
  doTransform(g, $img);
};

// Util - canvas to image space
function ptToImg($img, x, y) {
  var out = {
    x : 0, y : 0
  }

  out.x = (x-$img.width()/2-xOffs)/curScale;
  out.y = (y-$img.height()/2-yOffs)/curScale;

  return out;
};

(function( $ ) {
  // The annotator function - appplicable to any jQuery object collection
  $.fn.annotator = function(src, width, height) {
    return this.each(function() {
      var $zoomin, $zoomout, $pan, $annotate,
          $container, $img, $canvas, $type, g;

      // Check for annotator class
      $parent = $(this);

      // Update if we're passed an existing annotator
      if ($parent.hasClass("annotator")) {
        // Retrieve controls
        $zoomin     = $parent.find("#zoomin");
        $zoomout    = $parent.find("#zoomin");
        $pan        = $parent.find("#pan");
        $annotate   = $parent.find("#annot");

        $type       = $parent.find("#typesel");

        // Retrieve/resize container
        $container = $parent.find("div").width(width).height(height);

        // Reload the image
        $img = $parent.find("img").attr("src", src).width(width).height(height);

        // Retrieve canvas
        $canvas = $parent.find("canvas");

        // Reset pan/zoom
        curScale = 0.9;
        xOffs = 0;
        yOffs = 0;

        // Reset annotation
        att = new Annotation();
      }
      else {
        // Register and generate annotator components
        $parent.addClass("annotator");

        // Controls
    	  $zoomin    = $('<button id="zoomin">+</button>').appendTo($parent);
        $zoomout   = $('<button id="zoomout">-</button>').appendTo($parent);
        $pan       = $('<button id="pan">Pan</button>').appendTo($parent);
        $annotate  = $('<button id="annot">Annotate</button>').appendTo($parent);

        $type      = $('<select id="typesel"></select>')
                      .html('<option>Rect</option><option>Polygon</option>')
                      .appendTo($parent);

        // Canvas container
        $container = $('

')
                    .css(containercss)
                    .width(width)
                    .height(width)
                    .appendTo($parent);

        // Load the image
        $img = $('')
                    .width(width)
                    .height(height)
                    .hide()
                    .appendTo($parent);

        // The drawing canvas
        $canvas = $('<canvas>Unsupported browser.</canvas>')
                    .css(canvascss)
                    .appendTo($container);

        if (typeof G_vmlCanvasManager != 'undefined') {
          console.log("um");
          canvas = G_vmlCanvasManager.initElement(canvas);
        }

        // Zoom control
        $zoomin.click(function(){zoom(g, $img, 1.25 );});
        $zoomout.click(function(){zoom(g, $img, 0.8  );});

        // Canvas operations
        var x0, x1;
        var y0, y1;
        var op = "pan";
        var active = false;
        var polyC = 0;

        // Operation selection
        $type.change(function(){
          var str = $(this).val();
          if (str == "Rect") {
            att.type = "rect";
          }
          else if (str == "Polygon") {
            att.type = "poly";
          }
        });
        $pan.click(function(){
          op = "pan";
          $canvas.css("cursor", "move");
        });
        $annotate.click(function(){
          op = "annotate";
          $canvas.css("cursor", "crosshair");
        });

        // Mouse down - start drawing or panning
        $canvas.mousedown(function(e){
          if (!active) {
            var offset = $canvas.offset();
            x1 = x0 = e.pageX - offset.left;
            y1 = y0 = e.pageY - offset.top;
            active = true;
          }
        });

        // Movement continues draw/pan as long as the mouse button is held
        $canvas.mousemove(function(e){
          if (!active) return;

          var offset = $canvas.offset();
          x1 = e.pageX - offset.left;
          y1 = e.pageY - offset.top;

          var dx = x1 - x0;
          var dy = y1 - y0;

          if (op == "pan") {
            // Panning the image
            pan(g, $img, dx, dy);
            x0 = x1;
            y0 = y1;
          }
          else if (op == "annotate") {
            // Annotation - in image space
            var pt1 = ptToImg($img, x0, y0);
            var pt2 = ptToImg($img, x1, y1);

            if (att.type == "rect") {
              att.pts[0] = pt1;
              att.pts[1] = pt2;
            }
            else if (att.type == "poly") {
              att.pts[polyC] = pt2;
            }

            // Redraw
            doTransform(g, $img);
          }
        });

        // Operation end
        $canvas.mouseup(function(){
          // End ONLY if dragged
          if (op == "annotate") {
            if (x0 != x1 && y0 != y1) {
              if (att.type == "rect") active = false;
              else if (att.type == "poly") {
                x0 = x1;
                y0 = y1;
                polyC++;
              }
            }
          }
          else {
            active = false;
          }
        });
      } // end of conditional update

      // Scale the canvas to the original image
      $canvas[0].width = width;
      $canvas[0].height = height;

      // 'g' is the graphics context for rendering
      g = $canvas[0].getContext("2d");

      // We have to wait for the image to load before we can use it
      $img.load(function(){
        doTransform(g, $img);
      });
    });
  };
}(jQuery));
<|endoftext|>


<commit_before>/* jshint node: true */
'use strict';

var EventEmitter = require('events').EventEmitter;
var rtc = require('rtc');
var signaller = require('rtc-signaller');
var defaults = require('cog/defaults');
var reTrailingSlash = /\/$/;

/**
  # rtc-quickconnect

  This is a very high level helper library designed to help you get up
  an running with WebRTC really, really quickly.  By using this module you
  are trading off some flexibility, so if you need a more flexible
  configuration you should drill down into lower level components of the
  [rtc.io](http://www.rtc.io) suite.

  ## Example Usage

  In the simplest case you simply call quickconnect with a single string
  argument to establish a namespace for your demo or application.  This string
  will then be combined with randomly generated location hash that will
  determine the room for your application signalling.

  <<< examples/simple.js

  ## Example Usage (Using Data Channels)

  By default, the `RTCPeerConnection` created by quickconnect will not be
  "data channels ready".  You can change that very simply, by flagging
  `data` as `true` during quickconnect initialization:

  <<< examples/datachannel.js

  ## How it works?

  __NOTE:__ Our public test signaller is currently unavailable, you will
  need to run up a version of `rtc-switchboard` locally for the time being.

  The `rtc-quickconnect` module makes use of our internal, publicly available
  signaller which uses [primus](https://github.com/primus/primus) and our
  [signalling adapter](https://github.com/rtc-io/rtc-switchboard).

  Our test signaller is exactly that, __something we use for testing__.  If
  you want to run your own signaller this is very simple and you should
  consult the `rtc-signaller-socket.io` module for information on how to
  do this.  Once you have this running, simply provide quickconnect a
  signaller option when creating:

  ```js
  var quickconnect = require('rtc-quickconnect');

  quickconnect({ ns: 'test', signaller: 'http://mysignaller.com:3000' });
  ```

  ## Full Reactive Stream Conference Example

  <<< examples/conference.js

**/
module.exports = function(opts) {
  var hash = location.hash.slice(1);
  var emitter = new EventEmitter();
  var logger;
  var peers = {};
  var monitor;

  function channel(peerId, dc) {
    dc.onopen = emitter.emit.bind(emitter, 'dc:open', dc, peerId);
  }

  // if the opts is a string, then we only have a namespace
  if (typeof opts == 'string' || (opts instanceof String)) {
    opts = {
      ns: opts
    };
  }

  // initialise the deafult opts
  opts = defaults(opts, {
    signalhost: location.origin || 'http://localhost:3000',
    signaller: location.origin || 'http://localhost:3000',
    maxAttempts: 1
  });

  // create our logger
  logger = rtc.logger(opts.ns);

  // if debug is enabled, then let's get some noisy logging going
  if (opts.debug) {
    rtc.logger.enable('*');
  }

  // if the hash is not assigned, then create a random hash value
  if (! hash) {
    hash = location.hash = '' + (Math.pow(2, 53) * Math.random());
  }

  // load socket.io script
  signaller.loadPrimus(opts.signalhost, function() {
    var socket = Primus.connect(opts.signalhost || opts.signaller);

    // create our signaller
    var sig = signaller(socket);

    sig.on('announce', function(data) {
      var peer;
      var dc;
      var dcOpts = { reliable: false };

      // if this is a known peer then abort
      if ((! data) || peers[data.id]) {
        return;
      }

      // if the room is not a match, abort
      if (data.room !== (opts.ns + '#' + hash)) {
        return;
      }

      // create a peer
      peer = peers[data.id] = rtc.createConnection(opts);

      // if we are working with data channels, create a data channel too
      if (opts.data && (! data.answer)) {
        channel(data.id, peer.createDataChannel('tx', dcOpts));
      }
      else if (opts.data) {
        peer.ondatachannel = function(evt) {
          channel(data.id, evt.channel);
        };
      }

      // couple the connections
      monitor = rtc.couple(peer, { id: data.id }, sig, opts);

      // trigger the peer event
      emitter.emit('peer', peer, data.id, data, monitor);

      // if not an answer, then announce back to the caller
      if (! data.answer) {
        sig.to(data.id).announce({
          room: (opts.ns || '') + '#' + hash,
          answer: true
        });
      }
    });

    // pass on leave events
    sig.on('leave', emitter.emit.bind(emitter, 'leave'));

    socket.on('open', function() {
      // provide the signaller via an event so it can be used externally
      emitter.emit('signaller', sig);

      // announce ourselves to our new friend
      sig.announce({ room: (opts.ns || '') + '#' + hash });
    });

  });

  return emitter;
};<commit_msg>Added room option for overriding generated room<commit_after>/* jshint node: true */
'use strict';

var EventEmitter = require('events').EventEmitter;
var rtc = require('rtc');
var signaller = require('rtc-signaller');
var defaults = require('cog/defaults');
var reTrailingSlash = /\/$/;

/**
  # rtc-quickconnect

  This is a very high level helper library designed to help you get up
  an running with WebRTC really, really quickly.  By using this module you
  are trading off some flexibility, so if you need a more flexible
  configuration you should drill down into lower level components of the
  [rtc.io](http://www.rtc.io) suite.

  ## Example Usage

  In the simplest case you simply call quickconnect with a single string
  argument to establish a namespace for your demo or application.  This string
  will then be combined with randomly generated location hash that will
  determine the room for your application signalling.

  <<< examples/simple.js

  ## Example Usage (Using Data Channels)

  By default, the `RTCPeerConnection` created by quickconnect will not be
  "data channels ready".  You can change that very simply, by flagging
  `data` as `true` during quickconnect initialization:

  <<< examples/datachannel.js

  ## How it works?

  __NOTE:__ Our public test signaller is currently unavailable, you will
  need to run up a version of `rtc-switchboard` locally for the time being.

  The `rtc-quickconnect` module makes use of our internal, publicly available
  signaller which uses [primus](https://github.com/primus/primus) and our
  [signalling adapter](https://github.com/rtc-io/rtc-switchboard).

  Our test signaller is exactly that, __something we use for testing__.  If
  you want to run your own signaller this is very simple and you should
  consult the `rtc-signaller-socket.io` module for information on how to
  do this.  Once you have this running, simply provide quickconnect a
  signaller option when creating:

  ```js
  var quickconnect = require('rtc-quickconnect');

  quickconnect({ ns: 'test', signaller: 'http://mysignaller.com:3000' });
  ```

  ## Reference

  ```
  quickconnect(opts?) => EventEmitter
  ```

  The `rtc-quickconnect` module exports a single function that is used to
  create a node [EventEmitter](http://nodejs.org/api/events.html) and
  start the signalling process required to establish WebRTC peer connections.

  ### Valid Quick Connect Options

  The options provided to the `rtc-quickconnect` module function influence the
  behaviour of some of the underlying components used from the rtc.io suite.

  Listed below are some of the commonly used options:

  - `signalhost`: The host that will be used to coordinate signalling between
    peers.  This defaults to `http://localhost:3000` but during testing feel
    free to use our test signalling server (`http://sig.rtc.io:50000`).

  - `ns`: An optional namespace for your signalling room.  While quickconnect
    will generate a unique hash for the room, this can be made to be more
    unique by providing a namespace.  Using a namespace means two demos
    that have generated the same hash but use a different namespace will be
    in different rooms.

  - `room` (added 0.6): Rather than use the internal hash generation
    (plus optional namespace) for room name generation, simply use this room
    name instead.  __NOTE:__ Use of the `room` option takes precendence over
    `ns`.

**/
module.exports = function(opts) {
  var hash = location.hash.slice(1);
  var emitter = new EventEmitter();
  var logger;
  var peers = {};
  var monitor;

  function channel(peerId, dc) {
    dc.onopen = emitter.emit.bind(emitter, 'dc:open', dc, peerId);
  }

  // if the opts is a string, then we only have a namespace
  if (typeof opts == 'string' || (opts instanceof String)) {
    opts = {
      ns: opts
    };
  }

  // initialise the deafult opts
  opts = defaults({}, opts, {
    signalhost: location.origin || 'http://localhost:3000',
    signaller: location.origin || 'http://localhost:3000',
    maxAttempts: 1
  });

  // create our logger
  logger = rtc.logger(opts.ns);

  // if debug is enabled, then let's get some noisy logging going
  if (opts.debug) {
    rtc.logger.enable('*');
  }

  // if we haven't been provided an explicit room name generate it now
  if (! opts.room) {
    // if the hash is not assigned, then create a random hash value
    if (! hash) {
      hash = location.hash = '' + (Math.pow(2, 53) * Math.random());
    }

    // generate the room name
    opts.room = (opts.ns || '') + '#' + hash;
  }

  // load socket.io script
  signaller.loadPrimus(opts.signalhost, function() {
    var socket = Primus.connect(opts.signalhost || opts.signaller);

    // create our signaller
    var sig = signaller(socket);

    sig.on('announce', function(data) {
      var peer;
      var dc;
      var dcOpts = { reliable: false };

      // if this is a known peer then abort
      if ((! data) || peers[data.id]) {
        return;
      }

      // if the room is not a match, abort
      if (data.room !== opts.room) {
        return;
      }

      // create a peer
      peer = peers[data.id] = rtc.createConnection(opts);

      // if we are working with data channels, create a data channel too
      if (opts.data && (! data.answer)) {
        channel(data.id, peer.createDataChannel('tx', dcOpts));
      }
      else if (opts.data) {
        peer.ondatachannel = function(evt) {
          channel(data.id, evt.channel);
        };
      }

      // couple the connections
      monitor = rtc.couple(peer, { id: data.id }, sig, opts);

      // trigger the peer event
      emitter.emit('peer', peer, data.id, data, monitor);

      // if not an answer, then announce back to the caller
      if (! data.answer) {
        sig.to(data.id).announce({
          room: opts.room,
          answer: true
        });
      }
    });

    // pass on leave events
    sig.on('leave', emitter.emit.bind(emitter, 'leave'));

    socket.on('open', function() {
      // provide the signaller via an event so it can be used externally
      emitter.emit('signaller', sig);

      // announce ourselves to our new friend
      sig.announce({ room: opts.room });
    });

  });

  return emitter;
};

/**
  ## Additional examples

  ### Full Reactive Stream Conference Example

  <<< examples/conference.js
**/
<|endoftext|>


<commit_before>var resource = require('express-resource'),
    express = require('express'),
    cons = require('consolidate'),
    swig = require('swig');

var util = require('./lib/util'),
    settings = require('./lib/settings'),
    filters = require('./lib/filters'),
    middleware = require('./lib/middleware'),
    signals = require('./lib/signals'),

    feed = require('./lib/resources/feed'),
    conf = require('./lib/resources/conf'),
    sessions = require('./lib/resources/sessions'),
    users = require('./lib/resources/users'),
    posts = require('./lib/resources/posts'),
    tags = require('./lib/resources/tags');

var app = express();

var debug = settings.get('DEBUG'),
    templateDir = settings.get('TEMPLATE_DIR'),
    staticRoot = settings.get('STATIC_ROOT'),
    mediaRoot = settings.get('MEDIA_ROOT');

app.modules = {
  'settings': settings,
  'middleware': middleware,
  'signals': signals
};

// Templates
swig.init({
  root: templateDir,
  allowErrors: debug,
  cache: !debug,
  tzOffset: util.tzToMinutes(settings.get('TIME_ZONE')),
  filters: filters
});
app.set('views',templateDir);
app.set('view engine', 'html');
app.set('view options', { layout: false });
app.engine('.html', cons.swig);

// Middleware
app.use(express.static(staticRoot));
app.use(express.bodyParser({ keepExtensions: true, uploadDir: mediaRoot }));
app.use(express.cookieParser());
app.use(middleware.authenticate());
app.use(express.favicon(settings.get('FAVICON')));
app.use(express.logger('dev'));
app.use(app.router);
app.use(middleware.errorHandler());

// Routes
app.get('/', posts.index);
app.get('/posts/count', posts.count);
app.get('/posts/count_published', posts.countPublished);
app.post('/posts/:post/tags', posts.tags.set);
app.get('/posts/:post/tags', posts.tags.get);
app.resource('posts', posts);

app.get('/tags/:tag/posts', tags.posts.get);
app.get('/tags/count', tags.count);
app.resource('tags', tags);

app.get('/users/count', users.count);
app.resource('users', users);

app.resource('sessions', sessions);
app.resource('feed', feed);
app.resource('conf', conf);

// Locals
function cacheSettings() {
  ['SITE_TITLE', 'SITE_ID', 'SITE_URL', 'STATIC_URL', 'DATE_FORMAT', 'POSTS_BY_PAGE',
    'TIME_ZONE', 'THEME', 'SESSION_MAX_AGE'].forEach(function(s) {
      app.locals[s] = settings.get(s);
    });
}

signals.on('settings:change', cacheSettings);
cacheSettings();

if(require.main === module) {
  var port = settings.get('PORT');
  app.listen(port, function() {
    console.log('Listening at http://localhost:%d', port);
  });
}

module.exports = app;<commit_msg>dev vs prod configuration<commit_after>var resource = require('express-resource'),
    express = require('express'),
    cons = require('consolidate'),
    swig = require('swig');

var util = require('./lib/util'),
    settings = require('./lib/settings'),
    filters = require('./lib/filters'),
    middleware = require('./lib/middleware'),
    signals = require('./lib/signals'),

    feed = require('./lib/resources/feed'),
    conf = require('./lib/resources/conf'),
    sessions = require('./lib/resources/sessions'),
    users = require('./lib/resources/users'),
    posts = require('./lib/resources/posts'),
    tags = require('./lib/resources/tags');

var app = express();

var debug = settings.get('DEBUG'),
    templateDir = settings.get('TEMPLATE_DIR'),
    staticRoot = settings.get('STATIC_ROOT'),
    mediaRoot = settings.get('MEDIA_ROOT');

app.modules = {
  'settings': settings,
  'middleware': middleware,
  'signals': signals
};

// Templates
swig.init({
  root: templateDir,
  allowErrors: debug,
  cache: !debug,
  tzOffset: util.tzToMinutes(settings.get('TIME_ZONE')),
  filters: filters
});
app.set('views',templateDir);
app.set('view engine', 'html');
app.set('view options', { layout: false });
app.engine('.html', cons.swig);

// Middleware
app.configure('development', function() {
  app.use(express.static(staticRoot));
  app.use(express.logger('dev'));
  app.use(express.responseTime());
});

app.use(express.bodyParser({ keepExtensions: true, uploadDir: mediaRoot }));
app.use(express.cookieParser());
app.use(middleware.authenticate());
app.use(express.favicon(settings.get('FAVICON')));
app.use(app.router);
app.use(middleware.errorHandler());

// Routes
app.get('/', posts.index);
app.get('/posts/count', posts.count);
app.get('/posts/count_published', posts.countPublished);
app.post('/posts/:post/tags', posts.tags.set);
app.get('/posts/:post/tags', posts.tags.get);
app.resource('posts', posts);

app.get('/tags/:tag/posts', tags.posts.get);
app.get('/tags/count', tags.count);
app.resource('tags', tags);

app.get('/users/count', users.count);
app.resource('users', users);

app.resource('sessions', sessions);
app.resource('feed', feed);
app.resource('conf', conf);

// Locals
function cacheSettings() {
  ['SITE_TITLE', 'SITE_ID', 'SITE_URL', 'STATIC_URL', 'DATE_FORMAT', 'POSTS_BY_PAGE',
    'TIME_ZONE', 'THEME', 'SESSION_MAX_AGE'].forEach(function(s) {
      app.locals[s] = settings.get(s);
    });
}

signals.on('settings:change', cacheSettings);
cacheSettings();

if(require.main === module) {
  var port = settings.get('PORT');
  app.listen(port, function() {
    console.log('Listening at http://localhost:%d', port);
  });
}

module.exports = app;<|endoftext|>


<commit_before>const assert = require('assert');

let filesToProcess = [];

function printUsage() {
	console.log("Usage:\n");
}

function validateCmdArgs() {
	var result = false;

	return result;
}

if(!validateCmdArgs()) {
	printUsage();
	process.abort();
}

<commit_msg>Have it taking file arguments<commit_after>const assert = require('assert');
const _ = require('lodash');

var filesToProcess = [];

function printUsage() {
	console.log("Usage:\n");
}

function validateCmdArgs() {
	var fileArg = _.indexOf(process.argv, '--files');
	if(fileArg == -1)
		return false;

	var numberOfFiles = process.argv.length - fileArg - 1;
	console.log(numberOfFiles);

	if(numberOfFiles < 1)
		return false;

	return true;
}

if(!validateCmdArgs()) {
	printUsage();
	process.abort();
}<|endoftext|>


<commit_before>'use strict';

var del = require('del');
var GlobalsFormatter = require('es6-module-transpiler-globals-formatter');
var gulp = require('gulp');
var gutil = require('gulp-util');
var jspm = require('jspm');
var jspmCore = require('jspm/lib/core');
var karma = require('karma').server;
var merge = require('merge');
var open = require('open');
var path = require('path');
var plugins = require('gulp-load-plugins')();
var renamer = require('gulp-es6-imports-renamer');
var runSequence = require('run-sequence');
var sourcemaps = require('gulp-sourcemaps');
var babel = require('gulp-babel');
var through = require('through2');
var transpile = require('gulp-es6-module-transpiler');

function handleError(error) {
  console.error(error.toString());

  this.emit('end');
}

module.exports = function(options) {
  var bundleFileName = options.bundleFileName;
  var corePathFromSoy = options.corePathFromSoy || 'aui';
  var shouldSkipSoyTemplatesGeneration = options.shouldSkipSoyTemplatesGeneration;

  gulp.task('build', function(done) {
    runSequence('clean', ['soy', 'copy'], ['build:globals', 'build:min'], done);
  });

  gulp.task('build:globals', ['jspm'], function() {
    return gulp.src('src/**/*.js')
      .pipe(sourcemaps.init())
      .pipe(renamer({
        basePath: process.cwd(),
        configPath: path.resolve('config.js')
      })).on('error', handleError)
      .pipe(transpile({
        basePath: process.cwd(),
        bundleFileName: bundleFileName,
        formatter: new GlobalsFormatter({
          globalName: 'aui'
        })
      }))
      .pipe(babel({
        blacklist: 'useStrict',
        compact: false
      })).on('error', handleError)
      .pipe(sourcemaps.write('./'))
      .pipe(gulp.dest('build'));
  });

  gulp.task('build:min', ['build:globals'], function() {
    return gulp.src(path.join('build/', bundleFileName))
      .pipe(plugins.rename(function(path) {
        path.basename += '-min';
      }))
      .pipe(plugins.uglify({
        preserveComments: 'some'
      }))
      .pipe(banner(options.pkg))
      .pipe(gulp.dest('build'));
  });

  gulp.task('clean', function(done) {
    del(['build'], done);
  });

  gulp.task('copy', function() {
    return gulp.src('src/**/*.css')
      .pipe(gulp.dest('build'));
  });

  gulp.task('jspm', function(done) {
    jspm.promptDefaults(true);
    jspm.install(true, {
      lock: true
    }).then(function() {
      return jspmCore.checkDlLoader();
    }).then(function() {
      return jspmCore.setMode('local');
    }).then(function() {
      gutil.log(gutil.colors.cyan('Install complete'));
      done();
    }, function(err) {
      gutil.log(gutil.colors.red('err', err.stack || err));
      gutil.log(gutil.colors.red('Installation changes not saved.'));
      done();
    });
  });

  gulp.task('lint', function() {
    return gulp.src(['src/**/*.js', 'test/**/*.js'])
      .pipe(plugins.jshint())
      .pipe(plugins.jshint.reporter(require('jshint-stylish')));
  });

  gulp.task('soy', function() {
    return gulp.src('src/**/*.soy')
      .pipe(plugins.if(!shouldSkipSoyTemplatesGeneration, generateTemplatesAndExtractParams()))
      .pipe(plugins.if(!shouldSkipSoyTemplatesGeneration, gulp.dest('build')))
      .pipe(plugins.soynode({
        loadCompiledTemplates: false,
        shouldDeclareTopLevelNamespaces: false
      }))
      .pipe(plugins.ignore.exclude('*.soy'))
      .pipe(plugins.wrapper({
        header: getHeaderContent(corePathFromSoy),
        footer: getFooterContent
      }))
      .pipe(gulp.dest('src'));
  });

  gulp.task('test', function(done) {
    return runSequence('test:unit', /*'test:complexity', TODO(edu): ES6.*/ done);
  });

  gulp.task('test:complexity', function() {
    return gulp.src(['src/**/*.js', '!src/**/*.soy.js', '!src/promise/Promise.js', 'test/**/*.js'])
      .pipe(babel())
      .pipe(plugins.complexity({
        halstead: [15, 15, 20]
      }));
  });

  gulp.task('test:unit', ['jspm'], function(done) {
    runKarma({}, done);
  });

  gulp.task('test:coverage', ['jspm'], function(done) {
    runKarma({}, function() {
      open(path.resolve('coverage/lcov/lcov-report/index.html'));
      done();
    });
  });

  gulp.task('test:browsers', ['jspm'], function(done) {
    runKarma({
      browsers: ['Chrome', 'Firefox', 'Safari', 'IE9 - Win7', 'IE10 - Win7', 'IE11 - Win7']
    }, done);
  });

  gulp.task('test:saucelabs', ['jspm'], function(done) {
    var launchers = {
      sl_chrome: {
        base: 'SauceLabs',
        browserName: 'chrome'
      },
      sl_safari: {
        base: 'SauceLabs',
        browserName: 'safari'
      },
      sl_firefox: {
        base: 'SauceLabs',
        browserName: 'firefox'
      },
      sl_ie_9: {
        base: 'SauceLabs',
        browserName: 'internet explorer',
        platform: 'Windows 7',
        version: '9'
      },
      sl_ie_10: {
        base: 'SauceLabs',
        browserName: 'internet explorer',
        platform: 'Windows 7',
        version: '10'
      },
      sl_ie_11: {
        base: 'SauceLabs',
        browserName: 'internet explorer',
        platform: 'Windows 8.1',
        version: '11'
      },
      sl_iphone: {
        base: 'SauceLabs',
        browserName: 'iphone',
        platform: 'OS X 10.10',
        version: '7.1'
      },
      sl_android_4: {
        base: 'SauceLabs',
        browserName: 'android',
        platform: 'Linux',
        version: '4.4'
      },
      sl_android_5: {
        base: 'SauceLabs',
        browserName: 'android',
        platform: 'Linux',
        version: '5.0'
      }
    };

    runKarma({
      browsers: Object.keys(launchers),

      browserDisconnectTimeout: 10000,
      browserDisconnectTolerance: 2,
      browserNoActivityTimeout: 240000,

      captureTimeout: 240000,
      customLaunchers: launchers,

      reporters: ['coverage', 'progress', 'saucelabs'],

      sauceLabs: {
        testName: 'AlloyUI tests',
        recordScreenshots: false,
        startConnect: true,
        connectOptions: {
          port: 5757,
          'selenium-version': '2.41.0',
          logfile: 'sauce_connect.log'
        }
      }
    }, done);
  });

  gulp.task('test:watch', ['jspm'], function(done) {
    runKarma({
      singleRun: false
    }, done);
  });

  gulp.task('watch', ['build'], function() {
    gulp.watch('src/**/*', ['build']);
  });
};

// Private helpers
// ===============

function banner(pkg) {
  var stamp = [
    '/**',
    ' * <%= pkg.name %> - <%= pkg.description %>',
    ' * @version v<%= pkg.version %>',
    ' * @author <%= pkg.author.name %> <<%= pkg.author.email %>>',
    ' * @link http://liferay.com',
    ' * @license BSD',
    ' */',
    ''
  ].join('\n');

  return plugins.header(stamp, {
    pkg: pkg
  });
}

function createComponentSoy(moduleName) {
  return '\n/**\n* @param? children\n* @param data\n* @param ref\n*/\n' +
    '{deltemplate ' + moduleName + '}\n' +
      '{delcall Component}\n' +
        '{param children: $children /}\n' +
        '{param data: $data /}\n' +
        '{param name: \'' + moduleName + '\' /}\n' +
        '{param ref: $ref /}\n' +
      '{/delcall}\n' +
    '{/deltemplate}\n';
}

function createSurfaceSoy(moduleName, surfaceName) {
  return '\n/**\n* @param id\n*/\n' +
    '{deltemplate ' + moduleName + '.' + surfaceName + '}\n' +
      '
\n' +
        '{if $ij.renderChildComponents}\n' +
            '{call .' + surfaceName + ' data="all" /}\n' +
        '{/if}\n' +
      '
\n' +
    '{/deltemplate}\n';
}

var templateParams = {};
function extractTemplateParams(namespace, templateCmd, filePath) {
  var soyJsPath = filePath + '.js';
  templateParams[soyJsPath] = templateParams[soyJsPath] || {};

  var templateName = namespace + '.' + templateCmd.name;
  templateParams[soyJsPath][templateName] = [];

  var paramRegex = /{@param \s*(\S*)\s*:(.*)}/g;
  var currentMatch = paramRegex.exec(templateCmd.contents);
  while (currentMatch) {
    templateParams[soyJsPath][templateName].push(currentMatch[1]);
    currentMatch = paramRegex.exec(templateCmd.contents);
  }
}

function generateDelTemplate(namespace, templateCmd) {
  var moduleName = namespace.substr(10);
  if (templateCmd.name === 'element') {
    return createComponentSoy(moduleName);
  } else {
    return createSurfaceSoy(moduleName, templateCmd.name);
  }
}

function generateTemplatesAndExtractParams() {
  return through.obj(function(file, encoding, callback) {
    var fileString = file.contents.toString(encoding);
    fileString += '\n// The following templates were generated by alloyui-tasks.\n' +
      '// Please don\'t edit them by hand.\n';

    var namespace = /{namespace (.*)}/.exec(fileString)[1];
    var templateCmds = getAllTemplateCmds(fileString);
    for (var i = 0; i < templateCmds.length; i++) {
      fileString += generateDelTemplate(namespace, templateCmds[i]);
      extractTemplateParams(namespace, templateCmds[i], file.relative);
    }

    file.contents = new Buffer(fileString);
    this.push(file);
    callback();
  });
}

function getFooterContent(file) {
  var footer = '';
  var fileParams = templateParams[file.relative];
  for (var templateName in fileParams) {
    footer += '\n' + templateName + '.params = ' + JSON.stringify(fileParams[templateName]) + ';';
  }
  return footer + '\n/* jshint ignore:end */\n';
}

function getHeaderContent(corePathFromSoy) {
  var registryModulePath = path.join(corePathFromSoy, '/component/ComponentRegistry');
  return '/* jshint ignore:start */\n' +
    'import ComponentRegistry from \'' + registryModulePath + '\';\n' +
    'var Templates = ComponentRegistry.Templates;\n';
}

function getAllTemplateCmds(fileString) {
  var cmds = [];
  var regex = /{template (.*)}/g;
  var match = regex.exec(fileString);
  while (match) {
    var endIndex = fileString.indexOf('{/template}', match.index);
    cmds.push({
      contents: fileString.substring(match.index, endIndex),
      name: match[1].substr(1)
    });
    match = regex.exec(fileString);
  }
  return cmds;
}

function runKarma(config, done) {
  config = merge({
    configFile: path.resolve('karma.conf.js'),
    singleRun: true
  }, config);
  karma.start(config, done);
}
<commit_msg>Updates component deltemplate generation<commit_after>'use strict';

var del = require('del');
var GlobalsFormatter = require('es6-module-transpiler-globals-formatter');
var gulp = require('gulp');
var gutil = require('gulp-util');
var jspm = require('jspm');
var jspmCore = require('jspm/lib/core');
var karma = require('karma').server;
var merge = require('merge');
var open = require('open');
var path = require('path');
var plugins = require('gulp-load-plugins')();
var renamer = require('gulp-es6-imports-renamer');
var runSequence = require('run-sequence');
var sourcemaps = require('gulp-sourcemaps');
var babel = require('gulp-babel');
var through = require('through2');
var transpile = require('gulp-es6-module-transpiler');

function handleError(error) {
  console.error(error.toString());

  this.emit('end');
}

module.exports = function(options) {
  var bundleFileName = options.bundleFileName;
  var corePathFromSoy = options.corePathFromSoy || 'aui';
  var shouldSkipSoyTemplatesGeneration = options.shouldSkipSoyTemplatesGeneration;

  gulp.task('build', function(done) {
    runSequence('clean', ['soy', 'copy'], ['build:globals', 'build:min'], done);
  });

  gulp.task('build:globals', ['jspm'], function() {
    return gulp.src('src/**/*.js')
      .pipe(sourcemaps.init())
      .pipe(renamer({
        basePath: process.cwd(),
        configPath: path.resolve('config.js')
      })).on('error', handleError)
      .pipe(transpile({
        basePath: process.cwd(),
        bundleFileName: bundleFileName,
        formatter: new GlobalsFormatter({
          globalName: 'aui'
        })
      }))
      .pipe(babel({
        blacklist: 'useStrict',
        compact: false
      })).on('error', handleError)
      .pipe(sourcemaps.write('./'))
      .pipe(gulp.dest('build'));
  });

  gulp.task('build:min', ['build:globals'], function() {
    return gulp.src(path.join('build/', bundleFileName))
      .pipe(plugins.rename(function(path) {
        path.basename += '-min';
      }))
      .pipe(plugins.uglify({
        preserveComments: 'some'
      }))
      .pipe(banner(options.pkg))
      .pipe(gulp.dest('build'));
  });

  gulp.task('clean', function(done) {
    del(['build'], done);
  });

  gulp.task('copy', function() {
    return gulp.src('src/**/*.css')
      .pipe(gulp.dest('build'));
  });

  gulp.task('jspm', function(done) {
    jspm.promptDefaults(true);
    jspm.install(true, {
      lock: true
    }).then(function() {
      return jspmCore.checkDlLoader();
    }).then(function() {
      return jspmCore.setMode('local');
    }).then(function() {
      gutil.log(gutil.colors.cyan('Install complete'));
      done();
    }, function(err) {
      gutil.log(gutil.colors.red('err', err.stack || err));
      gutil.log(gutil.colors.red('Installation changes not saved.'));
      done();
    });
  });

  gulp.task('lint', function() {
    return gulp.src(['src/**/*.js', 'test/**/*.js'])
      .pipe(plugins.jshint())
      .pipe(plugins.jshint.reporter(require('jshint-stylish')));
  });

  gulp.task('soy', function() {
    return gulp.src('src/**/*.soy')
      .pipe(plugins.if(!shouldSkipSoyTemplatesGeneration, generateTemplatesAndExtractParams()))
      .pipe(plugins.if(!shouldSkipSoyTemplatesGeneration, gulp.dest('build')))
      .pipe(plugins.soynode({
        loadCompiledTemplates: false,
        shouldDeclareTopLevelNamespaces: false
      }))
      .pipe(plugins.ignore.exclude('*.soy'))
      .pipe(plugins.wrapper({
        header: getHeaderContent(corePathFromSoy),
        footer: getFooterContent
      }))
      .pipe(gulp.dest('src'));
  });

  gulp.task('test', function(done) {
    return runSequence('test:unit', /*'test:complexity', TODO(edu): ES6.*/ done);
  });

  gulp.task('test:complexity', function() {
    return gulp.src(['src/**/*.js', '!src/**/*.soy.js', '!src/promise/Promise.js', 'test/**/*.js'])
      .pipe(babel())
      .pipe(plugins.complexity({
        halstead: [15, 15, 20]
      }));
  });

  gulp.task('test:unit', ['jspm'], function(done) {
    runKarma({}, done);
  });

  gulp.task('test:coverage', ['jspm'], function(done) {
    runKarma({}, function() {
      open(path.resolve('coverage/lcov/lcov-report/index.html'));
      done();
    });
  });

  gulp.task('test:browsers', ['jspm'], function(done) {
    runKarma({
      browsers: ['Chrome', 'Firefox', 'Safari', 'IE9 - Win7', 'IE10 - Win7', 'IE11 - Win7']
    }, done);
  });

  gulp.task('test:saucelabs', ['jspm'], function(done) {
    var launchers = {
      sl_chrome: {
        base: 'SauceLabs',
        browserName: 'chrome'
      },
      sl_safari: {
        base: 'SauceLabs',
        browserName: 'safari'
      },
      sl_firefox: {
        base: 'SauceLabs',
        browserName: 'firefox'
      },
      sl_ie_9: {
        base: 'SauceLabs',
        browserName: 'internet explorer',
        platform: 'Windows 7',
        version: '9'
      },
      sl_ie_10: {
        base: 'SauceLabs',
        browserName: 'internet explorer',
        platform: 'Windows 7',
        version: '10'
      },
      sl_ie_11: {
        base: 'SauceLabs',
        browserName: 'internet explorer',
        platform: 'Windows 8.1',
        version: '11'
      },
      sl_iphone: {
        base: 'SauceLabs',
        browserName: 'iphone',
        platform: 'OS X 10.10',
        version: '7.1'
      },
      sl_android_4: {
        base: 'SauceLabs',
        browserName: 'android',
        platform: 'Linux',
        version: '4.4'
      },
      sl_android_5: {
        base: 'SauceLabs',
        browserName: 'android',
        platform: 'Linux',
        version: '5.0'
      }
    };

    runKarma({
      browsers: Object.keys(launchers),

      browserDisconnectTimeout: 10000,
      browserDisconnectTolerance: 2,
      browserNoActivityTimeout: 240000,

      captureTimeout: 240000,
      customLaunchers: launchers,

      reporters: ['coverage', 'progress', 'saucelabs'],

      sauceLabs: {
        testName: 'AlloyUI tests',
        recordScreenshots: false,
        startConnect: true,
        connectOptions: {
          port: 5757,
          'selenium-version': '2.41.0',
          logfile: 'sauce_connect.log'
        }
      }
    }, done);
  });

  gulp.task('test:watch', ['jspm'], function(done) {
    runKarma({
      singleRun: false
    }, done);
  });

  gulp.task('watch', ['build'], function() {
    gulp.watch('src/**/*', ['build']);
  });
};

// Private helpers
// ===============

function banner(pkg) {
  var stamp = [
    '/**',
    ' * <%= pkg.name %> - <%= pkg.description %>',
    ' * @version v<%= pkg.version %>',
    ' * @author <%= pkg.author.name %> <<%= pkg.author.email %>>',
    ' * @link http://liferay.com',
    ' * @license BSD',
    ' */',
    ''
  ].join('\n');

  return plugins.header(stamp, {
    pkg: pkg
  });
}

function createComponentSoy(moduleName) {
  return '\n/**\n * @param ref\n */\n' +
    '{deltemplate ' + moduleName + '}\n' +
      '{delcall Component data="all"}\n' +
        '{param componentName: \'' + moduleName + '\' /}\n' +
      '{/delcall}\n' +
    '{/deltemplate}\n';
}

function createSurfaceSoy(moduleName, surfaceName) {
  return '\n/**\n * @param id\n */\n' +
    '{deltemplate ' + moduleName + '.' + surfaceName + '}\n' +
      '
\n' +
        '{if $ij.renderChildComponents}\n' +
            '{call .' + surfaceName + ' data="all" /}\n' +
        '{/if}\n' +
      '
\n' +
    '{/deltemplate}\n';
}

var templateParams = {};
function extractTemplateParams(namespace, templateCmd, filePath) {
  var soyJsPath = filePath + '.js';
  templateParams[soyJsPath] = templateParams[soyJsPath] || {};

  var templateName = namespace + '.' + templateCmd.name;
  templateParams[soyJsPath][templateName] = [];

  var paramRegex = /{@param \s*(\S*)\s*:(.*)}/g;
  var currentMatch = paramRegex.exec(templateCmd.contents);
  while (currentMatch) {
    templateParams[soyJsPath][templateName].push(currentMatch[1]);
    currentMatch = paramRegex.exec(templateCmd.contents);
  }
}

function generateDelTemplate(namespace, templateCmd) {
  var moduleName = namespace.substr(10);
  if (templateCmd.name === 'element') {
    return createComponentSoy(moduleName);
  } else {
    return createSurfaceSoy(moduleName, templateCmd.name);
  }
}

function generateTemplatesAndExtractParams() {
  return through.obj(function(file, encoding, callback) {
    var fileString = file.contents.toString(encoding);
    fileString += '\n// The following templates were generated by alloyui-tasks.\n' +
      '// Please don\'t edit them by hand.\n';

    var namespace = /{namespace (.*)}/.exec(fileString)[1];
    var templateCmds = getAllTemplateCmds(fileString);
    for (var i = 0; i < templateCmds.length; i++) {
      fileString += generateDelTemplate(namespace, templateCmds[i]);
      extractTemplateParams(namespace, templateCmds[i], file.relative);
    }

    file.contents = new Buffer(fileString);
    this.push(file);
    callback();
  });
}

function getFooterContent(file) {
  var footer = '';
  var fileParams = templateParams[file.relative];
  for (var templateName in fileParams) {
    footer += '\n' + templateName + '.params = ' + JSON.stringify(fileParams[templateName]) + ';';
  }
  return footer + '\n/* jshint ignore:end */\n';
}

function getHeaderContent(corePathFromSoy) {
  var registryModulePath = path.join(corePathFromSoy, '/component/ComponentRegistry');
  return '/* jshint ignore:start */\n' +
    'import ComponentRegistry from \'' + registryModulePath + '\';\n' +
    'var Templates = ComponentRegistry.Templates;\n';
}

function getAllTemplateCmds(fileString) {
  var cmds = [];
  var regex = /{template (.*)}/g;
  var match = regex.exec(fileString);
  while (match) {
    var endIndex = fileString.indexOf('{/template}', match.index);
    cmds.push({
      contents: fileString.substring(match.index, endIndex),
      name: match[1].substr(1)
    });
    match = regex.exec(fileString);
  }
  return cmds;
}

function runKarma(config, done) {
  config = merge({
    configFile: path.resolve('karma.conf.js'),
    singleRun: true
  }, config);
  karma.start(config, done);
}
<|endoftext|>


<commit_before>'use strict';

const path = require('path');
const requireHelper = require('./../helpers/requireHelper');

/**
 * Implements the collections Loader class.
 */
class CollectionsLoader {

  /**
   * Creates new instance
   *
   * @param {ServiceLocator} locator The Service Locator for resolving dependencies.
   */
  constructor(locator) {
    this._locator = locator;

    /**
     * Current event bus.
     *
     * @type {EventEmitter}
     * @private
     */
    this._events = locator.resolve('events');

    /**
     * Current collections finder.
     *
     * @type {CollectionsFinder}
     * @private
     */
    this._collectionsFinder = locator.resolve('collectionsFinder');

    /**
     * Current map of the loaded collections by their names.
     *
     * @type {Object}
     * @private
     */
    this._loadedCollections = null;
  }

  /**
   * Loads all collections into the memory.
   *
   * @returns {Promise<Object>} The promise for map of loaded collections.
   */
  load() {
    if (this._loadedCollections) {
      return Promise.resolve(this._loadedCollections);
    }

    const result = Object.create(null);

    return this._collectionsFinder.find()
      .then(collections =>
        Object
          .keys(collections)
          .map(collection_name => this._getCollection(collections[collection_name]))
      )
      .then(collection_list => {
        collection_list.forEach(collection => {
          if (!collection || typeof (collection) !== 'object') {
            return;
          }

          this._events.emit('collectionLoaded', collection);
          result[collection.name] = collection;
        });

        this._loadedCollections = result;
        this._events.emit('allCollectionsLoaded', result);

        return this._loadedCollections;
      });
  }

  /**
   * Load/Reload collection
   *
   * @param {Object} descriptor Collection's descriptor
   * @return {void}
   * @private
   */
  loadCollection(descriptor) {
    const collection = this._getCollection(descriptor);

    if (collection) {

      this._loadedCollections[descriptor.name] = collection;
      this._events.emit('collectionLoaded', collection);

    } else if (this._loadedCollections[descriptor.name]) {

      // remove, if it was previously loaded
      this.removeCollection(descriptor.name);
    }
  }

  /**
   * Remove collection by name
   *
   * @param {String} name Collection's name
   * @return {void}
   */
  removeCollection(name) {
    delete this._loadedCollections[name];
  }

  /**
   * Gets a collection object by the found collection details.
   *
   * collection = {
   *   constructor: Class,
   *   name: ''
   *   properties: {
   *      logic: '',
   *      endpoints: {}
   *   }
   *   path: ''
   * }
   *
   * @param {Object} descriptor The found details.
   * @returns {Object} The collection object.
   * @private
   */
  _getCollection(descriptor) {
    const logic_path = this._getLogicPath(descriptor);

    let constructor;
    try {
      constructor = require(logic_path);
    } catch (e) {
      if (e.code === 'ENOENT' || e.message.indexOf('Cannot find module') !== -1) {
        this._events.emit('error', `In collection ${descriptor.name} the logic file has been moved or deleted. Skipping...`);
      } else {
        this._events.emit('error', `In collection ${descriptor.name} error. Skipping... \n ${e.stack}`);
      }
      return null;
    }

    if (typeof (constructor) !== 'function') {
      this._events.emit('warn',
        `File at ${logic_path} of collection "${descriptor.name}" not found or does not export the constructor. Skipping...`
      );
      return null;
    }

    const collection = Object.create(descriptor);
    collection.constructor = constructor;

    return collection;
  }

  /**
   * Return descriptor of collection by name
   *
   * @param name
   */
  getCollectionByName(name) {
    return this._loadedCollections[name];
  }

  /**
   * Return collections by name
   */
  getCollectionsByNames() {
    return this._loadedCollections;
  }

  /**
   * Gets an absolute path to the collection's logic file.
   * @param {Object} collectionDetails The collection details object.
   * @returns {string} The absolute path to the logic file.
   * @private
   */
  _getLogicPath(collectionDetails) {
    return path.resolve(path.dirname(collectionDetails.path), collectionDetails.properties.logic);
  }
}

module.exports = CollectionsLoader;
<commit_msg>Fix error report in CollectionLoader<commit_after>'use strict';

const path = require('path');
const requireHelper = require('./../helpers/requireHelper');

/**
 * Implements the collections Loader class.
 */
class CollectionsLoader {

  /**
   * Creates new instance
   *
   * @param {ServiceLocator} locator The Service Locator for resolving dependencies.
   */
  constructor(locator) {
    this._locator = locator;

    /**
     * Current event bus.
     *
     * @type {EventEmitter}
     * @private
     */
    this._events = locator.resolve('events');

    /**
     * Current collections finder.
     *
     * @type {CollectionsFinder}
     * @private
     */
    this._collectionsFinder = locator.resolve('collectionsFinder');

    /**
     * Current map of the loaded collections by their names.
     *
     * @type {Object}
     * @private
     */
    this._loadedCollections = null;
  }

  /**
   * Loads all collections into the memory.
   *
   * @returns {Promise<Object>} The promise for map of loaded collections.
   */
  load() {
    if (this._loadedCollections) {
      return Promise.resolve(this._loadedCollections);
    }

    const result = Object.create(null);

    return this._collectionsFinder.find()
      .then(collections =>
        Object
          .keys(collections)
          .map(collection_name => this._getCollection(collections[collection_name]))
      )
      .then(collection_list => {
        collection_list.forEach(collection => {
          if (!collection || typeof (collection) !== 'object') {
            return;
          }

          this._events.emit('collectionLoaded', collection);
          result[collection.name] = collection;
        });

        this._loadedCollections = result;
        this._events.emit('allCollectionsLoaded', result);

        return this._loadedCollections;
      });
  }

  /**
   * Load/Reload collection
   *
   * @param {Object} descriptor Collection's descriptor
   * @return {void}
   * @private
   */
  loadCollection(descriptor) {
    const collection = this._getCollection(descriptor);

    if (collection) {

      this._loadedCollections[descriptor.name] = collection;
      this._events.emit('collectionLoaded', collection);

    } else if (this._loadedCollections[descriptor.name]) {

      // remove, if it was previously loaded
      this.removeCollection(descriptor.name);
    }
  }

  /**
   * Remove collection by name
   *
   * @param {String} name Collection's name
   * @return {void}
   */
  removeCollection(name) {
    delete this._loadedCollections[name];
  }

  /**
   * Gets a collection object by the found collection details.
   *
   * collection = {
   *   constructor: Class,
   *   name: ''
   *   properties: {
   *      logic: '',
   *      endpoints: {}
   *   }
   *   path: ''
   * }
   *
   * @param {Object} descriptor The found details.
   * @returns {Object} The collection object.
   * @private
   */
  _getCollection(descriptor) {
    const logic_path = this._getLogicPath(descriptor);

    let constructor;
    try {
      constructor = require(logic_path);
    } catch (e) {
      if (e.code === 'ENOENT' || e.message.indexOf(logic_path) !== -1) {
        this._events.emit('error', `In collection "${descriptor.name}" the logic file has been moved or deleted. Skipping...`);
      } else {
        this._events.emit('error', `In collection "${descriptor.name}" error. Skipping... \n ${e.stack}`);
      }
      return null;
    }

    if (typeof (constructor) !== 'function') {
      this._events.emit('warn',
        `File at ${logic_path} of collection "${descriptor.name}" not found or does not export the constructor. Skipping...`
      );
      return null;
    }

    const collection = Object.create(descriptor);
    collection.constructor = constructor;

    return collection;
  }

  /**
   * Return descriptor of collection by name
   *
   * @param name
   */
  getCollectionByName(name) {
    return this._loadedCollections[name];
  }

  /**
   * Return collections by name
   */
  getCollectionsByNames() {
    return this._loadedCollections;
  }

  /**
   * Gets an absolute path to the collection's logic file.
   * @param {Object} collectionDetails The collection details object.
   * @returns {string} The absolute path to the logic file.
   * @private
   */
  _getLogicPath(collectionDetails) {
    return path.resolve(path.dirname(collectionDetails.path), collectionDetails.properties.logic);
  }
}

module.exports = CollectionsLoader;
<|endoftext|>