<commit_before>'use strict';
/**
 * @file
 * ImageEditor is used to upload and crop an image.
 *
 */

import React from 'react';

const ImageEditor = React.createClass({

  displayName: function() {
    return 'ReactImageEditor';
  },

  propTypes: function () {
    return {
      initialImageUrl: React.PropTypes.string(),
      onSave: React.PropTypes.func()
    };
  },

  getInitialState: function () {
    return {
      cvsImageWidth: null,
      cvsImageHeight: null,
      cropDragEnabled: false,
      dragEndX: null,
      dragEndY: null,
      fixedX: 0,
      fixedY: 0,
      image: null,
      isCroppable: false,
      positionX: 0,
      positionY: 0
    };
  },

  componentDidMount: function () {
    window.addEventListener('resize', this._handleResize);
    this.loadImage(this.props.initialImageUrl, this.drawImage);
  },

  componentDidUpdate: function () {
    this.drawImage();
  },

  componentWillUnmount: function () {
    window.removeEventListener('resize', this._handleResize);
  },

  drawImage: function () {
    let self = this;

    if (typeof this.state.image !== 'undefined') {
      // get drawing context
      let canvas = React.findDOMNode(this.refs.cvs);
      let ctx = canvas.getContext('2d');

      let image = this.state.image;

      // resize canvas dynamically
      ctx.canvas.width = window.innerWidth;
      ctx.canvas.height = window.innerWidth;

      let isLandscape = image.width > image.height;
      let newCvsImageWidth = isLandscape ? image.width * (ctx.canvas.width / image.height) : ctx.canvas.width;
      let newCvsImageHeight = isLandscape ? ctx.canvas.width : image.height * (ctx.canvas.width / image.width);
      let offsetX = self.state.positionX;
      let offsetY = self.state.positionY;

      ctx.drawImage(image, -offsetX, -offsetY, newCvsImageWidth, newCvsImageHeight);
    }
  },

  loadImage: function (url, callback) {
    let self = this;
    let image = new Image();
    image.onload = function () {
      // set new image and reset all other state
      let isCroppable = image.width !== image.height;
      self.setState({
        dragEndX: null,
        dragEndY: null,
        positionX: 0,
        positionY: 0,
        fixedX: 0,
        fixedY: 0,
        image: image,
        isCroppable: isCroppable,
        cvsImageWidth: image.width,
        cvsImageHeight: image.height,
        cropDragEnabled: false
      });

      if (typeof callback !== 'undefined') {
        callback();
      }
    };
    image.src = url;
  },

  handleFileChanged: function (e) {

    let files;
    files = e.target.files;

    if (files[0]) { // if file has been selected
      let reader = new FileReader();
      reader.onload = () => {
        let imageUrl = reader.result;
        this.loadImage(imageUrl);
        this.props.onSave(imageUrl);
      };
      reader.readAsDataURL(files[0]);
    }
  },

  handleSave: function () {
    // create new image from crop selection
    let canvas = React.findDOMNode(this.refs.cvs);
    let croppedImageUrl = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream');

    this.loadImage(croppedImageUrl, this._handleResize);

    // call save function passed as prop with image url
    this.props.onSave(croppedImageUrl);
  },

  _handleResize: function () {
    this.drawImage();
  },

  handleDragStart: function (e) {
    // mouse position inside crop frame
    let mouseX = e.clientX - e.target.getBoundingClientRect().left;
    let mouseY = e.clientY - e.target.getBoundingClientRect().top;

    // position in crop frame when drag initiated
    let dragStartX = mouseX;
    let dragStartY = mouseY;

    this.setState({
      cropDragEnabled: true,
      dragStartX: dragStartX,
      dragStartY: dragStartY
    });
  },

  handleDrag: function (e) {
    if (this.state.cropDragEnabled) {
      // mouse position inside crop frame
      let mouseX = e.clientX - e.target.getBoundingClientRect().left;
      let mouseY = e.clientY - e.target.getBoundingClientRect().top;

      // where is mouse relative to start drag
      let dX = this.state.dragStartX - mouseX;
      let dY = this.state.dragStartY - mouseY;

      // This state must be changed
      let positionX = this.state.fixedX + dX;
      let positionY = this.state.fixedY + dY;

      let isSquare = this.state.cvsImageWidth === this.state.cvsImageHeight;
      let isLandscape = this.state.cvsImageWidth > this.state.cvsImageHeight;

      if (isSquare) {
        // no panning - image is already as square as it can be.
        positionX = this.state.fixedX;
        positionY = this.state.fixedY;
      }
      else if (isLandscape) {

        // compute canvas image dimensions
        let canvas = React.findDOMNode(this.refs.cvs);
        let ctx = canvas.getContext('2d');
        let ratio = this.state.image.height / this.state.image.width;
        let cvsImageWidth = (1 / ratio) * ctx.canvas.width;
        let maxPositionX = cvsImageWidth - ctx.canvas.width;

        // limit panning by image height
        positionX = (positionX > maxPositionX) ? maxPositionX : positionX;
        positionX = (positionX < 0) ? 0 : positionX;

        // restrict vertical panning
        positionY = this.state.fixedY;

      }
      else {

        // compute canvas image dimensions
        let canvas = React.findDOMNode(this.refs.cvs);
        let ctx = canvas.getContext('2d');
        let ratio = this.state.image.height / this.state.image.width;
        let cvsImageHeight = ratio * ctx.canvas.height;
        let maxPositionY = cvsImageHeight - ctx.canvas.height;

        // limit panning by image height
        positionY = (positionY > maxPositionY) ? maxPositionY : positionY;
        positionY = (positionY < 0) ? 0 : positionY;

        // restrict vertical panning
        positionX = this.state.fixedX;
      }

      this.setState({
        positionX: positionX,
        positionY: positionY
      });
    }
  },

  handleDragEnd: function () {
    // This state must be changed
    let fixedX = this.state.positionX;
    let fixedY = this.state.positionY;

    this.setState({
      cropDragEnabled: false,
      fixedX: fixedX,
      fixedY: fixedY
    });
  },

  render: function () {
    let isCroppable = this.state.isCroppable;
    // const hasImageUrl = !!this.props.initialImageUrl;
    return (

        <canvas
          onMouseDown={this.handleDragStart}
          onMouseMove={this.handleDrag}
          onMouseUp={this.handleDragEnd}
          ref='cvs'/>
        <input onChange={this.handleFileChanged} type='file'/>
        <input disabled={!isCroppable} onClick={this.handleSave} ref='cropButton' type='button' value='Beskær'/>

    );
  }
});

export default ImageEditor;
<commit_msg>Accumulated commit of the following from branch 'origin/ready/mra':<commit_after>'use strict';
/**
 * @file
 * ImageEditor is used to upload and crop an image.
 *
 */

import React from 'react';

const ImageEditor = React.createClass({

  displayName: function() {
    return 'ReactImageEditor';
  },

  propTypes: function () {
    return {
      initialImageUrl: React.PropTypes.string(),
      onSave: React.PropTypes.func()
    };
  },

  getInitialState: function () {
    return {
      cvsImageWidth: null,
      cvsImageHeight: null,
      cropDragEnabled: false,
      dragEndX: null,
      dragEndY: null,
      fixedX: 0,
      fixedY: 0,
      image: null,
      isCroppable: false,
      positionX: 0,
      positionY: 0
    };
  },

  componentDidMount: function () {
    window.addEventListener('resize', this._handleResize);
    this.loadImage(this.props.initialImageUrl, this.drawImage);
  },

  componentDidUpdate: function () {
    this.drawImage();
  },

  componentWillUnmount: function () {
    window.removeEventListener('resize', this._handleResize);
  },

  drawImage: function () {
    let self = this;

    if (typeof this.state.image !== 'undefined') {
      // get drawing context
      let canvas = React.findDOMNode(this.refs.cvs);
      let ctx = canvas.getContext('2d');

      let image = this.state.image;

      // resize canvas dynamically
      ctx.canvas.width = window.innerWidth;
      ctx.canvas.height = window.innerWidth;

      let isLandscape = image.width > image.height;
      let newCvsImageWidth = isLandscape ? image.width * (ctx.canvas.width / image.height) : ctx.canvas.width;
      let newCvsImageHeight = isLandscape ? ctx.canvas.width : image.height * (ctx.canvas.width / image.width);
      let offsetX = self.state.positionX;
      let offsetY = self.state.positionY;

      ctx.drawImage(image, -offsetX, -offsetY, newCvsImageWidth, newCvsImageHeight);
    }
  },

  loadImage: function (url, callback) {
    let self = this;
    let image = new Image();
    image.onload = function () {
      // set new image and reset all other state
      let isCroppable = image.width !== image.height;
      self.setState({
        dragEndX: null,
        dragEndY: null,
        positionX: 0,
        positionY: 0,
        fixedX: 0,
        fixedY: 0,
        image: image,
        isCroppable: isCroppable,
        cvsImageWidth: image.width,
        cvsImageHeight: image.height,
        cropDragEnabled: false
      });

      if (typeof callback !== 'undefined') {
        callback();
      }
    };
    image.src = url;
  },

  handleFileChanged: function (e) {

    let files;
    files = e.target.files;

    if (files[0]) { // if file has been selected
      let reader = new FileReader();
      reader.onload = () => {
        let imageUrl = reader.result;
        this.loadImage(imageUrl);
        this.props.onSave(imageUrl);
      };
      reader.readAsDataURL(files[0]);
    }
  },

  handleSave: function () {
    // create new image from crop selection
    let canvas = React.findDOMNode(this.refs.cvs);
    let croppedImageUrl = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream');

    this.loadImage(croppedImageUrl, this._handleResize);

    // call save function passed as prop with image url
    this.props.onSave(croppedImageUrl);
  },

  _handleResize: function () {
    this.drawImage();
  },

  updateImagePosition: function(mouseX, mouseY) {

    // where is mouse relative to start drag
    let dX = this.state.dragStartX - mouseX;
    let dY = this.state.dragStartY - mouseY;

    // This state must be changed
    let positionX = this.state.fixedX + dX;
    let positionY = this.state.fixedY + dY;

    let isSquare = this.state.cvsImageWidth === this.state.cvsImageHeight;
    let isLandscape = this.state.cvsImageWidth > this.state.cvsImageHeight;

    if (isSquare) {
      // no panning - image is already as square as it can be.
      positionX = this.state.fixedX;
      positionY = this.state.fixedY;
    }
    else if (isLandscape) {

      // compute canvas image dimensions
      let canvas = React.findDOMNode(this.refs.cvs);
      let ctx = canvas.getContext('2d');
      let ratio = this.state.image.height / this.state.image.width;
      let cvsImageWidth = (1 / ratio) * ctx.canvas.width;
      let maxPositionX = cvsImageWidth - ctx.canvas.width;

      // limit panning by image height
      positionX = (positionX > maxPositionX) ? maxPositionX : positionX;
      positionX = (positionX < 0) ? 0 : positionX;

      // restrict vertical panning
      positionY = this.state.fixedY;

    }
    else {

      // compute canvas image dimensions
      let canvas = React.findDOMNode(this.refs.cvs);
      let ctx = canvas.getContext('2d');
      let ratio = this.state.image.height / this.state.image.width;
      let cvsImageHeight = ratio * ctx.canvas.height;
      let maxPositionY = cvsImageHeight - ctx.canvas.height;

      // limit panning by image height
      positionY = (positionY > maxPositionY) ? maxPositionY : positionY;
      positionY = (positionY < 0) ? 0 : positionY;

      // restrict vertical panning
      positionX = this.state.fixedX;
    }

    this.setState({
      positionX: positionX,
      positionY: positionY
    });
  },

  handleDragStart: function (e) {
    // mouse position inside crop frame
    let mouseX = e.clientX - e.target.getBoundingClientRect().left;
    let mouseY = e.clientY - e.target.getBoundingClientRect().top;

    // position in crop frame when drag initiated
    let dragStartX = mouseX;
    let dragStartY = mouseY;

    this.setState({
      cropDragEnabled: true,
      dragStartX: dragStartX,
      dragStartY: dragStartY
    });
  },

  handleDrag: function (e) {
    if (this.state.cropDragEnabled) {
      // mouse position inside crop frame
      let mouseX = e.clientX - e.target.getBoundingClientRect().left;
      let mouseY = e.clientY - e.target.getBoundingClientRect().top;

      this.updateImagePosition(mouseX, mouseY);
    }
  },

  handleDragEnd: function () {
    // This state must be changed
    let fixedX = this.state.positionX;
    let fixedY = this.state.positionY;

    this.setState({
      cropDragEnabled: false,
      fixedX: fixedX,
      fixedY: fixedY
    });
  },

  handleTouchStart: function(e) {
    // mouse position inside crop frame
    let mouseX = e.changedTouches[0].clientX - e.changedTouches[0].target.getBoundingClientRect().left;
    let mouseY = e.changedTouches[0].clientY - e.changedTouches[0].target.getBoundingClientRect().top;
    // position in crop frame when drag initiated
    let dragStartX = mouseX;
    let dragStartY = mouseY;

    this.setState({
      cropDragEnabled: true,
      dragStartX: dragStartX,
      dragStartY: dragStartY
    });
  },

  handleTouchMove: function(e) {

    // do not scroll window
    e.preventDefault();

    if (this.state.cropDragEnabled) {
      // mouse position inside crop frame
      let mouseX = e.changedTouches[0].clientX - e.changedTouches[0].target.getBoundingClientRect().left;
      let mouseY = e.changedTouches[0].clientY - e.changedTouches[0].target.getBoundingClientRect().top;

      this.updateImagePosition(mouseX, mouseY);
    }
  },

  render: function () {
    let isCroppable = this.state.isCroppable;
    // const hasImageUrl = !!this.props.initialImageUrl;
    return (

        <canvas
          onMouseDown={this.handleDragStart}
          onMouseMove={this.handleDrag}
          onMouseUp={this.handleDragEnd}
          onTouchEndCapture={this.handleDragEnd}
          onTouchMove={this.handleTouchMove}
          onTouchStartCapture={this.handleTouchStart}
          ref='cvs'/>
        <input onChange={this.handleFileChanged} type='file'/>
        <input disabled={!isCroppable} onClick={this.handleSave} ref='cropButton' type='button' value='Beskær'/>

    );
  }
});

