<commit_before>/**
 * @Author: liushaobo2005@163.com
 * @Date: 2017.5.12 上午 11:08
 * @Desc: 公共组件 - LoggerContainer
 * @Name: LoggerContainer.js
 * @LifeCycle：https://github.com/kinshasa/react-native-qatest
 */

import React, {Component, PropTypes} from "react";
import {ScrollView, StyleSheet, View, Text, TouchableNativeFeedback,InteractionManager} from "react-native";
import JSONTree from "react-native-json-tree";
import TitleBar from "../../../components/bar/TitleBar";
import FlatList from "../../../components/listview/flatList/FlatList";
import LoadingView from "../../../components/view/LoadingView";

export default class LoggerContainer extends Component {

    static propTypes = {
        style: View.propTypes.style,
        account: PropTypes.number,
        name: PropTypes.string,
        isTrue: PropTypes.bool,
        callback: PropTypes.func,
    };

    static defaultProps = {
        data: {}
    };

    constructor(props, context) {
        console.log("LoggerContainer constructor()");
        super(props, context);
        this.state = {data: []};
    }

    /**
     * 当前组件渲染次数
     * @type {number}
     */
    count = 0;

    componentWillMount() {
        console.log("LoggerContainer::componentWillMount()");

    }

    componentDidMount() {
        InteractionManager.runAfterInteractions(() => {
            // ...耗时较长的同步的任务...
            this.initData()
        });
    }

    componentWillReceiveProps(newProps) {
        console.log("LoggerContainer::componentWillReceiveProps()", newProps);
    }

    shouldComponentUpdate(nextProps, nextState) {
        let isUpdate = (this.props != nextProps) || (this.state != nextState);
        console.log("LoggerContainer::shouldComponentUpdate()", isUpdate);
        return isUpdate;
    }

    componentWillUpdate(nextProps, nextState) {
        console.log("LoggerContainer::componentWillUpdate()", new Date());
    }

    componentDidUpdate(prevProps, prevState) {
        console.log("LoggerContainer::componentDidUpdate()", new Date());
    }

    componentWillUnmount() {
        console.log("LoggerContainer::componentWillUnmount()");
    }

    shouldItemUpdate = (prev, next) => {
        /**
         * Note that this does not check state.horizontal or state.fixedheight
         * because we blow away the whole list by changing the key in those cases.
         * Make sure that you do the same in your code, or incorporate all relevant
         * data into the item data, or skip this optimization entirely.
         */
        return prev.item !== next.item;
    };

    render() {
        this.count++;
        console.log("LoggerContainer::render() count:", this.count);
        return (
            <View style={LoggerContainerStyles.container}>
                <TitleBar label="日志系统"/>
                {this.renderHeader()}
                <FlatList
                    legacyImplementation={false}
                    shouldItemUpdate={this.shouldItemUpdate}
                    refreshing={false}
                    data={this.state.data}
                    keyExtractor={(item: ItemT, index: number) => {
                        return index
                    }}
                    renderItem={({item: ItemT, index: number}) => this.renderItem(ItemT, number)}
                />
                <LoadingView
                    visible={false} ref={(ref) => {
                    this.loadingView = ref
                }}/>
            </View>
        );
    }

    renderHeader = () => {
        return (
            <View style={LoggerContainerStyles.headerView}>
                <TouchableNativeFeedback onPress={() => this.clear()}>
                    <View style={LoggerContainerStyles.headerViewBtn}>
                        <Text style={LoggerContainerStyles.headerViewText}>清空缓存</Text>
                    </View>
                </TouchableNativeFeedback>
                <TouchableNativeFeedback onPress={() => this.add()}>
                    <View style={LoggerContainerStyles.headerViewBtn}>
                        <Text>新增一条数据对象</Text>
                    </View>
                </TouchableNativeFeedback>
                <TouchableNativeFeedback >
                    <View style={LoggerContainerStyles.headerViewBtn}>
                        <Text>删除一条数据对象</Text>
                    </View>
                </TouchableNativeFeedback>
            </View>
        )
    };

    renderItem = (item: ItemT, index: number) => {
        console.log("LoggerContainer::renderItem() item:", item);
        return (
            <View
                style={{marginLeft: 10, marginRight: 10, paddingBottom: 10, borderBottomWidth: 1, borderColor: '#eee'}}>
                <ScrollView horizontal contentContainerStyle={{flex: 1}}>
                    <JSONTree hideRoot data={item}/>
                </ScrollView>
            </View>
        );
    };

    async initData() {
        let data = await LocalStorage.getAllDataForKey('logger');
        this.setState({data})
    }

    async clear() {
        await Loggers.c();
        await this.reStore();
    }

    async add(data = {key: 'key1', value: 'value1'}) {
        await Loggers.s(data);
        await this.reStore();
    }

    async reStore() {
        let data = await Loggers.g();
        this.setState({data});
    }
}

const LoggerContainerStyles = StyleSheet.create({
    container: {
        flex: 1
    },
    scrollView: {
        backgroundColor: '#888',
        width: getWidth(),
        height: getHeight(),
    },
    headerView: {
        flexDirection: 'row',
        marginTop: 20,
        marginBottom: 10
    },
    headerViewBtn: {
        flex: 1,
        backgroundColor: 'green',
        margin: 3,
        paddingTop: 15,
        paddingBottom: 15,
        alignItems:'center',
    },
    headerViewText:{
    }
});<commit_msg>add android-pay-module.@liushaobo2005@163.com<commit_after>/**
 * @Author: liushaobo2005@163.com
 * @Date: 2017.5.12 上午 11:08
 * @Desc: 公共组件 - LoggerContainer
 * @Name: LoggerContainer.js
 * @LifeCycle：https://github.com/kinshasa/react-native-qatest
 */

import React, {Component, PropTypes} from "react";
import {ScrollView, StyleSheet, View, Text, TouchableNativeFeedback, InteractionManager} from "react-native";
import JSONTree from "react-native-json-tree";
import TitleBar from "../../../components/bar/TitleBar";
import FlatList from "../../../components/listview/flatList/FlatList";
import LoadingView from "../../../components/view/LoadingView";

export default class LoggerContainer extends Component {

    static propTypes = {
        style: View.propTypes.style,
        account: PropTypes.number,
        name: PropTypes.string,
        isTrue: PropTypes.bool,
        callback: PropTypes.func,
    };

    static defaultProps = {
        data: {}
    };

    constructor(props, context) {
        console.log("LoggerContainer constructor()");
        super(props, context);
        this.state = {data: []};
    }

    /**
     * 当前组件渲染次数
     * @type {number}
     */
    count = 0;

    componentWillMount() {
        console.log("LoggerContainer::componentWillMount()");

    }

    componentDidMount() {
        InteractionManager.runAfterInteractions(() => {
            // ...耗时较长的同步的任务...
            this.initData()
        });
    }

    componentWillReceiveProps(newProps) {
        console.log("LoggerContainer::componentWillReceiveProps()", newProps);
    }

    shouldComponentUpdate(nextProps, nextState) {
        let isUpdate = (this.props != nextProps) || (this.state != nextState);
        console.log("LoggerContainer::shouldComponentUpdate()", isUpdate);
        return isUpdate;
    }

    componentWillUpdate(nextProps, nextState) {
        console.log("LoggerContainer::componentWillUpdate()", new Date());
    }

    componentDidUpdate(prevProps, prevState) {
        console.log("LoggerContainer::componentDidUpdate()", new Date());
    }

    componentWillUnmount() {
        console.log("LoggerContainer::componentWillUnmount()");
    }

    shouldItemUpdate = (prev, next) => {
        /**
         * Note that this does not check state.horizontal or state.fixedheight
         * because we blow away the whole list by changing the key in those cases.
         * Make sure that you do the same in your code, or incorporate all relevant
         * data into the item data, or skip this optimization entirely.
         */
        return prev.item !== next.item;
    };

    render() {
        this.count++;
        console.log("LoggerContainer::render() count:", this.count);
        return (
            <View style={LoggerContainerStyles.container}>
                <TitleBar label="日志系统"/>
                {this.renderHeader()}
                <FlatList
                    legacyImplementation={false}
                    showsVerticalScrollIndicator={false}
                    shouldItemUpdate={this.shouldItemUpdate}
                    refreshing={false}
                    data={this.state.data}
                    keyExtractor={(item, index) => index}
                    renderItem={({item, index}) => this.renderItem(item, index)}
                />
                <LoadingView
                    visible={!this.state.data || this.state.data.length<=0}
                    ref="loading"/>
            </View>
        );
    }

    renderHeader() {
        return (
            <View style={LoggerContainerStyles.headerView}>
                <TouchableNativeFeedback onPress={() => this.clear()}>
                    <View style={LoggerContainerStyles.headerViewBtn}>
                        <Text style={LoggerContainerStyles.headerViewText}>清空缓存</Text>
                    </View>
                </TouchableNativeFeedback>
                <TouchableNativeFeedback onPress={() => this.add()}>
                    <View style={LoggerContainerStyles.headerViewBtn}>
                        <Text style={LoggerContainerStyles.headerViewText}>新增数据</Text>
                    </View>
                </TouchableNativeFeedback>
                <TouchableNativeFeedback >
                    <View style={LoggerContainerStyles.headerViewBtn}>
                        <Text style={LoggerContainerStyles.headerViewText}>删除数据</Text>
                    </View>
                </TouchableNativeFeedback>
            </View>
        )
    }

    renderItem(item, index) {
        console.log("LoggerContainer::renderItem() item:", item);
        return (
            <ScrollView key={index} horizontal contentContainerStyle={LoggerContainerStyles.scrollView}>

                <JSONTree ref={'tree' + index} hideRoot data={item}/>
                <TouchableNativeFeedback onPress={() => this.togoExpend('tree' + index)}>
                    <View style={LoggerContainerStyles.rowViewBtn}>
                        <Text style={LoggerContainerStyles.rowViewText}>+</Text>
                    </View>
                </TouchableNativeFeedback>
            </ScrollView>
        );
    }

    async initData() {
        let data = await LocalStorage.getAllDataForKey('logger');
        this.setState({data})
    }

    async clear() {
        await Loggers.c();
        await this.reStore();
    }

    async add(data = {key: 'key1', value: 'value1'}) {
        await Loggers.s(data);
        await this.reStore();
    }

    async reStore() {
        let data = await Loggers.g();
        this.setState({data});
    }

    togoExpend(name) {
        if (this.refs[name]) {
            console.log(name);
        }
    }
}

const LoggerContainerStyles = StyleSheet.create({
    container: {
        flex: 1
    },
    scrollView: {
        padding: 10,
        minWidth: getWidth(),
        borderBottomWidth: 1,
        borderColor: '#ccc',
        backgroundColor: '#eee',
    },
    headerView: {
        flexDirection: 'row',
        marginTop: 20,
        marginBottom: 10
    },
    headerViewBtn: {
        flex: 1,
        backgroundColor: 'green',
        margin: 3,
        paddingTop: 15,
        paddingBottom: 15,
        alignItems: 'center',
    },
    headerViewText: {color: '#eee', fontSize: 14, fontWeight: 'bold'},
    rowViewBtn: {
        position: 'absolute',
        right: 10,
        top: 10,
        borderRadius: 10,
        backgroundColor: '#fff',
        borderColor: '#eee',
        borderWidth: StyleSheet.hairlineWidth,
        width: 20,
        height: 20,
        alignItems: 'center',
        justifyContent: 'center'
    },
    rowViewText: {color: '#999', fontSize: 16, fontWeight: 'bold'},
});<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */
 /* eslint-env node */

'use strict';
// This is a basic test file for use with testling.
// The test script language comes from tape.
var test = require('tape');

