<commit_before>/**
 * Copyright 2015-2016, Google, Inc.
 * 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.
 */

'use strict';

const express = require('express');
const pwaLib = require('../lib/pwa');
const Pwa = require('../models/pwa');
const router = express.Router(); // eslint-disable-line new-cap
const config = require('../config/config');
const CLIENT_ID = config.get('CLIENT_ID');
const CLIENT_SECRET = config.get('CLIENT_SECRET');
const LIST_PAGE_SIZE = 12;
const DEFAULT_PAGE_NUMBER = 1;
const DEFAULT_SORT_ORDER = 'newest';

/**
 * GET /pwas/add
 *
 * Display a page of PWAs (up to ten at a time).
 */
router.get('/', (req, res, next) => {
  const pageNumber = parseInt(req.query.page, 10) || DEFAULT_PAGE_NUMBER;
  const sortOrder = req.query.sort || DEFAULT_SORT_ORDER;
  const start = (pageNumber - 1) * LIST_PAGE_SIZE;

  pwaLib.list(start, LIST_PAGE_SIZE, sortOrder)
    .then(result => {
      res.render('pwas/list.hbs', {
        pwas: result.pwas,
        hasNextPage: result.hasMore,
        hasPreviousPage: pageNumber > 1,
        nextPageNumber: pageNumber + 1,
        previousPageNumber: pageNumber - 1,
        currentPageNumber: pageNumber,
        sortOrder: sortOrder,
        showNewest: sortOrder !== 'newest',
        showScore: sortOrder !== 'score'
      });
    })
    .catch(err => {
      next(err);
    });
});

/**
 * GET /pwas/add
 *
 * Display a form for creating a PWA.
 */
router.get('/add', (req, res) => {
  res.render('pwas/form.hbs', {
    pwa: {},
    action: 'Add'
  });
});

/**
 * POST /pwas/add
 *
 * Create a PWA.
 */
router.post('/add', (req, res, next) => {
  const manifestUrl = req.body.manifestUrl;
  const idToken = req.body.idToken;
  let pwa = new Pwa(manifestUrl);

  if (!manifestUrl) {
    res.render('pwas/form.hbs', {
      pwa,
      error: 'no manifest provided'
    });
    return;
  }

  if (!idToken) {
    res.render('pwas/form.hbs', {
      pwa,
      error: 'user not logged in'
    });
    return;
  }

  verifyIdToken(CLIENT_ID, CLIENT_SECRET, idToken)
    .then(user => {
      pwa.setUserId(user);
      return pwaLib.save(pwa);
    })
    .then(savedData => {
      res.redirect(req.baseUrl + '/' + savedData.id);
      return;
    })
    .catch(err => {
      if (typeof err === 'number') {
        switch (err) {
          case pwaLib.E_MANIFEST_INVALID_URL:
            err = `pwa.manifestUrl [${pwa.manifestUrl}] is not a valid URL`;
            break;
          case pwaLib.E_MISING_USER_INFORMATION:
            err = 'Missing user information';
            break;
          case pwaLib.E_MANIFEST_URL_MISSING:
            err = 'Missing manifestUrl';
            break;
          case pwaLib.E_NOT_A_PWA:
            err = 'pwa is not an instance of Pwa';
            break;
          default:
            return next(err);
        }
      }
      // Transform err from an array of strings (in a particular format) to a
      // comma-separated string.
      if (Array.isArray(err)) {
        const s = err.map(e => {
          const m = e.match(/^ERROR:\s+(.*)\.$/);
          return m ? m[1] : e; // if no match (format changed?), just return the string
        }).join(', ');
        err = s;
      }
      res.render('pwas/form.hbs', {
        pwa,
        error: err
      });
      return;
    });
});

/**
 * GET /pwas/:id
 *
 * Display a PWA.
 */
router.get('/:pwa', (req, res, next) => {
  pwaLib.find(req.params.pwa)
    .then(entity => {
      res.render('pwas/view.hbs', {
        pwa: entity
      });
    })
    .catch(() => {
      return next();
    });
});

/**
 * Errors on "/pwas/*" routes.
 */
router.use((err, req, res, next) => {
  // Format error and forward to generic error handler for logging and
  // responding to the request
  err.response = err.message;
  next(err);
});

/**
 * @param {string} clientId
 * @param {string} clientSecret
 * @param {string} idToken
 * @return {Promise<GoogleLogin>}
 */
function verifyIdToken(clientId, clientSecret, idToken) {
  const authFactory = new (require('google-auth-library'))();
  const client = new authFactory.OAuth2(clientId, clientSecret);
  return new Promise((resolve, reject) => {
    client.verifyIdToken(idToken, clientId, (err, user) => {
      if (err) {
        reject(err);
      }
      resolve(user);
    });
  });
}

module.exports = router;
<commit_msg>Convert http manifest urls to https<commit_after>/**
 * Copyright 2015-2016, Google, Inc.
 * 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.
 */

'use strict';

const express = require('express');
const pwaLib = require('../lib/pwa');
const Pwa = require('../models/pwa');
const router = express.Router(); // eslint-disable-line new-cap
const config = require('../config/config');
const CLIENT_ID = config.get('CLIENT_ID');
const CLIENT_SECRET = config.get('CLIENT_SECRET');
const LIST_PAGE_SIZE = 12;
const DEFAULT_PAGE_NUMBER = 1;
const DEFAULT_SORT_ORDER = 'newest';

/**
 * GET /pwas/add
 *
 * Display a page of PWAs (up to ten at a time).
 */
router.get('/', (req, res, next) => {
  const pageNumber = parseInt(req.query.page, 10) || DEFAULT_PAGE_NUMBER;
  const sortOrder = req.query.sort || DEFAULT_SORT_ORDER;
  const start = (pageNumber - 1) * LIST_PAGE_SIZE;

  pwaLib.list(start, LIST_PAGE_SIZE, sortOrder)
    .then(result => {
      res.render('pwas/list.hbs', {
        pwas: result.pwas,
        hasNextPage: result.hasMore,
        hasPreviousPage: pageNumber > 1,
        nextPageNumber: pageNumber + 1,
        previousPageNumber: pageNumber - 1,
        currentPageNumber: pageNumber,
        sortOrder: sortOrder,
        showNewest: sortOrder !== 'newest',
        showScore: sortOrder !== 'score'
      });
    })
    .catch(err => {
      next(err);
    });
});

/**
 * GET /pwas/add
 *
 * Display a form for creating a PWA.
 */
router.get('/add', (req, res) => {
  res.render('pwas/form.hbs', {
    pwa: {},
    action: 'Add'
  });
});

/**
 * POST /pwas/add
 *
 * Create a PWA.
 */
router.post('/add', (req, res, next) => {
  let manifestUrl = req.body.manifestUrl;
  if (manifestUrl.startsWith('http://')) {
    manifestUrl = manifestUrl.replace('http://', 'https://');
  }
  const idToken = req.body.idToken;
  let pwa = new Pwa(manifestUrl);

  if (!manifestUrl) {
    res.render('pwas/form.hbs', {
      pwa,
      error: 'no manifest provided'
    });
    return;
  }

  if (!idToken) {
    res.render('pwas/form.hbs', {
      pwa,
      error: 'user not logged in'
    });
    return;
  }

  verifyIdToken(CLIENT_ID, CLIENT_SECRET, idToken)
    .then(user => {
      pwa.setUserId(user);
      return pwaLib.save(pwa);
    })
    .then(savedData => {
      res.redirect(req.baseUrl + '/' + savedData.id);
      return;
    })
    .catch(err => {
      if (typeof err === 'number') {
        switch (err) {
          case pwaLib.E_MANIFEST_INVALID_URL:
            err = `pwa.manifestUrl [${pwa.manifestUrl}] is not a valid URL`;
            break;
          case pwaLib.E_MISING_USER_INFORMATION:
            err = 'Missing user information';
            break;
          case pwaLib.E_MANIFEST_URL_MISSING:
            err = 'Missing manifestUrl';
            break;
          case pwaLib.E_NOT_A_PWA:
            err = 'pwa is not an instance of Pwa';
            break;
          default:
            return next(err);
        }
      }
      // Transform err from an array of strings (in a particular format) to a
      // comma-separated string.
      if (Array.isArray(err)) {
        const s = err.map(e => {
          const m = e.match(/^ERROR:\s+(.*)\.$/);
          return m ? m[1] : e; // if no match (format changed?), just return the string
        }).join(', ');
        err = s;
      }
      res.render('pwas/form.hbs', {
        pwa,
        error: err
      });
      return;
    });
});

/**
 * GET /pwas/:id
 *
 * Display a PWA.
 */
router.get('/:pwa', (req, res, next) => {
  pwaLib.find(req.params.pwa)
    .then(entity => {
      res.render('pwas/view.hbs', {
        pwa: entity
      });
    })
    .catch(() => {
      return next();
    });
});

/**
 * Errors on "/pwas/*" routes.
 */
router.use((err, req, res, next) => {
  // Format error and forward to generic error handler for logging and
  // responding to the request
  err.response = err.message;
  next(err);
});

/**
 * @param {string} clientId
 * @param {string} clientSecret
 * @param {string} idToken
 * @return {Promise<GoogleLogin>}
 */
function verifyIdToken(clientId, clientSecret, idToken) {
  const authFactory = new (require('google-auth-library'))();
  const client = new authFactory.OAuth2(clientId, clientSecret);
  return new Promise((resolve, reject) => {
    client.verifyIdToken(idToken, clientId, (err, user) => {
      if (err) {
        reject(err);
      }
      resolve(user);
    });
  });
}

module.exports = router;
<|endoftext|>


<commit_before>'use strict';

var React = require('react-native');
import Message from './Message';
var GiftedSpinner = require('react-native-gifted-spinner');
var {
  Text,
  View,
  ListView,
  TextInput,
  Dimensions,
  Animated,
  Image,
  TouchableHighlight,
  Platform,
  PixelRatio
} = React;

var moment = require('moment');

var Button = require('react-native-button');