export default ImageEditor;
<|endoftext|>


<commit_before>import React from 'react';
import _ from 'lodash';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import ls from 'local-storage';

import PlayerActions from '../actions';
import SubtitleStore from './SubtitleText/store';
import SubtitleActions from './SubtitleText/actions';
import VisibilityStore from './Visibility/store';
import VisibilityActions from './Visibility/actions';
import player from '../utils/player';
import path from 'path';

const lang2country = {
    en: 'us',
    cs: 'cz',
    pb: 'br',
    he: 'il',
    el: 'gr',
    uk: 'ua',
    fa: 'ir',
    vi: 'vn'
}

export
default React.createClass({

    mixins: [PureRenderMixin],

    getInitialState() {
        return {
            open: false,
            playlist: player.wcjs.playlist || false,
            playlistSelected: SubtitleStore.getState().selectedSub
        }
    },
    componentWillMount() {
        VisibilityStore.listen(this.update);
    },

    componentWillUnmount() {
        VisibilityStore.unlisten(this.update);
    },
    update() {
        if (this.isMounted()) {
            this.setState({
                open: VisibilityStore.getState().subtitles,
                playlist: player.wcjs.playlist || false,
                playlistSelected: SubtitleStore.getState().selectedSub
            });
        }
    },

    close() {
        PlayerActions.openPlaylist(false);
    },

    getItems() {
        var itemDesc = player.itemDesc();
        if (itemDesc && itemDesc.setting && itemDesc.setting.subtitles) {
            return itemDesc.setting.subtitles;
        } else return [];
    },

    select(idx, item, itemId) {
        ls('lastLanguage', idx);
        player.wcjs.subtitles.track = 0;
        if (item) {
            SubtitleActions.loadSub(item);
            SubtitleActions.settingChange({
                selectedSub: itemId,
            });
        } else {
            SubtitleActions.settingChange({
                selectedSub: itemId,
                subtitle: [],
                trackSub: -1,
                text: ''
            });
        }
        VisibilityActions.settingChange({
            subtitles: false
        });
    },

    selectInternal(idx, item, itemId) {
        var wcjs = player.wcjs;
        if (item && (itemId - 1) < wcjs.subtitles.count) {
            wcjs.subtitles.track = idx;
            SubtitleActions.settingChange({
                selectedSub: itemId,
                subtitle: [],
                subText: ''
            });
            VisibilityActions.settingChange({
                subtitles: false
            });
        }
    },

    getInternalSubs() {
        var wcjs = player.wcjs;
        var internalSubs = [];
        if (wcjs.subtitles && wcjs.subtitles.count > 0) {
            for (var i = 1; i < wcjs.subtitles.count; i++)
                internalSubs.push(wcjs.subtitles[i]);
            return internalSubs;
        } else return [];
    },

    render() {
        var itemId = 1;
        if (!ls.isSet('menuFlags') || ls('menuFlags')) {
            var none = (
                <paper-item key={itemId} style={{backgroundColor: '#303030', color: 'white', padding: '4px 12px'}} onClick={this.select.bind(this, 'none', '', 1)} className={'sub-menu-item' + (this.state.playlistSelected == itemId ? ' iron-selected' : '')}>

                    <paper-item-body>
                    None
                    </paper-item-body>
                </paper-item>
            );
        } else {
            var none = (
                <paper-item key={itemId} style={{backgroundColor: '#303030', color: 'white', padding: '4px 22px'}} onClick={this.select.bind(this, 'none', '', 1)} className={'sub-menu-item' + (this.state.playlistSelected == itemId ? ' iron-selected' : '')}>
                <paper-item-body>
                    None
                </paper-item-body>
                </paper-item>
            );
        }
        return (

                {none}
                {
                        _.map(this.getInternalSubs(), (item, idx) => {
                            itemId++;
                            if (!ls.isSet('menuFlags') || ls('menuFlags')) {
                                return (
                                  <paper-item key={itemId} style={{backgroundColor: '#303030', color: 'white', padding: '4px 12px'}} onClick={this.selectInternal.bind(this, (idx + 1), item, itemId)} className={'sub-menu-item' + (this.state.playlistSelected == itemId ? ' iron-selected' : '')}>

                    <paper-item-body>
                                    {item}
                                    </paper-item-body>
                                  </paper-item>
                                );
                            } else {
                                return (
                                  <paper-item key={itemId} style={{backgroundColor: '#303030', color: 'white', padding: '4px 22px'}} onClick={this.selectInternal.bind(this, (idx + 1), item, itemId)} className={'sub-menu-item' + (this.state.playlistSelected == itemId ? ' iron-selected' : '')}>
                                    <paper-item-body>
                                    {item}
                                    </paper-item-body>
                                  </paper-item>
                                );
                            }
                        })
                    }
                    {
                        _.map(this.getItems(), (item, idx) => {
                            itemId++;
                            var lang = idx.split('[lg]');
                            if (lang2country[lang[1]]) lang[1] = lang2country[lang[1]];
                            if (!ls.isSet('menuFlags') || ls('menuFlags')) {
                                return (
                                  <paper-item key={itemId} style={{backgroundColor: '#303030', color: 'white', padding: '4px 12px'}} onClick={this.select.bind(this, idx, item, itemId)} className={'sub-menu-item' + (this.state.playlistSelected == itemId ? ' iron-selected' : '')}>

                                    <paper-item-body style={{ overflow: 'hidden', textOverflow: 'ellipsis', display: '-webkit-box', WebkitLineClamp: '1', WebkitBoxOrient: 'vertical', maxWidth: '192px' }}>
                                    {lang[0]}
                                    </paper-item-body>
                                  </paper-item>
                                );
                            } else {
                                return (
                                  <paper-item key={itemId} style={{backgroundColor: '#303030', color: 'white', padding: '4px 22px' }} onClick={this.select.bind(this, idx, item, itemId)} className={'sub-menu-item' + (this.state.playlistSelected == itemId ? ' iron-selected' : '')}>
                                    <paper-item-body style={{ overflow: 'hidden', textOverflow: 'ellipsis', display: '-webkit-box', WebkitLineClamp: '1', WebkitBoxOrient: 'vertical', maxWidth: '192px' }}>
                                    {lang[0]}
                                    </paper-item-body>
                                  </paper-item>
                                );
                            }
                        })
                    }

        );
    }

});<commit_msg>Browse For Sub Option in Sub Menu<commit_after>import React from 'react';
import _ from 'lodash';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import ls from 'local-storage';

import PlayerActions from '../actions';
import SubtitleStore from './SubtitleText/store';
import SubtitleActions from './SubtitleText/actions';
import VisibilityStore from './Visibility/store';
import VisibilityActions from './Visibility/actions';
import player from '../utils/player';
import path from 'path';
import {
    dialog
} from 'remote';

const lang2country = {
    en: 'us',
    cs: 'cz',
    pb: 'br',
    he: 'il',
    el: 'gr',
    uk: 'ua',
    fa: 'ir',
    vi: 'vn'
}