var webdriver = require('selenium-webdriver');
var seleniumHelpers = require('webrtc-utilities').seleniumLib;

test('Audio-only sample codec preference', function(t) {
  if (process.env.BROWSER === 'firefox') {
    t.pass('Firefox not supported yet');
    t.end();
    return;
  }
  var trackId;
  var driver = seleniumHelpers.buildDriver();

  driver.get((process.env.BASEURL ? process.env.BASEURL :
      ('file://' + process.cwd())) +
      '/src/content/peerconnection/audio/index.html');
  var codecs = ['opus', 'ISAC', 'G722', 'PCMU'];

  var last;
  codecs.forEach(function(codecName) {
    last = driver.findElement(webdriver.By.css(
        '#codec>option[value="' + codecName + '"]'))
    .click()
    .then(function() {
      return driver.findElement(webdriver.By.id('callButton')).click();
    })
    .then(function() {
      return driver.wait(function() {
        return driver.executeScript(
            'return pc2 && pc2.iceConnectionState === \'connected\';');
      }, 30 * 1000);
    })
    .then(function() {
      return driver.executeScript('return localStream.getAudioTracks()[0].id;');
    })
    .then(function(id) {
      trackId = id;
      return seleniumHelpers.getStats(driver, 'pc1');
    })
    .then(function(stats) {
      // Find the sending audio track.
      stats.forEach(function(report) {
        if (report.type === 'ssrc' && report.googTrackId === trackId) {
          t.ok(codecName === report.googCodecName, 'preferring ' + codecName);
        }
      });
      return driver.findElement(webdriver.By.id('hangupButton')).click();
    })
    .then(function() {
      return driver.wait(function() {
        return driver.executeScript('return pc1 === null');
      }, 30 * 1000);
    });
  });
  last.then(function() {
    t.end();
  })
  .then(null, function(err) {
    t.fail(err);
    t.end();
  });
});
<commit_msg>test: update audio codec test<commit_after>/*
 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */
 /* eslint-env node */

'use strict';
// This is a basic test file for use with testling.
// The test script language comes from tape.
var test = require('tape');

var webdriver = require('selenium-webdriver');
var seleniumHelpers = require('webrtc-utilities').seleniumLib;

test('Audio-only sample codec preference', function(t) {
  if (process.env.BROWSER === 'firefox') {
    t.pass('Firefox not supported yet');
    t.end();
    return;
  }
  var trackId;
  var driver = seleniumHelpers.buildDriver();

  driver.get((process.env.BASEURL ? process.env.BASEURL :
      ('file://' + process.cwd())) +
      '/src/content/peerconnection/audio/index.html');
  var codecs = ['opus', 'ISAC', 'G722', 'PCMU'];

  var last;
  codecs.forEach(function(codecName) {
    last = driver.findElement(webdriver.By.css(
        '#codec>option[value="' + codecName + '"]'))
    .click()
    .then(function() {
      return driver.findElement(webdriver.By.id('callButton')).click();
    })
    .then(function() {
      return driver.wait(function() {
        return driver.executeScript(
            'return pc2 && pc2.iceConnectionState === \'connected\';');
      }, 30 * 1000);
    })
    .then(function() {
      return driver.executeScript('return localStream.getAudioTracks()[0].id;');
    })
    .then(function(id) {
      trackId = id;
      return seleniumHelpers.getStats(driver, 'pc1');
    })
    .then(function(stats) {
      // Find the sending audio track.
      stats.forEach(function(report) {
        if (report.type === 'outbound-rtp') {
          var trackStats = stats.get(report.trackId);
          if (trackStats && trackStats.trackIdentifier === trackId) {
            var codecStats = stats.get(report.codecId);
            if (codecStats) {
              t.ok('audio/' + codecName === codecStats.mimeType,
                  'preferring ' + codecName);
            }
          }
        }
      });
      return driver.findElement(webdriver.By.id('hangupButton')).click();
    })
    .then(function() {
      return driver.wait(function() {
        return driver.executeScript('return pc1 === null');
      }, 30 * 1000);
    });
  });
  last.then(function() {
    t.end();
  })
  .then(null, function(err) {
    t.fail(err);
    t.end();
  });
});
<|endoftext|>


<commit_before>enyo.kind({
	name: "moon.InstantOnArranger",
	kind: "enyo.CardArranger",
	/* 	This is a temporary hack until BreadCrumbDecorator eliminates dependency on Arrangers for its hidden panels logic.
		TODO: Eliminate the dependency of BreadCrumbDecorator on Arranger having to set the hiding panels.
		All of the logic related to breadcrumbs shouold be encapsulated inside the BreadCrumbDecorator and not dependent on Arranger.
	*/
	finish: function() {
		this.inherited(arguments);
		var hiding = [];
		for (var i=0; i < this.container.toIndex; i++) {
			hiding.push(i);
		}
		this.container.hiddenPanels = hiding;
	}
});<commit_msg>panels.hiddenPanels[] needs to be updated before the breadcrumb decorator interrogates it.<commit_after>enyo.kind({
	name: "moon.InstantOnArranger",
	kind: "enyo.CardArranger",
	/* 	This is a temporary hack until BreadCrumbDecorator eliminates dependency on Arrangers for its hidden panels logic.
		TODO: Eliminate the dependency of BreadCrumbDecorator on Arranger having to set the hiding panels.
		All of the logic related to breadcrumbs shouold be encapsulated inside the BreadCrumbDecorator and not dependent on Arranger.
	*/
	start: function() {
		this.inherited(arguments);
		var hiding = [];
		for (var i=0; i < this.container.toIndex; i++) {
			hiding.push(i);
		}
		this.container.hiddenPanels = hiding;
	}
});<|endoftext|>


<commit_before>document.addEventListener('DOMContentLoaded', function () {
  // PeerJS server location
  var SERVER_IP = '192.168.0.25';
  var SERVER_PORT = 9000;

  // DOM elements manipulated as user interacts with the app
  var messageBox = document.querySelector('#messages');
  var callerIdEntry = document.querySelector('#caller-id');
  var connectBtn = document.querySelector('#connect');
  var recipientIdEntry = document.querySelector('#recipient-id');
  var dialBtn = document.querySelector('#dial');
  var remoteVideo = document.querySelector('#remote-video');
  var localVideo = document.querySelector('#local-video');

  // the ID set for this client
  var callerId = null;

  // PeerJS object, instantiated when this client connects with its
  // caller ID
  var peer = null;

  // the local video stream captured with getUserMedia()
  var localStream = null;

  // DOM utilities
  var makePara = function (text) {
    var p = document.createElement('p');
    p.innerText = text;
    return p;
  };

  var addMessage = function (para) {
    if (messageBox.firstChild) {
      messageBox.insertBefore(para, messageBox.firstChild);
    }
    else {
      messageBox.appendChild(para);
    }
  };

  var logError = function (text) {
    var p = makePara('ERROR: ' + text);
    p.style.color = 'red';
    addMessage(p);
  };

  var logMessage = function (text) {
    addMessage(makePara(text));
  };

  // get the local video and audio stream and show preview in the
  // "LOCAL" video element
  // successCb: has the signature successCb(stream); receives
  // the local video stream as an argument
  var getLocalStream = function (successCb) {
    if (localStream && successCb) {
      successCb(localStream);
    }
    else {
      navigator.webkitGetUserMedia(
        {
          audio: true,
          video: true
        },

        function (stream) {
          localStream = stream;

          localVideo.src = window.URL.createObjectURL(stream);

          if (successCb) {
            successCb(stream);
          }
        },

        function (err) {
          logError('failed to access local camera');
          logError(err.message);
        }
      );
    }
  };

  // set the "REMOTE" video element source
  var showRemoteStream = function (stream) {
    remoteVideo.src = window.URL.createObjectURL(stream);
  };

  // set caller ID and connect to the PeerJS server
  var connect = function () {
    callerId = callerIdEntry.value;

    if (!callerId) {
      logError('please set caller ID first');
      return;
    }

    try {
      // create connection to the ID server
      peer = new Peer(callerId, {host: SERVER_IP, port: SERVER_PORT});

      // hack to get around the fact that if a server connection cannot
      // be established, the peer and its socket property both still have
      // open === true; instead, listen to the wrapped WebSocket
      // and show an error if its readyState becomes CLOSED
      peer.socket._socket.onclose = function () {
        logError('no connection to server');
        peer = null;
      };

      // get local stream ready for incoming calls once the wrapped
      // WebSocket is open
      peer.socket._socket.onopen = function () {
        getLocalStream();
      };

      // handle events representing incoming calls
      peer.on('call', answer);
    }
    catch (e) {
      peer = null;
      logError('error while connecting to server');
    }
  };

  // make an outgoing call
  var dial = function () {
    if (!peer) {
      logError('please connect first');
      return;
    }

    if (!localStream) {
      logError('could not start call as there is no local camera');
      return
    }

    var recipientId = recipientIdEntry.value;

    if (!recipientId) {
      logError('could not start call as no recipient ID is set');
      return;
    }

    getLocalStream(function (stream) {
      logMessage('outgoing call initiated');

      var call = peer.call(recipientId, stream);

      call.on('stream', showRemoteStream);

      call.on('error', function (e) {
        logError('error with call');
        logError(e.message);
      });
    });
  };

  // answer an incoming call
  var answer = function (call) {
    if (!peer) {
      logError('cannot answer a call without a connection');
      return;
    }

    if (!localStream) {
      logError('could not answer call as there is no localStream ready');
      return;
    }

    logMessage('incoming call answered');

    call.on('stream', showRemoteStream);

    call.answer(localStream);
  };

  // wire up button events
  connectBtn.addEventListener('click', connect);
  dialBtn.addEventListener('click', dial);
});
<commit_msg>Update specified IP as 192.168.x.x to resolve Information Leaking problem. (#152)<commit_after>document.addEventListener('DOMContentLoaded', function () {
  // PeerJS server location
  var SERVER_IP = '192.168.x.x';
  var SERVER_PORT = 9000;

  // DOM elements manipulated as user interacts with the app
  var messageBox = document.querySelector('#messages');
  var callerIdEntry = document.querySelector('#caller-id');
  var connectBtn = document.querySelector('#connect');
  var recipientIdEntry = document.querySelector('#recipient-id');
  var dialBtn = document.querySelector('#dial');
  var remoteVideo = document.querySelector('#remote-video');
  var localVideo = document.querySelector('#local-video');

  // the ID set for this client
  var callerId = null;

  // PeerJS object, instantiated when this client connects with its
  // caller ID
  var peer = null;

  // the local video stream captured with getUserMedia()
  var localStream = null;

  // DOM utilities
  var makePara = function (text) {
    var p = document.createElement('p');
    p.innerText = text;
    return p;
  };

  var addMessage = function (para) {
    if (messageBox.firstChild) {
      messageBox.insertBefore(para, messageBox.firstChild);
    }
    else {
      messageBox.appendChild(para);
    }
  };

  var logError = function (text) {
    var p = makePara('ERROR: ' + text);
    p.style.color = 'red';
    addMessage(p);
  };

  var logMessage = function (text) {
    addMessage(makePara(text));
  };

  // get the local video and audio stream and show preview in the
  // "LOCAL" video element
  // successCb: has the signature successCb(stream); receives
  // the local video stream as an argument
  var getLocalStream = function (successCb) {
    if (localStream && successCb) {
      successCb(localStream);
    }
    else {
      navigator.webkitGetUserMedia(
        {
          audio: true,
          video: true
        },

        function (stream) {
          localStream = stream;

          localVideo.src = window.URL.createObjectURL(stream);

          if (successCb) {
            successCb(stream);
          }
        },

        function (err) {
          logError('failed to access local camera');
          logError(err.message);
        }
      );
    }
  };

  // set the "REMOTE" video element source
  var showRemoteStream = function (stream) {
    remoteVideo.src = window.URL.createObjectURL(stream);
  };

  // set caller ID and connect to the PeerJS server
  var connect = function () {
    callerId = callerIdEntry.value;

    if (!callerId) {
      logError('please set caller ID first');
      return;
    }

    try {
      // create connection to the ID server
      peer = new Peer(callerId, {host: SERVER_IP, port: SERVER_PORT});

      // hack to get around the fact that if a server connection cannot
      // be established, the peer and its socket property both still have
      // open === true; instead, listen to the wrapped WebSocket
      // and show an error if its readyState becomes CLOSED
      peer.socket._socket.onclose = function () {
        logError('no connection to server');
        peer = null;
      };

      // get local stream ready for incoming calls once the wrapped
      // WebSocket is open
      peer.socket._socket.onopen = function () {
        getLocalStream();
      };

      // handle events representing incoming calls
      peer.on('call', answer);
    }
    catch (e) {
      peer = null;
      logError('error while connecting to server');
    }
  };

  // make an outgoing call
  var dial = function () {
    if (!peer) {
      logError('please connect first');
      return;
    }

    if (!localStream) {
      logError('could not start call as there is no local camera');
      return
    }

    var recipientId = recipientIdEntry.value;

    if (!recipientId) {
      logError('could not start call as no recipient ID is set');
      return;
    }

    getLocalStream(function (stream) {
      logMessage('outgoing call initiated');

      var call = peer.call(recipientId, stream);

      call.on('stream', showRemoteStream);

      call.on('error', function (e) {
        logError('error with call');
        logError(e.message);
      });
    });
  };

  // answer an incoming call
  var answer = function (call) {
    if (!peer) {
      logError('cannot answer a call without a connection');
      return;
    }

    if (!localStream) {
      logError('could not answer call as there is no localStream ready');
      return;
    }

    logMessage('incoming call answered');

    call.on('stream', showRemoteStream);

    call.answer(localStream);
  };

  // wire up button events
  connectBtn.addEventListener('click', connect);
  dialBtn.addEventListener('click', dial);
});
<|endoftext|>