var GiftedMessenger = React.createClass({

  firstDisplay: true,
  listHeight: 0,
  footerY: 0,

  getDefaultProps() {
    return {
      displayNames: true,
      placeholder: 'Type a message...',
      styles: {},
      autoFocus: true,
      onErrorButtonPress: (message, rowID) => {},
      loadEarlierMessagesButton: false,
      loadEarlierMessagesButtonText: 'Load earlier messages',
      onLoadEarlierMessages: (oldestMessage, callback) => {},
      parseText: false,
      handleUrlPress: (url) => {},
      handlePhonePress: (phone) => {},
      handleEmailPress: (email) => {},
      initialMessages: [],
      messages: [],
      handleSend: (message, rowID) => {},
      maxHeight: Dimensions.get('window').height,
      senderName: 'Sender',
      senderImage: null,
      sendButtonText: 'Send',
      onImagePress: null,
      hideTextInput: false,
      submitOnReturn: false,
      forceRenderImage: false,
      onChangeText: (text) => {},
    };
  },

  propTypes: {
    displayNames: React.PropTypes.bool,
    placeholder: React.PropTypes.string,
    styles: React.PropTypes.object,
    autoFocus: React.PropTypes.bool,
    onErrorButtonPress: React.PropTypes.func,
    loadEarlierMessagesButton: React.PropTypes.bool,
    loadEarlierMessagesButtonText: React.PropTypes.string,
    onLoadEarlierMessages: React.PropTypes.func,
    parseText: React.PropTypes.bool,
    handleUrlPress: React.PropTypes.func,
    handlePhonePress: React.PropTypes.func,
    handleEmailPress: React.PropTypes.func,
    initialMessages: React.PropTypes.array,
    messages: React.PropTypes.array,
    handleSend: React.PropTypes.func,
    onCustomSend: React.PropTypes.func,
    renderCustomText: React.PropTypes.func,
    maxHeight: React.PropTypes.number,
    senderName: React.PropTypes.string,
    senderImage: React.PropTypes.object,
    sendButtonText: React.PropTypes.string,
    onImagePress: React.PropTypes.func,
    hideTextInput: React.PropTypes.bool,
    forceRenderImage: React.PropTypes.bool,
    onChangeText: React.PropTypes.func,
  },

  getInitialState: function() {
    this._data = [];
    this._rowIds = [];

    var textInputHeight = 0;
    if (this.props.hideTextInput === false) {
      textInputHeight = 44;
    }

    this.listViewMaxHeight = this.props.maxHeight - textInputHeight;

    var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => {
      if (typeof r1.status !== 'undefined') {
        return true;
      }
      return r1 !== r2;
    }});
    return {
      dataSource: ds.cloneWithRows([]),
      text: '',
      disabled: true,
      height: new Animated.Value(this.listViewMaxHeight),
      isLoadingEarlierMessages: false,
      allLoaded: false,
      appearAnim: new Animated.Value(0),
    };
  },

  getMessage(rowID) {
    if (typeof this._rowIds[this._rowIds.indexOf(rowID)] !== 'undefined') {
      if (typeof this._data[this._rowIds[this._rowIds.indexOf(rowID)]] !== 'undefined') {
        return this._data[this._rowIds[this._rowIds.indexOf(rowID)]];
      }
    }
    return null;
  },

  getPreviousMessage(rowID) {
    if (typeof this._rowIds[this._rowIds.indexOf(rowID - 1)] !== 'undefined') {
      if (typeof this._data[this._rowIds[this._rowIds.indexOf(rowID - 1)]] !== 'undefined') {
        return this._data[this._rowIds[this._rowIds.indexOf(rowID - 1)]];
      }
    }
    return null;
  },

  getNextMessage(rowID) {
    if (typeof this._rowIds[this._rowIds.indexOf(rowID + 1)] !== 'undefined') {
      if (typeof this._data[this._rowIds[this._rowIds.indexOf(rowID + 1)]] !== 'undefined') {
        return this._data[this._rowIds[this._rowIds.indexOf(rowID + 1)]];
      }
    }
    return null;
  },

  renderDate(rowData = {}, rowID = null) {
    var diffMessage = null;
    if (rowData.isOld === true) {
      diffMessage = this.getPreviousMessage(rowID);
    } else {
      diffMessage = this.getNextMessage(rowID);
    }
    if (rowData.date instanceof Date) {
      if (diffMessage === null) {
        return (
          <Text style={[this.styles.date]}>
            {moment(rowData.date).calendar()}
          </Text>
        );
      } else if (diffMessage.date instanceof Date) {
        let diff = moment(rowData.date).diff(moment(diffMessage.date), 'minutes');
        if (diff > 5) {
          return (
            <Text style={[this.styles.date]}>
              {moment(rowData.date).calendar()}
            </Text>
          );
        }
      }
    }
    return null;
  },

  renderRow(rowData = {}, sectionID = null, rowID = null) {

    var diffMessage = null;
    if (rowData.isOld === true) {
      diffMessage = this.getPreviousMessage(rowID);
    } else {
      diffMessage = this.getNextMessage(rowID);
    }

    return (
      <View>
        {this.renderDate(rowData, rowID)}
        <Message
          rowData={rowData}
          rowID={rowID}
          onErrorButtonPress={this.props.onErrorButtonPress}
          displayNames={this.props.displayNames}
          diffMessage={diffMessage}
          position={rowData.position}
          forceRenderImage={this.props.forceRenderImage}
          onImagePress={this.props.onImagePress}
          renderCustomText={this.props.renderCustomText}

          styles={this.styles}
        />
      </View>
    )
  },

  onChangeText(text) {
    this.setState({
      text: text
    })
    if (text.trim().length > 0) {
      this.setState({
        disabled: false
      })
    } else {
      this.setState({
        disabled: true
      })
    }

    this.props.onChangeText(text);
  },

  componentDidMount() {
    this.scrollResponder = this.refs.listView.getScrollResponder();

    if (this.props.messages.length > 0) {
      this.appendMessages(this.props.messages);
    } else if (this.props.initialMessages.length > 0) {
      this.appendMessages(this.props.initialMessages);
    } else {
      this.setState({
        allLoaded: true
      });
    }

  },

  componentWillReceiveProps(nextProps) {
    this._data = [];
    this._rowIds = [];
    this.appendMessages(nextProps.messages);
  },

  onKeyboardWillHide(e) {
    Animated.timing(this.state.height, {
      toValue: this.listViewMaxHeight,
      duration: 150,
    }).start();
  },

  onKeyboardWillShow(e) {
    Animated.timing(this.state.height, {
      toValue: this.listViewMaxHeight - (e.endCoordinates ? e.endCoordinates.height : e.end.height),
      duration: 200,
    }).start();
  },

  onKeyboardDidShow(e) {
    this.scrollToBottom();
  },

  scrollToBottom() {
    if (this.listHeight && this.footerY && this.footerY > this.listHeight) {
      var scrollDistance = this.listHeight - this.footerY;
      this.scrollResponder.scrollTo(-scrollDistance);
    }
  },

  scrollWithoutAnimationToBottom() {
    if (this.listHeight && this.footerY && this.footerY > this.listHeight) {
      var scrollDistance = this.listHeight - this.footerY;
      this.scrollResponder.scrollWithoutAnimationTo(0, -scrollDistance);
    }
  },

  onSend() {
    var message = {
      text: this.state.text.trim(),
      name: this.props.senderName,
      image: this.props.senderImage,
      position: 'right',
      date: new Date(),
    };
    if (this.props.onCustomSend) {
      this.props.onCustomSend(message);
    } else {
      var rowID = this.appendMessage(message);
      this.props.handleSend(message, rowID);
      this.onChangeText('');
    }
  },

  postLoadEarlierMessages(messages = [], allLoaded = false) {
    this.prependMessages(messages);
    this.setState({
      isLoadingEarlierMessages: false
    });
    if (allLoaded === true) {
      this.setState({
        allLoaded: true,
      });
    }
  },

  preLoadEarlierMessages() {
    this.setState({
      isLoadingEarlierMessages: true
    });
    this.props.onLoadEarlierMessages(this._data[this._rowIds[this._rowIds.length - 1]], this.postLoadEarlierMessages);
  },

  renderLoadEarlierMessages() {
    if (this.props.loadEarlierMessagesButton === true) {
      if (this.state.allLoaded === false) {
        if (this.state.isLoadingEarlierMessages === true) {
          return (
            <View style={this.styles.loadEarlierMessages}>
              <GiftedSpinner />
            </View>
          );
        } else {
          return (
            <View style={this.styles.loadEarlierMessages}>
              <Button
                style={this.styles.loadEarlierMessagesButton}
                onPress={() => {this.preLoadEarlierMessages()}}
              >
                {this.props.loadEarlierMessagesButtonText}
              </Button>
            </View>
          );
        }
      }
    }
    return null;
  },

  prependMessages(messages = []) {
    var rowID = null;
    for (let i = 0; i < messages.length; i++) {
      this._data.push(messages[i]);
      this._rowIds.unshift(this._data.length - 1);
      rowID = this._data.length - 1;
    }
    this.setState({
      dataSource: this.state.dataSource.cloneWithRows(this._data, this._rowIds),
    });
    return rowID;
  },

  prependMessage(message = {}) {
    var rowID = this.prependMessages([message]);
    return rowID;
  },

  appendMessages(messages = []) {
    var rowID = null;
    for (let i = 0; i < messages.length; i++) {
      messages[i].isOld = true;
      this._data.push(messages[i]);
      this._rowIds.push(this._data.length - 1);
      rowID = this._data.length - 1;
    }

    this.setState({
      dataSource: this.state.dataSource.cloneWithRows(this._data, this._rowIds),
    });

    return rowID;
  },

  appendMessage(message = {}, scrollToBottom = true) {
    var rowID = this.appendMessages([message]);

    if (scrollToBottom === true) {
      setTimeout(() => {
        // inspired by http://stackoverflow.com/a/34838513/1385109
        this.scrollToBottom();
      }, (Platform.OS === 'android' ? 200 : 100));
    }

    return rowID;
  },

  refreshRows() {
    this.setState({
      dataSource: this.state.dataSource.cloneWithRows(this._data, this._rowIds),
    });
  },

  setMessageStatus(status = '', rowID) {
    if (status === 'ErrorButton') {
      if (this._data[rowID].position === 'right') {
        this._data[rowID].status = 'ErrorButton';
        this.refreshRows();
      }
    } else {
      if (this._data[rowID].position === 'right') {
        this._data[rowID].status = status;

        // only 1 message can have a status
        for (let i = 0; i < this._data.length; i++) {
          if (i !== rowID && this._data[i].status !== 'ErrorButton') {
            this._data[i].status = '';
          }
        }
        this.refreshRows();
      }
    }
  },

  renderAnimatedView() {
    return (
      <Animated.View
        style={{
          height: this.state.height,
        }}

      >
        <ListView
          ref='listView'
          dataSource={this.state.dataSource}
          renderRow={this.renderRow}
          renderHeader={this.renderLoadEarlierMessages}
          onLayout={(event) => {
            var layout = event.nativeEvent.layout;
            this.listHeight = layout.height;
            if (this.firstDisplay === true) {
              requestAnimationFrame(() => {
                this.firstDisplay = false;
                this.scrollWithoutAnimationToBottom();
              });
            }

          }}
          renderFooter={() => {
            return <View onLayout={(event)=>{
              var layout = event.nativeEvent.layout;
              this.footerY = layout.y;
            }}></View>
          }}

          style={this.styles.listView}

          // not working android RN 0.14.2
          onKeyboardWillShow={this.onKeyboardWillShow}
          onKeyboardDidShow={this.onKeyboardDidShow}
          onKeyboardWillHide={this.onKeyboardWillHide}

          /*
            keyboardShouldPersistTaps={false} // @issue keyboardShouldPersistTaps={false} + textInput focused = 2 taps are needed to trigger the ParsedText links
            keyboardDismissMode='interactive'
          */

          keyboardShouldPersistTaps={true}
          keyboardDismissMode='interactive'

          initialListSize={10}
          pageSize={this.props.messages.length}

          {...this.props}
        />

      </Animated.View>
    );
  },

  render() {
    return (
      <View
        style={this.styles.container}
        ref='container'
      >
        {this.renderAnimatedView()}
        {this.renderTextInput()}
      </View>
    )
  },

  renderTextInput() {
    if (this.props.hideTextInput === false) {
      return (
        <View style={this.styles.textInputContainer}>
          <TextInput
            style={this.styles.textInput}
            placeholder={this.props.placeholder}
            ref='textInput'
            onChangeText={this.onChangeText}
            value={this.state.text}
            autoFocus={this.props.autoFocus}
            returnKeyType={this.props.submitOnReturn ? 'send' : 'default'}
            onSubmitEditing={this.props.submitOnReturn ? this.onSend : null}

            blurOnSubmit={false}
          />
          <Button
            style={this.styles.sendButton}
            onPress={this.onSend}
            disabled={this.state.disabled}
          >
            {this.props.sendButtonText}
          </Button>
        </View>
      );
    }
    return null;
  },

  componentWillMount() {
    this.styles = {
      container: {
        flex: 1,
        backgroundColor: '#FFF',
      },
      listView: {
        flex: 1,
      },
      textInputContainer: {
        height: 44,
        borderTopWidth: 1 / PixelRatio.get(),
        borderColor: '#b2b2b2',
        flexDirection: 'row',
        paddingLeft: 10,
        paddingRight: 10,
      },
      textInput: {
        alignSelf: 'center',
        height: 30,
        width: 100,
        backgroundColor: '#FFF',
        flex: 1,
        padding: 0,
        margin: 0,
        fontSize: 15,
      },
      sendButton: {
        marginTop: 11,
        marginLeft: 10,
      },
      date: {
        color: '#aaaaaa',
        fontSize: 12,
        textAlign: 'center',
        fontWeight: 'bold',
        marginBottom: 8,
      },
      link: {
        color: '#007aff',
        textDecorationLine: 'underline',
      },
      linkLeft: {
        color: '#000',
      },
      linkRight: {
        color: '#fff',
      },
      loadEarlierMessages: {
        height: 44,
        justifyContent: 'center',
        alignItems: 'center',
      },
      loadEarlierMessagesButton: {
        fontSize: 14,
      },
    };

    Object.assign(this.styles, this.props.styles);
  },
});