export
default React.createClass({

    mixins: [PureRenderMixin],

    getInitialState() {
        return {
            open: false,
            playlist: player.wcjs.playlist || false,
            playlistSelected: SubtitleStore.getState().selectedSub
        }
    },
    componentWillMount() {
        VisibilityStore.listen(this.update);
    },

    componentWillUnmount() {
        VisibilityStore.unlisten(this.update);
    },
    update() {
        if (this.isMounted()) {
            this.setState({
                open: VisibilityStore.getState().subtitles,
                playlist: player.wcjs.playlist || false,
                playlistSelected: SubtitleStore.getState().selectedSub
            });
        }
    },

    close() {
        PlayerActions.openPlaylist(false);
    },

    getItems() {
        var itemDesc = player.itemDesc();
        if (itemDesc && itemDesc.setting && itemDesc.setting.subtitles) {
            return itemDesc.setting.subtitles;
        } else return [];
    },

    select(idx, item, itemId) {
		if (itemId == 2) {
			dialog.showOpenDialog({
				title: 'Select player',
				properties: ['openFile'],
				filters: [ {name: 'Subtitles', extensions: ['srt', 'vtt', 'sub']} ]
			}, (file) => {
				if (file && file.length) {
					var subs = player.itemDesc().setting.subtitles || {};
					subs[path.basename(file[0])] = file[0];
					PlayerActions.setDesc({
						subtitles: subs
					});
					player.wcjs.subtitles.track = 0;
					SubtitleActions.loadSub(file[0]);
					SubtitleActions.settingChange({
						selectedSub: _.size(subs) + (player.wcjs.subtitles.count || 1) +1,
					});
					player.notifier.info('Subtitle Loaded', '', 3000);
				}
			});
			return
		}
        ls('lastLanguage', idx);
        player.wcjs.subtitles.track = 0;
        if (item) {
            SubtitleActions.loadSub(item);
            SubtitleActions.settingChange({
                selectedSub: itemId,
            });
        } else {
            SubtitleActions.settingChange({
                selectedSub: itemId,
                subtitle: [],
                trackSub: -1,
                text: ''
            });
        }
        VisibilityActions.settingChange({
            subtitles: false
        });
    },

    selectInternal(idx, item, itemId) {
        var wcjs = player.wcjs;
        if (item && (itemId - 1) < wcjs.subtitles.count) {
            wcjs.subtitles.track = idx;
            SubtitleActions.settingChange({
                selectedSub: itemId,
                subtitle: [],
                subText: ''
            });
            VisibilityActions.settingChange({
                subtitles: false
            });
        }
    },

    getInternalSubs() {
        var wcjs = player.wcjs;
        var internalSubs = [];
        if (wcjs.subtitles && wcjs.subtitles.count > 0) {
            for (var i = 1; i < wcjs.subtitles.count; i++)
                internalSubs.push(wcjs.subtitles[i]);
            return internalSubs;
        } else return [];
    },

    render() {
        var itemId = 1;
        if (!ls.isSet('menuFlags') || ls('menuFlags')) {
            var none = (
                <paper-item key={itemId} style={{backgroundColor: '#303030', color: 'white', padding: '4px 12px'}} onClick={this.select.bind(this, 'none', '', 1)} className={'sub-menu-item' + (this.state.playlistSelected == itemId ? ' iron-selected' : '')}>

                    <paper-item-body>
                    None
                    </paper-item-body>
                </paper-item>
            );
			itemId++
			var browseForSub = (
                <paper-item key={itemId} style={{backgroundColor: '#303030', color: 'white', padding: '4px 12px'}} onClick={this.select.bind(this, 'browse', '', 2)} className={'sub-menu-item' + (this.state.playlistSelected == itemId ? ' iron-selected' : '')}>

                    <paper-item-body>
                    Browse
                    </paper-item-body>
                </paper-item>
            );
        } else {
            var none = (
                <paper-item key={itemId} style={{backgroundColor: '#303030', color: 'white', padding: '4px 22px'}} onClick={this.select.bind(this, 'none', '', 1)} className={'sub-menu-item' + (this.state.playlistSelected == itemId ? ' iron-selected' : '')}>
                <paper-item-body>
                    None
                </paper-item-body>
                </paper-item>
            );
			itemId++
            var browseForSub = (
                <paper-item key={itemId} style={{backgroundColor: '#303030', color: 'white', padding: '4px 22px'}} onClick={this.select.bind(this, 'browse', '', 2)} className={'sub-menu-item' + (this.state.playlistSelected == itemId ? ' iron-selected' : '')}>
                <paper-item-body>
                    Browse
                </paper-item-body>
                </paper-item>
            );
        }
        return (

                {none}
				{browseForSub}
                {
                        _.map(this.getInternalSubs(), (item, idx) => {
                            itemId++;
                            if (!ls.isSet('menuFlags') || ls('menuFlags')) {
                                return (
                                  <paper-item key={itemId} style={{backgroundColor: '#303030', color: 'white', padding: '4px 12px'}} onClick={this.selectInternal.bind(this, (idx + 1), item, itemId)} className={'sub-menu-item' + (this.state.playlistSelected == itemId ? ' iron-selected' : '')}>

                    <paper-item-body>
                                    {item}
                                    </paper-item-body>
                                  </paper-item>
                                );
                            } else {
                                return (
                                  <paper-item key={itemId} style={{backgroundColor: '#303030', color: 'white', padding: '4px 22px'}} onClick={this.selectInternal.bind(this, (idx + 1), item, itemId)} className={'sub-menu-item' + (this.state.playlistSelected == itemId ? ' iron-selected' : '')}>
                                    <paper-item-body>
                                    {item}
                                    </paper-item-body>
                                  </paper-item>
                                );
                            }
                        })
                    }
                    {
                        _.map(this.getItems(), (item, idx) => {
                            itemId++;
                            var lang = idx.split('[lg]');
                            if (lang2country[lang[1]]) lang[1] = lang2country[lang[1]];
                            if (!ls.isSet('menuFlags') || ls('menuFlags')) {
                                return (
                                  <paper-item key={itemId} style={{backgroundColor: '#303030', color: 'white', padding: '4px 12px'}} onClick={this.select.bind(this, idx, item, itemId)} className={'sub-menu-item' + (this.state.playlistSelected == itemId ? ' iron-selected' : '')}>

                                    <paper-item-body style={{ overflow: 'hidden', textOverflow: 'ellipsis', display: '-webkit-box', WebkitLineClamp: '1', WebkitBoxOrient: 'vertical', maxWidth: '192px' }}>
                                    {lang[0]}
                                    </paper-item-body>
                                  </paper-item>
                                );
                            } else {
                                return (
                                  <paper-item key={itemId} style={{backgroundColor: '#303030', color: 'white', padding: '4px 22px' }} onClick={this.select.bind(this, idx, item, itemId)} className={'sub-menu-item' + (this.state.playlistSelected == itemId ? ' iron-selected' : '')}>
                                    <paper-item-body style={{ overflow: 'hidden', textOverflow: 'ellipsis', display: '-webkit-box', WebkitLineClamp: '1', WebkitBoxOrient: 'vertical', maxWidth: '192px' }}>
                                    {lang[0]}
                                    </paper-item-body>
                                  </paper-item>
                                );
                            }
                        })
                    }

        );
    }

});<|endoftext|>


<commit_before>
/**
 * @author GJS <1353990812@qq.com>
 *
 * GJS reserves all rights not expressly granted.
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 GJS
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
 * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * @providesModule RelativeContainer
 * @flow
 */

/*
控件功能：弹出框相对布局容器
*/

'use strict';

import React,{
    Component
} from 'react'
import {
    View,
    StyleSheet,
    Animated,
    Dimensions,
    ListView,
    Text,
    Easing,
    TouchableWithoutFeedback,
    TouchableOpacity,
    Image,
} from 'react-native'

import {
  Platform
} from 'react-native'

export default class RelativeContainer extends Component{
    constructor(props){
        super(props);
    }

    componentDidMount(){

    }

    render(){
      return (
        <View
          pointerEvents='box-none'
          // style={{
          //   flex: 1,
          //   position: 'absolute', top: 0, right: 0, left: 0, bottom: 0,
          //   zIndex: 888,
          //   overflow: 'hidden',
          // }}
          style={{
            // flex: 1,
            height: 1,
            zIndex: 888,
            overflow: 'visible',
            backgroundColor: 'transparent',
          }}
        >
          {this.props.children}
        </View>
      );
    }

}

const styles = StyleSheet.create({
  //
});

<commit_msg>RelativeContainer now can merge the style props<commit_after>
/**
 * @author GJS <1353990812@qq.com>
 *
 * GJS reserves all rights not expressly granted.
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 GJS
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
 * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * @providesModule RelativeContainer
 * @flow
 */

/*
控件功能：弹出框相对布局容器
*/

'use strict';

import React,{
    Component
} from 'react'
import {
    View,
    StyleSheet,
    Animated,
    Dimensions,
    ListView,
    Text,
    Easing,
    TouchableWithoutFeedback,
    TouchableOpacity,
    Image,
} from 'react-native'

import {
  Platform
} from 'react-native'

export default class RelativeContainer extends Component{
    constructor(props){
        super(props);
    }

    componentDidMount(){

    }

    render(){
      return (
        <View
          {...this.props}
          pointerEvents='box-none'
          // style={{
          //   flex: 1,
          //   position: 'absolute', top: 0, right: 0, left: 0, bottom: 0,
          //   zIndex: 888,
          //   overflow: 'hidden',
          // }}
          style={[
            {
              // flex: 1,
              height: 1,
              zIndex: 888,
              overflow: 'visible',
              backgroundColor: 'transparent',
            },
            this.props.style,
          ]}
        >
          {this.props.children}
        </View>
      );
    }

}

const styles = StyleSheet.create({
  //
});

<|endoftext|>


<commit_before>import { LitElement, html } from 'lit-element'
import { repeat } from 'lit-html/directives/repeat.js'
import { connect } from 'pwa-helpers/connect-mixin.js'
import { store } from '../../reduxStore.js'
import uuidv1 from 'uuid/v1.js'
import { addUniverse, removeUniverse, resetUniverseAndFixtures, setChannel, setUniverse } from '../../actions/index.js'
import { getUniverses, getLive } from '../../selectors/index.js'
import '../channel-grid/channel-grid.js'
import { addToBatch } from '../../utils/index.js'

import '@polymer/paper-button/paper-button.js'
import { buttons } from '../../styles/buttons.js'

/*
 * Handle all DMX512 universes
 */
class UniverseManager extends connect(store)(LitElement) {
  static get properties() {
    return {
      universes: { type: Array },
      live: { type: Boolean }
    }
  }