<commit_before>$(document).ready(function() {
    var update_viewers = function(stream_id) {
        $.ajax("/api/v1/streams/" + stream_id).done(function(data){
            count = data.data.viewers;
            console.log(data);
            console.log(count);
            cls_selector = ".viewers-count-stream-" + stream_id;
            if (count !== undefined) {
                $(cls_selector).html(count.toString() + " " + (count === 1 ? "viewer" : "viewers"));
            }
        });
    };

    $('.viewers-count-stream').each(function(){
        var that = this;
        var stream_id_class = $(that).attr("class").split(' ').filter(
                function(c) {
                    return c.indexOf("viewers-count-stream-") === 0;
                }
            )[0];
        var stream_id = +stream_id_class.split('-')[3];
        console.log("setInterval " + stream_id);
        setInterval(function() { update_viewers(stream_id); }, 5000);
    });
});
<commit_msg>viewers count should be requested less frequently methinks<commit_after>$(document).ready(function() {
    var update_viewers = function(stream_id) {
        $.ajax("/api/v1/streams/" + stream_id).done(function(data){
            count = data.data.viewers;
            console.log(data);
            console.log(count);
            cls_selector = ".viewers-count-stream-" + stream_id;
            if (count !== undefined) {
                $(cls_selector).html(count.toString() + " " + (count === 1 ? "viewer" : "viewers"));
            }
        });
    };

    $('.viewers-count-stream').each(function(){
        var that = this;
        var stream_id_class = $(that).attr("class").split(' ').filter(
                function(c) {
                    return c.indexOf("viewers-count-stream-") === 0;
                }
            )[0];
        var stream_id = +stream_id_class.split('-')[3];
        console.log("setInterval " + stream_id);
        setInterval(function() { update_viewers(stream_id); }, 20000);
    });
});
<|endoftext|>