module.exports = GiftedMessenger;
<commit_msg>fix warning<commit_after>'use strict';

var React = require('react-native');
import Message from './Message';
var GiftedSpinner = require('react-native-gifted-spinner');
var {
  Text,
  View,
  ListView,
  TextInput,
  Dimensions,
  Animated,
  Image,
  TouchableHighlight,
  Platform,
  PixelRatio
} = React;

var moment = require('moment');

var Button = require('react-native-button');

var GiftedMessenger = React.createClass({

  firstDisplay: true,
  listHeight: 0,
  footerY: 0,

  getDefaultProps() {
    return {
      displayNames: true,
      placeholder: 'Type a message...',
      styles: {},
      autoFocus: true,
      onErrorButtonPress: (message, rowID) => {},
      loadEarlierMessagesButton: false,
      loadEarlierMessagesButtonText: 'Load earlier messages',
      onLoadEarlierMessages: (oldestMessage, callback) => {},
      parseText: false,
      handleUrlPress: (url) => {},
      handlePhonePress: (phone) => {},
      handleEmailPress: (email) => {},
      initialMessages: [],
      messages: [],
      handleSend: (message, rowID) => {},
      maxHeight: Dimensions.get('window').height,
      senderName: 'Sender',
      senderImage: null,
      sendButtonText: 'Send',
      onImagePress: null,
      hideTextInput: false,
      submitOnReturn: false,
      forceRenderImage: false,
      onChangeText: (text) => {},
    };
  },

  propTypes: {
    displayNames: React.PropTypes.bool,
    placeholder: React.PropTypes.string,
    styles: React.PropTypes.object,
    autoFocus: React.PropTypes.bool,
    onErrorButtonPress: React.PropTypes.func,
    loadEarlierMessagesButton: React.PropTypes.bool,
    loadEarlierMessagesButtonText: React.PropTypes.string,
    onLoadEarlierMessages: React.PropTypes.func,
    parseText: React.PropTypes.bool,
    handleUrlPress: React.PropTypes.func,
    handlePhonePress: React.PropTypes.func,
    handleEmailPress: React.PropTypes.func,
    initialMessages: React.PropTypes.array,
    messages: React.PropTypes.array,
    handleSend: React.PropTypes.func,
    onCustomSend: React.PropTypes.func,
    renderCustomText: React.PropTypes.func,
    maxHeight: React.PropTypes.number,
    senderName: React.PropTypes.string,
    senderImage: React.PropTypes.object,
    sendButtonText: React.PropTypes.string,
    onImagePress: React.PropTypes.func,
    hideTextInput: React.PropTypes.bool,
    forceRenderImage: React.PropTypes.bool,
    onChangeText: React.PropTypes.func,
  },

  getInitialState: function() {
    this._data = [];
    this._rowIds = [];

    var textInputHeight = 0;
    if (this.props.hideTextInput === false) {
      textInputHeight = 44;
    }

    this.listViewMaxHeight = this.props.maxHeight - textInputHeight;

    var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => {
      if (typeof r1.status !== 'undefined') {
        return true;
      }
      return r1 !== r2;
    }});
    return {
      dataSource: ds.cloneWithRows([]),
      text: '',
      disabled: true,
      height: new Animated.Value(this.listViewMaxHeight),
      isLoadingEarlierMessages: false,
      allLoaded: false,
      appearAnim: new Animated.Value(0),
    };
  },

  getMessage(rowID) {
    if (typeof this._rowIds[this._rowIds.indexOf(rowID)] !== 'undefined') {
      if (typeof this._data[this._rowIds[this._rowIds.indexOf(rowID)]] !== 'undefined') {
        return this._data[this._rowIds[this._rowIds.indexOf(rowID)]];
      }
    }
    return null;
  },

  getPreviousMessage(rowID) {
    if (typeof this._rowIds[this._rowIds.indexOf(rowID - 1)] !== 'undefined') {
      if (typeof this._data[this._rowIds[this._rowIds.indexOf(rowID - 1)]] !== 'undefined') {
        return this._data[this._rowIds[this._rowIds.indexOf(rowID - 1)]];
      }
    }
    return null;
  },

  getNextMessage(rowID) {
    if (typeof this._rowIds[this._rowIds.indexOf(rowID + 1)] !== 'undefined') {
      if (typeof this._data[this._rowIds[this._rowIds.indexOf(rowID + 1)]] !== 'undefined') {
        return this._data[this._rowIds[this._rowIds.indexOf(rowID + 1)]];
      }
    }
    return null;
  },

  renderDate(rowData = {}, rowID = null) {
    var diffMessage = null;
    if (rowData.isOld === true) {
      diffMessage = this.getPreviousMessage(rowID);
    } else {
      diffMessage = this.getNextMessage(rowID);
    }
    if (rowData.date instanceof Date) {
      if (diffMessage === null) {
        return (
          <Text style={[this.styles.date]}>
            {moment(rowData.date).calendar()}
          </Text>
        );
      } else if (diffMessage.date instanceof Date) {
        let diff = moment(rowData.date).diff(moment(diffMessage.date), 'minutes');
        if (diff > 5) {
          return (
            <Text style={[this.styles.date]}>
              {moment(rowData.date).calendar()}
            </Text>
          );
        }
      }
    }
    return null;
  },

  renderRow(rowData = {}, sectionID = null, rowID = null) {

    var diffMessage = null;
    if (rowData.isOld === true) {
      diffMessage = this.getPreviousMessage(rowID);
    } else {
      diffMessage = this.getNextMessage(rowID);
    }

    return (
      <View>
        {this.renderDate(rowData, rowID)}
        <Message
          rowData={rowData}
          rowID={rowID}
          onErrorButtonPress={this.props.onErrorButtonPress}
          displayNames={this.props.displayNames}
          diffMessage={diffMessage}
          position={rowData.position}
          forceRenderImage={this.props.forceRenderImage}
          onImagePress={this.props.onImagePress}
          renderCustomText={this.props.renderCustomText}

          styles={this.styles}
        />
      </View>
    )
  },

  onChangeText(text) {
    this.setState({
      text: text
    })
    if (text.trim().length > 0) {
      this.setState({
        disabled: false
      })
    } else {
      this.setState({
        disabled: true
      })
    }

    this.props.onChangeText(text);
  },

  componentDidMount() {
    this.scrollResponder = this.refs.listView.getScrollResponder();

    if (this.props.messages.length > 0) {
      this.appendMessages(this.props.messages);
    } else if (this.props.initialMessages.length > 0) {
      this.appendMessages(this.props.initialMessages);
    } else {
      this.setState({
        allLoaded: true
      });
    }

  },

  componentWillReceiveProps(nextProps) {
    this._data = [];
    this._rowIds = [];
    this.appendMessages(nextProps.messages);
  },

  onKeyboardWillHide(e) {
    Animated.timing(this.state.height, {
      toValue: this.listViewMaxHeight,
      duration: 150,
    }).start();
  },

  onKeyboardWillShow(e) {
    Animated.timing(this.state.height, {
      toValue: this.listViewMaxHeight - (e.endCoordinates ? e.endCoordinates.height : e.end.height),
      duration: 200,
    }).start();
  },

  onKeyboardDidShow(e) {
    this.scrollToBottom();
  },

  scrollToBottom() {
    if (this.listHeight && this.footerY && this.footerY > this.listHeight) {
      var scrollDistance = this.listHeight - this.footerY;
      this.scrollResponder.scrollTo(-scrollDistance);
    }
  },

  scrollWithoutAnimationToBottom() {
    if (this.listHeight && this.footerY && this.footerY > this.listHeight) {
      var scrollDistance = this.listHeight - this.footerY;
      this.scrollResponder.scrollTo(-scrollDistance, 0, false);
    }
  },

  onSend() {
    var message = {
      text: this.state.text.trim(),
      name: this.props.senderName,
      image: this.props.senderImage,
      position: 'right',
      date: new Date(),
    };
    if (this.props.onCustomSend) {
      this.props.onCustomSend(message);
    } else {
      var rowID = this.appendMessage(message);
      this.props.handleSend(message, rowID);
      this.onChangeText('');
    }
  },

  postLoadEarlierMessages(messages = [], allLoaded = false) {
    this.prependMessages(messages);
    this.setState({
      isLoadingEarlierMessages: false
    });
    if (allLoaded === true) {
      this.setState({
        allLoaded: true,
      });
    }
  },

  preLoadEarlierMessages() {
    this.setState({
      isLoadingEarlierMessages: true
    });
    this.props.onLoadEarlierMessages(this._data[this._rowIds[this._rowIds.length - 1]], this.postLoadEarlierMessages);
  },

  renderLoadEarlierMessages() {
    if (this.props.loadEarlierMessagesButton === true) {
      if (this.state.allLoaded === false) {
        if (this.state.isLoadingEarlierMessages === true) {
          return (
            <View style={this.styles.loadEarlierMessages}>
              <GiftedSpinner />
            </View>
          );
        } else {
          return (
            <View style={this.styles.loadEarlierMessages}>
              <Button
                style={this.styles.loadEarlierMessagesButton}
                onPress={() => {this.preLoadEarlierMessages()}}
              >
                {this.props.loadEarlierMessagesButtonText}
              </Button>
            </View>
          );
        }
      }
    }
    return null;
  },

  prependMessages(messages = []) {
    var rowID = null;
    for (let i = 0; i < messages.length; i++) {
      this._data.push(messages[i]);
      this._rowIds.unshift(this._data.length - 1);
      rowID = this._data.length - 1;
    }
    this.setState({
      dataSource: this.state.dataSource.cloneWithRows(this._data, this._rowIds),
    });
    return rowID;
  },

  prependMessage(message = {}) {
    var rowID = this.prependMessages([message]);
    return rowID;
  },

  appendMessages(messages = []) {
    var rowID = null;
    for (let i = 0; i < messages.length; i++) {
      messages[i].isOld = true;
      this._data.push(messages[i]);
      this._rowIds.push(this._data.length - 1);
      rowID = this._data.length - 1;
    }

    this.setState({
      dataSource: this.state.dataSource.cloneWithRows(this._data, this._rowIds),
    });

    return rowID;
  },

  appendMessage(message = {}, scrollToBottom = true) {
    var rowID = this.appendMessages([message]);

    if (scrollToBottom === true) {
      setTimeout(() => {
        // inspired by http://stackoverflow.com/a/34838513/1385109
        this.scrollToBottom();
      }, (Platform.OS === 'android' ? 200 : 100));
    }

    return rowID;
  },

  refreshRows() {
    this.setState({
      dataSource: this.state.dataSource.cloneWithRows(this._data, this._rowIds),
    });
  },

  setMessageStatus(status = '', rowID) {
    if (status === 'ErrorButton') {
      if (this._data[rowID].position === 'right') {
        this._data[rowID].status = 'ErrorButton';
        this.refreshRows();
      }
    } else {
      if (this._data[rowID].position === 'right') {
        this._data[rowID].status = status;

        // only 1 message can have a status
        for (let i = 0; i < this._data.length; i++) {
          if (i !== rowID && this._data[i].status !== 'ErrorButton') {
            this._data[i].status = '';
          }
        }
        this.refreshRows();
      }
    }
  },

  renderAnimatedView() {
    return (
      <Animated.View
        style={{
          height: this.state.height,
        }}

      >
        <ListView
          ref='listView'
          dataSource={this.state.dataSource}
          renderRow={this.renderRow}
          renderHeader={this.renderLoadEarlierMessages}
          onLayout={(event) => {
            var layout = event.nativeEvent.layout;
            this.listHeight = layout.height;
            if (this.firstDisplay === true) {
              requestAnimationFrame(() => {
                this.firstDisplay = false;
                this.scrollWithoutAnimationToBottom();
              });
            }

          }}
          renderFooter={() => {
            return <View onLayout={(event)=>{
              var layout = event.nativeEvent.layout;
              this.footerY = layout.y;
            }}></View>
          }}

          style={this.styles.listView}

          // not working android RN 0.14.2
          onKeyboardWillShow={this.onKeyboardWillShow}
          onKeyboardDidShow={this.onKeyboardDidShow}
          onKeyboardWillHide={this.onKeyboardWillHide}

          /*
            keyboardShouldPersistTaps={false} // @issue keyboardShouldPersistTaps={false} + textInput focused = 2 taps are needed to trigger the ParsedText links
            keyboardDismissMode='interactive'
          */

          keyboardShouldPersistTaps={true}
          keyboardDismissMode='interactive'

          initialListSize={10}
          pageSize={this.props.messages.length}

          {...this.props}
        />

      </Animated.View>
    );
  },

  render() {
    return (
      <View
        style={this.styles.container}
        ref='container'
      >
        {this.renderAnimatedView()}
        {this.renderTextInput()}
      </View>
    )
  },

  renderTextInput() {
    if (this.props.hideTextInput === false) {
      return (
        <View style={this.styles.textInputContainer}>
          <TextInput
            style={this.styles.textInput}
            placeholder={this.props.placeholder}
            ref='textInput'
            onChangeText={this.onChangeText}
            value={this.state.text}
            autoFocus={this.props.autoFocus}
            returnKeyType={this.props.submitOnReturn ? 'send' : 'default'}
            onSubmitEditing={this.props.submitOnReturn ? this.onSend : null}

            blurOnSubmit={false}
          />
          <Button
            style={this.styles.sendButton}
            onPress={this.onSend}
            disabled={this.state.disabled}
          >
            {this.props.sendButtonText}
          </Button>
        </View>
      );
    }
    return null;
  },

  componentWillMount() {
    this.styles = {
      container: {
        flex: 1,
        backgroundColor: '#FFF',
      },
      listView: {
        flex: 1,
      },
      textInputContainer: {
        height: 44,
        borderTopWidth: 1 / PixelRatio.get(),
        borderColor: '#b2b2b2',
        flexDirection: 'row',
        paddingLeft: 10,
        paddingRight: 10,
      },
      textInput: {
        alignSelf: 'center',
        height: 30,
        width: 100,
        backgroundColor: '#FFF',
        flex: 1,
        padding: 0,
        margin: 0,
        fontSize: 15,
      },
      sendButton: {
        marginTop: 11,
        marginLeft: 10,
      },
      date: {
        color: '#aaaaaa',
        fontSize: 12,
        textAlign: 'center',
        fontWeight: 'bold',
        marginBottom: 8,
      },
      link: {
        color: '#007aff',
        textDecorationLine: 'underline',
      },
      linkLeft: {
        color: '#000',
      },
      linkRight: {
        color: '#fff',
      },
      loadEarlierMessages: {
        height: 44,
        justifyContent: 'center',
        alignItems: 'center',
      },
      loadEarlierMessagesButton: {
        fontSize: 14,
      },
    };

    Object.assign(this.styles, this.props.styles);
  },
});