  _stateChanged(state) {
    this.universes = getUniverses(state)
    this.live = getLive(state)
  }

  addUniverse() {
    const id = uuidv1()
    store.dispatch(addUniverse({
      id,
      channels: [...Array(512)].map(() => 0),
      name: `${id}`,
      refresh: true
    }))
  }

  removeUniverse(e) {
    const { universeId } = e.target
    store.dispatch(removeUniverse(universeId))
  }

  resetUniverse(e) {
    store.dispatch(resetUniverseAndFixtures(0))
  }

  /**
   * Update a specific channel.
   *
   * @param {Object} e - The event that contains the channel and the value
   */
  updateChannel(e) {
    const { channelIndex, channelValue } = e.detail

    store.dispatch(setChannel(0, channelIndex, channelValue))

    addToBatch(channelIndex, channelValue)

    const now = new Date()

    // Send the universe to the UsbDmxManager
    window.dispatchEvent(new CustomEvent('send-universe-to-usb-dmx-controller', { detail: { now } }))

    // Send the universe to the FivetwelveManager
    window.dispatchEvent(new CustomEvent('send-universe-to-fivetwelve', { detail: { now } }))
  }

  /**
   * Value of refresh was updated
   *
   * @param {Object} e - The event
   */
  handleRefreshChange(e) {
    const { universeId } = e.target
    const refresh = e.target.checked

    store.dispatch(setUniverse(universeId, { refresh }))
  }

  render() {
    const { universes, live } = this

    return html`
      ${buttons}

      ${
        live
        ? ''
        : html`<paper-button @click="${e => this.addUniverse(e)}" class="primary">Add universe</paper-button>`
      }

      ${repeat(universes, universe => html`

          ${
            live
            ? ''
            : html`

${universe.name}

              <paper-button @click="${e => this.removeUniverse(e)}" .universeId="${universe.id}" class="warning">Remove</paper-button>
            `
          }

          <paper-button @click="${e => this.resetUniverse(e)}" .universeId="${universe.id}">Reset</paper-button>

          Auto-Refresh
          <input
            name="refresh"
            type="checkbox"
            .checked="${universe.refresh}"
            .universeId="${universe.id}"
            @click="${e => this.handleRefreshChange(e)}" />

            <channel-grid
              .channels="${universe.channels}"
              @update-channel="${e => this.updateChannel(e)}"
              .refresh="${universe.refresh}"
            ></channel-grid>

      `)}

    `
  }
}

customElements.define('universe-manager', UniverseManager)
<commit_msg>fix(universe): Default refresh should be false<commit_after>import { LitElement, html } from 'lit-element'
import { repeat } from 'lit-html/directives/repeat.js'
import { connect } from 'pwa-helpers/connect-mixin.js'
import { store } from '../../reduxStore.js'
import uuidv1 from 'uuid/v1.js'
import { addUniverse, removeUniverse, resetUniverseAndFixtures, setChannel, setUniverse } from '../../actions/index.js'
import { getUniverses, getLive } from '../../selectors/index.js'
import '../channel-grid/channel-grid.js'
import { addToBatch } from '../../utils/index.js'

import '@polymer/paper-button/paper-button.js'
import { buttons } from '../../styles/buttons.js'

/*
 * Handle all DMX512 universes
 */
class UniverseManager extends connect(store)(LitElement) {
  static get properties() {
    return {
      universes: { type: Array },
      live: { type: Boolean }
    }
  }

  _stateChanged(state) {
    this.universes = getUniverses(state)
    this.live = getLive(state)
  }

  addUniverse() {
    const id = uuidv1()
    store.dispatch(addUniverse({
      id,
      channels: [...Array(512)].map(() => 0),
      name: `${id}`,
      refresh: false
    }))
  }

  removeUniverse(e) {
    const { universeId } = e.target
    store.dispatch(removeUniverse(universeId))
  }

  resetUniverse(e) {
    store.dispatch(resetUniverseAndFixtures(0))
  }

  /**
   * Update a specific channel.
   *
   * @param {Object} e - The event that contains the channel and the value
   */
  updateChannel(e) {
    const { channelIndex, channelValue } = e.detail

    store.dispatch(setChannel(0, channelIndex, channelValue))

    addToBatch(channelIndex, channelValue)

    const now = new Date()

    // Send the universe to the UsbDmxManager
    window.dispatchEvent(new CustomEvent('send-universe-to-usb-dmx-controller', { detail: { now } }))

    // Send the universe to the FivetwelveManager
    window.dispatchEvent(new CustomEvent('send-universe-to-fivetwelve', { detail: { now } }))
  }

  /**
   * Value of refresh was updated
   *
   * @param {Object} e - The event
   */
  handleRefreshChange(e) {
    const { universeId } = e.target
    const refresh = e.target.checked

    store.dispatch(setUniverse(universeId, { refresh }))
  }

  render() {
    const { universes, live } = this

    return html`
      ${buttons}

      ${
        live
        ? ''
        : html`<paper-button @click="${e => this.addUniverse(e)}" class="primary">Add universe</paper-button>`
      }

      ${repeat(universes, universe => html`

          ${
            live
            ? ''
            : html`

${universe.name}

              <paper-button @click="${e => this.removeUniverse(e)}" .universeId="${universe.id}" class="warning">Remove</paper-button>
            `
          }

          <paper-button @click="${e => this.resetUniverse(e)}" .universeId="${universe.id}">Reset</paper-button>

          Auto-Refresh
          <input
            name="refresh"
            type="checkbox"
            .checked="${universe.refresh}"
            .universeId="${universe.id}"
            @click="${e => this.handleRefreshChange(e)}" />

            <channel-grid
              .channels="${universe.channels}"
              @update-channel="${e => this.updateChannel(e)}"
              .refresh="${universe.refresh}"
            ></channel-grid>

      `)}

    `
  }
}

customElements.define('universe-manager', UniverseManager)
<|endoftext|>


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