<commit_before>(function () {
  'use strict';

  angular
    .module('app')
    .controller('SpotsController', Spots);

  Spots.$inject = ['$cordovaDevice', '$cordovaFile', '$document', '$ionicModal', '$ionicPopover', '$ionicPopup',
    '$location', '$log', '$scope', '$window', 'ProjectFactory', 'SpotFactory', 'UserFactory'];

  function Spots($cordovaDevice, $cordovaFile, $document, $ionicModal, $ionicPopover, $ionicPopup, $location, $log,
                 $scope, $window, ProjectFactory, SpotFactory, UserFactory) {
    var vm = this;

    var visibleDatasets = [];

    vm.activeDatasets = [];
    vm.checkedDataset = checkedDataset;
    vm.closeModal = closeModal;
    vm.deleteAllActiveSpots = deleteAllActiveSpots;
    vm.deleteSelected = false;
    vm.deleteSpot = deleteSpot;
    vm.exportToCSV = exportToCSV;
    vm.filter = filter;
    vm.filterModal = {};
    vm.filterOn = false;
    vm.goToSpot = goToSpot;
    vm.isDatasetChecked = isDatasetChecked;
    vm.isOnlineLoggedIn = isOnlineLoggedIn;
    vm.loadMoreSpots = loadMoreSpots;
    vm.moreSpotsCanBeLoaded = moreSpotsCanBeLoaded;
    vm.newSpot = newSpot;
    vm.spots = [];
    vm.spotsDisplayed = [];

    activate();

    /**
     * Private Functions
     */

    function activate() {
      SpotFactory.clearCurrentSpot();           // Make sure the current spot is empty
      visibleDatasets = SpotFactory.getVisibleDatasets();
      setVisibleSpots();
      createPopover();

      $ionicModal.fromTemplateUrl('app/spot/spots-filter-modal.html', {
        'scope': $scope,
        'animation': 'slide-in-up',
        'backdropClickToClose': false,
        'hardwareBackButtonClose': false
      }).then(function (modal) {
        vm.filterModal = modal;
      });

      // Cleanup the modal when we're done with it!
      $scope.$on('$destroy', function () {
        vm.filterModal.remove();
      });
    }

    function createPopover() {
      $ionicPopover.fromTemplateUrl('app/spot/spots-popover.html', {
        'scope': $scope
      }).then(function (popover) {
        vm.popover = popover;
      });

      // Cleanup the popover when we're done with it!
      $scope.$on('$destroy', function () {
        vm.popover.remove();
      });
    }

    function setVisibleSpots() {
      var activeSpots = SpotFactory.getActiveSpots();
      if (_.isEmpty(visibleDatasets)) {
        vm.spots = activeSpots;
        vm.filterOn = false;
      }
      else {
        var datasetIdsToSpotIds = ProjectFactory.getSpotIds();
        var visibleSpotsIds = [];
        _.each(visibleDatasets, function (visibleDataset) {
          visibleSpotsIds.push(datasetIdsToSpotIds[visibleDataset]);
        });
        visibleSpotsIds = _.flatten(visibleSpotsIds);
        vm.spots = _.filter(activeSpots, function (activeSpot) {
          return _.contains(visibleSpotsIds, activeSpot.properties.id);
        });
        vm.filterOn = true;
      }
      _.sortBy(vm.spots, function (spot) {
        return spot.properties.modified_timestamp;
      }).reverse();
      vm.spotsDisplayed = angular.fromJson(angular.toJson(vm.spots)).slice(0, 20);
    }

    /**
     * Public Functions
     */

    function checkedDataset(dataset) {
      $log.log('visibleDatasets:', visibleDatasets);
      var i = _.indexOf(visibleDatasets, dataset);
      if (i === -1) visibleDatasets.push(dataset);
      else visibleDatasets.splice(i, 1);
      SpotFactory.setVisibleDatasets(visibleDatasets);
      $log.log('visibleDatasets after:', visibleDatasets);
    }

    function closeModal() {
      setVisibleSpots();
      vm.filterModal.hide();
    }

    // clears all spots
    function deleteAllActiveSpots() {
      vm.popover.hide();
      var confirmPopup = $ionicPopup.confirm({
        'title': 'Delete Spots',
        'template': 'Are you sure you want to delete ALL active spots? This will also delete any associated image basemaps.'
      });
      confirmPopup.then(
        function (res) {
          if (res) {
            SpotFactory.clearActiveSpots().then(function () {
              // update the spots list
              vm.spots = [];
              vm.spotsDisplayed = [];
            });
          }
        }
      );
    }

    function deleteSpot(spot) {
      vm.deleteSelected = true;

      if (SpotFactory.isSafeDelete(spot)) {
        var confirmPopup = $ionicPopup.confirm({
          'title': 'Delete Spot',
          'template': 'Are you sure you want to delete Spot ' + spot.properties.name + '?'
        });
        confirmPopup.then(function (res) {
          if (res) {
            SpotFactory.destroy(spot.properties.id).then(function () {
              vm.spots = SpotFactory.getActiveSpots();
              vm.spotsDisplayed = angular.fromJson(angular.toJson(vm.spots)).slice(0, 20);
            });
          }
          vm.deleteSelected = false;
        });
      }
      else {
        var alertPopup = $ionicPopup.alert({
          'title': 'Spot Deletion Prohibited!',
          'template': 'This Spot has at least one image being used as an image basemap. Remove any image basemaps' +
          ' from this Spot before deleting.'
        });
        alertPopup.then(function () {
          vm.deleteSelected = false;
        });
      }
    }

    // Export data to CSV
    function exportToCSV() {
      vm.popover.hide();
      // Convert the spot objects to a csv format
      function convertToCSV() {
        // Get all the fields for the csv header row
        var allHeaders = [];
        _.each(vm.spots,
          function (spot) {
            var headers = _.keys(spot.properties);
            // If there are custom fields, loop through the custom object grabbing those fields
            var i = _.indexOf(headers, 'custom');
            if (i !== -1) {
              headers = _.without(headers, 'custom');
              var customHeaders = _.keys(spot.properties.custom);
              customHeaders = _.map(customHeaders,
                function (header) {
                  return 'custom_' + header;
                }
              );
              allHeaders = _.union(headers, allHeaders, customHeaders);
            }
            else {
              allHeaders = _.union(headers, allHeaders);
            }
          }
        );
        // Add the two fields for the geometry
        allHeaders.push('geometry_type');
        allHeaders.push('geometry_coordinates');

        var allHeadersQuoted = _.map(allHeaders,
          function (ele) {
            return '\'' + ele + '\'';
          }
        );
        var csv = allHeadersQuoted.toString() + '\r\n';

        // Get all the values for each csv data row
        _.each(vm.spots,
          function (spot) {
            var row = new Array(allHeaders.length);
            row = _.map(row,
              function (ele) {
                return '';
              }
            );
            _.each(spot.properties,
              function (value, key) {
                // If the value is actually an object
                var i = _.indexOf(allHeaders, key);
                if (_.isObject(value)) {
                  // Separate date parts
                  if (value instanceof Date) {
                    if (key === 'time') {
                      row[i] = value.toLocaleTimeString();
                    }
                    else if (key === 'date') {
                      row[i] = value.toLocaleDateString();
                    }
                    else {
                      row[i] = value.toJSON();
                    }
                  }
                  // Flatten the child values
                  else {
                    row[i] = '\'' + _.flatten(value).join(', ') + '\'';
                  }
                }
                else {
                  row[i] = '\'' + value + '\'';
                }
              }
            );
            // Add the values for the geometry fields
            if (angular.isDefined(spot.geometry) && angular.isDefined(spot.geometry.type)) {
              var i = _.indexOf(allHeaders, 'geometry_type');
              row[i] = '\'' + spot.geometry.type + '\'';
              if (angular.isDefined(spot.geometry.coordinates)) {
                i = _.indexOf(allHeaders, 'geometry_coordinates');
                row[i] = '\'' + _.flatten(spot.geometry.coordinates).join(', ') + '\'';
              }
            }
            csv += row.toString() + '\r\n';
          }
        );
        return csv;
      }

      var spotData = convertToCSV(vm.spots);

      // If this is a web browser and not using cordova
      if ($document[0].location.protocol !== 'file:') { // Phonegap is not present }
        spotData = spotData.replace(/\r\n/g, '
');
        var win = $window.open();
        win.document.body.innerHTML = spotData;
        return;
      }

      var d = new Date();
      d = d.toLocaleDateString() + '-' + d.toLocaleTimeString();
      d = d.replace(/\//g, '-');
      d = d.replace(/:/g, '');
      d = d.replace(/ /g, '');
      var fileName = d + '-' + 'strabo-data.csv';

      var devicePath;
      switch ($cordovaDevice.getPlatform()) {
        case 'Android':
          devicePath = cordova.file.externalRootDirectory;
          break;
        case 'iOS':
          devicePath = cordova.file.documentsDirectory;
          break;
        default:
          // uh oh?  TODO: what about windows and blackberry?
          devicePath = cordova.file.externalRootDirectory;
          break;
      }

      var directory = 'strabo';

      function writeFile(dir) {
        $cordovaFile.writeFile(devicePath + dir, fileName, spotData, true).then(
          function (success) {
            $log.log(success);
            $ionicPopup.alert({
              'title': 'Success!',
              'template': 'CSV written to ' + devicePath + dir + fileName
            });
          },
          function (error) {
            $log.log(error);
          }
        );
      }

      $cordovaFile.checkDir(devicePath, directory).then(
        function (success) {
          $log.log(success);
          writeFile(success.fullPath);
        },
        function (error) {
          $cordovaFile.createDir(devicePath, directory, false).then(
            function (success) {
              $log.log(success);
              writeFile(success.fullPath);
            },
            function (error) {
              $log.log(error);
            }
          );
        }
      );
    }

    function filter() {
      vm.activeDatasets = ProjectFactory.getActiveDatasets();
      vm.filterModal.show();
    }

    function goToSpot(id) {
      if (!vm.deleteSelected) {
        $location.path('/app/spotTab/' + id + '/spot');
      }
    }

    function isDatasetChecked(id) {
      return _.find(visibleDatasets, function (visibleDataset) {
        return visibleDataset === id;
      });
    }

    // Is the user online and logged in
    function isOnlineLoggedIn() {
      return navigator.onLine && UserFactory.getUser();
    }

    function loadMoreSpots() {
      var moreSpots = angular.fromJson(angular.toJson(vm.spots)).splice(vm.spotsDisplayed.length,
        vm.spotsDisplayed.length + 20);
      vm.spotsDisplayed = _.union(vm.spotsDisplayed, moreSpots);
      $scope.$broadcast('scroll.infiniteScrollComplete');
    }

    function moreSpotsCanBeLoaded() {
      return vm.spotsDisplayed.length !== vm.spots.length;
    }

    // Create a new Spot
    function newSpot() {
      SpotFactory.setNewSpot({}).then(function (id) {
        $location.path('/app/spotTab/' + id + '/spot');
      });
    }
  }
}());
<commit_msg>fixed spots sort by modified_timestamp bug<commit_after>(function () {
  'use strict';

  angular
    .module('app')
    .controller('SpotsController', Spots);

  Spots.$inject = ['$cordovaDevice', '$cordovaFile', '$document', '$ionicModal', '$ionicPopover', '$ionicPopup',
    '$location', '$log', '$scope', '$window', 'ProjectFactory', 'SpotFactory', 'UserFactory'];

  function Spots($cordovaDevice, $cordovaFile, $document, $ionicModal, $ionicPopover, $ionicPopup, $location, $log,
                 $scope, $window, ProjectFactory, SpotFactory, UserFactory) {
    var vm = this;

    var visibleDatasets = [];

    vm.activeDatasets = [];
    vm.checkedDataset = checkedDataset;
    vm.closeModal = closeModal;
    vm.deleteAllActiveSpots = deleteAllActiveSpots;
    vm.deleteSelected = false;
    vm.deleteSpot = deleteSpot;
    vm.exportToCSV = exportToCSV;
    vm.filter = filter;
    vm.filterModal = {};
    vm.filterOn = false;
    vm.goToSpot = goToSpot;
    vm.isDatasetChecked = isDatasetChecked;
    vm.isOnlineLoggedIn = isOnlineLoggedIn;
    vm.loadMoreSpots = loadMoreSpots;
    vm.moreSpotsCanBeLoaded = moreSpotsCanBeLoaded;
    vm.newSpot = newSpot;
    vm.spots = [];
    vm.spotsDisplayed = [];

    activate();

    /**
     * Private Functions
     */

    function activate() {
      SpotFactory.clearCurrentSpot();           // Make sure the current spot is empty
      visibleDatasets = SpotFactory.getVisibleDatasets();
      setVisibleSpots();
      createPopover();

      $ionicModal.fromTemplateUrl('app/spot/spots-filter-modal.html', {
        'scope': $scope,
        'animation': 'slide-in-up',
        'backdropClickToClose': false,
        'hardwareBackButtonClose': false
      }).then(function (modal) {
        vm.filterModal = modal;
      });

      // Cleanup the modal when we're done with it!
      $scope.$on('$destroy', function () {
        vm.filterModal.remove();
      });
    }

    function createPopover() {
      $ionicPopover.fromTemplateUrl('app/spot/spots-popover.html', {
        'scope': $scope
      }).then(function (popover) {
        vm.popover = popover;
      });

      // Cleanup the popover when we're done with it!
      $scope.$on('$destroy', function () {
        vm.popover.remove();
      });
    }

    function setVisibleSpots() {
      var activeSpots = SpotFactory.getActiveSpots();
      if (_.isEmpty(visibleDatasets)) {
        vm.spots = activeSpots;
        vm.filterOn = false;
      }
      else {
        var datasetIdsToSpotIds = ProjectFactory.getSpotIds();
        var visibleSpotsIds = [];
        _.each(visibleDatasets, function (visibleDataset) {
          visibleSpotsIds.push(datasetIdsToSpotIds[visibleDataset]);
        });
        visibleSpotsIds = _.flatten(visibleSpotsIds);
        vm.spots = _.filter(activeSpots, function (activeSpot) {
          return _.contains(visibleSpotsIds, activeSpot.properties.id);
        });
        vm.filterOn = true;
      }
      vm.spots = _.sortBy(vm.spots, function (spot) {
        return spot.properties.modified_timestamp;
      }).reverse();
      vm.spotsDisplayed = angular.fromJson(angular.toJson(vm.spots)).slice(0, 20);
    }

    /**
     * Public Functions
     */

    function checkedDataset(dataset) {
      $log.log('visibleDatasets:', visibleDatasets);
      var i = _.indexOf(visibleDatasets, dataset);
      if (i === -1) visibleDatasets.push(dataset);
      else visibleDatasets.splice(i, 1);
      SpotFactory.setVisibleDatasets(visibleDatasets);
      $log.log('visibleDatasets after:', visibleDatasets);
    }

    function closeModal() {
      setVisibleSpots();
      vm.filterModal.hide();
    }

    // clears all spots
    function deleteAllActiveSpots() {
      vm.popover.hide();
      var confirmPopup = $ionicPopup.confirm({
        'title': 'Delete Spots',
        'template': 'Are you sure you want to delete ALL active spots? This will also delete any associated image basemaps.'
      });
      confirmPopup.then(
        function (res) {
          if (res) {
            SpotFactory.clearActiveSpots().then(function () {
              // update the spots list
              vm.spots = [];
              vm.spotsDisplayed = [];
            });
          }
        }
      );
    }

    function deleteSpot(spot) {
      vm.deleteSelected = true;

      if (SpotFactory.isSafeDelete(spot)) {
        var confirmPopup = $ionicPopup.confirm({
          'title': 'Delete Spot',
          'template': 'Are you sure you want to delete Spot ' + spot.properties.name + '?'
        });
        confirmPopup.then(function (res) {
          if (res) {
            SpotFactory.destroy(spot.properties.id).then(function () {
              vm.spots = SpotFactory.getActiveSpots();
              vm.spotsDisplayed = angular.fromJson(angular.toJson(vm.spots)).slice(0, 20);
            });
          }
          vm.deleteSelected = false;
        });
      }
      else {
        var alertPopup = $ionicPopup.alert({
          'title': 'Spot Deletion Prohibited!',
          'template': 'This Spot has at least one image being used as an image basemap. Remove any image basemaps' +
          ' from this Spot before deleting.'
        });
        alertPopup.then(function () {
          vm.deleteSelected = false;
        });
      }
    }

    // Export data to CSV
    function exportToCSV() {
      vm.popover.hide();
      // Convert the spot objects to a csv format
      function convertToCSV() {
        // Get all the fields for the csv header row
        var allHeaders = [];
        _.each(vm.spots,
          function (spot) {
            var headers = _.keys(spot.properties);
            // If there are custom fields, loop through the custom object grabbing those fields
            var i = _.indexOf(headers, 'custom');
            if (i !== -1) {
              headers = _.without(headers, 'custom');
              var customHeaders = _.keys(spot.properties.custom);
              customHeaders = _.map(customHeaders,
                function (header) {
                  return 'custom_' + header;
                }
              );
              allHeaders = _.union(headers, allHeaders, customHeaders);
            }
            else {
              allHeaders = _.union(headers, allHeaders);
            }
          }
        );
        // Add the two fields for the geometry
        allHeaders.push('geometry_type');
        allHeaders.push('geometry_coordinates');

        var allHeadersQuoted = _.map(allHeaders,
          function (ele) {
            return '\'' + ele + '\'';
          }
        );
        var csv = allHeadersQuoted.toString() + '\r\n';

        // Get all the values for each csv data row
        _.each(vm.spots,
          function (spot) {
            var row = new Array(allHeaders.length);
            row = _.map(row,
              function (ele) {
                return '';
              }
            );
            _.each(spot.properties,
              function (value, key) {
                // If the value is actually an object
                var i = _.indexOf(allHeaders, key);
                if (_.isObject(value)) {
                  // Separate date parts
                  if (value instanceof Date) {
                    if (key === 'time') {
                      row[i] = value.toLocaleTimeString();
                    }
                    else if (key === 'date') {
                      row[i] = value.toLocaleDateString();
                    }
                    else {
                      row[i] = value.toJSON();
                    }
                  }
                  // Flatten the child values
                  else {
                    row[i] = '\'' + _.flatten(value).join(', ') + '\'';
                  }
                }
                else {
                  row[i] = '\'' + value + '\'';
                }
              }
            );
            // Add the values for the geometry fields
            if (angular.isDefined(spot.geometry) && angular.isDefined(spot.geometry.type)) {
              var i = _.indexOf(allHeaders, 'geometry_type');
              row[i] = '\'' + spot.geometry.type + '\'';
              if (angular.isDefined(spot.geometry.coordinates)) {
                i = _.indexOf(allHeaders, 'geometry_coordinates');
                row[i] = '\'' + _.flatten(spot.geometry.coordinates).join(', ') + '\'';
              }
            }
            csv += row.toString() + '\r\n';
          }
        );
        return csv;
      }

      var spotData = convertToCSV(vm.spots);

      // If this is a web browser and not using cordova
      if ($document[0].location.protocol !== 'file:') { // Phonegap is not present }
        spotData = spotData.replace(/\r\n/g, '
');
        var win = $window.open();
        win.document.body.innerHTML = spotData;
        return;
      }

      var d = new Date();
      d = d.toLocaleDateString() + '-' + d.toLocaleTimeString();
      d = d.replace(/\//g, '-');
      d = d.replace(/:/g, '');
      d = d.replace(/ /g, '');
      var fileName = d + '-' + 'strabo-data.csv';

      var devicePath;
      switch ($cordovaDevice.getPlatform()) {
        case 'Android':
          devicePath = cordova.file.externalRootDirectory;
          break;
        case 'iOS':
          devicePath = cordova.file.documentsDirectory;
          break;
        default:
          // uh oh?  TODO: what about windows and blackberry?
          devicePath = cordova.file.externalRootDirectory;
          break;
      }

      var directory = 'strabo';

      function writeFile(dir) {
        $cordovaFile.writeFile(devicePath + dir, fileName, spotData, true).then(
          function (success) {
            $log.log(success);
            $ionicPopup.alert({
              'title': 'Success!',
              'template': 'CSV written to ' + devicePath + dir + fileName
            });
          },
          function (error) {
            $log.log(error);
          }
        );
      }

      $cordovaFile.checkDir(devicePath, directory).then(
        function (success) {
          $log.log(success);
          writeFile(success.fullPath);
        },
        function (error) {
          $cordovaFile.createDir(devicePath, directory, false).then(
            function (success) {
              $log.log(success);
              writeFile(success.fullPath);
            },
            function (error) {
              $log.log(error);
            }
          );
        }
      );
    }

    function filter() {
      vm.activeDatasets = ProjectFactory.getActiveDatasets();
      vm.filterModal.show();
    }

    function goToSpot(id) {
      if (!vm.deleteSelected) {
        $location.path('/app/spotTab/' + id + '/spot');
      }
    }

    function isDatasetChecked(id) {
      return _.find(visibleDatasets, function (visibleDataset) {
        return visibleDataset === id;
      });
    }

    // Is the user online and logged in
    function isOnlineLoggedIn() {
      return navigator.onLine && UserFactory.getUser();
    }

    function loadMoreSpots() {
      var moreSpots = angular.fromJson(angular.toJson(vm.spots)).splice(vm.spotsDisplayed.length,
        vm.spotsDisplayed.length + 20);
      vm.spotsDisplayed = _.union(vm.spotsDisplayed, moreSpots);
      $scope.$broadcast('scroll.infiniteScrollComplete');
    }

    function moreSpotsCanBeLoaded() {
      return vm.spotsDisplayed.length !== vm.spots.length;
    }

    // Create a new Spot
    function newSpot() {
      SpotFactory.setNewSpot({}).then(function (id) {
        $location.path('/app/spotTab/' + id + '/spot');
      });
    }
  }
}());
<|endoftext|>


<commit_before>!function(e){function t(n){if(i[n])return i[n].exports;var r=i[n]={exports:{},id:n,loaded:!1};return e[n].call(r.exports,r,r.exports,t),r.loaded=!0,r.exports}var i={};return t.m=e,t.c=i,t.p="",t(0)}([function(e,t,i){"use strict";angular.module("mdDatetime",["ngMaterial"]),i(4),i(3)},function(e,t){e.exports='<md-datepicker ng-model=DT.params.date ng-change=DT.updateDate()></md-datepicker> <md-timepicker ng-model=DT.params.time ng-change=DT.updateTime() mode=24h></md-timepicker> <md-button class="md-datetime-picker-reset md-icon-button md-ink-ripple" ng-click=DT.reset() ng-if=DT.canReset> <md-icon> <svg height=24 viewBox="0 0 24 24" width=24 xmlns=http://www.w3.org/2000/svg> <path d="M12 6v3l4-4-4-4v3c-4.42 0-8 3.58-8 8 0 1.57.46 3.03 1.24 4.26L6.7 14.8c-.45-.83-.7-1.79-.7-2.8 0-3.31 2.69-6 6-6zm6.76 1.74L17.3 9.2c.44.84.7 1.79.7 2.8 0 3.31-2.69 6-6 6v-3l-4 4 4 4v-3c4.42 0 8-3.58 8-8 0-1.57-.46-3.03-1.24-4.26z"/> <path d="M0 0h24v24H0z" fill=none /> </svg> </md-icon> <md-tooltip>Reset to NOW</md-tooltip> </md-button>'},function(e,t){e.exports='<md-button class="md-timepicker-button md-icon-button md-ink-ripple" type=button aria-label="pick time" ng-click=T.togglePicking($event) ng-class="{ active: T.picking }"> <md-icon> <svg height=24 viewBox="0 0 24 24" width=24 xmlns=http://www.w3.org/2000/svg> <path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/> <path d="M0 0h24v24H0z" fill=none /> <path d="M12.5 7H11v6l5.25 3.15.75-1.23-4.5-2.67z"/> </svg> </md-icon> </md-button>
 <md-input-container> <input class=md-timepicker-input type=text aria-label="time input" ng-model=T.viewValue ng-pattern=T.timePattern ng-change=T.parse()> <md-button class="md-datepicker-triangle-button md-icon-button" ng-click=T.togglePicking($event) aria-label="pick time">

 </md-button> </md-input-container>
 <md-toolbar class=md-timepicker-time>  {{T.time.hour()}}  :  {{T.time.minute()}}  </md-toolbar>
 am/pm

 {{::hour.viewValue}}

 {{::hour.viewValue}}

 {{::minute.viewValue}}

'},function(e,t,i){"use strict";angular.module("mdDatetime").component("mdDatetime",{require:{modelCtrl:"ngModel"},template:i(1),controller:["$attrs",function(e){var t=this;this.$onInit=function(){t.modelCtrl.$render=function(){t.datetime=moment(t.modelCtrl.$modelValue),t.updateParams()}},this.updateDate=function(){var e=moment(t.params.date);t.datetime.year(e.year()),t.datetime.month(e.month()),t.datetime.date(e.date()),t.updateParams()},this.updateTime=function(){t.datetime.hour(t.params.time.hour),t.datetime.minute(t.params.time.minute),t.updateParams()},this.updateParams=function(){t.params={date:t.datetime.toDate(),time:{hour:t.datetime.hour(),minute:t.datetime.minute()}},t.modelCtrl.$setViewValue(t.datetime.toISOString())},this.canReset=!("noReset"in e),this.reset=function(){t.datetime=moment(),t.updateParams()}}],controllerAs:"DT"})},function(e,t,i){"use strict";var n=function(){function e(e,t){var i=[],n=!0,r=!1,o=void 0;try{for(var m,a=e[Symbol.iterator]();!(n=(m=a.next()).done)&&(i.push(m.value),!t||i.length!==t);n=!0);}catch(u){r=!0,o=u}finally{try{!n&&a["return"]&&a["return"]()}finally{if(r)throw o}}return i}return function(t,i){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,i);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}();angular.module("mdDatetime").component("mdTimepicker",{template:i(2),bindings:{mode:"@"},require:{modelCtrl:"ngModel"},controller:["$scope","$window",function(e,t){var i=this;this.$onInit=function(){i.modelCtrl.$render=function(){i.viewValue=moment(i.modelCtrl.$modelValue).format("HH:mm");var e=i.modelCtrl.$modelValue,t=e.hour,n=e.minute;i.hours.forEach(function(e){e.selected=e.realValue==t}),i.minutes.forEach(function(e,t){e.selected=(Math.floor(n/5)+11)%12==t})},angular.element(t).on("click",function(){i.picking=!1,e.$digest()})},this.keepPicking=function(e){e.stopPropagation()},this.outerHours=["1","2","3","4","5","6","7","8","9","10","11","12"],this.innerHours=["13","14","15","16","17","18","19","20","21","22","23","00"],this.minutes=["05","10","15","20","25","30","35","40","45","50","55","00"];var r=function(e,t){return function(i,n){var r=30*n+30;return{type:e,viewValue:i,realValue:parseInt(i,10),style:{transform:"rotate("+r+"deg) translate(0, -"+t+"px) rotate(-"+r+"deg)"}}}};this.outerHours=this.outerHours.map(r("hour",80)),this.innerHours=this.innerHours.map(r("hour",55)),this.ampm="ampm"==this.mode,this.ampm&&(this.innerHours=[]),this.hours=this.outerHours.concat(this.innerHours),this.minutes=this.minutes.map(r("minute",80)),this.togglePicking=function(e){return i.picking?i.picking=!1:(i.picking=!0,i.pickHour(),void i.keepPicking(e))},this.pickHour=function(){i.pickingMinute=!1,i.pickingHour=!0},this.pickMinute=function(){i.pickingHour=!1,i.pickingMinute=!0},this.selectHour=function(e){i.modelCtrl.$setViewValue({hour:e.realValue,minute:i.modelCtrl.$modelValue.minute}),i.outerHours.forEach(function(e){e.selected=!1}),i.innerHours.forEach(function(e){e.selected=!1}),e.selected=!0,i.pickMinute()},this.selectMinute=function(e){i.modelCtrl.$setViewValue({hour:i.modelCtrl.$modelValue.hour,minute:e.realValue}),i.minutes.forEach(function(e){e.selected=!1}),e.selected=!0,i.picking=!1},this.timePattern=/^[0-2]?[0-9]:[0-5][0-9]$/,this.parse=function(){if(i.viewValue){var e=i.viewValue.split(":"),t=n(e,2),r=t[0],o=t[1];i.modelCtrl.$setViewValue({hour:r,minute:o})}},this.time={hour:function(){return moment(i.modelCtrl.$modelValue).format("HH")},minute:function(){return moment(i.modelCtrl.$modelValue).format("mm")}}}],controllerAs:"T"})}]);<commit_msg>update dist<commit_after>!function(e){function t(n){if(i[n])return i[n].exports;var r=i[n]={exports:{},id:n,loaded:!1};return e[n].call(r.exports,r,r.exports,t),r.loaded=!0,r.exports}var i={};return t.m=e,t.c=i,t.p="",t(0)}([function(e,t,i){"use strict";angular.module("mdDatetime",["ngMaterial"]),i(4),i(3)},function(e,t){e.exports='<md-datepicker ng-model=DT.params.date ng-change=DT.updateDate()></md-datepicker> <md-timepicker ng-model=DT.params.time ng-change=DT.updateTime() mode=24h></md-timepicker> <md-button class="md-datetime-picker-reset md-icon-button md-ink-ripple" ng-click=DT.reset() ng-if=DT.canReset> <md-icon> <svg height=24 viewBox="0 0 24 24" width=24 xmlns=http://www.w3.org/2000/svg> <path d="M12 6v3l4-4-4-4v3c-4.42 0-8 3.58-8 8 0 1.57.46 3.03 1.24 4.26L6.7 14.8c-.45-.83-.7-1.79-.7-2.8 0-3.31 2.69-6 6-6zm6.76 1.74L17.3 9.2c.44.84.7 1.79.7 2.8 0 3.31-2.69 6-6 6v-3l-4 4 4 4v-3c4.42 0 8-3.58 8-8 0-1.57-.46-3.03-1.24-4.26z"/> <path d="M0 0h24v24H0z" fill=none /> </svg> </md-icon> <md-tooltip>Reset to NOW</md-tooltip> </md-button>'},function(e,t){e.exports='<md-button class="md-timepicker-button md-icon-button md-ink-ripple" type=button aria-label="pick time" ng-click=T.togglePicking($event) ng-class="{ active: T.picking }"> <md-icon> <svg height=24 viewBox="0 0 24 24" width=24 xmlns=http://www.w3.org/2000/svg> <path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/> <path d="M0 0h24v24H0z" fill=none /> <path d="M12.5 7H11v6l5.25 3.15.75-1.23-4.5-2.67z"/> </svg> </md-icon> </md-button>
 <md-input-container> <input class=md-timepicker-input type=text aria-label="time input" ng-model=T.viewValue ng-pattern=T.timePattern ng-change=T.parse()> <md-button class="md-datepicker-triangle-button md-icon-button" ng-click=T.togglePicking($event) aria-label="pick time">

 </md-button> </md-input-container>
 <md-toolbar class=md-timepicker-time>  {{T.time.hour()}}  :  {{T.time.minute()}}  </md-toolbar>
 am/pm

 {{::hour.viewValue}}

 {{::hour.viewValue}}

 {{::minute.viewValue}}

'},function(e,t,i){"use strict";angular.module("mdDatetime").component("mdDatetime",{require:{modelCtrl:"ngModel"},template:i(1),controller:["$attrs",function(e){var t=this;this.$onInit=function(){t.modelCtrl.$render=function(){t.datetime=moment(t.modelCtrl.$modelValue),t.updateParams(!0)}},this.updateDate=function(){var e=moment(t.params.date);t.datetime.year(e.year()),t.datetime.month(e.month()),t.datetime.date(e.date()),t.updateParams()},this.updateTime=function(){t.datetime.hour(t.params.time.hour),t.datetime.minute(t.params.time.minute),t.updateParams()},this.updateParams=function(e){t.params={date:t.datetime.toDate(),time:{hour:t.datetime.hour(),minute:t.datetime.minute()}},e||t.modelCtrl.$setViewValue(t.datetime.toISOString())},this.canReset=!("noReset"in e),this.reset=function(){t.datetime=moment(),t.updateParams()}}],controllerAs:"DT"})},function(e,t,i){"use strict";var n=function(){function e(e,t){var i=[],n=!0,r=!1,o=void 0;try{for(var m,a=e[Symbol.iterator]();!(n=(m=a.next()).done)&&(i.push(m.value),!t||i.length!==t);n=!0);}catch(u){r=!0,o=u}finally{try{!n&&a["return"]&&a["return"]()}finally{if(r)throw o}}return i}return function(t,i){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,i);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}();angular.module("mdDatetime").component("mdTimepicker",{template:i(2),bindings:{mode:"@"},require:{modelCtrl:"ngModel"},controller:["$scope","$window",function(e,t){var i=this;this.$onInit=function(){i.modelCtrl.$render=function(){i.viewValue=moment(i.modelCtrl.$modelValue).format("HH:mm");var e=i.modelCtrl.$modelValue,t=e.hour,n=e.minute;i.hours.forEach(function(e){e.selected=e.realValue==t}),i.minutes.forEach(function(e,t){e.selected=(Math.floor(n/5)+11)%12==t})},angular.element(t).on("click",function(){i.picking=!1,e.$digest()})},this.keepPicking=function(e){e.stopPropagation()},this.outerHours=["1","2","3","4","5","6","7","8","9","10","11","12"],this.innerHours=["13","14","15","16","17","18","19","20","21","22","23","00"],this.minutes=["05","10","15","20","25","30","35","40","45","50","55","00"];var r=function(e,t){return function(i,n){var r=30*n+30;return{type:e,viewValue:i,realValue:parseInt(i,10),style:{transform:"rotate("+r+"deg) translate(0, -"+t+"px) rotate(-"+r+"deg)"}}}};this.outerHours=this.outerHours.map(r("hour",80)),this.innerHours=this.innerHours.map(r("hour",55)),this.ampm="ampm"==this.mode,this.ampm&&(this.innerHours=[]),this.hours=this.outerHours.concat(this.innerHours),this.minutes=this.minutes.map(r("minute",80)),this.togglePicking=function(e){return i.picking?i.picking=!1:(i.picking=!0,i.pickHour(),void i.keepPicking(e))},this.pickHour=function(){i.pickingMinute=!1,i.pickingHour=!0},this.pickMinute=function(){i.pickingHour=!1,i.pickingMinute=!0},this.selectHour=function(e){i.modelCtrl.$setViewValue({hour:e.realValue,minute:i.modelCtrl.$modelValue.minute}),i.outerHours.forEach(function(e){e.selected=!1}),i.innerHours.forEach(function(e){e.selected=!1}),e.selected=!0,i.pickMinute()},this.selectMinute=function(e){i.modelCtrl.$setViewValue({hour:i.modelCtrl.$modelValue.hour,minute:e.realValue}),i.minutes.forEach(function(e){e.selected=!1}),e.selected=!0,i.picking=!1},this.timePattern=/^[0-2]?[0-9]:[0-5][0-9]$/,this.parse=function(){if(i.viewValue){var e=i.viewValue.split(":"),t=n(e,2),r=t[0],o=t[1];i.modelCtrl.$setViewValue({hour:r,minute:o})}},this.time={hour:function(){return moment(i.modelCtrl.$modelValue).format("HH")},minute:function(){return moment(i.modelCtrl.$modelValue).format("mm")}}}],controllerAs:"T"})}]);<|endoftext|>


<commit_before>function SwatButton(id, show_processing_throbber)
{
	this.id = id;

	this.button = document.getElementById(this.id);

	// deprecated
	this.show_processing_throbber = show_processing_throbber;

	this.confirmation_message = '';
	this.throbber_container = null;

	if (show_processing_throbber) {
		this.initThrobber();
	}

	YAHOO.util.Event.addListener(this.button, 'click',
		this.handleClick, this, true);
}

SwatButton.prototype.handleClick = function(e)
{
	var confirmed = (this.confirmation_message) ?
		confirm(this.confirmation_message) : true;

	if (confirmed) {
		if (this.throbber_container !== null) {
			this.button.disabled = true;

			// add button to form data manually since we disabled it above
			var div = document.createElement('div');
			var hidden_field = document.createElement('input');
			hidden_field.type = 'hidden';
			hidden_field.name = this.id;
			hidden_field.value = this.button.value;
			div.appendChild(hidden_field);
			this.button.form.appendChild(div);

			this.button.form.submit(); // needed for IE
			this.showThrobber();
		}
	} else {
		YAHOO.util.Event.preventDefault(e);
	}
};

SwatButton.prototype.initThrobber = function()
{
	this.throbber_container = document.createElement('span');

	YAHOO.util.Dom.addClass(this.throbber_container,
		'swat-button-processing-throbber');

	this.button.parentNode.appendChild(this.throbber_container);
};

SwatButton.prototype.showThrobber = function()
{
	var animation = new YAHOO.util.Anim(this.throbber_container,
		{ opacity: { to: 0.5 }}, 1, YAHOO.util.Easing.easingNone);

	animation.animate();
};

SwatButton.prototype.setProcessingMessage = function(message)
{
	if (this.throbber_container === null) {
		this.initThrobber();
	}

	if (message.length > 0) {
		this.throbber_container.appendChild(document.createTextNode(message));
		YAHOO.util.Dom.addClass(this.throbber_container,
			'swat-button-processing-throbber-text');
	} else {
		// the following string is a UTF-8 encoded non breaking space
		this.throbber_container.appendChild(document.createTextNode(' '))
	}
};

SwatButton.prototype.setConfirmationMessage = function(message)
{
	this.confirmation_message = message;
};
<commit_msg>When showing processing throbber, set insensitive class on button.<commit_after>function SwatButton(id, show_processing_throbber)
{
	this.id = id;

	this.button = document.getElementById(this.id);

	// deprecated
	this.show_processing_throbber = show_processing_throbber;

	this.confirmation_message = '';
	this.throbber_container = null;

	if (show_processing_throbber) {
		this.initThrobber();
	}

	YAHOO.util.Event.addListener(this.button, 'click',
		this.handleClick, this, true);
}

SwatButton.prototype.handleClick = function(e)
{
	var confirmed = (this.confirmation_message) ?
		confirm(this.confirmation_message) : true;

	if (confirmed) {
		if (this.throbber_container !== null) {
			this.button.disabled = true;
			YAHOO.util.Dom.addClass(this.button, 'swat-insensitive');

			// add button to form data manually since we disabled it above
			var div = document.createElement('div');
			var hidden_field = document.createElement('input');
			hidden_field.type = 'hidden';
			hidden_field.name = this.id;
			hidden_field.value = this.button.value;
			div.appendChild(hidden_field);
			this.button.form.appendChild(div);

			this.button.form.submit(); // needed for IE
			this.showThrobber();
		}
	} else {
		YAHOO.util.Event.preventDefault(e);
	}
};

SwatButton.prototype.initThrobber = function()
{
	this.throbber_container = document.createElement('span');

	YAHOO.util.Dom.addClass(this.throbber_container,
		'swat-button-processing-throbber');

	this.button.parentNode.appendChild(this.throbber_container);
};

SwatButton.prototype.showThrobber = function()
{
	var animation = new YAHOO.util.Anim(this.throbber_container,
		{ opacity: { to: 0.5 }}, 1, YAHOO.util.Easing.easingNone);

	animation.animate();
};

SwatButton.prototype.setProcessingMessage = function(message)
{
	if (this.throbber_container === null) {
		this.initThrobber();
	}

	if (message.length > 0) {
		this.throbber_container.appendChild(document.createTextNode(message));
		YAHOO.util.Dom.addClass(this.throbber_container,
			'swat-button-processing-throbber-text');
	} else {
		// the following string is a UTF-8 encoded non breaking space
		this.throbber_container.appendChild(document.createTextNode(' '))
	}
};

SwatButton.prototype.setConfirmationMessage = function(message)
{
	this.confirmation_message = message;
};
<|endoftext|>


<commit_before>let kuro
let _msg
let _stickers = {}
let _table = 'stickers'
let assets = './files/stickers'
const fs = require('fs')
const axios = require('axios')
const FormData = require('form-data')
const concat = require('concat-stream')

exports.init = function(bot) {
	kuro = bot

	// Create sticker folder if it doesn't exist
	fs.existsSync(assets) || fs.mkdirSync(assets)

	// Create the table where we will be storing this module's data
	bot.db.schema.createTableIfNotExists(_table, (table) => {
		table.increments()
		table.string('name')
		table.string('file')
		table.string('url')
	}).then(() => {
		// Lets load up the existing stickers
		bot.db.table(_table).then((rows) => {
			for (let row of rows) {
				if (row.url !== '' && row.url !== undefined) {
					_stickers[row.name] = row.url
				} else {
					_stickers[row.name] = row.file
				}
			}
		})
	})
	.catch((error) => { kuro.error(error) })
}

exports.run = function(msg, args) {
	_msg = msg

	if (!(args instanceof Array)) {
		if (_stickers.hasOwnProperty(args)) return this.sendSticker(args)
		return _msg.delete()
	}

	let newargs = []
	for (let i = 1; i < args.length; i++) {
		newargs.push(args[i])
	}

	// Subcommand?
	if (args[0] === 'add') return this.add(newargs)
	if (args[0] === 'del') return this.del(newargs)
	if (args[0] === 'ren') return this.ren(newargs)
	if (args[0] === 'list') return this.list()
	if (args[0] === 'migrate') return this.migrate()

	// Not a subcommand, let's see if it's a sticker
	if (_stickers.hasOwnProperty(args[0])) return this.sendSticker(args[0])

	// Ded
	_msg.delete()
}

exports.sendSticker = function(name) {
	if (_stickers[name].startsWith('http')) {
		_msg.edit({
			embed: {
				image: { url: _stickers[name] }
			}
		});
	} else {
		let file = `${assets}/${_stickers[name]}`
		fs.access(file, fs.constants.R_OK, (err) => {
			if (err) return _msg.edit(`**Error:**\n${err}`)

			_msg.delete()
			let img = fs.readFileSync(file)
			return _msg.channel.sendFile(img, _stickers[name])
		})
	}
}

exports.add = function(args) {
	if (args[0] === undefined) {
		kuro.edit(_msg, 'No name provided.')
		return
	}

	let name = args[0]

	// Is the name of the sticker already used?
	if (_stickers.hasOwnProperty(name)) {
		kuro.edit(_msg, 'Name already in use.')
		return
	}

	// Prepare the destination container
	let dest = `${assets}/${name}`
	let url = ''

	// Stupid discord renaming stuff, breaks everything
	let discordFilename = ''
	if (args[1] !== undefined) {
		url = args[1]
	} else {
		if (typeof _msg.attachments.first() !== 'undefined') {
			if ('proxyURL' in _msg.attachments.first()) {
				url = _msg.attachments.first().proxyURL
				discordFilename = _msg.attachments.first().filename
			}
		}
	}

	if (url === '') {
		// Welp, couldn't figure out a url
		kuro.edit(_msg, 'You didnt supply either a url nor attachment, or there was an error with the attachment.')
		return
	}

	// Try and gather the extension of the file
	let re = /(?:\.([^.]+))?$/
	let ext = re.exec(url)[1]

	if (discordFilename !== '') {
		ext = re.exec(discordFilename)[1]
	}

	if (ext === undefined) {
		kuro.edit(_msg, 'The file you are linking or trying to attach doesn\'t have an extension. Kuro needs that thingy. pls fam')
		return
	}

	dest = `${dest}.${ext}`
	this.downloadImage(name, url, dest, ext)
}

exports.del = function(args) {
	if (args[0] === undefined) return kuro.edit(_msg, 'No name provided.')

	if (args[0] in _stickers) {
		kuro.db.table(_table)
			.where('name', args[0])
			.del()
			.then(() => {
				delete (_stickers[args[0]])
				return kuro.edit(_msg, 'The sticker was removed.', 1000)
			})
			.catch((e) => { kuro.edit(_msg, `Error: \n${e}`, 0) })
	} else {
		return kuro.edit(_msg, 'There is no sticker by that name.')
	}
}

exports.ren = function(args) {
	if (args[0] === undefined) return kuro.edit(_msg, 'No source sticker supplied.')
	if (args[1] === undefined) return kuro.edit(_msg, 'No destination sticker supplied.')

	if (args[0] in _stickers) {
		kuro.db.table(_table)
			.where('name', args[0])
			.update({ name: args[1] })
			.then(() => {
				_stickers[args[1]] = _stickers[args[0]]
				delete (_stickers[args[0]])
				return kuro.edit(_msg, 'Sticker renamed.', 1000)
			})
			.catch((e) => { kuro.edit(_msg, `Error: \n${e}`, 0) })
	} else {
		return kuro.edit(_msg, 'There is no sticker by that name.')
	}
}

exports.list = function() {
	let list = ''
	for (let sticker in _stickers) {
		if ({}.hasOwnProperty.call(_stickers, sticker)) {
			list = `${list}${sticker}, `
		}
	}

	list = list.substr(0, list.length - 2)
	return kuro.edit(_msg, `**__Stickers list__**\n\`\`\`\n${list}\n\`\`\``, 10000)
}

exports.downloadImage = function(name, url, dest, ext) {
	let saveFile = require('request')
		.get(url)
		.on('error', (err) => {
			kuro.log(err)
			_msg.edit(`***Error:*** ${err}`)
		})
		.pipe(fs.createWriteStream(dest))

	saveFile.on('finish', () => {
		this.uploadImage(name, dest, ext)
	})
}

exports.uploadImage = function(name, dest, ext) {
	const fd = new FormData()

	fd.append('files[]', fs.createReadStream(dest))
	fd.pipe(concat({ encoding: 'buffer' }, data => {
		axios.post('https://safe.moe/api/upload', data, { headers: fd.getHeaders() })
		.then((response) => {
			if (response.data.success === false) {
				console.error('Error uploading to safe.moe: ', response.description)
				kuro.error('Error saving sticker. Check logs')
				return this.saveStickerToDB(name, ext, '')
			}

			return this.saveStickerToDB(name, ext, response.data.files[0].url)
		})
		.catch((err) => console.log(err))
	}))
}

exports.saveStickerToDB = function(name, ext, url) {
	kuro.db.table(_table).insert({
		name: name,
		file: `${name}.${ext}`,
		url: url
	})
	.then(() => {
		_stickers[name] = `${name}.${ext}`
		if (url !== '') _stickers[name] = url
		kuro.edit(_msg, 'Sticker added', 1000)
	})
}

exports.migrate = function() {
	console.log('Starting migration')
	_msg.edit('*Starting migration to kuro v4.1.0, this might take a while depending how many stickers you have. Check the console.*')

	try {

		kuro.db.schema.table(_table, (table) => {
			table.string('url')
		}).then(() => {
			// Done for now
			kuro.db.table(_table).then((rows) => {
				console.log('Found ' + rows.length + ' stickers, starting the upload to safe.moe')

				let counter = 1
				for (let row of rows) {
					if (row.url === '' || row.url === undefined || row.url === null) {
						const fd = new FormData()

						fd.append('files[]', fs.createReadStream(`${assets}/${row.file}`))
						fd.pipe(concat({ encoding: 'buffer' }, data => {
							axios.post('https://safe.moe/api/upload', data, { headers: fd.getHeaders() })
							.then((response) => {
								if (response.data.success === false) {
									console.error('Error uploading to safe.moe: ', response.description)
								} else {
									kuro.db.table(_table).where('id', row.id).update(
										{ url: response.data.files[0].url }
									)
									.then(() => {
										console.log('Finished uploading ' + counter + '/' + rows.length + ': ' + row.name)
										counter++
										_stickers[row.name] = response.data.files[0].url
										if (counter > rows.length) {
											console.log('Migration finished, you can keep using Kuro like you normally would')
											_msg.edit('*Migration finished, you can keep using Kuro like you normally would*')
										}
									})
								}
							})
							.catch((err) => console.log(err))
						}))
					}
				}
			})
		})

		.catch((error) => { kuro.error(error) })
	} catch (e) {
		kuro.error(e)
	}
}

exports.stickerCount = function() {
	return Object.keys(_stickers).length
}

<commit_msg>Changed the pill color of sticker embeds<commit_after>let kuro
let _msg
let _stickers = {}
let _table = 'stickers'
let assets = './files/stickers'
const fs = require('fs')
const axios = require('axios')
const FormData = require('form-data')
const concat = require('concat-stream')

exports.init = function(bot) {
	kuro = bot

	// Create sticker folder if it doesn't exist
	fs.existsSync(assets) || fs.mkdirSync(assets)

	// Create the table where we will be storing this module's data
	bot.db.schema.createTableIfNotExists(_table, (table) => {
		table.increments()
		table.string('name')
		table.string('file')
		table.string('url')
	}).then(() => {
		// Lets load up the existing stickers
		bot.db.table(_table).then((rows) => {
			for (let row of rows) {
				if (row.url !== '' && row.url !== undefined) {
					_stickers[row.name] = row.url
				} else {
					_stickers[row.name] = row.file
				}
			}
		})
	})
	.catch((error) => { kuro.error(error) })
}

exports.run = function(msg, args) {
	_msg = msg

	if (!(args instanceof Array)) {
		if (_stickers.hasOwnProperty(args)) return this.sendSticker(args)
		return _msg.delete()
	}

	let newargs = []
	for (let i = 1; i < args.length; i++) {
		newargs.push(args[i])
	}

	// Subcommand?
	if (args[0] === 'add') return this.add(newargs)
	if (args[0] === 'del') return this.del(newargs)
	if (args[0] === 'ren') return this.ren(newargs)
	if (args[0] === 'list') return this.list()
	if (args[0] === 'migrate') return this.migrate()

	// Not a subcommand, let's see if it's a sticker
	if (_stickers.hasOwnProperty(args[0])) return this.sendSticker(args[0])

	// Ded
	_msg.delete()
}

exports.sendSticker = function(name) {
	if (_stickers[name].startsWith('http')) {
		_msg.edit({
			embed: {
				image: { url: _stickers[name] },
				color: 3290683
			}
		});
	} else {
		let file = `${assets}/${_stickers[name]}`
		fs.access(file, fs.constants.R_OK, (err) => {
			if (err) return _msg.edit(`**Error:**\n${err}`)

			_msg.delete()
			let img = fs.readFileSync(file)
			return _msg.channel.sendFile(img, _stickers[name])
		})
	}
}

exports.add = function(args) {
	if (args[0] === undefined) {
		kuro.edit(_msg, 'No name provided.')
		return
	}

	let name = args[0]

	// Is the name of the sticker already used?
	if (_stickers.hasOwnProperty(name)) {
		kuro.edit(_msg, 'Name already in use.')
		return
	}

	// Prepare the destination container
	let dest = `${assets}/${name}`
	let url = ''

	// Stupid discord renaming stuff, breaks everything
	let discordFilename = ''
	if (args[1] !== undefined) {
		url = args[1]
	} else {
		if (typeof _msg.attachments.first() !== 'undefined') {
			if ('proxyURL' in _msg.attachments.first()) {
				url = _msg.attachments.first().proxyURL
				discordFilename = _msg.attachments.first().filename
			}
		}
	}

	if (url === '') {
		// Welp, couldn't figure out a url
		kuro.edit(_msg, 'You didnt supply either a url nor attachment, or there was an error with the attachment.')
		return
	}

	// Try and gather the extension of the file
	let re = /(?:\.([^.]+))?$/
	let ext = re.exec(url)[1]

	if (discordFilename !== '') {
		ext = re.exec(discordFilename)[1]
	}

	if (ext === undefined) {
		kuro.edit(_msg, 'The file you are linking or trying to attach doesn\'t have an extension. Kuro needs that thingy. pls fam')
		return
	}

	dest = `${dest}.${ext}`
	this.downloadImage(name, url, dest, ext)
}

exports.del = function(args) {
	if (args[0] === undefined) return kuro.edit(_msg, 'No name provided.')

	if (args[0] in _stickers) {
		kuro.db.table(_table)
			.where('name', args[0])
			.del()
			.then(() => {
				delete (_stickers[args[0]])
				return kuro.edit(_msg, 'The sticker was removed.', 1000)
			})
			.catch((e) => { kuro.edit(_msg, `Error: \n${e}`, 0) })
	} else {
		return kuro.edit(_msg, 'There is no sticker by that name.')
	}
}

exports.ren = function(args) {
	if (args[0] === undefined) return kuro.edit(_msg, 'No source sticker supplied.')
	if (args[1] === undefined) return kuro.edit(_msg, 'No destination sticker supplied.')

	if (args[0] in _stickers) {
		kuro.db.table(_table)
			.where('name', args[0])
			.update({ name: args[1] })
			.then(() => {
				_stickers[args[1]] = _stickers[args[0]]
				delete (_stickers[args[0]])
				return kuro.edit(_msg, 'Sticker renamed.', 1000)
			})
			.catch((e) => { kuro.edit(_msg, `Error: \n${e}`, 0) })
	} else {
		return kuro.edit(_msg, 'There is no sticker by that name.')
	}
}

exports.list = function() {
	let list = ''
	for (let sticker in _stickers) {
		if ({}.hasOwnProperty.call(_stickers, sticker)) {
			list = `${list}${sticker}, `
		}
	}

	list = list.substr(0, list.length - 2)
	return kuro.edit(_msg, `**__Stickers list__**\n\`\`\`\n${list}\n\`\`\``, 10000)
}

exports.downloadImage = function(name, url, dest, ext) {
	let saveFile = require('request')
		.get(url)
		.on('error', (err) => {
			kuro.log(err)
			_msg.edit(`***Error:*** ${err}`)
		})
		.pipe(fs.createWriteStream(dest))

	saveFile.on('finish', () => {
		this.uploadImage(name, dest, ext)
	})
}

exports.uploadImage = function(name, dest, ext) {
	const fd = new FormData()

	fd.append('files[]', fs.createReadStream(dest))
	fd.pipe(concat({ encoding: 'buffer' }, data => {
		axios.post('https://safe.moe/api/upload', data, { headers: fd.getHeaders() })
		.then((response) => {
			if (response.data.success === false) {
				console.error('Error uploading to safe.moe: ', response.description)
				kuro.error('Error saving sticker. Check logs')
				return this.saveStickerToDB(name, ext, '')
			}

			return this.saveStickerToDB(name, ext, response.data.files[0].url)
		})
		.catch((err) => console.log(err))
	}))
}

exports.saveStickerToDB = function(name, ext, url) {
	kuro.db.table(_table).insert({
		name: name,
		file: `${name}.${ext}`,
		url: url
	})
	.then(() => {
		_stickers[name] = `${name}.${ext}`
		if (url !== '') _stickers[name] = url
		kuro.edit(_msg, 'Sticker added', 1000)
	})
}

exports.migrate = function() {
	console.log('Starting migration')
	_msg.edit('*Starting migration to kuro v4.1.0, this might take a while depending how many stickers you have. Check the console.*')

	try {

		kuro.db.schema.table(_table, (table) => {
			table.string('url')
		}).then(() => {
			// Done for now
			kuro.db.table(_table).then((rows) => {
				console.log('Found ' + rows.length + ' stickers, starting the upload to safe.moe')

				let counter = 1
				for (let row of rows) {
					if (row.url === '' || row.url === undefined || row.url === null) {
						const fd = new FormData()

						fd.append('files[]', fs.createReadStream(`${assets}/${row.file}`))
						fd.pipe(concat({ encoding: 'buffer' }, data => {
							axios.post('https://safe.moe/api/upload', data, { headers: fd.getHeaders() })
							.then((response) => {
								if (response.data.success === false) {
									console.error('Error uploading to safe.moe: ', response.description)
								} else {
									kuro.db.table(_table).where('id', row.id).update(
										{ url: response.data.files[0].url }
									)
									.then(() => {
										console.log('Finished uploading ' + counter + '/' + rows.length + ': ' + row.name)
										counter++
										_stickers[row.name] = response.data.files[0].url
										if (counter > rows.length) {
											console.log('Migration finished, you can keep using Kuro like you normally would')
											_msg.edit('*Migration finished, you can keep using Kuro like you normally would*')
										}
									})
								}
							})
							.catch((err) => console.log(err))
						}))
					}
				}
			})
		})

		.catch((error) => { kuro.error(error) })
	} catch (e) {
		kuro.error(e)
	}
}

exports.stickerCount = function() {
	return Object.keys(_stickers).length
}

<|endoftext|>


<commit_before>var five = require('johnny-five');
var songs = require('j5-songs');
var temporal = require("temporal");

var board = new five.Board();

board.on("ready", function() {

  var servoPan = new five.Servo({ pin: 4,
                                  range: [40,60]});
  var servoTilt = new five.Servo({ pin: 12,
                                  range: [40,120]});

  var eyeLt = new five.Led.Matrix({
    addresses: [0x70],
    controller: "HT16K33",
    rotation: 4,
  });

  var eyeRt = new five.Led.Matrix({
    addresses: [0x71],
    controller: "HT16K33",
    rotation: 4,
  });

  var mouthLt = new five.Led.Matrix({
    addresses: [0x72],
    controller: "HT16K33",
    rotation: 4,
  });

  var mouthRt = new five.Led.Matrix({
    addresses: [0x73],
    controller: "HT16K33",
    rotation: 4,
  });

  var Eyes = {
    grumpyEye: [
    "00011000",
    "01100110",
    "01100110",
    "11111111",
    "11111111",
    "01111110",
    "01111110",
    "00011000"
    ],

    roundEye: [
    "00111100",
    "01111110",
    "11100111",
    "11000011",
    "11000011",
    "11100111",
    "01111110",
    "00111100"
    ],

    roundBigEye: [
    "00111100",
    "01100110",
    "11000011",
    "11000011",
    "11000011",
    "11000011",
    "01100110",
    "00111100"
    ],

    ovalEye: [
    "00000000",
    "00111100",
    "01111110",
    "11100111",
    "11100111",
    "01111110",
    "00111100",
    "00000000"
    ],

    ovalBigEye: [
    "00000000",
    "00111100",
    "01100110",
    "11000011",
    "11000011",
    "01100110",
    "00111100",
    "00000000"
    ],

    closeEye: [
    "00000000",
    "00000000",
    "00111100",
    "11111111",
    "11111111",
    "00111100",
    "00000000",
    "00000000"
    ],
  };

  var smileLt = [
    "00000000",
    "00000000",
    "11000000",
    "01100000",
    "00110000",
    "00011111",
    "00000111",
    "00000000"
  ];

  var smileRt = [
    "00000000",
    "00000000",
    "00000011",
    "00000110",
    "00001100",
    "11111000",
    "11100000",
    "00000000"
  ];
  var grumpyLt = [
    "00000000",
    "00000000",
    "00000011",
    "00000111",
    "00001100",
    "00011000",
    "00011000",
    "00011000"
  ];

  var grumpyRt = [
    "00000000",
    "00000000",
    "11000000",
    "11100000",
    "00110000",
    "00011000",
    "00011000",
    "00011000"
  ];

  var piezo = new five.Piezo(5);

  var digits = new five.Led.Digits({
    controller: "HT16K33",
    addresses: [0x74]
  });

  var proximity = new five.Proximity({
    controller: "MB1000",
    pin: "A4",
    freq: "100"
  });

  var distanceCM

  proximity.on("data", function() {
    var fixed_num = parseFloat(this.cm).toFixed( 1 );
    digits.print(fixed_num);
    digitsCM = fixed_num;
    console.log("Entfernung: ");
    console.log("  cm  : ", fixed_num);
    console.log("-----------------");
  });

  var song = songs.load('nyan-melody');

  doNyanCat();

  function doNyanCat() {
  // Load a song object
    temporal.queue([ //<3>
      {
         // stop del
         delay: 10,
         task: sleep,
      },
      {
         // back up
         delay: 5000,
         task: wakeup,
      },
      {
         // back up
         delay: 2000,
         task: playsong,
      },
      {
         // back up
         delay: 33000,
         task: twinkle,
      },
      {
         // go to slepp
         delay: 3000,
         task: sleep,
      },
   ])
  };

  function sleep() {
    servoPan.center();
    servoTilt.max();

    eyeLt.draw(Eyes.closeEye);
    eyeRt.draw(Eyes.closeEye);
    mouthLt.draw(grumpyLt);
    mouthRt.draw(grumpyRt);
  };

  function wakeup() {
    servoPan.min();
    servoTilt.center();

    eyeLt.draw(Eyes.roundEye);
    eyeRt.draw(Eyes.roundEye);
    mouthLt.draw(smileLt);
    mouthRt.draw(smileRt);
  };

  function playsong() {
    // Play it !
    piezo.play(song);
    servoPan.sweep({
        range: [40, 60]
    });
  };

 function twinkle() {
    servoPan.stop();
    eyeLt.draw(Eyes.ovalEye);
    eyeLt.draw(Eyes.closeEye);
    eyeLt.draw(Eyes.roundEye);
  };

});

<commit_msg>Update house-pet.js<commit_after>var five = require('johnny-five');
var songs = require('j5-songs');
var temporal = require("temporal");

var board = new five.Board();

board.on("ready", function() {

  var servoPan = new five.Servo({ pin: 4,
                                  range: [40,60]});
  var servoTilt = new five.Servo({ pin: 12,
                                  range: [40,120]});

  var eyeLt = new five.Led.Matrix({
    addresses: [0x70],
    controller: "HT16K33",
    rotation: 4,
  });

  var eyeRt = new five.Led.Matrix({
    addresses: [0x71],
    controller: "HT16K33",
    rotation: 4,
  });

  var mouthLt = new five.Led.Matrix({
    addresses: [0x72],
    controller: "HT16K33",
    rotation: 4,
  });

  var mouthRt = new five.Led.Matrix({
    addresses: [0x73],
    controller: "HT16K33",
    rotation: 4,
  });

  var Eyes = {
    grumpyEye: [
    "00011000",
    "01100110",
    "01100110",
    "11111111",
    "11111111",
    "01111110",
    "01111110",
    "00011000"
    ],

    roundEye: [
    "00111100",
    "01111110",
    "11100111",
    "11000011",
    "11000011",
    "11100111",
    "01111110",
    "00111100"
    ],

    roundBigEye: [
    "00111100",
    "01100110",
    "11000011",
    "11000011",
    "11000011",
    "11000011",
    "01100110",
    "00111100"
    ],

    ovalEye: [
    "00000000",
    "00111100",
    "01111110",
    "11100111",
    "11100111",
    "01111110",
    "00111100",
    "00000000"
    ],

    ovalBigEye: [
    "00000000",
    "00111100",
    "01100110",
    "11000011",
    "11000011",
    "01100110",
    "00111100",
    "00000000"
    ],

    closeEye: [
    "00000000",
    "00000000",
    "00111100",
    "11111111",
    "11111111",
    "00111100",
    "00000000",
    "00000000"
    ],
  };

  var smileLt = [
    "00000000",
    "00000000",
    "11000000",
    "01100000",
    "00110000",
    "00011111",
    "00000111",
    "00000000"
  ];

  var smileRt = [
    "00000000",
    "00000000",
    "00000011",
    "00000110",
    "00001100",
    "11111000",
    "11100000",
    "00000000"
  ];
  var grumpyLt = [
    "00000000",
    "00000000",
    "00000011",
    "00000111",
    "00001100",
    "00011000",
    "00011000",
    "00011000"
  ];

  var grumpyRt = [
    "00000000",
    "00000000",
    "11000000",
    "11100000",
    "00110000",
    "00011000",
    "00011000",
    "00011000"
  ];

  var piezo = new five.Piezo(5);

  var digits = new five.Led.Digits({
    controller: "HT16K33",
    addresses: [0x74]
  });

  var proximity = new five.Proximity({
    controller: "MB1000",
    pin: "A4",
    freq: "100"
  });

  var distanceCM

  proximity.on("data", function() {
    var fixed_num = parseFloat(this.cm).toFixed( 1 );
    digits.print(fixed_num);
    digitsCM = fixed_num;
    console.log("Entfernung: ");
    console.log("  cm  : ", fixed_num);
    console.log("-----------------");
  });

  var song = songs.load('nyan-melody');

  doNyanCat();

  function doNyanCat() {
  // Load a song object
    temporal.queue([ //<3>
      {
         // stop del
         delay: 10,
         task: sleep,
      },
      {
         // back up
         delay: 5000,
         task: wakeup,
      },
      {
         // back up
         delay: 2000,
         task: playsong,
      },
      {
         // back up
         delay: 40000,
         task: twinkle,
      },
      {
         // go to slepp
         delay: 3000,
         task: sleep,
      },
   ])
  };

  function sleep() {
    servoPan.center();
    servoTilt.max();

    eyeLt.draw(Eyes.closeEye);
    eyeRt.draw(Eyes.closeEye);
    mouthLt.draw(grumpyLt);
    mouthRt.draw(grumpyRt);
  };

  function wakeup() {
    servoPan.min();
    servoTilt.center();

    eyeLt.draw(Eyes.roundEye);
    eyeRt.draw(Eyes.roundEye);
    mouthLt.draw(smileLt);
    mouthRt.draw(smileRt);
  };

  function playsong() {
    // Play it !
    piezo.play(song);
    servoPan.sweep({
        range: [40, 60]
    });
  };

 function twinkle() {
    servoPan.stop();
    eyeLt.draw(Eyes.ovalEye);
    eyeLt.draw(Eyes.closeEye);
    eyeLt.draw(Eyes.roundEye);
  };

});

<|endoftext|>