module.exports = GiftedMessenger;
<|endoftext|>


<commit_before>;(function ($) {
	var widget = window.embedWidget;

	widget = {
		options: {},
		optgroups: {},
		init: function () {
			var EmbedFields = widget.EmbedFields = $('.embedding'),
				EmbedWidgets = widget.EmbedWidgets,
				EmbedBars = widget.EmbedBars,
				EmbedButtons = widget.EmbedButtons,
				EmbedSelects = widget.EmbedSelects;

			EmbedFields.wrap($('
'));
			EmbedWidgets = $('.embed-widget');
			EmbedWidgets.prepend($('
'));
			EmbedBars = $('.embed-toolbar');
			EmbedBars.append('<select class="embed-select"></select><button class="embed-button">Embed</button>');
			EmbedButtons = $('.embed-button');
			EmbedSelects = $('.embed-select');

			widget.parseContentTypes();
			EmbedSelects.each(widget.populateSelect);

			EmbedButtons.click(widget.buttonHandler);
		},
		parseContentTypes: function () {
			var string = widget.EmbedFields.eq(0).attr('data-content-types'),
				data = $.parseJSON(string),
				i=0,
				current_app_label = '',
				optgroups = {};

				// this loop relies on data being clustered by app
				for(i=0; i < data.length; i++){
					item = data[i]
					// run this next loop every time we encounter a new app label
					if (item.app_label !== current_app_label) {
						current_app_label = item.app_label;
						optgroups[current_app_label] = {}
					}
					optgroups[current_app_label][item.verbose_name] = [item.app_label,item.object_name].join('.');

					widget.optgroups = optgroups;
				}
		},
		populateSelect: function () {
			var $this = $(this),
				optgroups = widget.optgroups,
				optgroup_els = {},
				optgroup_el, group;

			// append a title
			$this.append('<option value="">Media Types</option>');

			// for each group
			for (name in optgroups){
				if(optgroups.hasOwnProperty(name)){
					// assign the group to variable group, temporarily
					group = optgroups[name];
					// create an element for this group and assign it to optgroup_el, temporarily
					optgroup_el = optgroup_els[name] = $('<optgroup label="'+name+'" />');
					// append this element to the select menu
					$this.append(optgroup_el);
					// for each item in the group
					for (name in group) {
						// append an option to the optgroup
						optgroup_el.append('<option value='+group[name]+'>'+name+'</option>');
					}
				}
			}
		},
		buttonHandler: function (e) {
			var $this = $(this),
				select = $this.prev('select'),
				embed_widget = $this.closest('.embed-widget'),
				textarea = embed_widget.children('.embedding').eq(0),
				val, app_label, object_name,
				href,
				win;

			// prevent the button from submitting the form
			e.preventDefault();
			// handle the case that they haven't chosen a type to embed
			if (select.val()==='') {
				alert('Please select a media type to embed.');
				textarea.focus();
				return;
			}

			// split the val into app and object
			val = select.val();
			app_label = val.split('.')[0];
			object_name = val.split('.')[1];

			// generate the url
			// TODO: Find a better way to get ADMIN_URL. Currently this only works with grappelli, which provides the javascript global ADMIN_URL
			href=[ADMIN_URL, app_label,  '/', object_name, '/?pop=1'].join('');

			// this is a bit hackish. let's walk through it.
			// TODO: best to write our own template for this in the future

			// open a new window
			win = window.open(href, id_to_windowname(textarea.attr('id')), 'height=500,width=980,resizable=yes,scrollbars=yes');

			// when the window finishes loading
			win.addEventListener('load', function(){
				// collect all the links to objects in that window
				var links = win.django.jQuery('#changelist th:first-child a');
					// for each link
					links.each(function(){
						// capture the pk
						var pk = $(this).attr('href').split('/')[0];
						// bind our own function to onclick instead of the function that's currently there
						this.onclick = function () { widget.appendEmbed(textarea, val, pk); win.close(); return false; };
					});
			}, false)

			// return focus to the textarea
			textarea.focus();
		},
		appendEmbed: function (textarea, embed_type, embed_id) {
			var $textarea = $(textarea),
				textarea = $textarea[0], // make sure we're *not* working with a jQuery object
				current_selection = [textarea.selectionStart, textarea.selectionEnd],
				current_text = $textarea.val(),
				embed_string = ['{% embed', embed_type, embed_id, '%}'].join(' '),
				new_text = current_text.substring(0, current_selection[0]) + embed_string + current_text.substring(current_selection[1]);

			$textarea.val(new_text);
		}
	}

	$(widget.init);
}(django.jQuery));<commit_msg>Made the embed widget javascript work by overloading the dismissRelatedLookupPopup function.<commit_after>;(function ($) {
	var widget = window.embedWidget;

	widget = {
		options: {},
		optgroups: {},
		init: function () {
			var EmbedFields = widget.EmbedFields = $('.embedding'),
				EmbedWidgets = widget.EmbedWidgets,
				EmbedBars = widget.EmbedBars,
				EmbedButtons = widget.EmbedButtons,
				EmbedSelects = widget.EmbedSelects;

			EmbedFields.wrap($('
'));
			EmbedWidgets = $('.embed-widget');
			EmbedWidgets.prepend($('
'));
			EmbedBars = $('.embed-toolbar');
			EmbedBars.append('<select class="embed-select"></select><button class="embed-button">Embed</button>');
			EmbedButtons = $('.embed-button');
			EmbedSelects = $('.embed-select');

			widget.parseContentTypes();
			EmbedSelects.each(widget.populateSelect);

			EmbedButtons.click(widget.buttonHandler);

			// overload the dismissRelatedLookupPopup function
			oldDismissRelatedLookupPopup = window.dismissRelatedLookupPopup;
			window.dismissRelatedLookupPopup = function (win, chosenId) {
				var name = windowname_to_id(win.name),
					elem = $('#'+win.name), val;
				// if the original element was an embed widget, run our script
				if (elem.parent().hasClass('embed-widget')) {
					contenttype = $('select',elem.parent()).val();
					widget.appendEmbed(elem, contenttype, chosenId);
					elem.focus();
					win.close();
					return;
				}
				// otherwise, do what you usually do
				oldDismissRelatedLookupPopup.apply(this, arguments);
			}
		},
		parseContentTypes: function () {
			var string = widget.EmbedFields.eq(0).attr('data-content-types'),
				data = $.parseJSON(string),
				i=0,
				current_app_label = '',
				optgroups = {};

				// this loop relies on data being clustered by app
				for(i=0; i < data.length; i++){
					item = data[i]
					// run this next loop every time we encounter a new app label
					if (item.app_label !== current_app_label) {
						current_app_label = item.app_label;
						optgroups[current_app_label] = {}
					}
					optgroups[current_app_label][item.verbose_name] = [item.app_label,item.object_name].join('.');

					widget.optgroups = optgroups;
				}
		},
		populateSelect: function () {
			var $this = $(this),
				optgroups = widget.optgroups,
				optgroup_els = {},
				optgroup_el, group;

			// append a title
			$this.append('<option value="">Media Types</option>');

			// for each group
			for (name in optgroups){
				if(optgroups.hasOwnProperty(name)){
					// assign the group to variable group, temporarily
					group = optgroups[name];
					// create an element for this group and assign it to optgroup_el, temporarily
					optgroup_el = optgroup_els[name] = $('<optgroup label="'+name+'" />');
					// append this element to the select menu
					$this.append(optgroup_el);
					// for each item in the group
					for (name in group) {
						// append an option to the optgroup
						optgroup_el.append('<option value='+group[name]+'>'+name+'</option>');
					}
				}
			}
		},
		buttonHandler: function (e) {
			var $this = $(this),
				select = $this.prev('select'),
				embed_widget = $this.closest('.embed-widget'),
				textarea = embed_widget.children('.embedding').eq(0),
				val, app_label, object_name,
				href,
				win;

			// prevent the button from submitting the form
			e.preventDefault();

			// handle the case that they haven't chosen a type to embed
			if (select.val()==='') {
				alert('Please select a media type to embed.');
				textarea.focus();
				return;
			}

			// split the val into app and object
			val = select.val();
			app_label = val.split('.')[0];
			object_name = val.split('.')[1];

			// generate the url for the popup
			// TODO: Find a better way to get the admin URL if possible. This will break if the URL patterns for the admin ever change.
			href=['../../../', app_label,  '/', object_name, '/?pop=1'].join('');

			// open a new window
			win = window.open(href, id_to_windowname(textarea.attr('id')), 'height=500,width=980,resizable=yes,scrollbars=yes');
		},
		appendEmbed: function (textarea, embed_type, embed_id) {
			var $textarea = $(textarea),
				textarea = $textarea[0], // make sure we're *not* working with a jQuery object
				current_selection = [textarea.selectionStart, textarea.selectionEnd],
				current_text = $textarea.val(),
				embed_string = ['{% embed', embed_type, embed_id, '%}'].join(' '),
				new_text = current_text.substring(0, current_selection[0]) + embed_string + current_text.substring(current_selection[1]),
				new_cursor_pos = current_selection[0]+embed_string.length;
			$textarea.val(new_text);
			textarea.setSelectionRange(new_cursor_pos, new_cursor_pos);
		}
	}

	$(widget.init);
}(django.jQuery));<|endoftext|>


<commit_before>
Value.addListener(document, 'elm_log', function(e) { console.log(e.value); });
Value.addListener(document, 'elm_title', function(e) {document.title = e.value;});
Value.addListener(document, 'elm_redirect', function(e) {
	if (e.value.length > 0) { window.location = e.value; }
    });

var Elm = Elm || {};
Elm.Prelude = function() {
    var mod = function(x) { return function(y) {
	    var r = x % y;
	    var m = x==0 ? 0 : (y>0 ? (x>=0 ? r : r+y) : -mod(-x)(-y));
	    return m == y ? 0 : m;
	}; };

    var min = function(x) { return function(y) { return Math.min(x,y); }; };
    var max = function(x) { return function(y) { return Math.max(x,y); }; };

    var flip=function(f){return function(x){return function(y){return f(y)(x);};};};
    var clamp = function(lo) { return function(hi) {
	    return function(x) { return Math.min(hi, Math.max(lo, x)); };
	};
    };
    var curry = function(f) { return function(x) { return function(y) {
		return f(["Tuple2",x,y]); }; };
    };
    var uncurry = function(f) { return function(p) {
	    if (p[0] !== "Tuple2") {
		throw "Function was uncurry'd but was not given a pair.";
	    }
	    return f(p[1])(p[2]); };
    };

    var logBase=function(b){return function(x){return Math.log(x)/Math.log(b);};};

    return {eq   : Value.eq,
	    id   : function(x) { return x; },
	    not  : function(b) { return !b; },
	    fst  : function(p) { return p[1]; },
	    snd  : function(p) { return p[2]; },
	    rem  : function(x) { return function(y) { return x % y; }; },
	    div  : function(x) { return function(y) { return ~~(x / y); }; },
	    compare : function(x) { return function (y) {
		x = (typeof x === "object") ? toText(x) : x;
		y = (typeof y === "object") ? toText(y) : y;
		return [ x === y ? 'EQ' : (x < y ? 'LT' : 'GT') ];
	      };
	    },
	    toFloat : function(x) { return x; },
	    round : function(n) { return Math.round(n); },
	    floor : function(n) { return Math.floor(n); },
	    ceiling : function(n) { return Math.ceil(n); },
	    truncate : function(n) { return ~~n; },
	    sqrt : Math.sqrt,
	    abs  : Math.abs,
	    pi   : Math.PI,
	    e    : Math.E,
	    sin  : Math.sin,
	    cos  : Math.cos,
	    tan  : Math.tan,
	    asin : Math.asin,
	    acos : Math.acos,
	    atan : Math.atan,
	    atan2 : function(y) { return function(x) { return Math.atan2(y,x); }; },
	    mod  : mod,
	    min  : min,
	    max  : max,
	    flip : flip,
	    clamp : clamp,
	    curry : curry,
	    uncurry : uncurry,
	    logBase : logBase,
	    Just    : Elm.Maybe.Just,
	    Nothing : Elm.Maybe.Nothing,
	    maybe   : Elm.Maybe.maybe,
	    map     : Elm.List.map,
	    filter  : Elm.List.filter,
	    head    : Elm.List.head,
	    tail    : Elm.List.tail,
	    last    : Elm.List.last,
	    length  : Elm.List.length,
	    reverse : Elm.List.reverse,
	    foldr   : Elm.List.foldr,
	    foldr1  : Elm.List.foldr1,
	    foldl   : Elm.List.foldl,
	    foldl1  : Elm.List.foldl1,
	    and     : Elm.List.and,
	    or      : Elm.List.or,
	    all     : Elm.List.all,
	    any     : Elm.List.any,
	    sum     : Elm.List.sum,
	    product : Elm.List.product,
	    concat  : Elm.List.concat,
	    concatMap : Elm.List.concatMap,
	    maximum : Elm.List.maximum,
	    minimum : Elm.List.minimum,
	    scanl   : Elm.List.scanl,
	    scanl1  : Elm.List.scanl1,
	    take    : Elm.List.take,
	    drop    : Elm.List.drop,
	    zip     : Elm.List.zip,
	    unzip   : Elm.List.unzip,
	    lift  : Elm.Signal.lift,
	    lift2 : Elm.Signal.lift2,
	    lift3 : Elm.Signal.lift3,
	    lift4 : Elm.Signal.lift4,
	    foldp : Elm.Signal.foldp,
	    foldp1 : Elm.Signal.foldp1,
	    foldp_ : Elm.Signal.foldp_,
	    constant : Elm.Signal.constant,
	    count : Elm.Signal.count,
	    keepIf : Elm.Signal.keepIf,
	    dropIf : Elm.Signal.dropIf,
	    keepWhen : Elm.Signal.keepWhen,
	    dropWhen : Elm.Signal.dropWhen,
	    dropRepeats : Elm.Signal.dropRepeats,
	    sampleOn : Elm.Signal.sampleOn
	    };

}();

(function() {
  var include = function(library) {
    for (var i in library) {
	Elm.Prelude[i] = library[i];
    }
  };
  include (Elm.Graphics.Color);
  include (Elm.Graphics.Text);
  include (Elm.Graphics.Element);

  show = Value.show;

}());
<commit_msg>Add the `readInt` and `readFloat` functions.<commit_after>
Value.addListener(document, 'elm_log', function(e) { console.log(e.value); });
Value.addListener(document, 'elm_title', function(e) {document.title = e.value;});
Value.addListener(document, 'elm_redirect', function(e) {
	if (e.value.length > 0) { window.location = e.value; }
    });

var Elm = Elm || {};
Elm.Prelude = function() {
    var mod = function(x) { return function(y) {
	    var r = x % y;
	    var m = x==0 ? 0 : (y>0 ? (x>=0 ? r : r+y) : -mod(-x)(-y));
	    return m == y ? 0 : m;
	}; };

    var min = function(x) { return function(y) { return Math.min(x,y); }; };
    var max = function(x) { return function(y) { return Math.max(x,y); }; };

    var flip=function(f){return function(x){return function(y){return f(y)(x);};};};
    var clamp = function(lo) { return function(hi) {
	    return function(x) { return Math.min(hi, Math.max(lo, x)); };
	};
    };
    var curry = function(f) { return function(x) { return function(y) {
		return f(["Tuple2",x,y]); }; };
    };
    var uncurry = function(f) { return function(p) {
	    if (p[0] !== "Tuple2") {
		throw "Function was uncurry'd but was not given a pair.";
	    }
	    return f(p[1])(p[2]); };
    };

    var logBase=function(b){return function(x){return Math.log(x)/Math.log(b);};};

    function readInt(str) {
	var s = JavaScript.castStringToJSString(str);
	var len = s.length;
	if (len === 0) { return Nothing; }
	var start = 0;
	if (s[0] == '-') {
	    if (len === 1) { return Nothing; }
	    start = 1;
	}
	for (var i = start; i < len; ++i) {
	    if (!Char.isDigit(s[i])) { return Nothing; }
	}
	return Just(parseInt(s));
    }

    function readFloat(str) {
	var s = JavaScript.castStringToJSString(str);
	var len = s.length;
	if (len === 0) { return Nothing; }
	var start = 0;
	if (s[0] == '-') {
	    if (len === 1) { return Nothing; }
	    start = 1;
	}
	var dotCount = 0;
	for (var i = start; i < len; ++i) {
	    if (Char.isDigit(s[i])) { continue; }
	    if (s[i] === '.') {
		dotCount += 1;
		if (dotCount <= 1) { continue; }
	    }
	    return Nothing;
	}
	return Just(parseFloat(s));
    }

    return {eq   : Value.eq,
	    id   : function(x) { return x; },
	    not  : function(b) { return !b; },
	    fst  : function(p) { return p[1]; },
	    snd  : function(p) { return p[2]; },
	    rem  : function(x) { return function(y) { return x % y; }; },
	    div  : function(x) { return function(y) { return ~~(x / y); }; },
	    compare : function(x) { return function (y) {
		x = (typeof x === "object") ? toText(x) : x;
		y = (typeof y === "object") ? toText(y) : y;
		return [ x === y ? 'EQ' : (x < y ? 'LT' : 'GT') ];
	      };
	    },
	    toFloat : function(x) { return x; },
	    round : function(n) { return Math.round(n); },
	    floor : function(n) { return Math.floor(n); },
	    ceiling : function(n) { return Math.ceil(n); },
	    truncate : function(n) { return ~~n; },
	    readInt : readInt,
	    readFloat : readFloat,
	    sqrt : Math.sqrt,
	    abs  : Math.abs,
	    pi   : Math.PI,
	    e    : Math.E,
	    sin  : Math.sin,
	    cos  : Math.cos,
	    tan  : Math.tan,
	    asin : Math.asin,
	    acos : Math.acos,
	    atan : Math.atan,
	    atan2 : function(y) { return function(x) { return Math.atan2(y,x); }; },
	    mod  : mod,
	    min  : min,
	    max  : max,
	    flip : flip,
	    clamp : clamp,
	    curry : curry,
	    uncurry : uncurry,
	    logBase : logBase,
	    Just    : Elm.Maybe.Just,
	    Nothing : Elm.Maybe.Nothing,
	    maybe   : Elm.Maybe.maybe,
	    map     : Elm.List.map,
	    filter  : Elm.List.filter,
	    head    : Elm.List.head,
	    tail    : Elm.List.tail,
	    last    : Elm.List.last,
	    length  : Elm.List.length,
	    reverse : Elm.List.reverse,
	    foldr   : Elm.List.foldr,
	    foldr1  : Elm.List.foldr1,
	    foldl   : Elm.List.foldl,
	    foldl1  : Elm.List.foldl1,
	    and     : Elm.List.and,
	    or      : Elm.List.or,
	    all     : Elm.List.all,
	    any     : Elm.List.any,
	    sum     : Elm.List.sum,
	    product : Elm.List.product,
	    concat  : Elm.List.concat,
	    concatMap : Elm.List.concatMap,
	    maximum : Elm.List.maximum,
	    minimum : Elm.List.minimum,
	    scanl   : Elm.List.scanl,
	    scanl1  : Elm.List.scanl1,
	    take    : Elm.List.take,
	    drop    : Elm.List.drop,
	    zip     : Elm.List.zip,
	    unzip   : Elm.List.unzip,
	    lift  : Elm.Signal.lift,
	    lift2 : Elm.Signal.lift2,
	    lift3 : Elm.Signal.lift3,
	    lift4 : Elm.Signal.lift4,
	    foldp : Elm.Signal.foldp,
	    foldp1 : Elm.Signal.foldp1,
	    foldp_ : Elm.Signal.foldp_,
	    constant : Elm.Signal.constant,
	    count : Elm.Signal.count,
	    keepIf : Elm.Signal.keepIf,
	    dropIf : Elm.Signal.dropIf,
	    keepWhen : Elm.Signal.keepWhen,
	    dropWhen : Elm.Signal.dropWhen,
	    dropRepeats : Elm.Signal.dropRepeats,
	    sampleOn : Elm.Signal.sampleOn
	    };

}();

(function() {
  var include = function(library) {
    for (var i in library) {
	Elm.Prelude[i] = library[i];
    }
  };
  include (Elm.Graphics.Color);
  include (Elm.Graphics.Text);
  include (Elm.Graphics.Element);

  show = Value.show;

}());
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2012 Google Inc. All Rights Reserved.
 *
 * 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.
 */

function IN_BROWSER() { return typeof vm == "undefined" || ! vm.runInThisContext; }
function IN_NODEJS() { return ! IN_BROWSER(); }
function IN_CHROME_APP() { return window.chrome && window.chrome.runtime && (!! window.chrome.runtime.id) };
function IN_BROWSER_NOT_APP() { return IN_BROWSER() && ! IN_CHROME_APP(); }

var __EXTRA_PROPERTIES__;

var files = [
//  ['ServiceWorker', function() { return window.navigator && navigator.serviceWorker; }],
  [ 'firefox',  function() { return window.navigator && navigator.userAgent.indexOf('Firefox') != -1; }],
  [ 'funcName', function() { return ! Number.name; }],
  [ 'safari',   function() { return window.navigator && navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1; }],
  [ 'internetexplorer',  function() { return ( window.Element && (!('remove' in Element.prototype))); }],
  [ 'node',     IN_NODEJS ],
  [ 'i18n',     IN_BROWSER ],
  'stdlib',
  ['WeakMap',  function() { return ! this['WeakMap']; }],
  'async',
  'parse',
  'event',
  'JSONUtil',
  'XMLUtil',
  'context',
  'JSONParser',
  'TemplateUtil',
  [ 'ChromeEval', IN_CHROME_APP ],
  'FOAM',
  // To use FO, uncomment the next line
  // and comment out all lines from FObject to mm6Misc
  // inclusively
//  'experimental/fo',
//  'experimental/protobuffeatures',
  'FObject',
  'BootstrapModel',
  'mm1Model',
  'mm2Property',
  [ __EXTRA_PROPERTIES__, function() { return __EXTRA_PROPERTIES__ != undefined; } ],
  'mm3Types',
  'mm4Method',
  'mm5Debug',
  'mm6Misc',
  '../js/foam/core/bootstrap/OrDAO',
  [ '../js/foam/core/bootstrap/BrowserFileDAO', IN_BROWSER_NOT_APP ],
  [ '../js/node/dao/ModelFileDAO', IN_NODEJS ],
  '../js/foam/ui/Window',
  'value',
  'view',
  '../js/foam/ui/FoamTagView',
  'cview',
  '../js/foam/grammars/CSS3',
  'HTMLParser',
  'mlang',
  'mlang1',
  'mlang2',
  'glang',
  'QueryParser',
  'oam',
  'visitor',
  'messaging',
//  '../js/foam/dao/ProxyDAO',
  'dao',
  'arrayDAO',
  'index',
  'models',
  'oauth',
  [ 'ModelDAO', IN_BROWSER_NOT_APP ],
  [ '../js/foam/core/bootstrap/ChromeAppFileDAO', IN_CHROME_APP ],
  [ 'ChromeAppModelDAO', IN_CHROME_APP ],
  [ 'NodeModelDAO', IN_NODEJS ]
];
<commit_msg>Fix for EXTRA_PROPERTIES breaking BuildApp.<commit_after>/**
 * @license
 * Copyright 2012 Google Inc. All Rights Reserved.
 *
 * 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.
 */

function IN_BROWSER() { return typeof vm == "undefined" || ! vm.runInThisContext; }
function IN_NODEJS() { return ! IN_BROWSER(); }
function IN_CHROME_APP() { return window.chrome && window.chrome.runtime && (!! window.chrome.runtime.id) };
function IN_BROWSER_NOT_APP() { return IN_BROWSER() && ! IN_CHROME_APP(); }

var __EXTRA_PROPERTIES__;

var files = [
//  ['ServiceWorker', function() { return window.navigator && navigator.serviceWorker; }],
  [ 'firefox',  function() { return window.navigator && navigator.userAgent.indexOf('Firefox') != -1; }],
  [ 'funcName', function() { return ! Number.name; }],
  [ 'safari',   function() { return window.navigator && navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1; }],
  [ 'internetexplorer',  function() { return ( window.Element && (!('remove' in Element.prototype))); }],
  [ 'node',     IN_NODEJS ],
  [ 'i18n',     IN_BROWSER ],
  'stdlib',
  ['WeakMap',  function() { return ! this['WeakMap']; }],
  'async',
  'parse',
  'event',
  'JSONUtil',
  'XMLUtil',
  'context',
  'JSONParser',
  'TemplateUtil',
  [ 'ChromeEval', IN_CHROME_APP ],
  'FOAM',
  // To use FO, uncomment the next line
  // and comment out all lines from FObject to mm6Misc
  // inclusively
//  'experimental/fo',
//  'experimental/protobuffeatures',
  'FObject',
  'BootstrapModel',
  'mm1Model',
  'mm2Property',
  [ __EXTRA_PROPERTIES__, function() { return __EXTRA_PROPERTIES__; } ],
  'mm3Types',
  'mm4Method',
  'mm5Debug',
  'mm6Misc',
  '../js/foam/core/bootstrap/OrDAO',
  [ '../js/foam/core/bootstrap/BrowserFileDAO', IN_BROWSER_NOT_APP ],
  [ '../js/node/dao/ModelFileDAO', IN_NODEJS ],
  '../js/foam/ui/Window',
  'value',
  'view',
  '../js/foam/ui/FoamTagView',
  'cview',
  '../js/foam/grammars/CSS3',
  'HTMLParser',
  'mlang',
  'mlang1',
  'mlang2',
  'glang',
  'QueryParser',
  'oam',
  'visitor',
  'messaging',
//  '../js/foam/dao/ProxyDAO',
  'dao',
  'arrayDAO',
  'index',
  'models',
  'oauth',
  [ 'ModelDAO', IN_BROWSER_NOT_APP ],
  [ '../js/foam/core/bootstrap/ChromeAppFileDAO', IN_CHROME_APP ],
  [ 'ChromeAppModelDAO', IN_CHROME_APP ],
  [ 'NodeModelDAO', IN_NODEJS ]
];
<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */
var util = require('util')
  , StanzaError = require('junction').StanzaError;

/**
 * Parse retract requests.
 *
 * This middleware parses requests to delete an item from a node.
 * `stanza.action` indicates the action, in this case always _retract_.
 * `stanza.node` indicates the node from which the entity wishes to delete the
 * item.  `stanza.itemID` indicates the item ID of the item to delete.
 *
 * Junction/PubSub activates this middleware automatically.  Your program should
 * not need to use it manually.
 *
 * References:
 * - [XEP-0060: Publish-Subscribe](http://xmpp.org/extensions/xep-0060.html#publisher-delete)
 *
 * @return {Function}
 * @api private
 */
module.exports = function retractParser() {

  return function retractParser(stanza, next) {
    if (!stanza.is('iq')) { return next(); }
    var pubsub = stanza.getChild('pubsub', 'http://jabber.org/protocol/pubsub');
    if (!pubsub) { return next(); }
    var retract = pubsub.getChild('retract');
    if (!retract) { return next(); }
    var item = retract.getChild('item');

    if (stanza.type != 'set') {
      return next(new StanzaError("Retract request must be an IQ-set stanza.", 'modify', 'bad-request'));
    }
    if (!retract.attrs.node) {
      return next(new StanzaError("Retract request must possess a 'node' attribute.", 'modify', 'bad-request'));
    }
    if (!item) {
      return next(new StanzaError("Retract request must contain one 'item' element.", 'modify', 'bad-request'));
    }
    if (!item.attrs.id) {
      return next(new StanzaError("Retract 'item' element must possess an 'id' attribute.", 'modify', 'bad-request'));
    }

    stanza.action = 'retract';
    stanza.node = retract.attrs.node;
    stanza.itemID = item.attrs.id;
    stanza.notify = false;
    if (retract.attrs.notify === 'true' || retract.attrs.notify === '1') {
      stanza.notify = true;
    }
    next();
  }
}
<commit_msg>Document stanza.notify property set by retractParser middleware.<commit_after>/**
 * Module dependencies.
 */
var util = require('util')
  , StanzaError = require('junction').StanzaError;

/**
 * Parse retract requests.
 *
 * This middleware parses requests to delete an item from a node.
 * `stanza.action` indicates the action, in this case always _retract_.
 * `stanza.node` indicates the node from which the entity wishes to delete the
 * item.  `stanza.itemID` indicates the item ID of the item to delete.
 * `stanza.notify` is set to `true` if subscribers should be notified of the
 * deletion, `false` otherwise.
 *
 * Junction/PubSub activates this middleware automatically.  Your program should
 * not need to use it manually.
 *
 * References:
 * - [XEP-0060: Publish-Subscribe](http://xmpp.org/extensions/xep-0060.html#publisher-delete)
 *
 * @return {Function}
 * @api private
 */
module.exports = function retractParser() {

  return function retractParser(stanza, next) {
    if (!stanza.is('iq')) { return next(); }
    var pubsub = stanza.getChild('pubsub', 'http://jabber.org/protocol/pubsub');
    if (!pubsub) { return next(); }
    var retract = pubsub.getChild('retract');
    if (!retract) { return next(); }
    var item = retract.getChild('item');

    if (stanza.type != 'set') {
      return next(new StanzaError("Retract request must be an IQ-set stanza.", 'modify', 'bad-request'));
    }
    if (!retract.attrs.node) {
      return next(new StanzaError("Retract request must possess a 'node' attribute.", 'modify', 'bad-request'));
    }
    if (!item) {
      return next(new StanzaError("Retract request must contain one 'item' element.", 'modify', 'bad-request'));
    }
    if (!item.attrs.id) {
      return next(new StanzaError("Retract 'item' element must possess an 'id' attribute.", 'modify', 'bad-request'));
    }

    stanza.action = 'retract';
    stanza.node = retract.attrs.node;
    stanza.itemID = item.attrs.id;
    stanza.notify = false;
    if (retract.attrs.notify === 'true' || retract.attrs.notify === '1') {
      stanza.notify = true;
    }
    next();
  }
}
<|endoftext|>


<commit_before>/**
 * GitHub popuplar projects followers indexer.
 * Usage:
 *   node followersIndexer repositories.json followers --tokens="A,B,C"
 *
 * Where:
 *   - repositories.json: file generated by repoIndexer.js
 *   - followers: leveldb name where to save indexed followers
 */

var tokens = require('./lib/tokens')();
var fs = require('fs');

if (tokens.enabled === 0) {
  printTokenHelp();
  return -1;
}

var githubClient = require('./lib/ghclient')(tokens);
var repositoriesFileName = process.argv[2];
var inputArgumentsValid = fs.existsSync(repositoriesFileName);

if (!inputArgumentsValid) {
  printInputArgumentsHelp();
  return -2;
}

var allRepositories = getIndexedRepositories(repositoriesFileName);
var processedRepositoriesName = getProcessedRepositoriesFileName(process.argv[3], repositoriesFileName);
var db = require('./lib/ldb')(processedRepositoriesName);

db.getAllKeys()
  .then(function (processedRepositoriesKeys) {
    var processedRepositories = {};
    processedRepositoriesKeys.forEach(function (key) { processedRepositories[key] = 1; });

    var remainingRepositories = getRemainingRepositories(allRepositories, processedRepositories);
    printStats(allRepositories, processedRepositories, remainingRepositories);

    var indexFollowers = require('./lib/indexFollowers');
    indexFollowers(remainingRepositories, db, githubClient);
  });

function printTokenHelp() {
  [
    'Github access token is not present in environment variables',
    'Go to https://github.com/settings/applications and click "Create new token"',
    'Pass tokens as a comma-separated argument --tokens="A,B,C"'
  ].forEach(function (line) { console.log(line); });
}

function printInputArgumentsHelp() {
  [
    'GitHub popuplar projects followers indexer.',
    'Usage:',
    '  node followersIndexer repositories.json followers --tokens="A,B,C"',
    '',
    'Where: ',
    ' - repositories.json: file generated by repoIndexer.js',
    ' - followers: leveldb name where to save indexed followers'
  ].forEach(function (line) { console.log(line); });
}

function printStats(allRepositories, processedRepositories, remainingRepositories) {
  console.log('Statistics:');
  console.log('  Total:', allRepositories.length);
  console.log('  Processed:', Object.keys(processedRepositories).length);
  console.log('  Remaining:', remainingRepositories.length);
}

function readJson(fileName) {
  return JSON.parse(fs.readFileSync(fileName, 'utf8'));
}

function getIndexedRepositories(repositoriesFileName) {
  console.log('Reading repositories file', repositoriesFileName);
  var repositories = readJson(repositoriesFileName);
  console.log('Read', repositories.length, 'repositories');
  return repositories;
}

function getRemainingRepositories(allRepositories, indexedRepositories) {
  return allRepositories.filter(function (x) { return !indexedRepositories[x.name]; });
}

function getProcessedRepositoriesFileName(followersFileName, repositoriesFileName) {
  if (fs.existsSync(followersFileName)) {
    console.log('Indexed followers:', followersFileName);
    return followersFileName;
  }

  console.log('Indexed followers database is not found.');
  var path = require('path');
  var absoluteRepositoriesFileName = path.resolve(repositoriesFileName);
  var repoPath = path.dirname(absoluteRepositoriesFileName);
  followersFileName = path.join(repoPath, path.basename(absoluteRepositoriesFileName, '.json') + 'Followers');
  console.log('Trying to use', followersFileName, 'as indexed followers db.');
  return followersFileName;
}
<commit_msg>No need to check file name anymore<commit_after>/**
 * GitHub popuplar projects followers indexer.
 * Usage:
 *   node followersIndexer repositories.json followers --tokens="A,B,C"
 *
 * Where:
 *   - repositories.json: file generated by repoIndexer.js
 *   - followers: leveldb name where to save indexed followers
 */

var tokens = require('./lib/tokens')();
var fs = require('fs');

if (tokens.enabled === 0) {
  printTokenHelp();
  return -1;
}

var githubClient = require('./lib/ghclient')(tokens);
var repositoriesFileName = process.argv[2];
var inputArgumentsValid = fs.existsSync(repositoriesFileName);

if (!inputArgumentsValid) {
  printInputArgumentsHelp();
  return -2;
}

var allRepositories = getIndexedRepositories(repositoriesFileName);
var processedRepositoriesName = process.argv[3];
var db = require('./lib/ldb')(processedRepositoriesName);

db.getAllKeys()
  .then(function (processedRepositoriesKeys) {
    var processedRepositories = {};
    processedRepositoriesKeys.forEach(function (key) { processedRepositories[key] = 1; });

    var remainingRepositories = getRemainingRepositories(allRepositories, processedRepositories);
    printStats(allRepositories, processedRepositories, remainingRepositories);

    var indexFollowers = require('./lib/indexFollowers');
    indexFollowers(remainingRepositories, db, githubClient);
  });

function printTokenHelp() {
  [
    'Github access token is not present in environment variables',
    'Go to https://github.com/settings/applications and click "Create new token"',
    'Pass tokens as a comma-separated argument --tokens="A,B,C"'
  ].forEach(function (line) { console.log(line); });
}

function printInputArgumentsHelp() {
  [
    'GitHub popuplar projects followers indexer.',
    'Usage:',
    '  node followersIndexer repositories.json followers --tokens="A,B,C"',
    '',
    'Where: ',
    ' - repositories.json: file generated by repoIndexer.js',
    ' - followers: leveldb name where to save indexed followers'
  ].forEach(function (line) { console.log(line); });
}

function printStats(allRepositories, processedRepositories, remainingRepositories) {
  console.log('Statistics:');
  console.log('  Total:', allRepositories.length);
  console.log('  Processed:', Object.keys(processedRepositories).length);
  console.log('  Remaining:', remainingRepositories.length);
}

function readJson(fileName) {
  return JSON.parse(fs.readFileSync(fileName, 'utf8'));
}

function getIndexedRepositories(repositoriesFileName) {
  console.log('Reading repositories file', repositoriesFileName);
  var repositories = readJson(repositoriesFileName);
  console.log('Read', repositories.length, 'repositories');
  return repositories;
}

function getRemainingRepositories(allRepositories, indexedRepositories) {
  return allRepositories.filter(function (x) { return !indexedRepositories[x.name]; });
}
<|endoftext|>


<commit_before>/**
 * @file EditableField component
 * @author chao(chao.zhang@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';

import TextField from '../TextField/TextField';
import TipProvider from '../TipProvider';

import Event from '../_vendors/Event';

export default class EditableField extends Component {

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.state = {
            hide: true,
            text: props.value,
            changeText: props.value
        };

        this.onInputChange = ::this.onInputChange;
        this.showInput = ::this.showInput;
        this.downHandle = ::this.downHandle;
        this.triggerElement = ::this.triggerElement;
        this.keyDownHandle = ::this.keyDownHandle;
        this.finishEdit = ::this.finishEdit;

    }

    triggerElement(el, targetEl) {
        while (el) {
            if (el == targetEl) {
                return true;
            }
            el = el.parentNode;
        }
        return false;
    }

    onInputChange(text) {
        this.setState({
            changeText: text
        });
    }

    /**
     * 显示input并获得焦点
     */
    showInput(e) {
        this.setState({
            hide: false
        }, () => {
            this.refs.textField.refs.input.focus();
            this.props.onEditStart && this.props.onEditStart(e);
        });
    }

    /**
     * 通过坐标判断是否在input区域内点击，防止点击‘清空’时，input消失
     */
    downHandle(ev) {
        let oEvent = ev || event;
        if (this.state.hide === false && (!this.triggerElement(oEvent.srcElement, this.refs.editableField))) {
            this.finishEdit(ev);
        }
    }

    finishEdit(ev) {
        const change = this.state.text !== this.state.changeText;

        if (change && this.props.beforeChange && this.props.beforeChange(this.state.changeText) === false) {
            ev.preventDefault();
            return;
        }

        this.setState({
            hide: true,
            text: this.state.changeText
        }, () => {
            this.props.onEditEnd && this.props.onEditEnd(ev);
            change && this.props.onChange && this.props.onChange(this.state.text);
        });
    }

    keyDownHandle(ev) {
        const {regExp} = this.props;

        if (regExp && !regExp.test(ev.key)) {
            event.preventDefault();
            return false;
        }
        return true;
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.value !== this.state.text) {
            this.setState({
                text: nextProps.value,
                changeText: nextProps.value
            });
        }
        if (nextProps.disabled === true && nextProps.disabled !== this.props.disabled) {
            this.setState({
                hide: true,
                changeText: this.state.text
            }, () => {
                this.props.onEditEnd && this.props.onEditEnd();
            });
        }
    }

    componentDidMount() {
        Event.addEvent(document, 'mousedown', this.downHandle);
        Event.addEvent(document, 'keydown', this.keyDownHandle);
    }

    componentWillUnmount() {
        Event.removeEvent(document, 'mousedown', this.downHandle);
        Event.removeEvent(document, 'keydown', this.keyDownHandle);
    }

    render() {

        const {
            children, className, style, name, disabled, tip, tipPosition, title,
            onMouseDown, onTouchTap, showModal
        } = this.props;

        return (
            <TipProvider text={tip}
                         position={tipPosition}>
                <div ref="editableField"
                     className={`editable-field ${className}`}
                     style={style}
                     title={`${disabled ? '' : title}`}
                     onMouseDown={onMouseDown}
                     onTouchTap={onTouchTap}>

                    <span className={`editable-field-text`}
                          disabled={disabled}>{this.state.text}

                    {
                        this.state.hide === true
                            ?
                            {this.state.text}
                            : <TextField ref="textField"
                                         className={'editable-field-input'}
                                         value={this.state.changeText}
                                         onChange={this.onInputChange}/>
                    }

                    <input type="hidden"
                           value={this.state.text}
                           readOnly
                           name={name}/>

                    {
                        showModal && !this.state.hide
                            ?

                            :
                            null
                    }

                    {children}

            </TipProvider>
        );
    }
};

EditableField.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * The value of the editableField.
     */
    value: PropTypes.string,

    /**
     * The name of the editableField.
     */
    name: PropTypes.string,

    /**
     * The title of the editableField.
     */
    title: PropTypes.string,

    /**
     * The tip of the editableField.
     */
    tip: PropTypes.string,

    /**
     * The tipPosition of the editableField.
     */
    tipPosition: PropTypes.string,

    /**
     * The regular expression of the input.
     */
    regExp: PropTypes.object,

    /**
     * If true, the input is disabled.
     */
    disabled: PropTypes.bool,

    /**
     * If true, the shadow is under the input.
     */
    showModal: PropTypes.bool,

    onMouseDown: PropTypes.func,

    /**
     * Callback function when touch the editableField.
     */
    onTouchTap: PropTypes.func,

    /**
     * Callback function fired when the editableField blur.
     */
    onBlur: PropTypes.func,

    /**
     * Callback function fired when the editableField change.
     */
    onChange: PropTypes.func,

    /**
     * Callback function fired when start editableField change.
     */
    onEditStart: PropTypes.func,

    /**
     * Callback function fired when end editableField change.
     */
    onEditEnd: PropTypes.func,

    /**
     * Callback function fired when before editableField change.
     */
    beforeChange: PropTypes.func

};

EditableField.defaultProps = {

    className: '',
    style: null,

    title: '',
    value: 'text',
    name: '',
    disabled: false,
    showModal: false

};<commit_msg>editable field<commit_after>/**
 * @file EditableField component
 * @author chao(chao.zhang@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';

import TextField from '../TextField/TextField';
import TipProvider from '../TipProvider';

import Event from '../_vendors/Event';

export default class EditableField extends Component {

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.state = {
            hide: true,
            text: props.value,
            changeText: props.value
        };

        this.onInputChange = ::this.onInputChange;
        this.showInput = ::this.showInput;
        this.downHandle = ::this.downHandle;
        this.triggerElement = ::this.triggerElement;
        this.keyDownHandle = ::this.keyDownHandle;
        this.finishEdit = ::this.finishEdit;

    }

    triggerElement(el, targetEl) {
        while (el) {
            if (el == targetEl) {
                return true;
            }
            el = el.parentNode;
        }
        return false;
    }

    onInputChange(text) {
        this.setState({
            changeText: text
        });
    }

    /**
     * 显示input并获得焦点
     */
    showInput(e) {
        this.setState({
            hide: false
        }, () => {
            this.refs.textField.refs.input.focus();
            this.props.onEditStart && this.props.onEditStart(e);
        });
    }

    /**
     * 通过坐标判断是否在input区域内点击，防止点击‘清空’时，input消失
     */
    downHandle(ev) {
        let oEvent = ev || event;
        if (this.state.hide === false && (!this.triggerElement(oEvent.target, this.refs.editableField))) {
            this.finishEdit(ev);
        }
    }

    finishEdit(ev) {
        const change = this.state.text !== this.state.changeText;

        if (change && this.props.beforeChange && this.props.beforeChange(this.state.changeText) === false) {
            ev.preventDefault();
            return;
        }

        this.setState({
            hide: true,
            text: this.state.changeText
        }, () => {
            this.props.onEditEnd && this.props.onEditEnd(ev);
            change && this.props.onChange && this.props.onChange(this.state.text);
        });
    }

    keyDownHandle(ev) {
        const {regExp} = this.props;

        if (regExp && !regExp.test(ev.key)) {
            event.preventDefault();
            return false;
        }
        return true;
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.value !== this.state.text) {
            this.setState({
                text: nextProps.value,
                changeText: nextProps.value
            });
        }
        if (nextProps.disabled === true && nextProps.disabled !== this.props.disabled) {
            this.setState({
                hide: true,
                changeText: this.state.text
            }, () => {
                this.props.onEditEnd && this.props.onEditEnd();
            });
        }
    }

    componentDidMount() {
        Event.addEvent(document, 'mousedown', this.downHandle);
        Event.addEvent(document, 'keydown', this.keyDownHandle);
    }

    componentWillUnmount() {
        Event.removeEvent(document, 'mousedown', this.downHandle);
        Event.removeEvent(document, 'keydown', this.keyDownHandle);
    }

    render() {

        const {
            children, className, style, name, disabled, tip, tipPosition, title,
            onMouseDown, onTouchTap, showModal
        } = this.props;

        return (
            <TipProvider text={tip}
                         position={tipPosition}>
                <div ref="editableField"
                     className={`editable-field ${className}`}
                     style={style}
                     title={`${disabled ? '' : title}`}
                     onMouseDown={onMouseDown}
                     onTouchTap={onTouchTap}>

                    <span className={`editable-field-text`}
                          disabled={disabled}>{this.state.text}

                    {
                        this.state.hide === true
                            ?
                            {this.state.text}
                            : <TextField ref="textField"
                                         className={'editable-field-input'}
                                         value={this.state.changeText}
                                         onChange={this.onInputChange}/>
                    }

                    <input type="hidden"
                           value={this.state.text}
                           readOnly
                           name={name}/>

                    {
                        showModal && !this.state.hide
                            ?

                            :
                            null
                    }

                    {children}

            </TipProvider>
        );
    }
};

EditableField.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * The value of the editableField.
     */
    value: PropTypes.string,

    /**
     * The name of the editableField.
     */
    name: PropTypes.string,

    /**
     * The title of the editableField.
     */
    title: PropTypes.string,

    /**
     * The tip of the editableField.
     */
    tip: PropTypes.string,

    /**
     * The tipPosition of the editableField.
     */
    tipPosition: PropTypes.string,

    /**
     * The regular expression of the input.
     */
    regExp: PropTypes.object,

    /**
     * If true, the input is disabled.
     */
    disabled: PropTypes.bool,

    /**
     * If true, the shadow is under the input.
     */
    showModal: PropTypes.bool,

    onMouseDown: PropTypes.func,

    /**
     * Callback function when touch the editableField.
     */
    onTouchTap: PropTypes.func,

    /**
     * Callback function fired when the editableField blur.
     */
    onBlur: PropTypes.func,

    /**
     * Callback function fired when the editableField change.
     */
    onChange: PropTypes.func,

    /**
     * Callback function fired when start editableField change.
     */
    onEditStart: PropTypes.func,

    /**
     * Callback function fired when end editableField change.
     */
    onEditEnd: PropTypes.func,

    /**
     * Callback function fired when before editableField change.
     */
    beforeChange: PropTypes.func

};

EditableField.defaultProps = {

    className: '',
    style: null,

    title: '',
    value: 'text',
    name: '',
    disabled: false,
    showModal: false

};<|endoftext|>


<commit_before>var OpenInChrome = {
    init: function() {
        var keyset = document.getElementById("mainKeyset");
        // TODO Custom keybindings
        var key = document.createElement("key");
        key.setAttribute("id", "OpenInChrome");
        key.setAttribute("key", 'o');
        key.setAttribute("oncommand", "OpenInChrome.go();");
        key.setAttribute("modifiers", "accel shift");
        keyset.appendChild(key);
        OpenInChrome.chromePath();
    },

    chromePath: function() {
        var xrt = Components.classes["@mozilla.org/xre/app-info;1"].getService(Components.interfaces.nsIXULRuntime);
        if (xrt.OS == "Darwin") {
            return ['/usr/bin/open', '-a', 'Google Chrome'];
        } else {
            // TODO Linux support
            return null;
        }
    },

    go: function() {
        var url = document.location.href;
        var args = OpenInChrome.chromePath();
        if (url && args) {
            args.push(window.content.location.href);
            var cmd = args.shift()
            var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
            var process = window.Components.classes['@mozilla.org/process/util;1'].createInstance(Components.interfaces.nsIProcess);
            file.initWithPath(cmd);
            process.init(file)
            process.run(false, args, args.length);
        }
    }
}

window.addEventListener("load", OpenInChrome.init, false);
<commit_msg>Linux.<commit_after>var OpenInChrome = {
    init: function() {
        var keyset = document.getElementById("mainKeyset");
        var key = document.createElement("key");
        key.setAttribute("id", "OpenInChrome");
        key.setAttribute("key", 'o');
        key.setAttribute("oncommand", "OpenInChrome.go();");
        key.setAttribute("modifiers", "accel shift");
        keyset.appendChild(key);
        OpenInChrome.chromePath();
    },

    chromePath: function() {
        var xrt = Components.classes["@mozilla.org/xre/app-info;1"].getService(Components.interfaces.nsIXULRuntime);
        if (xrt.OS == "Darwin") {
            return ['/usr/bin/open', '-a', 'Google Chrome'];
        } else {
            return ['google-chrome'];
        }
    },

    go: function() {
        var url = document.location.href;
        var args = OpenInChrome.chromePath();
        if (url && args) {
            args.push(window.content.location.href);
            var cmd = args.shift()
            var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
            var process = window.Components.classes['@mozilla.org/process/util;1'].createInstance(Components.interfaces.nsIProcess);
            file.initWithPath(cmd);
            process.init(file)
            process.run(false, args, args.length);
        }
    }
}

window.addEventListener("load", OpenInChrome.init, false);
<|endoftext|>