module.exports = {
    poll: function(target, room, user) {
        if (!this.can('broadcast', null, room)) return this.sendReply('/poll - Access denied.');
        if (!Poll[room.id]) Poll.reset(room.id);
        if (Poll[room.id].question) return this.sendReply('There is currently a poll going on already.');
        if (!this.canTalk()) return;

        var options = Poll.splint(target);
        if (options.length < 3) return this.sendReply('/poll [question], [option 1], [option 2]... - Create a poll where users can vote on an option.');

        var question = options.shift();

        options = options.join(',').toLowerCase().split(',');

        Poll[room.id].question = question;
        Poll[room.id].optionList = options;

        var pollOptions = '';
        var start = 0;
        while (start < Poll[room.id].optionList.length) {
            pollOptions += '<button name="send" value="/vote ' + Tools.escapeHTML(Poll[room.id].optionList[start]) + '">' + Tools.escapeHTML(Poll[room.id].optionList[start]) + '</button> ';
            start++;
        }
        Poll[room.id].display = '
' + Tools.escapeHTML(Poll[room.id].question) + '  /vote OPTION
Poll started by ' + user.name + '

    ' + pollOptions;
        room.add('|raw|
' + Poll[room.id].display + '
');
    },

    vote: function(target, room, user) {
        if (!Poll[room.id]) Poll.reset(room.id);
        if (!Poll[room.id].question) return this.sendReply('There is no poll currently going on in this room.');
        if (!this.canTalk()) return;
        if (!target) return this.sendReply('/vote [option] - Vote for an option in the poll.');
        if (Poll[room.id].optionList.indexOf(target.toLowerCase()) === -1) return this.sendReply('\'' + target + '\' is not an option for the current poll.');

        var ips = JSON.stringify(user.ips);
        Poll[room.id].options[ips] = target.toLowerCase();

        return this.sendReply('You are now voting for ' + target + '.');
    },

    pr: 'pollremind',
    pollremind: function(target, room, user) {
        if (!Poll[room.id]) Poll.reset(room.id);
        if (!Poll[room.id].question) return this.sendReply('There is no poll currently going on in this room.');
        if (!this.canBroadcast()) return;
        this.sendReplyBox(Poll[room.id].display);
    },

    votes: function(target, room, user) {
        if (!this.canBroadcast()) return;
        if (!Poll[room.id]) Poll.reset(room.id);
        if (!Poll[room.id].question) return this.sendReply('There is no poll currently going on in this room.');
        this.sendReply('NUMBER OF VOTES: ' + Object.keys(Poll[room.id].options).length);
    },

    endpoll: function(target, room, user) {
        if (!this.can('broadcast', null, room)) return this.sendReply('/endpoll - Access denied.');
        if (!Poll[room.id]) Poll.reset(room.id);
        if (!Poll[room.id].question) return this.sendReply('There is no poll to end in this room.');

        var votes = Object.keys(Poll[room.id].options).length;

        if (votes === 0) {
            Poll.reset(room.id);
            return room.add('|raw|
The poll was canceled because of lack of voters.
');
        }

        var options = {};

        for (var l in Poll[room.id].optionList) {
            options[Poll[room.id].optionList[l]] = 0;
        }

        for (var o in Poll[room.id].options) {
            options[Poll[room.id].options[o]]++;
        }

        var data = [];
        for (var i in options) {
            data.push([i, options[i]]);
        }
        data.sort(function(a, b) {
            return a[1] - b[1];
        });

        var results = '';
        var len = data.length;
        var topOption = data[len - 1][0];
        while (len--) {
            if (data[len][1] > 0) {
                results += '• ' + data[len][0] + ' - ' + Math.floor(data[len][1] / votes * 100) + '% (' + data[len][1] + ')
';
            }
        }
        room.add('|raw|

Results to "' + Poll[room.id].question + '"
Poll ended by ' + user.name + '

' + results + '
');
        Poll.reset(room.id);
        Poll[room.id].topOption = topOption;
    },

    tpoll: 'tierpoll',
    tierspoll: 'tierpoll',
    tierpoll: function(target, room, user) {
        if (!this.can('broadcast', null, room)) return this.sendReply('/tierpoll - Access denied.');
        this.parse('/poll Tournament Tier, abcab ubers, abcab ou, randbats, ou, ubers, uu, ru, nu, pu, lc, customgame, random doubles, doubles, stabmons, almostanyability, challenge cup, cc1v1, 1v1, cc hackmons, hackmons, balanced hackmons, inverse battle, ou mono, tier shift, mediocremons, random triples, random mono, hidden type, inheritance, Anything goes, Triples, random triples, stabmons, gen1random, super staff bros');
    },

    hv: 'helpvotes',
    helpvotes: function(target, room, user) {
        return this.parse('/wall Remember to **vote** even if you don\'t want to battle; that way you\'re still voting for what tier battles you want to watch!');
    },

    strawpoll: function(target, room, user) {
        if (!this.can('strawpoll')) return this.sendReply('/strawpoll - Access denied.');
        if (!target || target.split(',').length < 2) return this.sendReply('/strawpoll [question], [option 1], [option 2]... - Create a strawpoll, declares the link to all rooms and pm all users in the server.');

        var formData = {
            title:  target.split(',')[0],
            options: target.split(',').slice(1).map(function(option) {
                return option.trim();
            })
        };

        var hash;
        request.post({url:'http://strawpoll.me/api/v2/polls', form: formData}, function(err, res, body) {
            hash = body.split(':')[1].slice(0, -1);
            for (var id in Rooms.rooms) {
                if (id !== 'global') {
                    Rooms.rooms[id].addRaw('\

\

' + formData.title + '
\

\
                        http://strawpoll.me/' + hash +
                        '

\

\
                        ');
                    Rooms.rooms[id].update();
                }
            }
            for (var name in Users.users) {
                Users.users[name].send('|pm|~StrawPoll| ' + Users.users[name].userid + '|' + formData.title + ': http://strawpoll.me/' + hash);
            }
        });

        var fiveMinutes = 1000 * 60 * 5;
        setTimeout(function() {
            for (var id in Rooms.rooms) {
                if (id !== 'global') {
                    Rooms.rooms[id].addRaw('\

\

' + formData.title + '\'s Results
\

\
                        http://strawpoll.me/' + hash + '/r\

\

\
                        ');
                    Rooms.rooms[id].update();
                }
            }
            for (var name in Users.users) {
                Users.users[name].send('|pm|~StrawPoll| ' + Users.users[name].userid + '|' + formData.title + '\'s Results: http://strawpoll.me/' + hash + '/r');
            }
        }, fiveMinutes);
    }
};
<commit_msg>Update poll.js<commit_after>var request = require('request');

module.exports = {
    poll: function(target, room, user) {
        if (!this.can('broadcast', null, room)) return this.sendReply('/poll - Access denied.');
        if (!Poll[room.id]) Poll.reset(room.id);
        if (Poll[room.id].question) return this.sendReply('There is currently a poll going on already.');
        if (!this.canTalk()) return;

        var options = Poll.splint(target);
        if (options.length < 3) return this.sendReply('/poll [question], [option 1], [option 2]... - Create a poll where users can vote on an option.');

        var question = options.shift();

        options = options.join(',').toLowerCase().split(',');

        Poll[room.id].question = question;
        Poll[room.id].optionList = options;

        var pollOptions = '';
        var start = 0;
        while (start < Poll[room.id].optionList.length) {
            pollOptions += '<button name="send" value="/vote ' + Tools.escapeHTML(Poll[room.id].optionList[start]) + '">' + Tools.escapeHTML(Poll[room.id].optionList[start]) + '</button> ';
            start++;
        }
        Poll[room.id].display = '
' + Tools.escapeHTML(Poll[room.id].question) + '  /vote OPTION
Poll started by ' + user.name + '

    ' + pollOptions;
        room.add('|raw|
' + Poll[room.id].display + '
');
    },

    vote: function(target, room, user) {
        if (!Poll[room.id]) Poll.reset(room.id);
        if (!Poll[room.id].question) return this.sendReply('There is no poll currently going on in this room.');
        if (!this.canTalk()) return;
        if (!target) return this.sendReply('/vote [option] - Vote for an option in the poll.');
        if (Poll[room.id].optionList.indexOf(target.toLowerCase()) === -1) return this.sendReply('\'' + target + '\' is not an option for the current poll.');

        var ips = JSON.stringify(user.ips);
        Poll[room.id].options[ips] = target.toLowerCase();

        return this.sendReply('You are now voting for ' + target + '.');
    },

    pr: 'pollremind',
    pollremind: function(target, room, user) {
        if (!Poll[room.id]) Poll.reset(room.id);
        if (!Poll[room.id].question) return this.sendReply('There is no poll currently going on in this room.');
        if (!this.canBroadcast()) return;
        this.sendReplyBox(Poll[room.id].display);
    },

    votes: function(target, room, user) {
        if (!this.canBroadcast()) return;
        if (!Poll[room.id]) Poll.reset(room.id);
        if (!Poll[room.id].question) return this.sendReply('There is no poll currently going on in this room.');
        this.sendReply('NUMBER OF VOTES: ' + Object.keys(Poll[room.id].options).length);
    },

    endpoll: function(target, room, user) {
        if (!this.can('broadcast', null, room)) return this.sendReply('/endpoll - Access denied.');
        if (!Poll[room.id]) Poll.reset(room.id);
        if (!Poll[room.id].question) return this.sendReply('There is no poll to end in this room.');

        var votes = Object.keys(Poll[room.id].options).length;

        if (votes === 0) {
            Poll.reset(room.id);
            return room.add('|raw|
The poll was canceled because of lack of voters.
');
        }

        var options = {};

        for (var l in Poll[room.id].optionList) {
            options[Poll[room.id].optionList[l]] = 0;
        }

        for (var o in Poll[room.id].options) {
            options[Poll[room.id].options[o]]++;
        }

        var data = [];
        for (var i in options) {
            data.push([i, options[i]]);
        }
        data.sort(function(a, b) {
            return a[1] - b[1];
        });

        var results = '';
        var len = data.length;
        var topOption = data[len - 1][0];
        while (len--) {
            if (data[len][1] > 0) {
                results += '• ' + data[len][0] + ' - ' + Math.floor(data[len][1] / votes * 100) + '% (' + data[len][1] + ')
';
            }
        }
        room.add('|raw|

Results to "' + Poll[room.id].question + '"
Poll ended by ' + user.name + '

' + results + '
');
        Poll.reset(room.id);
        Poll[room.id].topOption = topOption;
    },

    tpoll: 'tierpoll',
    tierspoll: 'tierpoll',
    tierpoll: function(target, room, user) {
        if (!this.can('broadcast', null, room)) return this.sendReply('/tierpoll - Access denied.');
        this.parse('/poll Tournament Tier, Monotype, Ubers, OU, UU, RU, NU, PU, LC, Random Battles, Random Monotype, Random LC, Gen1 Random, BC1v1, Anything Goes, Super Staff Bros, Tier Shift,');
    },

    hv: 'helpvotes',
    helpvotes: function(target, room, user) {
        return this.parse('/wall Remember to **vote** even if you don\'t want to battle; that way you\'re still voting for what tier battles you want to watch!');
    },

    strawpoll: function(target, room, user) {
        if (!this.can('strawpoll')) return this.sendReply('/strawpoll - Access denied.');
        if (!target || target.split(',').length < 2) return this.sendReply('/strawpoll [question], [option 1], [option 2]... - Create a strawpoll, declares the link to all rooms and pm all users in the server.');

        var formData = {
            title:  target.split(',')[0],
            options: target.split(',').slice(1).map(function(option) {
                return option.trim();
            })
        };

        var hash;
        request.post({url:'http://strawpoll.me/api/v2/polls', form: formData}, function(err, res, body) {
            hash = body.split(':')[1].slice(0, -1);
            for (var id in Rooms.rooms) {
                if (id !== 'global') {
                    Rooms.rooms[id].addRaw('\

\

' + formData.title + '
\

\
                        http://strawpoll.me/' + hash +
                        '

\

\
                        ');
                    Rooms.rooms[id].update();
                }
            }
            for (var name in Users.users) {
                Users.users[name].send('|pm|~StrawPoll| ' + Users.users[name].userid + '|' + formData.title + ': http://strawpoll.me/' + hash);
            }
        });

        var fiveMinutes = 1000 * 60 * 5;
        setTimeout(function() {
            for (var id in Rooms.rooms) {
                if (id !== 'global') {
                    Rooms.rooms[id].addRaw('\

\

' + formData.title + '\'s Results
\

\
                        http://strawpoll.me/' + hash + '/r\

\

\
                        ');
                    Rooms.rooms[id].update();
                }
            }
            for (var name in Users.users) {
                Users.users[name].send('|pm|~StrawPoll| ' + Users.users[name].userid + '|' + formData.title + '\'s Results: http://strawpoll.me/' + hash + '/r');
            }
        }, fiveMinutes);
    }
};
<|endoftext|>


<commit_before>var redis = require('./redis');
var queue = require('./queue');
var utility = require('./utility');
var config = require('./config');
var getReplayUrl = require('./getReplayUrl');
var db = require('./db');
var insertMatch = require('./queries').insertMatch;
var buildSets = require('./buildSets');
var bodyParser = require('body-parser');
var express = require('express');
var moment = require('moment');
var app = express();
var port = config.PORT || config.WORK_PORT;
var active_jobs = {};
var pooled_jobs = {};
var startedAt = moment();
var counts = {};
var schema = utility.getParseSchema();
/*
var memwatch = require('memwatch-next');
var hd = new memwatch.HeapDiff();
memwatch.on('leak', function(info) {
    console.error(info);
});
memwatch.on('stats', function(stats) {
    var diff = hd.end();
    console.log(JSON.stringify(diff));
    hd = new memwatch.HeapDiff();
    console.log(stats);
});
*/
buildSets(db, redis, function(err) {
    if (err) {
        throw err;
    }
    var pool_size = 500;
    queue.parse.process(pool_size, function(job, cb) {
        //save the callback for this job
        job.cb = cb;
        var match = job.data.payload;
        //get the replay url and save it to db
        return getReplayUrl(db, redis, match, function(err) {
            if (err) {
                return cb(err);
            }
            //put it in the pool
            pooled_jobs[job.jobId] = job;
            console.log('loaded job %s into pool, %s jobs in pool, %s jobs active', job.jobId, Object.keys(pooled_jobs).length, Object.keys(active_jobs).length);
        });
    });
    start();
});

function start() {
    app.use(bodyParser.json({
        limit: '1mb'
    }));
    app.get("/", function(req, res) {
        res.json({
            started_at: startedAt.format(),
            started_ago: startedAt.fromNow()
        });
    });
    app.get('/parse', function(req, res) {
        if (config.RETRIEVER_SECRET && req.query.key !== config.RETRIEVER_SECRET) {
            return res.status(500).json({
                error: "invalid key"
            });
        }
        var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
        console.log('client %s requested work', ip);
        var job = pooled_jobs[Object.keys(pooled_jobs)[0]];
        if (!job) {
            console.log('no work available');
            return res.status(500).json({
                error: "no work available"
            });
        }
        delete pooled_jobs[job.jobId];
        active_jobs[job.jobId] = job;
        job.submitWork = function(parsed_data) {
            if (parsed_data.error) {
                return job.exit(parsed_data.error);
            }
            var match = job.data.payload;
            var hostname = parsed_data.hostname;
            /*
            //track replays parsed by each node
            if (!counts[hostname]) {
                counts[hostname] = 0;
            }
            counts[hostname] += 1;
            console.log(JSON.stringify(counts));
            */
            redis.zadd("parser:" + hostname, moment().format('X'), match.match_id);
            delete parsed_data.key;
            delete parsed_data.jobId;
            delete parsed_data.hostname;
            //extend match object with parsed data, keep existing data if key conflict (match_id)
            //match.players was deleted earlier during insertion of api data
            for (var key in parsed_data) {
                match[key] = match[key] || parsed_data[key];
            }
            match.parse_status = 2;
            return insertMatch(db, redis, queue, match, {
                type: "parsed"
            }, job.exit);
        };
        job.expire = setTimeout(function() {
            console.log('job %s expired', job.jobId);
            return job.exit("timeout");
        }, 180 * 1000);
        job.exit = function(err) {
            delete active_jobs[job.jobId];
            clearTimeout(job.expire);
            job.cb(err);
            job = null;
        };
        console.log('server sent jobid %s', job.jobId);
        return res.json({
            jobId: job.jobId,
            data: job.data
        });
    });
    app.post('/parse', function(req, res) {
        //validate request
        if (config.RETRIEVER_SECRET && req.body.key !== config.RETRIEVER_SECRET) {
            return res.status(500).json({
                error: "invalid key"
            });
        }
        if (req.body.version !== schema.version) {
            return res.status(500).json({
                error: "version mismatch"
            });
        }
        console.log('received submitted work');
        if (active_jobs[req.body.jobId]) {
            var job = active_jobs[req.body.jobId];
            job.submitWork(req.body);
            job = null;
            return res.json({
                error: null
            });
        }
        else {
            return res.status(500).json({
                error: "no active job with this jobid"
            });
        }
    });
    var server = app.listen(port, function() {
        var host = server.address().address;
        console.log('[WORKSERVER] listening at http://%s:%s', host, port);
    });
}
<commit_msg>remove null<commit_after>var redis = require('./redis');
var queue = require('./queue');
var utility = require('./utility');
var config = require('./config');
var getReplayUrl = require('./getReplayUrl');
var db = require('./db');
var insertMatch = require('./queries').insertMatch;
var buildSets = require('./buildSets');
var bodyParser = require('body-parser');
var express = require('express');
var moment = require('moment');
var app = express();
var port = config.PORT || config.WORK_PORT;
var active_jobs = {};
var pooled_jobs = {};
var startedAt = moment();
var counts = {};
var schema = utility.getParseSchema();
/*
var memwatch = require('memwatch-next');
var hd = new memwatch.HeapDiff();
memwatch.on('leak', function(info) {
    console.error(info);
});
memwatch.on('stats', function(stats) {
    var diff = hd.end();
    console.log(JSON.stringify(diff));
    hd = new memwatch.HeapDiff();
    console.log(stats);
});
*/
buildSets(db, redis, function(err) {
    if (err) {
        throw err;
    }
    var pool_size = 500;
    queue.parse.process(pool_size, function(job, cb) {
        //save the callback for this job
        job.cb = cb;
        var match = job.data.payload;
        //get the replay url and save it to db
        return getReplayUrl(db, redis, match, function(err) {
            if (err) {
                return cb(err);
            }
            //put it in the pool
            pooled_jobs[job.jobId] = job;
            console.log('loaded job %s into pool, %s jobs in pool, %s jobs active', job.jobId, Object.keys(pooled_jobs).length, Object.keys(active_jobs).length);
        });
    });
    start();
});

function start() {
    app.use(bodyParser.json({
        limit: '1mb'
    }));
    app.get("/", function(req, res) {
        res.json({
            started_at: startedAt.format(),
            started_ago: startedAt.fromNow()
        });
    });
    app.get('/parse', function(req, res) {
        if (config.RETRIEVER_SECRET && req.query.key !== config.RETRIEVER_SECRET) {
            return res.status(500).json({
                error: "invalid key"
            });
        }
        var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
        console.log('client %s requested work', ip);
        var job = pooled_jobs[Object.keys(pooled_jobs)[0]];
        if (!job) {
            console.log('no work available');
            return res.status(500).json({
                error: "no work available"
            });
        }
        delete pooled_jobs[job.jobId];
        active_jobs[job.jobId] = job;
        job.submitWork = function(parsed_data) {
            if (parsed_data.error) {
                return job.exit(parsed_data.error);
            }
            var match = job.data.payload;
            var hostname = parsed_data.hostname;
            /*
            //track replays parsed by each node
            if (!counts[hostname]) {
                counts[hostname] = 0;
            }
            counts[hostname] += 1;
            console.log(JSON.stringify(counts));
            */
            redis.zadd("parser:" + hostname, moment().format('X'), match.match_id);
            delete parsed_data.key;
            delete parsed_data.jobId;
            delete parsed_data.hostname;
            //extend match object with parsed data, keep existing data if key conflict (match_id)
            //match.players was deleted earlier during insertion of api data
            for (var key in parsed_data) {
                match[key] = match[key] || parsed_data[key];
            }
            match.parse_status = 2;
            return insertMatch(db, redis, queue, match, {
                type: "parsed"
            }, job.exit);
        };
        job.expire = setTimeout(function() {
            console.log('job %s expired', job.jobId);
            return job.exit("timeout");
        }, 180 * 1000);
        job.exit = function(err) {
            delete active_jobs[job.jobId];
            clearTimeout(job.expire);
            job.cb(err);
        };
        console.log('server sent jobid %s', job.jobId);
        return res.json({
            jobId: job.jobId,
            data: job.data
        });
    });
    app.post('/parse', function(req, res) {
        //validate request
        if (config.RETRIEVER_SECRET && req.body.key !== config.RETRIEVER_SECRET) {
            return res.status(500).json({
                error: "invalid key"
            });
        }
        if (req.body.version !== schema.version) {
            return res.status(500).json({
                error: "version mismatch"
            });
        }
        console.log('received submitted work');
        if (active_jobs[req.body.jobId]) {
            var job = active_jobs[req.body.jobId];
            job.submitWork(req.body);
            return res.json({
                error: null
            });
        }
        else {
            return res.status(500).json({
                error: "no active job with this jobid"
            });
        }
    });
    var server = app.listen(port, function() {
        var host = server.address().address;
        console.log('[WORKSERVER] listening at http://%s:%s', host, port);
    });
}
<|endoftext|>


<commit_before>'use strict';

const got = require('got');
const path = require('path');
const moment = require('moment');
const pad = require('lodash.padstart');
const _ = require('lodash');
const AWS = require('aws-sdk')
const local = require('kes/src/local');
const metadata = require('../../lib/metadata');
var through2 = require('through2')

const bands = [
  'ANG.txt',
  'B1.TIF',
  'B2.TIF',
  'B3.TIF',
  'B4.TIF',
  'B5.TIF',
  'B6.TIF',
  'B7.TIF',
  'B8.TIF',
  'B9.TIF',
  'B10.TIF',
  'B11.TIF',
  'BQA.TIF',
  'MTL.txt'
];

const s3 = new AWS.S3()

function googleLinks(data) {
  const row = pad(data.row, 3, '0');
  const _path = pad(data.path, 3, '0');
  //const sceneId = data.sceneID;
  const productId = data.LANDSAT_PRODUCT_ID;

  const c1Console = `https://console.cloud.google.com/storage/browser/gcp-public-data-landsat/LC08/01/${path.join(_path, row, productId)}`;
  const c1Base = `https://storage.googleapis.com/gcp-public-data-landsat/LC08/01/${path.join(_path, row, productId)}`;

  const c1Files = bands.map((b) => `${c1Base}/${productId}_${b}`);

  const c1 = {
    index: c1Console,
    files: c1Files
  };

  return { c1 };
}

//! Check to see if a URL exists
function fileExists(url) {
  var params = {
    Bucket: 'landsat-pds',
    Key: url.slice(36)
  }
  return new Promise(function(resolve, reject) {
    s3.headObject(params, function (err, metadata) {
      if (err && err.code === 'NotFound') {
        reject(url)
      } else {
        resolve(url)
      }
    })
  })
  /*return new Promise(function(resolve, reject) {
    got(url).then(response => {
      resolve(url);
    }).catch(e => {
      reject(url);
    });
  });*/
}

//! iterate over an array synchronously, invoke function on each element
function arrayIterate(values, fn) {
  return new Promise(function(resolve, reject) {
    // Are there any values to check?
    if (values.length === 0) {
      // All were rejected
      reject();
    }
    // Try the first value
    fn(values[0]).then(function(val) {
      // Resolved, we're all done
      resolve(val);
    }).catch(function() {
      // Rejected, remove the first item from the array and recursively
      // try the next one
      values.shift();
      arrayIterate(values, fn).then(resolve).catch(reject);
    });
  });
}

function awsLinks(data) {
  const row = pad(data.row, 3, '0');
  const _path = pad(data.path, 3, '0');
  const sceneId = data.sceneID;
  const productId = data.LANDSAT_PRODUCT_ID;

  const c1Base = `https://landsat-pds.s3.amazonaws.com/c1/L8/${path.join(_path, row, productId)}`;
  const c1Files = bands.map((b) => `${c1Base}/${productId}_${b}`);

  const c1 = {
    index: `${c1Base}/index.html`,
    files: c1Files,
    thumbnail: `${c1Base}/${productId}_thumb_large.jpg`
  };

  return new Promise(function(resolve, reject) {
    // AWS doesn't include all C1 scenes, we return the old urls for
    // any scenes that is before May 1 2017
    info = {};
    if (moment(data.acquisitionDate) > moment('2017-04-30')) {
      resolve(c1)
    } else {
      const _sceneId = sceneId.slice(0, -2);
      var sid;
      const rev = sceneId.slice(-2)
      var prefix = `http://landsat-pds.s3.amazonaws.com/L8/${path.join(_path, row, _sceneId)}`;
      var links = _.range(rev, -1, -1).map(r => `${prefix}` + pad(r, 2, '0') + '/index.html');

      arrayIterate(links.reverse(), fileExists).then(val => {
        prefix = prefix + val.slice(-13, -11)
        sid = _sceneId + val.slice(-13, -11)
        const pre = {
          index: `${prefix}/index.html`,
          files: bands.map((b) => `${prefix}/${sid}_${b}`),
          thumbnail: `${prefix}/${sid}_thumb_large.jpg`
        };
        resolve(pre);
      }).catch(e => {
        reject(`${prefix} not available`);
      });
    }
  });
}

function transform(data, encoding, next) {
  const numberFields = [
    'cloudCoverFull',
    'path',
    'row',
    'upperLeftCornerLatitude',
    'upperLeftCornerLongitude',
    'upperRightCornerLatitude',
    'upperRightCornerLongitude',
    'lowerLeftCornerLatitude',
    'lowerLeftCornerLongitude',
    'lowerRightCornerLatitude',
    'lowerRightCornerLongitude',
    'sceneCenterLatitude',
    'sceneCenterLongitude',
    'cloudCover',
    'sunElevation',
    'sunAzimuth',
    'receivingStation',
    'imageQuality1',
    //'ROLL_ANGLE',
    //'GEOMETRIC_RMSE_MODEL',
    //'GEOMETRIC_RMSE_MODEL_X',
    //'GEOMETRIC_RMSE_MODEL_Y',
    //'COLLECTION_NUMBER',
    //'CLOUD_COVER_LAND'
  ];

  numberFields.forEach(f => {
    data[f] = parseFloat(data[f]);
  });

  const data_geometry = { // eslint-disable-line camelcase
    type: 'Polygon',
    crs: {
      type: 'name',
      properties: {
        name: 'urn:ogc:def:crs:EPSG:8.9:4326'
      }
    },
    coordinates: [[
      [data.upperRightCornerLongitude, data.upperRightCornerLatitude],
      [data.upperLeftCornerLongitude, data.upperLeftCornerLatitude],
      [data.lowerLeftCornerLongitude, data.lowerLeftCornerLatitude],
      [data.lowerRightCornerLongitude, data.lowerRightCornerLatitude],
      [data.upperRightCornerLongitude, data.upperRightCornerLatitude]
    ]]
  };

  const leftLong = Math.min(data.lowerLeftCornerLongitude, data.upperLeftCornerLongitude)
  const rightLong = Math.max(data.lowerRightCornerLongitude, data.upperRightCornerLongitude)
  if (leftLong > rightLong) {
    console.log(`warning: skipping ${data.sceneID} for crossing 180th Meridian (${JSON.stringify(data_geometry)})`)
    next()
  } else {
    const google = googleLinks(data);

    const customFields = {
      scene_id: data.sceneID,
      product_id: data.LANDSAT_PRODUCT_ID,
      satellite_name: 'landsat-8',
      cloud_coverage: data.cloudCoverFull,
      date: data.acquisitionDate,
      thumbnail: data.browseURL,
      data_geometry,
      download_links: {
        usgs: `https://earthexplorer.usgs.gov/download/12864/${data.sceneID}/STANDARD/EE`,
        aws_s3: [],
        google: google.c1.files
      },
      aws_thumbnail: null,
      aws_index: null,
      google_index: google.c1.index,
    };

    delete data.cloudCoverFull

    awsLinks(data).then((info) => {
      //console.log('awslinks', info)
      customFields.download_links.aws_s3 = info.files
      customFields.aws_thumbnail = info.thumbnail
      customFields.aws_index = info.index
      record = Object.assign({}, customFields, data)
      this.push(record)
      next()
    }).catch(e => {
      console.log(`error processing ${customFields.scene_id}: ${e}`)
      next()
    })
  }

  //if (thumbnailUrl) {
  //customFields.thumbnail = url.resolve(thumbnailUrl, `${data.LANDSAT_PRODUCT_ID}.jpg`);
  //}
}

function handler (event, context, cb) {
  var _transform = through2({'objectMode': true, 'consume': true}, transform)
  console.log('Landsat handler:', event)
  metadata.update(event, _transform, cb)
}

local.localRun(() => {
  const a = {
    bucket: 'sat-api',
    key: 'testing',
    satellite: 'landsat',
    currentFileNum: 293222212,
    lastFileNum: 293222212
  };
  console.log('running locally')

  handler(a, null, (e, r) => {});
});

module.exports.handler = handler;
<commit_msg>remove crs from geom<commit_after>'use strict';

const got = require('got');
const path = require('path');
const moment = require('moment');
const pad = require('lodash.padstart');
const _ = require('lodash');
const AWS = require('aws-sdk')
const local = require('kes/src/local');
const metadata = require('../../lib/metadata');
var through2 = require('through2')

const bands = [
  'ANG.txt',
  'B1.TIF',
  'B2.TIF',
  'B3.TIF',
  'B4.TIF',
  'B5.TIF',
  'B6.TIF',
  'B7.TIF',
  'B8.TIF',
  'B9.TIF',
  'B10.TIF',
  'B11.TIF',
  'BQA.TIF',
  'MTL.txt'
];

const s3 = new AWS.S3()

function googleLinks(data) {
  const row = pad(data.row, 3, '0');
  const _path = pad(data.path, 3, '0');
  //const sceneId = data.sceneID;
  const productId = data.LANDSAT_PRODUCT_ID;

  const c1Console = `https://console.cloud.google.com/storage/browser/gcp-public-data-landsat/LC08/01/${path.join(_path, row, productId)}`;
  const c1Base = `https://storage.googleapis.com/gcp-public-data-landsat/LC08/01/${path.join(_path, row, productId)}`;

  const c1Files = bands.map((b) => `${c1Base}/${productId}_${b}`);

  const c1 = {
    index: c1Console,
    files: c1Files
  };

  return { c1 };
}

//! Check to see if a URL exists
function fileExists(url) {
  var params = {
    Bucket: 'landsat-pds',
    Key: url.slice(36)
  }
  return new Promise(function(resolve, reject) {
    s3.headObject(params, function (err, metadata) {
      if (err && err.code === 'NotFound') {
        reject(url)
      } else {
        resolve(url)
      }
    })
  })
  /*return new Promise(function(resolve, reject) {
    got(url).then(response => {
      resolve(url);
    }).catch(e => {
      reject(url);
    });
  });*/
}

//! iterate over an array synchronously, invoke function on each element
function arrayIterate(values, fn) {
  return new Promise(function(resolve, reject) {
    // Are there any values to check?
    if (values.length === 0) {
      // All were rejected
      reject();
    }
    // Try the first value
    fn(values[0]).then(function(val) {
      // Resolved, we're all done
      resolve(val);
    }).catch(function() {
      // Rejected, remove the first item from the array and recursively
      // try the next one
      values.shift();
      arrayIterate(values, fn).then(resolve).catch(reject);
    });
  });
}

function awsLinks(data) {
  const row = pad(data.row, 3, '0');
  const _path = pad(data.path, 3, '0');
  const sceneId = data.sceneID;
  const productId = data.LANDSAT_PRODUCT_ID;

  const c1Base = `https://landsat-pds.s3.amazonaws.com/c1/L8/${path.join(_path, row, productId)}`;
  const c1Files = bands.map((b) => `${c1Base}/${productId}_${b}`);

  const c1 = {
    index: `${c1Base}/index.html`,
    files: c1Files,
    thumbnail: `${c1Base}/${productId}_thumb_large.jpg`
  };

  return new Promise(function(resolve, reject) {
    // AWS doesn't include all C1 scenes, we return the old urls for
    // any scenes that is before May 1 2017
    info = {};
    if (moment(data.acquisitionDate) > moment('2017-04-30')) {
      resolve(c1)
    } else {
      const _sceneId = sceneId.slice(0, -2);
      var sid;
      const rev = sceneId.slice(-2)
      var prefix = `http://landsat-pds.s3.amazonaws.com/L8/${path.join(_path, row, _sceneId)}`;
      var links = _.range(rev, -1, -1).map(r => `${prefix}` + pad(r, 2, '0') + '/index.html');

      arrayIterate(links.reverse(), fileExists).then(val => {
        prefix = prefix + val.slice(-13, -11)
        sid = _sceneId + val.slice(-13, -11)
        const pre = {
          index: `${prefix}/index.html`,
          files: bands.map((b) => `${prefix}/${sid}_${b}`),
          thumbnail: `${prefix}/${sid}_thumb_large.jpg`
        };
        resolve(pre);
      }).catch(e => {
        reject(`${prefix} not available`);
      });
    }
  });
}

function transform(data, encoding, next) {
  const numberFields = [
    'cloudCoverFull',
    'path',
    'row',
    'upperLeftCornerLatitude',
    'upperLeftCornerLongitude',
    'upperRightCornerLatitude',
    'upperRightCornerLongitude',
    'lowerLeftCornerLatitude',
    'lowerLeftCornerLongitude',
    'lowerRightCornerLatitude',
    'lowerRightCornerLongitude',
    'sceneCenterLatitude',
    'sceneCenterLongitude',
    'cloudCover',
    'sunElevation',
    'sunAzimuth',
    'receivingStation',
    'imageQuality1',
    //'ROLL_ANGLE',
    //'GEOMETRIC_RMSE_MODEL',
    //'GEOMETRIC_RMSE_MODEL_X',
    //'GEOMETRIC_RMSE_MODEL_Y',
    //'COLLECTION_NUMBER',
    //'CLOUD_COVER_LAND'
  ];

  numberFields.forEach(f => {
    data[f] = parseFloat(data[f]);
  });

  const data_geometry = { // eslint-disable-line camelcase
    type: 'Polygon',
    coordinates: [[
      [data.upperRightCornerLongitude, data.upperRightCornerLatitude],
      [data.upperLeftCornerLongitude, data.upperLeftCornerLatitude],
      [data.lowerLeftCornerLongitude, data.lowerLeftCornerLatitude],
      [data.lowerRightCornerLongitude, data.lowerRightCornerLatitude],
      [data.upperRightCornerLongitude, data.upperRightCornerLatitude]
    ]]
  };

  const leftLong = Math.min(data.lowerLeftCornerLongitude, data.upperLeftCornerLongitude)
  const rightLong = Math.max(data.lowerRightCornerLongitude, data.upperRightCornerLongitude)
  if (leftLong > rightLong) {
    console.log(`warning: skipping ${data.sceneID} for crossing 180th Meridian (${JSON.stringify(data_geometry)})`)
    next()
  } else {
    const google = googleLinks(data);

    const customFields = {
      scene_id: data.sceneID,
      product_id: data.LANDSAT_PRODUCT_ID,
      satellite_name: 'landsat-8',
      cloud_coverage: data.cloudCoverFull,
      date: data.acquisitionDate,
      thumbnail: data.browseURL,
      data_geometry,
      download_links: {
        usgs: `https://earthexplorer.usgs.gov/download/12864/${data.sceneID}/STANDARD/EE`,
        aws_s3: [],
        google: google.c1.files
      },
      aws_thumbnail: null,
      aws_index: null,
      google_index: google.c1.index,
    };

    delete data.cloudCoverFull

    awsLinks(data).then((info) => {
      //console.log('awslinks', info)
      customFields.download_links.aws_s3 = info.files
      customFields.aws_thumbnail = info.thumbnail
      customFields.aws_index = info.index
      record = Object.assign({}, customFields, data)
      this.push(record)
      next()
    }).catch(e => {
      console.log(`error processing ${customFields.scene_id}: ${e}`)
      next()
    })
  }

  //if (thumbnailUrl) {
  //customFields.thumbnail = url.resolve(thumbnailUrl, `${data.LANDSAT_PRODUCT_ID}.jpg`);
  //}
}

function handler (event, context, cb) {
  var _transform = through2({'objectMode': true, 'consume': true}, transform)
  console.log('Landsat handler:', event)
  metadata.update(event, _transform, cb)
}

local.localRun(() => {
  const a = {
    bucket: 'sat-api',
    key: 'testing',
    satellite: 'landsat',
    currentFileNum: 293222212,
    lastFileNum: 293222212
  };
  console.log('running locally')

  handler(a, null, (e, r) => {});
});

module.exports.handler = handler;
<|endoftext|>


<commit_before>/**
 * Visual Blocks Language
 *
 * Copyright 2012 Google Inc.
 * http://code.google.com/p/blockly/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview Logic blocks for Blockly.
 * @author fraser@google.com (Neil Fraser)
 */

if (!Blockly.Language) Blockly.Language = {};

Blockly.Language.logic_compare = {
  // Comparison operator.
  category: Blockly.LANG_CATEGORY_LOGIC,
  helpUrl: Blockly.LANG_LOGIC_COMPARE_HELPURL,
  init: function() {
    this.setColour(120);
    this.setOutput(true, Boolean);
    this.appendInput('', Blockly.INPUT_VALUE, 'A', null);
    var dropdown = new Blockly.FieldDropdown(this.OPERATORS);
    this.appendInput([dropdown, 'OP'], Blockly.INPUT_VALUE, 'B', null);
    this.setInputsInline(true);
    // Assign 'this' to a variable for use in the tooltip closure below.
    var thisBlock = this;
    this.setTooltip(function() {
      var op = thisBlock.getTitleValue('OP');
      return Blockly.Language.logic_compare.TOOLTIPS[op];
    });
  }
};

Blockly.Language.logic_compare.OPERATORS =
    [['=', 'EQ'],
     ['\u2260', 'NEQ'],
     ['<', 'LT'],
     ['\u2264', 'LTE'],
     ['>', 'GT'],
     ['\u2265', 'GTE']];

Blockly.Language.logic_compare.TOOLTIPS = {
  EQ: Blockly.LANG_LOGIC_COMPARE_TOOLTIP_EQ,
  NEQ: Blockly.LANG_LOGIC_COMPARE_TOOLTIP_NEQ,
  LT: Blockly.LANG_LOGIC_COMPARE_TOOLTIP_LT,
  LTE: Blockly.LANG_LOGIC_COMPARE_TOOLTIP_LTE,
  GT: Blockly.LANG_LOGIC_COMPARE_TOOLTIP_GT,
  GTE: Blockly.LANG_LOGIC_COMPARE_TOOLTIP_GTE
};

Blockly.Language.logic_operation = {
  // Logical operations: 'and', 'or'.
  category: Blockly.LANG_CATEGORY_LOGIC,
  helpUrl: Blockly.LANG_LOGIC_OPERATION_HELPURL,
  init: function() {
    this.setColour(120);
    this.setOutput(true, Boolean);
    this.appendInput('', Blockly.INPUT_VALUE, 'A', Boolean);
    var dropdown = new Blockly.FieldDropdown(this.OPERATORS);
    this.appendInput([dropdown, 'OP'], Blockly.INPUT_VALUE, 'B', Boolean);
    this.setInputsInline(true);
    // Assign 'this' to a variable for use in the tooltip closure below.
    var thisBlock = this;
    this.setTooltip(function() {
      var op = thisBlock.getTitleValue('OP');
      return Blockly.Language.logic_operation.TOOLTIPS[op];
    });
  }
};

Blockly.Language.logic_operation.OPERATORS =
    [[Blockly.LANG_LOGIC_OPERATION_AND, 'AND'],
     [Blockly.LANG_LOGIC_OPERATION_OR, 'OR']];

Blockly.Language.logic_operation.TOOLTIPS = {
  AND: Blockly.LANG_LOGIC_OPERATION_TOOLTIP_AND,
  OR: Blockly.LANG_LOGIC_OPERATION_TOOLTIP_OR
};

Blockly.Language.logic_negate = {
  // Negation.
  category: Blockly.LANG_CATEGORY_LOGIC,
  helpUrl: Blockly.LANG_LOGIC_NEGATE_HELPURL,
  init: function() {
    this.setColour(120);
    this.setOutput(true, Boolean);
    this.appendInput(Blockly.LANG_LOGIC_NEGATE_INPUT_NOT,
        Blockly.INPUT_VALUE, 'BOOL', Boolean);
    this.setTooltip(Blockly.LANG_LOGIC_NEGATE_TOOLTIP_1);
  }
};

Blockly.Language.logic_boolean = {
  // Boolean data type: true and false.
  category: Blockly.LANG_CATEGORY_LOGIC,
  helpUrl: Blockly.LANG_LOGIC_BOOLEAN_HELPURL,
  init: function() {
    this.setColour(120);
    this.setOutput(true, Boolean);
    var dropdown = new Blockly.FieldDropdown(this.OPERATORS);
    this.appendTitle(dropdown, 'BOOL');
    this.setTooltip(Blockly.LANG_LOGIC_BOOLEAN_TOOLTIP_1);
  }
};

Blockly.Language.logic_boolean.OPERATORS =
    [[Blockly.LANG_LOGIC_BOOLEAN_TRUE, 'TRUE'],
     [Blockly.LANG_LOGIC_BOOLEAN_FALSE, 'FALSE']];
<commit_msg>simply removed some blank lines<commit_after>/**
 * Visual Blocks Language
 *
 * Copyright 2012 Google Inc.
 * http://code.google.com/p/blockly/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview Logic blocks for Blockly.
 * @author fraser@google.com (Neil Fraser)
 */

if (!Blockly.Language) Blockly.Language = {};

Blockly.Language.logic_compare = {
  // Comparison operator.
  category: Blockly.LANG_CATEGORY_LOGIC,
  helpUrl: Blockly.LANG_LOGIC_COMPARE_HELPURL,
  init: function() {
    this.setColour(120);
    this.setOutput(true, Boolean);
    this.appendInput('', Blockly.INPUT_VALUE, 'A', null);
    var dropdown = new Blockly.FieldDropdown(this.OPERATORS);
    this.appendInput([dropdown, 'OP'], Blockly.INPUT_VALUE, 'B', null);
    this.setInputsInline(true);
    // Assign 'this' to a variable for use in the tooltip closure below.
    var thisBlock = this;
    this.setTooltip(function() {
      var op = thisBlock.getTitleValue('OP');
      return Blockly.Language.logic_compare.TOOLTIPS[op];
    });
  }
};

Blockly.Language.logic_compare.OPERATORS =
    [['=', 'EQ'],
     ['\u2260', 'NEQ'],
     ['<', 'LT'],
     ['\u2264', 'LTE'],
     ['>', 'GT'],
     ['\u2265', 'GTE']];

Blockly.Language.logic_compare.TOOLTIPS = {
  EQ: Blockly.LANG_LOGIC_COMPARE_TOOLTIP_EQ,
  NEQ: Blockly.LANG_LOGIC_COMPARE_TOOLTIP_NEQ,
  LT: Blockly.LANG_LOGIC_COMPARE_TOOLTIP_LT,
  LTE: Blockly.LANG_LOGIC_COMPARE_TOOLTIP_LTE,
  GT: Blockly.LANG_LOGIC_COMPARE_TOOLTIP_GT,
  GTE: Blockly.LANG_LOGIC_COMPARE_TOOLTIP_GTE
};

Blockly.Language.logic_operation = {
  // Logical operations: 'and', 'or'.
  category: Blockly.LANG_CATEGORY_LOGIC,
  helpUrl: Blockly.LANG_LOGIC_OPERATION_HELPURL,
  init: function() {
    this.setColour(120);
    this.setOutput(true, Boolean);
    this.appendInput('', Blockly.INPUT_VALUE, 'A', Boolean);
    var dropdown = new Blockly.FieldDropdown(this.OPERATORS);
    this.appendInput([dropdown, 'OP'], Blockly.INPUT_VALUE, 'B', Boolean);
    this.setInputsInline(true);
    // Assign 'this' to a variable for use in the tooltip closure below.
    var thisBlock = this;
    this.setTooltip(function() {
      var op = thisBlock.getTitleValue('OP');
      return Blockly.Language.logic_operation.TOOLTIPS[op];
    });
  }
};

Blockly.Language.logic_operation.OPERATORS =
    [[Blockly.LANG_LOGIC_OPERATION_AND, 'AND'],
     [Blockly.LANG_LOGIC_OPERATION_OR, 'OR']];

Blockly.Language.logic_operation.TOOLTIPS = {
  AND: Blockly.LANG_LOGIC_OPERATION_TOOLTIP_AND,
  OR: Blockly.LANG_LOGIC_OPERATION_TOOLTIP_OR
};

Blockly.Language.logic_negate = {
  // Negation.
  category: Blockly.LANG_CATEGORY_LOGIC,
  helpUrl: Blockly.LANG_LOGIC_NEGATE_HELPURL,
  init: function() {
    this.setColour(120);
    this.setOutput(true, Boolean);
    this.appendInput(Blockly.LANG_LOGIC_NEGATE_INPUT_NOT,
        Blockly.INPUT_VALUE, 'BOOL', Boolean);
    this.setTooltip(Blockly.LANG_LOGIC_NEGATE_TOOLTIP_1);
  }
};

Blockly.Language.logic_boolean = {
  // Boolean data type: true and false.
  category: Blockly.LANG_CATEGORY_LOGIC,
  helpUrl: Blockly.LANG_LOGIC_BOOLEAN_HELPURL,
  init: function() {
    this.setColour(120);
    this.setOutput(true, Boolean);
    var dropdown = new Blockly.FieldDropdown(this.OPERATORS);
    this.appendTitle(dropdown, 'BOOL');
    this.setTooltip(Blockly.LANG_LOGIC_BOOLEAN_TOOLTIP_1);
  }
};

Blockly.Language.logic_boolean.OPERATORS =
    [[Blockly.LANG_LOGIC_BOOLEAN_TRUE, 'TRUE'],
     [Blockly.LANG_LOGIC_BOOLEAN_FALSE, 'FALSE']];
<|endoftext|>