<commit_before>// @flow

import type { Config } from './Config';

import Telegraf from 'telegraf';

import appConfig from '../../../app-config';
import bus from '../../bus';
import botNetwork from './network';

const config: Config = appConfig.telegram;

const chat = config[process.env.NODE_ENV === 'prod' ? 'prod' : 'dev'];

const { BOT_TOKEN } = config;

const client: Telegraf = new Telegraf(BOT_TOKEN);

type User = {
  id: number,
  is_bot: boolean,
  first_name: string,
  last_name?: string,
  username?: string,
  language_code?: string
}

class Name {
  static from(user: User) {
    if (user.username) {
      return user.username;
    }

    if (user.last_name) {
      return `${user.first_name} ${user.last_name}`;
    }

    return user.first_name;
  }
}

class Message {
  msg: Object;

  constructor(msg: Object) {
    this.msg = msg;
  }

  toString() {
    return this.msg.text || '';
  }
}

class ReplyToMessage extends Message {
  static test(msg) {
    const replyToMessage = msg.reply_to_message;
    const isReplyWithText = replyToMessage && replyToMessage.text;
    return isReplyWithText;
  }

  getDetails() {
    const msg = this.msg;
    const replyToMessage = msg.reply_to_message;
    const nick = Name.from(replyToMessage.from);
    const message = replyToMessage.text;

    return [nick, message];
  }

  toString() {
    const msg = this.msg;
    let [nick, message] = this.getDetails();

    // adds quoting brackets
    message = message.replace(/\n/g, '\n>> ');

    return `>> <${nick}> ${message}\n${msg.text}`;
  }
}

class ForwardedMessage extends Message {
  static test(msg) {
    return msg.forward_from;
  }

  toString() {
    const msg = this.msg;
    const nick = Name.from(msg.forward_from);

    // adds quoting brackets
    const message = msg.text.replace(/\n/g, '\n>> ');

    return `>> <${nick}> ${message}`;
  }
}

class BotMessage extends ReplyToMessage {
  static test(msg) {
    const replyToMessage = msg.reply_to_message;

    const isReplyWithText = replyToMessage && replyToMessage.text;
    if (!isReplyWithText) {
      return false;
    }

    const isReplyFromOurBot = BOT_TOKEN.indexOf(replyToMessage.from.id) > -1;

    return isReplyFromOurBot;
  }

  getDetails() {
    const msg = this.msg;
    const replyToMessage = msg.reply_to_message;
    const text = replyToMessage.text;
    const lineEndPos = text.indexOf('\n');
    const _nick = text.slice(0, lineEndPos);
    const _message = text.slice(lineEndPos + 1);
    return [_nick, _message];
  }
}

function messageFactory(msg) {
  if (ForwardedMessage.test(msg)) {
    return new ForwardedMessage(msg);
  }

  if (!ReplyToMessage.test(msg)) {
    return new Message(msg);
  }

  if (BotMessage.test(msg)) {
    return new BotMessage(msg);
  }

  return new ReplyToMessage(msg);
}

function prepareMessage(msg) {
  const message = messageFactory(msg);
  const stringMessage = message.toString();

  return stringMessage;
}

function prepareEmittingMessageDetails(message) {
  const room = message.chat.title;
  if (room !== chat.title) {
    return null;
  }

  const name = Name.from(message.from);
  const msg = prepareMessage(message);

  return {network: botNetwork, room, name, message: msg};
}

client.on('text', (ctx, next) => {
  const msg = prepareEmittingMessageDetails(ctx.message);
  if (msg) {
    bus.emit('message', msg);
    next();
  }
});

client.on('sticker', (ctx, next) => {
  const msg = prepareEmittingMessageDetails(ctx.message);
  if (msg) {
    const sticker = ctx.message.sticker;
    const emoji = sticker.emoji;
    msg.message = emoji || msg.message;
    bus.emit('message', msg);
    next();
  }
});

client.startPolling();

export default client;
<commit_msg>Telegram: update client.js<commit_after>// @flow

import type { Config } from './Config';

import type {
  Telegram$User,
  Telegram$Message
} from './telegram.h';

import Telegraf from 'telegraf';

import appConfig from '../../../app-config';
import bus from '../../bus';
import botNetwork from './network';

const config: Config = appConfig.telegram;

const chat = config[process.env.NODE_ENV === 'prod' ? 'prod' : 'dev'];

const { BOT_TOKEN } = config;

const client: Telegraf = new Telegraf(BOT_TOKEN);

class Name {
  static from(user: Telegram$User): string {
    if (user.username) {
      return user.username;
    }

    if (user.last_name) {
      return `${user.first_name} ${user.last_name}`;
    }

    return user.first_name;
  }
}

class Message {
  msg: Telegram$Message;

  constructor(msg: Telegram$Message) {
    this.msg = msg;
  }

  toString(): string {
    return this.msg.text || '';
  }
}

class ReplyToMessage extends Message {
  static test(msg: Telegram$Message): boolean {
    const replyToMessage = msg.reply_to_message;
    const isReplyWithText = replyToMessage && replyToMessage.text;

    return !!isReplyWithText;
  }

  getDetails(): [string, string] {
    const msg = this.msg;
    const replyToMessage = msg.reply_to_message;

    if (!replyToMessage) return ['', ''];

    const nick = Name.from(replyToMessage.from);
    const message = replyToMessage && replyToMessage.text;

    return [nick, message || ''];
  }

  toString(): string {
    const msg = this.msg;
    let [nick, message] = this.getDetails();

    // adds quoting brackets
    message = message.replace(/\n/g, '\n>> ');

    return `>> <${nick}> ${message}\n${msg.text || ''}`;
  }
}

class ForwardedMessage extends Message {
  static test(msg: Telegram$Message): boolean {
    return !!msg.forward_from;
  }

  toString(): string {
    const msg = this.msg;

    if (!msg.forward_from) return '';

    const nick = Name.from(msg.forward_from);

    // adds quoting brackets
    const message = msg.text ? msg.text.replace(/\n/g, '\n>> ') : '';

    return `>> <${nick}> ${message}`;
  }
}

class BotMessage extends ReplyToMessage {
  static test(msg: Telegram$Message): boolean {
    const replyToMessage = msg.reply_to_message;

    if (!replyToMessage) return false;

    const isReplyWithText: boolean = !!replyToMessage.text;

    if (!isReplyWithText) {
      return false;
    }

    const isReplyFromOurBot = BOT_TOKEN.indexOf(
      replyToMessage.from.id.toString()
    ) > -1;

    return isReplyFromOurBot;
  }

  getDetails(): [string, string] {
    const msg = this.msg;
    const replyToMessage = msg.reply_to_message;
    const text = replyToMessage ? (replyToMessage.text || '') : '';
    const lineEndPos = text.indexOf('\n');
    const _nick = text.slice(0, lineEndPos);
    const _message = text.slice(lineEndPos + 1);

    return [_nick, _message];
  }
}

function messageFactory(msg: Telegram$Message) {
  if (ForwardedMessage.test(msg)) {
    return new ForwardedMessage(msg);
  }

  if (!ReplyToMessage.test(msg)) {
    return new Message(msg);
  }

  if (BotMessage.test(msg)) {
    return new BotMessage(msg);
  }

  return new ReplyToMessage(msg);
}

function prepareMessage(msg) {
  const message = messageFactory(msg);
  const stringMessage = message.toString();

  return stringMessage;
}

function prepareEmittingMessageDetails(message: Telegram$Message) {
  const room = message.chat.title;

  if (room !== chat.title) {
    return null;
  }

  const name = Name.from(message.from);
  const msg = prepareMessage(message);

  return {network: botNetwork, room, name, message: msg};
}

client.on('text', (ctx: Object, next: Function) => {
  const msg = prepareEmittingMessageDetails(ctx.message);
  if (msg) {
    bus.emit('message', msg);
    next();
  }
});

client.on('sticker', (ctx: Object, next: Function) => {
  const msg = prepareEmittingMessageDetails(ctx.message);
  if (msg) {
    const sticker = ctx.message.sticker;
    const emoji = sticker.emoji;
    msg.message = emoji || msg.message;
    bus.emit('message', msg);
    next();
  }
});

client.startPolling();

export default client;
<|endoftext|>


<commit_before><commit_msg>Echo bot messages to console<commit_after><|endoftext|>


<commit_before>
const SPLITTER_COLOR = [255, 20, 147];
const SPLITTER_WIDTH = 4;

export default class Component {
    static get Splitter(){
        return Splitter;
    }
}

class Emitter {
    constructor(){
        this.listeners = {};
    }
    emit(eventName, arg){
        if(this.listeners.hasOwnProperty(eventName) === true){
            this.listeners[eventName](arg);
        }
    }
    on(eventName, listener){
        this.listeners[eventName] = listener;
    }
    off(eventName){
        this.listeners[eventName] = null;
    }
}

class Splitter extends Emitter {
    constructor(parentDOM, horizontal = true){
        super();
        this.parentDOM = parentDOM;
        this.horizontal = horizontal;
        this.wrap   = document.createElement('div');
        this.first  = document.createElement('div');
        this.split  = document.createElement('div');
        this.second = document.createElement('div');
        this.isDown = false;
        this.prev = [0, 0];

        // styling
        appendStyle(this.wrap, {
            width: '100%',
            height: '100%',
            display: 'flex',
            flexDirection: this.horizontal === true ? 'column' : 'row',
            overflow: 'hidden',
        });
        appendStyle(this.split, {
            backgroundColor: `rgb(${SPLITTER_COLOR.join(',')})`,
            userSelect: 'none',
        });

        // appending
        this.wrap.appendChild(this.first);
        this.wrap.appendChild(this.split);
        this.wrap.appendChild(this.second);
        this.parentDOM.appendChild(this.wrap);

        // event setting
        const DOWN = (evt) => {
            this.isDown = true;
            // let bound = this.parentDOM.getBoundingClientRect();
            // this.prev = [evt.clientX - bound.left, evt.clientY - bound.top];
            window.addEventListener('mousemove', MOVE, false);
            window.addEventListener('mouseup', UP, false);
        };
        const MOVE = (evt) => {
            if(this.isDown !== true){return;}
            let bound = this.parentDOM.getBoundingClientRect();
            let x = (evt.clientX - bound.left) / bound.width;
            let y = (evt.clientY - bound.top) / bound.height;
            if(this.horizontal === true){
                this.update(y);
            }else{
                this.update(x);
            }
            this.emit('change', {x, y});
        };
        const UP = (evt) => {
            this.isDown = false;
            window.removeEventListener('mousemove', MOVE);
            window.removeEventListener('mouseup', UP);
        };
        this.split.addEventListener('mousedown', DOWN, false);

        this.update();
    }
    update(ratio = 0.5){
        let first = `calc(${ratio * 100}% - ${SPLITTER_WIDTH / 2}px)`;
        let second = `calc(${100 - first}% - ${SPLITTER_WIDTH / 2}px)`;
        if(this.horizontal === true){
            appendStyle(this.first, {
                width: '100%',
                height: first,
            });
            appendStyle(this.split, {
                borderTop: `1px solid rgba(0, 0, 0, 0.3)`,
                borderBottom: `1px solid rgba(0, 0, 0, 0.3)`,
                width: '100%',
                minHeight: `${SPLITTER_WIDTH}px`,
                maxHeight: `${SPLITTER_WIDTH}px`,
                cursor: 'row-resize',
            });
            appendStyle(this.second, {
                width: '100%',
                height: second,
            });
        }else{
            appendStyle(this.first, {
                width: first,
                height: '100%',
            });
            appendStyle(this.split, {
                borderLeft: `1px solid rgba(0, 0, 0, 0.3)`,
                borderRight: `1px solid rgba(0, 0, 0, 0.3)`,
                minWidth: `${SPLITTER_WIDTH}px`,
                maxWidth: `${SPLITTER_WIDTH}px`,
                height: '100%',
                cursor: 'col-resize',
            });
            appendStyle(this.second, {
                width: second,
                height: '100%',
            });
        }
    }
}

function appendStyle(target, style){
    for(let s in style){
        target.style[s] = style[s];
    }
}

<commit_msg>add tabstrip component<commit_after>
const SPLITTER_COLOR = [255, 20, 147];
const SPLITTER_WIDTH = 4;
const TABSTRIP_COLOR = [240, 240, 240];
const TABSTRIP_TAB_WIDTH = 100;
const TABSTRIP_TAB_HEIGHT = 20;
const TABSTRIP_TAB_LINE_WIDTH = 4;

export default class Component {
    static get Splitter(){
        return Splitter;
    }
    static get TabStrip(){
        return TabStrip;
    }
}

class Emitter {
    constructor(){
        this.listeners = {};
    }
    emit(eventName, arg){
        if(this.listeners.hasOwnProperty(eventName) === true){
            this.listeners[eventName](arg);
        }
    }
    on(eventName, listener){
        this.listeners[eventName] = listener;
    }
    off(eventName){
        this.listeners[eventName] = null;
    }
}

class Splitter extends Emitter {
    constructor(parentDOM, horizontal = true){
        super();
        this.parentDOM = parentDOM;
        this.horizontal = horizontal;
        this.wrap   = document.createElement('div');
        this.first  = document.createElement('div');
        this.split  = document.createElement('div');
        this.second = document.createElement('div');
        this.isDown = false;
        this.prev = [0, 0];

        // styling
        appendStyle(this.wrap, {
            width: '100%',
            height: '100%',
            display: 'flex',
            flexDirection: this.horizontal === true ? 'column' : 'row',
            overflow: 'hidden',
        });
        appendStyle(this.split, {
            backgroundColor: `rgb(${SPLITTER_COLOR.join(',')})`,
            userSelect: 'none',
        });

        // appending
        this.wrap.appendChild(this.first);
        this.wrap.appendChild(this.split);
        this.wrap.appendChild(this.second);
        this.parentDOM.appendChild(this.wrap);

        // event setting
        const DOWN = (evt) => {
            this.isDown = true;
            // let bound = this.parentDOM.getBoundingClientRect();
            // this.prev = [evt.clientX - bound.left, evt.clientY - bound.top];
            window.addEventListener('mousemove', MOVE, false);
            window.addEventListener('mouseup', UP, false);
        };
        const MOVE = (evt) => {
            if(this.isDown !== true){return;}
            let bound = this.parentDOM.getBoundingClientRect();
            let x = (evt.clientX - bound.left) / bound.width;
            let y = (evt.clientY - bound.top) / bound.height;
            if(this.horizontal === true){
                this.update(y);
            }else{
                this.update(x);
            }
            this.emit('change', {x, y});
        };
        const UP = (evt) => {
            this.isDown = false;
            window.removeEventListener('mousemove', MOVE);
            window.removeEventListener('mouseup', UP);
        };
        this.split.addEventListener('mousedown', DOWN, false);

        this.update();
    }
    update(ratio = 0.5){
        let first = `calc(${ratio * 100}% - ${SPLITTER_WIDTH / 2}px)`;
        let second = `calc(${100 - ratio * 100}% - ${SPLITTER_WIDTH / 2}px)`;
        if(this.horizontal === true){
            appendStyle(this.first, {
                width: '100%',
                height: first,
            });
            appendStyle(this.split, {
                borderTop: `1px solid rgba(0, 0, 0, 0.3)`,
                borderBottom: `1px solid rgba(0, 0, 0, 0.3)`,
                width: '100%',
                minHeight: `${SPLITTER_WIDTH}px`,
                maxHeight: `${SPLITTER_WIDTH}px`,
                cursor: 'row-resize',
            });
            appendStyle(this.second, {
                width: '100%',
                height: second,
            });
        }else{
            appendStyle(this.first, {
                width: first,
                height: '100%',
            });
            appendStyle(this.split, {
                borderLeft: `1px solid rgba(0, 0, 0, 0.3)`,
                borderRight: `1px solid rgba(0, 0, 0, 0.3)`,
                minWidth: `${SPLITTER_WIDTH}px`,
                maxWidth: `${SPLITTER_WIDTH}px`,
                height: '100%',
                cursor: 'col-resize',
            });
            appendStyle(this.second, {
                width: second,
                height: '100%',
            });
        }
    }
}

class TabStrip extends Emitter {
    constructor(parentDOM, tabs, selectedIndex){
        super();
        this.parentDOM = parentDOM;
        this.count = Math.max(1, tabs.length);
        this.index = Math.min(this.count - 1, selectedIndex);
        this.tabs = [];
        this.inners = [];
        this.wrap = document.createElement('div');
        this.tabBlock = document.createElement('div');
        this.innerBlock = document.createElement('div');

        // styling
        appendStyle(this.wrap, {
            width: '100%',
            height: '100%',
            display: 'flex',
            flexDirection: 'column',
        });
        appendStyle(this.tabBlock, {
            lineHeight: `${TABSTRIP_TAB_HEIGHT}px`,
            width: '100%',
            minHeight: `${TABSTRIP_TAB_HEIGHT + TABSTRIP_TAB_LINE_WIDTH}px`,
            maxHeight: `${TABSTRIP_TAB_HEIGHT + TABSTRIP_TAB_LINE_WIDTH}px`,
            display: 'flex',
            flexDirection: 'row',
        });
        appendStyle(this.innerBlock, {
            width: '100%',
            height: '100%',
        });

        // appending
        this.parentDOM.appendChild(this.wrap);
        this.wrap.appendChild(this.tabBlock);
        this.wrap.appendChild(this.innerBlock);
        tabs.forEach((v, index) => {
            let item = new Tab(this.tabBlock, index, v, this.index === index);
            item.on('click', (idx) => {
                this.tabs.forEach((tab, i) => {
                    tab.update(idx === i);
                });
            });
            this.tabs.push(item);
            let inner = document.createElement('div');
            appendStyle(inner, {
                width: '100%',
                height: '100%',
                overflow: 'hidden',
            });
            inner.setAttribute('id', `page${index}_${v}`);
            inner.textContent = index;
            this.innerBlock.appendChild(inner);
            this.inners.push(inner);
        });

        // event setting
    }
    getPage(index){
        return this.inners[index];
    }
}

class Tab extends Emitter {
    static get ACTIVE(){return `${TABSTRIP_TAB_LINE_WIDTH}px solid rgb(${TABSTRIP_COLOR.join(',')})`;}
    static get DEACTIVE(){return `${TABSTRIP_TAB_LINE_WIDTH}px solid rgba(${TABSTRIP_COLOR.join(',')},0.3)`;}
    static get ACTIVE_COLOR(){return `rgb(${TABSTRIP_COLOR.join(',')})`;}
    static get DEACTIVE_COLOR(){return `rgba(${TABSTRIP_COLOR.join(',')},0.3)`;}
    constructor(parentDOM, index, title, isActive = false){
        super();
        this.parentDOM = parentDOM;
        this.index = index;
        this.wrap = document.createElement('div');
        this.wrap.textContent = title;
        this.active = isActive;
        // styling
        appendStyle(this.wrap, {
            borderBottom: this.active === true ? Tab.ACTIVE : Tab.DEACTIVE,
            color: this.active === true ? Tab.ACTIVE_COLOR : Tab.DEACTIVE_COLOR,
            lineHeight: `${TABSTRIP_TAB_HEIGHT}px`,
            minWidth: `${TABSTRIP_TAB_WIDTH}px`,
            maxWidth: `${TABSTRIP_TAB_WIDTH}px`,
            whiteSpace: 'nowrap',
            textOverflow: 'ellipsis',
            overflow: 'hidden',
        });
        // appending
        this.parentDOM.appendChild(this.wrap);
        // event setting
        this.wrap.addEventListener('click', () => {
            this.emit('click', index);
        }, false);
        this.wrap.addEventListener('mouseenter', () => {
            appendStyle(this.wrap, {
                borderBottom: Tab.ACTIVE,
            });
        }, false);
        this.wrap.addEventListener('mouseleave', () => {
            this.update();
        }, false);
    }
    setActive(isActive){
        if(isActive == null){return;}
        this.active = isActive;
    }
    update(isActive){
        this.setActive(isActive);
        appendStyle(this.wrap, {
            color: this.active === true ? Tab.ACTIVE_COLOR : Tab.DEACTIVE_COLOR,
            borderBottom: this.active === true ? Tab.ACTIVE : Tab.DEACTIVE,
        });
    }
}

function appendStyle(target, style){
    for(let s in style){
        target.style[s] = style[s];
    }
}

<|endoftext|>


<commit_before>import { Observable } from 'rx';
import { curry, converge, prop, path, pipe, defaultTo } from 'ramda';
import { watch } from '../../util/FileUtil';
import { DEFAULT_CONFIG } from '../../CONST';
import {
  getJsGlobPattern,
  getCssGlobPattern,
  getHtmlGlobPattern,
  getJsRender,
  getCssRender,
  getHtmlRender,
  getPostProcessorForCss
} from '../../util/AssetUtil';
import { readToStr } from '../../util/FileUtil';

const getLocalsFromPlayground = converge(
  (title, cssBase, stylesheets, scripts) => ({title, cssBase, stylesheets, scripts}),
  [
    pipe(prop('title'), defaultTo(DEFAULT_CONFIG.title)),
    pipe(path(['css', 'base']), defaultTo(null)),
    pipe(path(['css', 'external']), defaultTo(null)),
    pipe(path(['js', 'external']), defaultTo(null))
  ]
);

export const setLocals = curry(function (serveAssets, config) {
  pipe(getLocalsFromPlayground, serveAssets.setLocals)(config);
});

function processHtmlFile({targetDir}, serveAssets, config) {
  return watch(getHtmlGlobPattern(targetDir, config))
    .debounce(100)
    .flatMap(readToStr)
    .flatMap(getHtmlRender(config))
    .startWith('

')
    .retry()
    .doOnNext(serveAssets.updateAsset('html'));
}

function processJsFile({targetDir}, serveAssets, config) {
  return watch(getJsGlobPattern(targetDir, config))
    .debounce(100)
    .flatMap(readToStr)
    .flatMap(getJsRender(config))
    .startWith("try {\n  document.getElementById('playground').innerHTML = 'hello, playground!';\n} catch (err) {}")
    .retry()
    .doOnNext(serveAssets.updateAsset('js'));
}

function processCssFile({targetDir}, serveAssets, config) {
  return watch(getCssGlobPattern(targetDir, config))
    .debounce(100)
    .flatMap(readToStr)
    .flatMap(getCssRender(config))
    .flatMap(getPostProcessorForCss(config))
    .startWith('#playground {\n  color: rebeccapurple;\n}')
    .retry()
    .doOnNext(serveAssets.updateAsset('css'));
}

export const processAssetFiles = curry(function (opts, serveAssets, config) {
  return Observable.combineLatest(
    processJsFile(opts, serveAssets, config),
    processCssFile(opts, serveAssets, config),
    processHtmlFile(opts, serveAssets, config)
  );
});
<commit_msg>Remove dup<commit_after>import { Observable } from 'rx';
import { curry, converge, prop, path, pipe, defaultTo } from 'ramda';
import { watch, readToStr } from '../../util/FileUtil';
import { DEFAULT_CONFIG } from '../../CONST';
import {
  getJsGlobPattern,
  getCssGlobPattern,
  getHtmlGlobPattern,
  getJsRender,
  getCssRender,
  getHtmlRender,
  getPostProcessorForCss
} from '../../util/AssetUtil';

const getLocalsFromPlayground = converge(
  (title, cssBase, stylesheets, scripts) => ({title, cssBase, stylesheets, scripts}),
  [
    pipe(prop('title'), defaultTo(DEFAULT_CONFIG.title)),
    pipe(path(['css', 'base']), defaultTo(null)),
    pipe(path(['css', 'external']), defaultTo(null)),
    pipe(path(['js', 'external']), defaultTo(null))
  ]
);

export const setLocals = curry(function (serveAssets, config) {
  pipe(getLocalsFromPlayground, serveAssets.setLocals)(config);
});

function processHtmlFile({targetDir}, serveAssets, config) {
  return watch(getHtmlGlobPattern(targetDir, config))
    .debounce(100)
    .flatMap(readToStr)
    .flatMap(getHtmlRender(config))
    .startWith('

')
    .retry()
    .doOnNext(serveAssets.updateAsset('html'));
}

function processJsFile({targetDir}, serveAssets, config) {
  return watch(getJsGlobPattern(targetDir, config))
    .debounce(100)
    .flatMap(readToStr)
    .flatMap(getJsRender(config))
    .startWith("try {\n  document.getElementById('playground').innerHTML = 'hello, playground!';\n} catch (err) {}")
    .retry()
    .doOnNext(serveAssets.updateAsset('js'));
}

function processCssFile({targetDir}, serveAssets, config) {
  return watch(getCssGlobPattern(targetDir, config))
    .debounce(100)
    .flatMap(readToStr)
    .flatMap(getCssRender(config))
    .flatMap(getPostProcessorForCss(config))
    .startWith('#playground {\n  color: rebeccapurple;\n}')
    .retry()
    .doOnNext(serveAssets.updateAsset('css'));
}

export const processAssetFiles = curry(function (opts, serveAssets, config) {
  return Observable.combineLatest(
    processJsFile(opts, serveAssets, config),
    processCssFile(opts, serveAssets, config),
    processHtmlFile(opts, serveAssets, config)
  );
});
<|endoftext|>


<commit_before>//
// Copyright (c) 2016-2017 DrSmugleaf
//

"use strict"
const commando = require("discord.js-commando")
const Quote = require("./base/quote")
const responses = require("../../util/constants").responses.QUOTE
const winston = require("winston")

module.exports = class QuoteCommand extends commando.Command {
  constructor(client) {
    super(client, {
      name: "quote",
      aliases: ["quote"],
      group: "misc",
      memberName: "quote",
      description: "Add, remove or get a quote from the list.",
      examples: ["quote", "quote 25", "quote add Hello World", "quote del 25"],
      guildOnly: true,
      throttling: {
        usages: 2,
        duration: 3
      },
      args: [
        {
          key: "mode",
          prompt: "Add, delete or get a quote",
          type: "string",
          default: "",
          parse: (mode) => {
            if(["add", "put"].includes(mode)) return "add"
            if(["del", "delete", "rem", "remove"].includes(mode)) return "delete"
            if(["find", "get"].includes(mode)) return "get"
            if(!mode) return "get"
            if(!isNaN(mode)) return mode
            return mode
          }
        },
        {
          key: "id_text",
          label: "ID or text",
          prompt: "ID of the quote to add or delete or text of the quote to add to the list of quotes",
          type: "string",
          default: ""
        }
      ]
    })

    this.client.once("dbReady", async () => {
      const quote = new Quote(this.client)
      await quote.init()
      this.quote = quote
    })
  }

  async run(msg, args) {
    const mode = args.id_text ? this.args[0].parse(args.mode) : "get"
    const id = parseInt(args.mode, 10) || parseInt(args.id_text, 10) || null
    const text = args.id_text
    var parameters
    const commandPrefix = msg.guild.commandPrefix
    const prefix = commandPrefix ? commandPrefix : commandPrefix === "" ?
      `<@${msg.client.user.id}>` : msg.client.options.commandPrefix

    switch (mode) {
    case "add":
      if(!text) return msg.reply(responses.NO_TEXT[msg.language])

      parameters = { text: text, submitter: msg.author.id, guild: msg.guild.id }
      this.quote.add(parameters).then((id) => {
        return msg.reply(responses.ADDED[msg.language](id, `${prefix}quote`))
      }).catch((e) => {
        winston.info(e)
        return msg.reply(responses.ERROR[msg.language])
      })
      break
    case "delete":
      parameters = { id: id, guild: msg.guild.id }
      if(!this.quote.has(parameters)) return msg.reply(responses.MISSING[msg.language])
      if(!this.quote.get(parameters).submitter === msg.author.id) {
        return msg.reply(responses.NO_PERMISSION[msg.language](id))
      }

      this.quote.delete(parameters).then(() => {
        return msg.reply(responses.REMOVED[msg.language](id))
      }).catch(() => {
        return msg.reply(responses.ERROR[msg.language])
      })
      break
    case "get": {
      parameters = { id: id, guild: msg.guild.id }
      if(this.quote.empty(msg.guild.id)) return msg.reply(responses.EMPTY[msg.language])
      if(id && !this.quote.has(parameters)) return msg.reply(responses.MISSING[msg.language](id))

      const quote = this.quote.get(parameters)
      msg.reply(responses.GET[msg.language](quote.id, quote.text))
      break
    }
    default:
      return msg.reply(responses.NO_MODE[msg.language](mode))
    }
  }
}
<commit_msg>Fixed quote delete permission check<commit_after>//
// Copyright (c) 2016-2017 DrSmugleaf
//

"use strict"
const commando = require("discord.js-commando")
const Quote = require("./base/quote")
const responses = require("../../util/constants").responses.QUOTE
const winston = require("winston")

module.exports = class QuoteCommand extends commando.Command {
  constructor(client) {
    super(client, {
      name: "quote",
      aliases: ["quote"],
      group: "misc",
      memberName: "quote",
      description: "Add, remove or get a quote from the list.",
      examples: ["quote", "quote 25", "quote add Hello World", "quote del 25"],
      guildOnly: true,
      throttling: {
        usages: 2,
        duration: 3
      },
      args: [
        {
          key: "mode",
          prompt: "Add, delete or get a quote",
          type: "string",
          default: "",
          parse: (mode) => {
            if(["add", "put"].includes(mode)) return "add"
            if(["del", "delete", "rem", "remove"].includes(mode)) return "delete"
            if(["find", "get"].includes(mode)) return "get"
            if(!mode) return "get"
            if(!isNaN(mode)) return mode
            return mode
          }
        },
        {
          key: "id_text",
          label: "ID or text",
          prompt: "ID of the quote to add or delete or text of the quote to add to the list of quotes",
          type: "string",
          default: ""
        }
      ]
    })

    this.client.once("dbReady", async () => {
      const quote = new Quote(this.client)
      await quote.init()
      this.quote = quote
    })
  }

  async run(msg, args) {
    const mode = args.id_text ? this.args[0].parse(args.mode) : "get"
    const id = parseInt(args.mode, 10) || parseInt(args.id_text, 10) || null
    const text = args.id_text
    var parameters
    const commandPrefix = msg.guild.commandPrefix
    const prefix = commandPrefix ? commandPrefix : commandPrefix === "" ?
      `<@${msg.client.user.id}>` : msg.client.options.commandPrefix

    switch (mode) {
    case "add":
      if(!text) return msg.reply(responses.NO_TEXT[msg.language])

      parameters = { text: text, submitter: msg.author.id, guild: msg.guild.id }
      this.quote.add(parameters).then((id) => {
        return msg.reply(responses.ADDED[msg.language](id, `${prefix}quote`))
      }).catch((e) => {
        winston.info(e)
        return msg.reply(responses.ERROR[msg.language])
      })
      break
    case "delete":
      parameters = { id: id, guild: msg.guild.id }
      if(!this.quote.has(parameters)) return msg.reply(responses.MISSING[msg.language])
      if(this.quote.get(parameters).submitter !== msg.author.id && !msg.member.hasPermission("ADMINISTRATOR")) {
        return msg.reply(responses.NO_PERMISSION[msg.language](id))
      }

      this.quote.delete(parameters).then(() => {
        return msg.reply(responses.REMOVED[msg.language](id))
      }).catch(() => {
        return msg.reply(responses.ERROR[msg.language])
      })
      break
    case "get": {
      parameters = { id: id, guild: msg.guild.id }
      if(this.quote.empty(msg.guild.id)) return msg.reply(responses.EMPTY[msg.language])
      if(id && !this.quote.has(parameters)) return msg.reply(responses.MISSING[msg.language](id))

      const quote = this.quote.get(parameters)
      msg.reply(responses.GET[msg.language](quote.id, quote.text))
      break
    }
    default:
      return msg.reply(responses.NO_MODE[msg.language](mode))
    }
  }
}
<|endoftext|>


<commit_before>import firebase from "firebase/app";
import "firebase/auth";

import firebaseConfig from "./config/firebaseConfig";

// const firebaseConfig = {
//   apiKey: process.env.REACT_APP_API_KEY,
//   authDomain: process.env.REACT_APP_AUTH_DOMAIN,
//   projectId: process.env.REACT_APP_PROJECT_ID,
//   storageBucket: process.env.REACT_APP_STORAGE_BUCKET,
//   messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID,
//   appId: process.env.REACT_APP_APP_ID,
//   measurementId: process.env.REACT_APP_MEASUREMENT_ID,
// };

console.log(firebaseConfig);

firebase.initializeApp(firebaseConfig);

export const auth = firebase.auth();

const googleProvider = new firebase.auth.GoogleAuthProvider();
export const signInWithGoogle = () => {
  auth
    .signInWithPopup(googleProvider)
    .then((res) => {
      console.log("authed here");
      console.log(res.user);
    })
    .catch((error) => {
      console.log(error.message);
    });
};

export const onAuthStateChange = (callback) => {
  return firebase.auth().onAuthStateChanged((user) => {
    if (user) {
      callback({
        signedIn: true,
        name: user.displayName,
        email: user.email,
      });
    } else {
      callback({
        signedIn: false,
      });
    }
  });
};

export const signOut = () => {
  firebase.auth().signOut();
};
<commit_msg>Delete console logs<commit_after>import firebase from "firebase/app";
import "firebase/auth";

import firebaseConfig from "./config/firebaseConfig";

// const firebaseConfig = {
//   apiKey: process.env.REACT_APP_API_KEY,
//   authDomain: process.env.REACT_APP_AUTH_DOMAIN,
//   projectId: process.env.REACT_APP_PROJECT_ID,
//   storageBucket: process.env.REACT_APP_STORAGE_BUCKET,
//   messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID,
//   appId: process.env.REACT_APP_APP_ID,
//   measurementId: process.env.REACT_APP_MEASUREMENT_ID,
// };

console.log(firebaseConfig);

firebase.initializeApp(firebaseConfig);

export const auth = firebase.auth();

const googleProvider = new firebase.auth.GoogleAuthProvider();
export const signInWithGoogle = () => {
  auth
    .signInWithPopup(googleProvider)
    .then()
    .catch((error) => {
      console.log(error.message);
    });
};

export const onAuthStateChange = (callback) => {
  return firebase.auth().onAuthStateChanged((user) => {
    if (user) {
      callback({
        signedIn: true,
        name: user.displayName,
        email: user.email,
      });
    } else {
      callback({
        signedIn: false,
      });
    }
  });
};

export const signOut = () => {
  firebase.auth().signOut();
};
<|endoftext|>


<commit_before>import Immutable from 'immutable';
import { rpc } from 'lib/rpc';
import { getRates } from 'lib/marketApi';
import { address } from 'lib/validators';
import { loadTokenBalanceOf } from './tokenActions';
import log from 'electron-log';
import { toHex, toNumber } from 'lib/convert';
import { gotoScreen, catchError } from './screenActions';

export function loadAccountBalance(accountId) {
    return (dispatch, getState) => {
        rpc.call('eth_getBalance', [accountId, 'latest']).then((result) => {
            dispatch({
                type: 'ACCOUNT/SET_BALANCE',
                accountId,
                value: result,
            });
        });
        // const tokens = getState().tokens;
        // if (!tokens.get('loading')) {
        //     tokens.get('tokens')
        //       .map((token) => dispatch(loadTokenBalanceOf(token, accountId)));
        // }
    };
}

export function loadAccountsList() {
    return (dispatch, getState) => {
        dispatch({
            type: 'ACCOUNT/LOADING',
        });
        let chain = getState().network.getIn(['chain', 'name']);
        rpc.call('emerald_listAccounts', [{chain}]).then((result) => {
            dispatch({
                type: 'ACCOUNT/SET_LIST',
                accounts: result,
            });
            result.map((acct) => dispatch(loadAccountBalance(acct.address))
            );
        });
    };
}

export function loadAccountTxCount(accountId) {
    return (dispatch) => {
        rpc.call('eth_getTransactionCount', [accountId, 'latest']).then((result) => {
            dispatch({
                type: 'ACCOUNT/SET_TXCOUNT',
                accountId,
                value: result,
            });
        });
    };
}

/*
 *
 * TODO: Error handling
*/
export function createAccount(passphrase, name, description) {
    return (dispatch, getState) => {
        let chain = getState().network.getIn(['chain', 'name']);
        rpc.call('emerald_newAccount', [{
            passphrase,
            name,
            description,
        }, {chain}]).then((result) => {
            dispatch({
                type: 'ACCOUNT/ADD_ACCOUNT',
                accountId: result,
                name,
                description,
            });
            dispatch(loadAccountBalance(result));
        });
    }
}

export function updateAccount(address, name, description) {
    return (dispatch, getState) => {
        let chain = getState().network.getIn(['chain', 'name']);
        rpc.call('emerald_updateAccount', [{
            name,
            description,
            address,
        }, {chain}]).then((result) => {
            dispatch({
                type: 'ACCOUNT/UPDATE_ACCOUNT',
                address,
                name,
                description,
            });
        });
    }
}

function sendRawTransaction(signed) {
    return rpc.call('eth_sendRawTransaction', [signed])
}

function unwrap(list) {
    return new Promise((resolve, reject) => {
        if (list.length === 1) {
            resolve(list[0])
        } else {
            reject(new Error(`Invalid list size ${list.length}`))
        }
    })
}

function onTxSend(dispatch, sourceTx) {
    return (txhash) => {
        dispatch({
            type: 'ACCOUNT/SEND_TRANSACTION',
            account: sourceTx.from,
            txHash: txhash,
        });
        dispatch(loadAccountBalance(sourceTx.from));
        const senttx = Object.assign({}, sourceTx, {hash: txhash});
        dispatch(trackTx(senttx));
        dispatch(gotoScreen('transaction', senttx));
    }
}

function getNonce(addr) {
    return rpc.call('eth_getTransactionCount', [addr, 'latest'])
}

function withNonce(tx) {
    return (nonce) => new Promise((resolve, reject) =>
        resolve(Object.assign({}, tx, {nonce}))
    )
}

function incNonce(nonce) {
    return new Promise((resolve) => {
        let nonceDec = toNumber(nonce);
        resolve(toHex(nonceDec + 1))
    })
}

function emeraldSign(txData, chain) {
    return rpc.call('emerald_signTransaction', [txData, {chain}])
}

export function sendTransaction(accountId, passphrase, to, gas, gasPrice, value) {
    let originalTx = {
        from: accountId,
        passphrase,
        to,
        gas,
        gasPrice,
        value,
    };
    return (dispatch, getState) => {
        let chain = getState().network.getIn(['chain', 'name']);
        getNonce(accountId)
            .then(incNonce)
            .then(withNonce(originalTx))
            .then((tx) =>
                emeraldSign(tx, chain)
                    .then(unwrap)
                    .then(sendRawTransaction)
                    .then(onTxSend(dispatch, tx))
                    .catch(catchError(dispatch))
            )
            .catch(catchError(dispatch));
    }
}

export function createContract(accountId, passphrase, gas, gasPrice, data) {
    let txData = {
        from: accountId,
        passphrase,
        gas,
        gasPrice,
        data,
    };
    return (dispatch, getState) => {
        let chain = getState().network.getIn(['chain', 'name']);
        rpc.call('emerald_signTransaction', [txData, {chain}])
            .then(unwrap)
            .then(sendRawTransaction)
            .then(onTxSend(dispatch, accountId))
            .catch(log.error);
    }
}

export function importWallet(wallet, name, description) {
    return (dispatch, getState) => {
        let chain = getState().network.getIn(['chain', 'name']);
        return new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.readAsText(wallet);
            reader.onload = (event) => {
                let data;
                try {
                    data = JSON.parse(event.target.result);
                    data.filename = wallet.name;
                    data.name = name;
                    data.description = description;
                } catch (e) {
                    reject({error: e});
                }
                return rpc.call('emerald_importAccount', [data, {chain}]).then((result) => {
                    dispatch({
                        type: 'ACCOUNT/IMPORT_WALLET',
                        accountId: result,
                    });
                    // Reload accounts.
                    if (address(result)) {
                        dispatch({
                            type: 'ACCOUNT/ADD_ACCOUNT',
                            accountId: result,
                            name,
                            description,
                        });
                        dispatch(loadAccountBalance(result));
                        resolve(result);
                    } else {
                        reject({error: result});
                    }
                });
            };
        });
    };
}

function loadStoredTransactions() {
    return (dispatch) => {
        if (localStorage) {
            const storedTxs = localStorage.getItem('trackedTransactions');
            if (storedTxs !== null) {
                const storedTxsJSON = JSON.parse(storedTxs);
                dispatch({
                    type: 'ACCOUNT/LOAD_STORED_TXS',
                    transactions: storedTxsJSON,
                });
            }
        }
    };
}

export function loadPendingTransactions() {
    return (dispatch, getState) =>
        rpc.call('eth_getBlockByNumber', ['pending', true])
            .then((result) => {
                const addrs = getState().accounts.get('accounts')
                    .map((acc) => acc.get('id'));
                const txes = result.transactions.filter((t) =>
                    (addrs.includes(t.to) || addrs.includes(t.from))
                );
                dispatch({
                    type: 'ACCOUNT/PENDING_TX',
                    txList: txes,
                });
                dispatch(loadStoredTransactions());
                for (const tx of txes) {
                    const disp = {
                        type: 'ACCOUNT/PENDING_BALANCE',
                        value: tx.value,
                        gas: tx.gas,
                        gasPrice: tx.gasPrice,
                    };
                    if (addrs.includes(tx.from)) {
                        disp.from = tx.from;
                        dispatch(disp);
                    }
                    if (addrs.includes(tx.to)) {
                        disp.to = tx.to;
                        dispatch(disp);
                    }
                }
            });
}

export function refreshTransaction(hash) {
    return (dispatch) =>
        rpc.call('eth_getTransactionByHash', [hash]).then((result) => {
            if (typeof result === 'object') {
                dispatch({
                    type: 'ACCOUNT/UPDATE_TX',
                    tx: result,
                });
                /** TODO: Check for input data **/
                if ((result.creates !== undefined) && (address(result.creates) === undefined)) {
                    dispatch({
                        type: 'CONTRACT/UPDATE_CONTRACT',
                        tx: result,
                        address: result.creates,
                    });
                }
            }
        });
}

export function refreshTrackedTransactions() {
    return (dispatch, getState) => {
        getState().accounts.get('trackedTransactions').map(
            (tx) => dispatch(refreshTransaction(tx.get('hash')))
        );
    };
}

export function trackTx(tx) {
    return {
        type: 'ACCOUNT/TRACK_TX',
        tx,
    };
}

export function getGasPrice() {
    return (dispatch) => {
        rpc.call('eth_gasPrice', ['latest']).then((result) => {
            dispatch({
                type: 'ACCOUNT/GAS_PRICE',
                value: result,
            });
        });
    };
}

export function getExchangeRates() {
    return (dispatch) => {
        getRates.call().then((result) => {
            dispatch({
                type: 'ACCOUNT/EXCHANGE_RATES',
                rates: result,
            });
        });
    };
}
<commit_msg>store/accountActions: fix incorrect use of address validator<commit_after>import Immutable from 'immutable';
import { rpc } from 'lib/rpc';
import { getRates } from 'lib/marketApi';
import { address } from 'lib/validators';
import { loadTokenBalanceOf } from './tokenActions';
import log from 'electron-log';
import { toHex, toNumber } from 'lib/convert';
import { gotoScreen, catchError } from './screenActions';

export function loadAccountBalance(accountId) {
    return (dispatch, getState) => {
        rpc.call('eth_getBalance', [accountId, 'latest']).then((result) => {
            dispatch({
                type: 'ACCOUNT/SET_BALANCE',
                accountId,
                value: result,
            });
        });
        // const tokens = getState().tokens;
        // if (!tokens.get('loading')) {
        //     tokens.get('tokens')
        //       .map((token) => dispatch(loadTokenBalanceOf(token, accountId)));
        // }
    };
}

export function loadAccountsList() {
    return (dispatch, getState) => {
        dispatch({
            type: 'ACCOUNT/LOADING',
        });
        let chain = getState().network.getIn(['chain', 'name']);
        rpc.call('emerald_listAccounts', [{chain}]).then((result) => {
            dispatch({
                type: 'ACCOUNT/SET_LIST',
                accounts: result,
            });
            result.map((acct) => dispatch(loadAccountBalance(acct.address))
            );
        });
    };
}

export function loadAccountTxCount(accountId) {
    return (dispatch) => {
        rpc.call('eth_getTransactionCount', [accountId, 'latest']).then((result) => {
            dispatch({
                type: 'ACCOUNT/SET_TXCOUNT',
                accountId,
                value: result,
            });
        });
    };
}

/*
 *
 * TODO: Error handling
*/
export function createAccount(passphrase, name, description) {
    return (dispatch, getState) => {
        let chain = getState().network.getIn(['chain', 'name']);
        rpc.call('emerald_newAccount', [{
            passphrase,
            name,
            description,
        }, {chain}]).then((result) => {
            dispatch({
                type: 'ACCOUNT/ADD_ACCOUNT',
                accountId: result,
                name,
                description,
            });
            dispatch(loadAccountBalance(result));
        });
    }
}

export function updateAccount(address, name, description) {
    return (dispatch, getState) => {
        let chain = getState().network.getIn(['chain', 'name']);
        rpc.call('emerald_updateAccount', [{
            name,
            description,
            address,
        }, {chain}]).then((result) => {
            dispatch({
                type: 'ACCOUNT/UPDATE_ACCOUNT',
                address,
                name,
                description,
            });
        });
    }
}

function sendRawTransaction(signed) {
    return rpc.call('eth_sendRawTransaction', [signed])
}

function unwrap(list) {
    return new Promise((resolve, reject) => {
        if (list.length === 1) {
            resolve(list[0])
        } else {
            reject(new Error(`Invalid list size ${list.length}`))
        }
    })
}

function onTxSend(dispatch, sourceTx) {
    return (txhash) => {
        dispatch({
            type: 'ACCOUNT/SEND_TRANSACTION',
            account: sourceTx.from,
            txHash: txhash,
        });
        dispatch(loadAccountBalance(sourceTx.from));
        const senttx = Object.assign({}, sourceTx, {hash: txhash});
        dispatch(trackTx(senttx));
        dispatch(gotoScreen('transaction', senttx));
    }
}

function getNonce(addr) {
    return rpc.call('eth_getTransactionCount', [addr, 'latest'])
}

function withNonce(tx) {
    return (nonce) => new Promise((resolve, reject) =>
        resolve(Object.assign({}, tx, {nonce}))
    )
}

function incNonce(nonce) {
    return new Promise((resolve) => {
        let nonceDec = toNumber(nonce);
        resolve(toHex(nonceDec + 1))
    })
}

function emeraldSign(txData, chain) {
    return rpc.call('emerald_signTransaction', [txData, {chain}])
}

export function sendTransaction(accountId, passphrase, to, gas, gasPrice, value) {
    let originalTx = {
        from: accountId,
        passphrase,
        to,
        gas,
        gasPrice,
        value,
    };
    return (dispatch, getState) => {
        let chain = getState().network.getIn(['chain', 'name']);
        getNonce(accountId)
            .then(incNonce)
            .then(withNonce(originalTx))
            .then((tx) =>
                emeraldSign(tx, chain)
                    .then(unwrap)
                    .then(sendRawTransaction)
                    .then(onTxSend(dispatch, tx))
                    .catch(catchError(dispatch))
            )
            .catch(catchError(dispatch));
    }
}

export function createContract(accountId, passphrase, gas, gasPrice, data) {
    let txData = {
        from: accountId,
        passphrase,
        gas,
        gasPrice,
        data,
    };
    return (dispatch, getState) => {
        let chain = getState().network.getIn(['chain', 'name']);
        rpc.call('emerald_signTransaction', [txData, {chain}])
            .then(unwrap)
            .then(sendRawTransaction)
            .then(onTxSend(dispatch, accountId))
            .catch(log.error);
    }
}

export function importWallet(wallet, name, description) {
    return (dispatch, getState) => {
        let chain = getState().network.getIn(['chain', 'name']);
        return new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.readAsText(wallet);
            reader.onload = (event) => {
                let data;
                try {
                    data = JSON.parse(event.target.result);
                    data.filename = wallet.name;
                    data.name = name;
                    data.description = description;
                } catch (e) {
                    reject({error: e});
                }
                return rpc.call('emerald_importAccount', [data, {chain}]).then((result) => {
                    dispatch({
                        type: 'ACCOUNT/IMPORT_WALLET',
                        accountId: result,
                    });
                    // Reload accounts.
                    if (address(result) === undefined) {
                        dispatch({
                            type: 'ACCOUNT/ADD_ACCOUNT',
                            accountId: result,
                            name,
                            description,
                        });
                        dispatch(loadAccountBalance(result));
                        resolve(result);
                    } else {
                        reject({error: result});
                    }
                });
            };
        });
    };
}

function loadStoredTransactions() {
    return (dispatch) => {
        if (localStorage) {
            const storedTxs = localStorage.getItem('trackedTransactions');
            if (storedTxs !== null) {
                const storedTxsJSON = JSON.parse(storedTxs);
                dispatch({
                    type: 'ACCOUNT/LOAD_STORED_TXS',
                    transactions: storedTxsJSON,
                });
            }
        }
    };
}

export function loadPendingTransactions() {
    return (dispatch, getState) =>
        rpc.call('eth_getBlockByNumber', ['pending', true])
            .then((result) => {
                const addrs = getState().accounts.get('accounts')
                    .map((acc) => acc.get('id'));
                const txes = result.transactions.filter((t) =>
                    (addrs.includes(t.to) || addrs.includes(t.from))
                );
                dispatch({
                    type: 'ACCOUNT/PENDING_TX',
                    txList: txes,
                });
                dispatch(loadStoredTransactions());
                for (const tx of txes) {
                    const disp = {
                        type: 'ACCOUNT/PENDING_BALANCE',
                        value: tx.value,
                        gas: tx.gas,
                        gasPrice: tx.gasPrice,
                    };
                    if (addrs.includes(tx.from)) {
                        disp.from = tx.from;
                        dispatch(disp);
                    }
                    if (addrs.includes(tx.to)) {
                        disp.to = tx.to;
                        dispatch(disp);
                    }
                }
            });
}

export function refreshTransaction(hash) {
    return (dispatch) =>
        rpc.call('eth_getTransactionByHash', [hash]).then((result) => {
            if (typeof result === 'object') {
                dispatch({
                    type: 'ACCOUNT/UPDATE_TX',
                    tx: result,
                });
                /** TODO: Check for input data **/
                if ((result.creates !== undefined) && (address(result.creates) === undefined)) {
                    dispatch({
                        type: 'CONTRACT/UPDATE_CONTRACT',
                        tx: result,
                        address: result.creates,
                    });
                }
            }
        });
}

export function refreshTrackedTransactions() {
    return (dispatch, getState) => {
        getState().accounts.get('trackedTransactions').map(
            (tx) => dispatch(refreshTransaction(tx.get('hash')))
        );
    };
}

export function trackTx(tx) {
    return {
        type: 'ACCOUNT/TRACK_TX',
        tx,
    };
}

export function getGasPrice() {
    return (dispatch) => {
        rpc.call('eth_gasPrice', ['latest']).then((result) => {
            dispatch({
                type: 'ACCOUNT/GAS_PRICE',
                value: result,
            });
        });
    };
}

export function getExchangeRates() {
    return (dispatch) => {
        getRates.call().then((result) => {
            dispatch({
                type: 'ACCOUNT/EXCHANGE_RATES',
                rates: result,
            });
        });
    };
}
<|endoftext|>


<commit_before>morpheus.OpenFileTool = function(options) {
	this.options = options || {};
};
morpheus.OpenFileTool.prototype = {
	toString : function() {
		return 'Open File';
	},
	gui : function() {
		var array = [ {
			name : 'open_file_action',
			options : [ {
				name : 'Annotate columns',
				value : 'Annotate Columns'
			}, {
				name : 'Annotate rows',
				value : 'Annotate Rows'
			}, {
				divider : true
			}, {
				name : 'Append rows to current dataset',
				value : 'append'
			}, {
				name : 'Append columns to current dataset',
				value : 'append columns'
			}, {
				name : 'Overlay onto current dataset',
				value : 'overlay'
			}, {
				name : 'Open dataset in new tab',
				value : 'open'
			}, {
				divider : true
			}, {
				name : 'Open dendrogram',
				value : 'Open dendrogram'
			} ],
			value : 'open',
			type : 'bootstrap-select'
		}, {
			name : 'file',
			showLabel : false,
			placeholder : 'Open your own file',
			value : '',
			type : 'file',
			required : true,
			help : morpheus.DatasetUtil.DATASET_FILE_FORMATS
		} ];
		array.options = {
			ok : false,
			size : 'modal-lg'
		};
		return array;
	},
	init : function(project, form, initOptions) {
		form.$form.find('[name=open_file_action]').on(
				'change',
				function(e) {
					var action = $(this).val();
					if (action === 'append columns' || action === 'append'
							|| action === 'open' || action === 'overlay') {
						form.setHelpText('file',
								morpheus.DatasetUtil.DATASET_FILE_FORMATS);
					} else if (action === 'Open dendrogram') {
						form.setHelpText('file',
								morpheus.DatasetUtil.DENDROGRAM_FILE_FORMATS);
					} else {
						form.setHelpText('file',
								morpheus.DatasetUtil.ANNOTATION_FILE_FORMATS);
					}
				});
		$('
Use your own file
').insertAfter(
				form.$form.find('.form-group:first'));
		var _this = this;
		var id = _.uniqueId('morpheus');
		form.$form.append('
Or select a preloaded dataset
');
		var $sampleDatasets = $('

');
		form.$form.append($sampleDatasets);
		var sampleDatasets = new morpheus.SampleDatasets({
			$el : $sampleDatasets,
			callback : function(heatMapOptions) {
				form.setValue('file', heatMapOptions.dataset);
				_this.ok();

			}
		});
		form.on('change', function(e) {
			var value = e.value;
			if (value !== '' && value != null) {
				form.setValue('file', value);
				_this.ok();
			}
		});

	},

	execute : function(options) {
		var that = this;
		if (this.options.file) {
			options.input.file = this.options.file;
		}

		var project = options.project;
		if (options.input.open_file_action === 'append columns'
				|| options.input.open_file_action === 'append'
				|| options.input.open_file_action === 'open'
				|| options.input.open_file_action === 'overlay') {
			new morpheus.OpenDatasetTool().execute(options);
		} else if (options.input.open_file_action === 'Open dendrogram') {
			morpheus.HeatMap.showTool(new morpheus.OpenDendrogramTool(
					options.input.file), options.controller);
		} else { // annotate rows or columns
			var controller = options.controller;
			var isAnnotateColumns = options.input.open_file_action == 'Annotate Columns';
			var fileOrUrl = options.input.file;
			var dataset = project.getFullDataset();
			var fileName = morpheus.Util.getFileName(fileOrUrl);
			if (morpheus.Util.endsWith(fileName, '.cls')) {
				var result = morpheus.Util.readLines(fileOrUrl);
				result.done(function(lines) {
					that.annotateCls(controller, dataset, fileName,
							isAnnotateColumns, lines);
				});
			} else if (morpheus.Util.endsWith(fileName, '.gmt')) {
				morpheus.BufferedReader.getArrayBuffer(fileOrUrl, function(err,
						buf) {
					if (err) {
						throw new Error('Unable to read ' + fileOrUrl);
					}
					var sets = new morpheus.GmtReader()
							.read(new morpheus.BufferedReader(new Uint8Array(
									buf)));
					that.prompt(null, dataset, controller, isAnnotateColumns,
							sets);
				});

			} else {
				var result = morpheus.Util.readLines(fileOrUrl);
				result.done(function(lines) {
					that.prompt(lines, dataset, controller, isAnnotateColumns,
							null);
				});

			}

		}
	},
	annotateCls : function(controller, dataset, fileName, isColumns, lines) {
		if (isColumns) {
			dataset = morpheus.DatasetUtil.transposedView(dataset);
		}
		var assignments = new morpheus.ClsReader().read(lines);
		if (assignments.length !== dataset.getRowCount()) {
			throw new Error(
					'Number of samples in cls file does not match dataset.');
		}
		var vector = dataset.getRowMetadata().add(
				morpheus.Util.getBaseFileName(fileName));
		for (var i = 0; i < assignments.length; i++) {
			vector.setValue(i, assignments[i]);
		}
		if (controller) {
			controller.getProject().trigger('trackChanged', {
				vectors : [ vector ],
				render : [ 'color' ],
				columns : isColumns
			});
		}
	},
	/**
	 *
	 * @param lines
	 *            Lines of text in annotation file or null if a gmt file
	 * @param dataset
	 *            Current dataset
	 * @param isColumns
	 *            Whether annotating columns
	 * @param sets
	 *            Sets if a gmt file or null
	 * @param metadataName
	 *            The dataset metadata name to match on
	 * @param fileColumnName
	 *            The metadata file name to match on
	 * @param fileColumnNamesToInclude
	 *            An array of column names to include from the metadata file or
	 *            null to include all
	 */
	annotate : function(lines, dataset, isColumns, sets, metadataName,
			fileColumnName, fileColumnNamesToInclude) {
		if (isColumns) {
			dataset = morpheus.DatasetUtil.transposedView(dataset);
		}
		var vector = dataset.getRowMetadata().getByName(metadataName);
		if (!vector) {
			throw new Error('vector ' + metadataName + ' not found.');
		}
		var vectors = [];
		var idToIndices = morpheus.VectorUtil.createValueToIndicesMap(vector);
		if (!lines) {
			_
					.each(
							sets,
							function(set) {
								var name = set.name;
								var members = set.ids;
								// var v = dataset.getRowMetadata()
								// .getByName(name);
								// overwrite existing values
								// if (!v) {
								var v = dataset.getRowMetadata().add(name);
								// }
								vectors.push(v);
								_
										.each(
												members,
												function(id) {
													var indices = idToIndices
															.get(id);
													if (indices !== undefined) {
														for (var i = 0, nIndices = indices.length; i < nIndices; i++) {
															v.setValue(
																	indices[i],
																	name);
														}
													}
												});
							});
		} else {
			var tab = /\t/;
			var header = lines[0].split(tab);
			var fileMatchOnColumnIndex = _.indexOf(header, fileColumnName);
			if (fileMatchOnColumnIndex === -1) {
				throw new Error(fileColumnName + ' not found in header:'
						+ header);
			}
			var columnIndices = [];
			var nheaders = header.length;
			for (var j = 0; j < header.length; j++) {
				var name = header[j];
				if (j === fileMatchOnColumnIndex) {
					continue;
				}
				if (fileColumnNamesToInclude
						&& _.indexOf(fileColumnNamesToInclude, name) === -1) {
					continue;
				}
				var v = dataset.getRowMetadata().getByName(name);
				if (!v) {
					v = dataset.getRowMetadata().add(name);
				}
				columnIndices.push(j);
				vectors.push(v);
			}
			var nheaders = columnIndices.length;
			for (var i = 1, nrows = lines.length; i < nrows; i++) {
				var line = lines[i].split(tab);
				var id = line[fileMatchOnColumnIndex];
				var indices = idToIndices.get(id);
				if (indices !== undefined) {
					var nIndices = indices.length;
					for (var j = 0; j < nheaders; j++) {
						var token = line[columnIndices[j]];
						var v = vectors[j];
						for (var r = 0; r < nIndices; r++) {
							v.setValue(indices[r], token);
						}
					}
				}
			}
		}
		for (var i = 0; i < vectors.length; i++) {
			morpheus.VectorUtil.maybeConvertStringToNumber(vectors[i]);
		}
		return vectors;
	},
	// prompt for metadata field name in dataset and in file
	prompt : function(lines, dataset, controller, isColumns, sets) {
		var promptTool = {};
		var _this = this;
		var header = lines != null ? lines[0].split('\t') : null;
		promptTool.execute = function(options) {
			var metadataName = options.input.dataset_field_name;
			var fileColumnName = options.input.file_field_name;
			var vectors = _this.annotate(lines, dataset, isColumns, sets,
					metadataName, fileColumnName);
			var render = [];
			for (var i = 0; i < vectors.length; i++) {
				render.push('color');
			}
			controller.getProject().trigger('trackChanged', {
				vectors : vectors,
				render : render,
				columns : isColumns
			});
		};
		promptTool.toString = function() {
			return 'Select Fields To Match On';
		};
		promptTool.gui = function() {
			var items = [ {
				name : 'dataset_field_name',
				options : morpheus.MetadataUtil
						.getMetadataNames(isColumns ? dataset
								.getColumnMetadata() : dataset.getRowMetadata()),
				type : 'select',
				required : true
			} ];
			if (lines) {
				items.push({
					name : 'file_field_name',
					type : 'select',
					options : _.map(header, function(item) {
						return {
							name : item,
							value : item
						};
					}),
					required : true
				});
			}
			return items;
		};
		morpheus.HeatMap.showTool(promptTool, controller);
	}
};<commit_msg>fix open file using drag and drop<commit_after>morpheus.OpenFileTool = function(options) {
	this.options = options || {};
};
morpheus.OpenFileTool.prototype = {
	toString : function() {
		return 'Open File';
	},
	gui : function() {
		var array = [ {
			name : 'open_file_action',
			value : 'open',
			type : 'bootstrap-select',
			options : [ {
				name : 'Annotate columns',
				value : 'Annotate Columns'
			}, {
				name : 'Annotate rows',
				value : 'Annotate Rows'
			}, {
				divider : true
			}, {
				name : 'Append rows to current dataset',
				value : 'append'
			}, {
				name : 'Append columns to current dataset',
				value : 'append columns'
			}, {
				name : 'Overlay onto current dataset',
				value : 'overlay'
			}, {
				name : 'Open dataset in new tab',
				value : 'open'
			}, {
				divider : true
			}, {
				name : 'Open dendrogram',
				value : 'Open dendrogram'
			} ]
		} ];
		if (this.options.file == null) {
			array.push({
				name : 'file',
				showLabel : false,
				placeholder : 'Open your own file',
				value : '',
				type : 'file',
				required : true,
				help : morpheus.DatasetUtil.DATASET_FILE_FORMATS
			});
		}
		array.options = {
			ok : this.options.file != null,
			size : 'modal-lg'
		};
		return array;
	},
	init : function(project, form, initOptions) {
		form.$form.find('[name=open_file_action]').on(
				'change',
				function(e) {
					var action = $(this).val();
					if (action === 'append columns' || action === 'append'
							|| action === 'open' || action === 'overlay') {
						form.setHelpText('file',
								morpheus.DatasetUtil.DATASET_FILE_FORMATS);
					} else if (action === 'Open dendrogram') {
						form.setHelpText('file',
								morpheus.DatasetUtil.DENDROGRAM_FILE_FORMATS);
					} else {
						form.setHelpText('file',
								morpheus.DatasetUtil.ANNOTATION_FILE_FORMATS);
					}
				});
		if (this.options.file == null) {
			$('
Use your own file
').insertAfter(
					form.$form.find('.form-group:first'));
			var _this = this;
			var id = _.uniqueId('morpheus');
			form.$form
					.append('
Or select a preloaded dataset
');
			var $sampleDatasets = $('

');
			form.$form.append($sampleDatasets);
			var sampleDatasets = new morpheus.SampleDatasets({
				$el : $sampleDatasets,
				callback : function(heatMapOptions) {
					form.setValue('file', heatMapOptions.dataset);
					_this.ok();

				}
			});
		}
		form.on('change', function(e) {
			var value = e.value;
			if (value !== '' && value != null) {
				form.setValue('file', value);
				_this.ok();
			}
		});

	},

	execute : function(options) {
		var that = this;
		if (this.options.file) {
			options.input.file = this.options.file;
		}

		var project = options.project;
		if (options.input.open_file_action === 'append columns'
				|| options.input.open_file_action === 'append'
				|| options.input.open_file_action === 'open'
				|| options.input.open_file_action === 'overlay') {
			new morpheus.OpenDatasetTool().execute(options);
		} else if (options.input.open_file_action === 'Open dendrogram') {
			morpheus.HeatMap.showTool(new morpheus.OpenDendrogramTool(
					options.input.file), options.controller);
		} else { // annotate rows or columns
			var controller = options.controller;
			var isAnnotateColumns = options.input.open_file_action == 'Annotate Columns';
			var fileOrUrl = options.input.file;
			var dataset = project.getFullDataset();
			var fileName = morpheus.Util.getFileName(fileOrUrl);
			if (morpheus.Util.endsWith(fileName, '.cls')) {
				var result = morpheus.Util.readLines(fileOrUrl);
				result.done(function(lines) {
					that.annotateCls(controller, dataset, fileName,
							isAnnotateColumns, lines);
				});
			} else if (morpheus.Util.endsWith(fileName, '.gmt')) {
				morpheus.BufferedReader.getArrayBuffer(fileOrUrl, function(err,
						buf) {
					if (err) {
						throw new Error('Unable to read ' + fileOrUrl);
					}
					var sets = new morpheus.GmtReader()
							.read(new morpheus.BufferedReader(new Uint8Array(
									buf)));
					that.prompt(null, dataset, controller, isAnnotateColumns,
							sets);
				});

			} else {
				var result = morpheus.Util.readLines(fileOrUrl);
				result.done(function(lines) {
					that.prompt(lines, dataset, controller, isAnnotateColumns,
							null);
				});

			}

		}
	},
	annotateCls : function(controller, dataset, fileName, isColumns, lines) {
		if (isColumns) {
			dataset = morpheus.DatasetUtil.transposedView(dataset);
		}
		var assignments = new morpheus.ClsReader().read(lines);
		if (assignments.length !== dataset.getRowCount()) {
			throw new Error(
					'Number of samples in cls file does not match dataset.');
		}
		var vector = dataset.getRowMetadata().add(
				morpheus.Util.getBaseFileName(fileName));
		for (var i = 0; i < assignments.length; i++) {
			vector.setValue(i, assignments[i]);
		}
		if (controller) {
			controller.getProject().trigger('trackChanged', {
				vectors : [ vector ],
				render : [ 'color' ],
				columns : isColumns
			});
		}
	},
	/**
	 *
	 * @param lines
	 *            Lines of text in annotation file or null if a gmt file
	 * @param dataset
	 *            Current dataset
	 * @param isColumns
	 *            Whether annotating columns
	 * @param sets
	 *            Sets if a gmt file or null
	 * @param metadataName
	 *            The dataset metadata name to match on
	 * @param fileColumnName
	 *            The metadata file name to match on
	 * @param fileColumnNamesToInclude
	 *            An array of column names to include from the metadata file or
	 *            null to include all
	 */
	annotate : function(lines, dataset, isColumns, sets, metadataName,
			fileColumnName, fileColumnNamesToInclude) {
		if (isColumns) {
			dataset = morpheus.DatasetUtil.transposedView(dataset);
		}
		var vector = dataset.getRowMetadata().getByName(metadataName);
		if (!vector) {
			throw new Error('vector ' + metadataName + ' not found.');
		}
		var vectors = [];
		var idToIndices = morpheus.VectorUtil.createValueToIndicesMap(vector);
		if (!lines) {
			_
					.each(
							sets,
							function(set) {
								var name = set.name;
								var members = set.ids;
								// var v = dataset.getRowMetadata()
								// .getByName(name);
								// overwrite existing values
								// if (!v) {
								var v = dataset.getRowMetadata().add(name);
								// }
								vectors.push(v);
								_
										.each(
												members,
												function(id) {
													var indices = idToIndices
															.get(id);
													if (indices !== undefined) {
														for (var i = 0, nIndices = indices.length; i < nIndices; i++) {
															v.setValue(
																	indices[i],
																	name);
														}
													}
												});
							});
		} else {
			var tab = /\t/;
			var header = lines[0].split(tab);
			var fileMatchOnColumnIndex = _.indexOf(header, fileColumnName);
			if (fileMatchOnColumnIndex === -1) {
				throw new Error(fileColumnName + ' not found in header:'
						+ header);
			}
			var columnIndices = [];
			var nheaders = header.length;
			for (var j = 0; j < header.length; j++) {
				var name = header[j];
				if (j === fileMatchOnColumnIndex) {
					continue;
				}
				if (fileColumnNamesToInclude
						&& _.indexOf(fileColumnNamesToInclude, name) === -1) {
					continue;
				}
				var v = dataset.getRowMetadata().getByName(name);
				if (!v) {
					v = dataset.getRowMetadata().add(name);
				}
				columnIndices.push(j);
				vectors.push(v);
			}
			var nheaders = columnIndices.length;
			for (var i = 1, nrows = lines.length; i < nrows; i++) {
				var line = lines[i].split(tab);
				var id = line[fileMatchOnColumnIndex];
				var indices = idToIndices.get(id);
				if (indices !== undefined) {
					var nIndices = indices.length;
					for (var j = 0; j < nheaders; j++) {
						var token = line[columnIndices[j]];
						var v = vectors[j];
						for (var r = 0; r < nIndices; r++) {
							v.setValue(indices[r], token);
						}
					}
				}
			}
		}
		for (var i = 0; i < vectors.length; i++) {
			morpheus.VectorUtil.maybeConvertStringToNumber(vectors[i]);
		}
		return vectors;
	},
	// prompt for metadata field name in dataset and in file
	prompt : function(lines, dataset, controller, isColumns, sets) {
		var promptTool = {};
		var _this = this;
		var header = lines != null ? lines[0].split('\t') : null;
		promptTool.execute = function(options) {
			var metadataName = options.input.dataset_field_name;
			var fileColumnName = options.input.file_field_name;
			var vectors = _this.annotate(lines, dataset, isColumns, sets,
					metadataName, fileColumnName);
			var render = [];
			for (var i = 0; i < vectors.length; i++) {
				render.push('color');
			}
			controller.getProject().trigger('trackChanged', {
				vectors : vectors,
				render : render,
				columns : isColumns
			});
		};
		promptTool.toString = function() {
			return 'Select Fields To Match On';
		};
		promptTool.gui = function() {
			var items = [ {
				name : 'dataset_field_name',
				options : morpheus.MetadataUtil
						.getMetadataNames(isColumns ? dataset
								.getColumnMetadata() : dataset.getRowMetadata()),
				type : 'select',
				required : true
			} ];
			if (lines) {
				items.push({
					name : 'file_field_name',
					type : 'select',
					options : _.map(header, function(item) {
						return {
							name : item,
							value : item
						};
					}),
					required : true
				});
			}
			return items;
		};
		morpheus.HeatMap.showTool(promptTool, controller);
	}
};<|endoftext|>


<commit_before>/**
 * == Zepto ==
 **/

/** section: Zepto
 *
 * class zebedee
 *
 * creates an accordion widget
 **/

/** section: Zepto
 * new zebedee(container [, options])
 *
 * - container (String | HTMLDOMElement | Zepto Object): The containing div for the accordion
 * - options (Object): Optional options object for overriding default configuration
 *
 * Creates a new zebedee accordion
 **/
var zebedee = (function(container,options){

    /** section: Zepto
     * zebedee._scope -> zebedee
     *
     * Internal variable to enable event handlers to be executed in the main object's scope
     **/
	var _scope = this;

	if(typeof container == 'string')
		container = '#' + container;

	if(!$(container))
		throw new Exception('Element ' + container + " does not exist!");

    /** section: Zepto
     * zebedee._container -> Zepto Object
     *
     * Internal reference to container element
     **/
	this._container = $(container);

	//utility methods
    /** section: Zepto
     * zebdee._getObjVars(obj) -> Array
     *
     * - obj (Object) - The object to get the properties of
     *
     *  Utility method to get array of object properties
     **/
	this._getObjVars = function(obj){
		if (typeof obj !== 'Object')
			return [];

		var vars = [];
	    for (var prop in obj)
	      vars.push(obj[prop]);
	    console.log(vars)
	    return vars;
	}

    /** section: Zepto
     * zebedee._merge(destination,source) -> Object
     *
     * - destination (Object): The object to have it's properties overridden
     * - source (Object): The object with the new properties
     *
     * Merges two objects together, overwriting the properties of the first with the new values from the second.
     **/
	this._merge = function(destination,source){
		var property,prop;
		for (property in source){
			if(this._getObjVars(destination[property]).length>0 && this._getObjVars(source[property]).length>0){
				for(prop in source[property])
 			 		destination[property][prop] = source[property][prop];
 			 } else {
 			 	destination[property] = source[property];
 			 }
 		}
		return destination;
	};

	//public members
    /** section: Zepto
     * zebedee.toggle(e)
     *
     * - e (Event): The trigger event for the opening/closing of the accordion
     *
     * Event handler for opening/closing the accordion.  Checks for any opened blocks, and if they're not the one clicked, closes them.  Then
     * either opens or closes the clicked block as necessary.
     **/
	this.toggle = function(e){
		var open = $('#' + _scope._container.attr('id') + ">." + _scope.options.classNames.handleActive).get(0);
		if(open !== 'undefined' && open!=e.currentTarget)
			_scope.close($('#' + _scope._container.attr('id') + ">." + _scope.options.classNames.handleActive).get(0));
		if($(e.currentTarget).hasClass(_scope.options.classNames.handleActive))
			_scope.close(e.currentTarget);
		else
			_scope.open(e.currentTarget);

	};

    /** section: Zepto
     * zebedee.open(el)
     *
     * - el (HTMLDOMElement): The handle clicked
     *
     * Opens the content block for the handle selected
     **/
	this.open = function(el){
		$(el).addClass(this.options.classNames.handleActive).next().anim(null,this.options.duration,this.options.transition).css('height',$(el).next().attr('data-zebheight')+"px");
	};

	/** section: Zepto
     * zebedee.close(el)
     *
     * - el (HTMLDOMElement): The handle clicked
     *
     * Closes the content block for the handle selected
     **/
	this.close = function(el){
		$(el).removeClass(this.options.classNames.handleActive).next().anim(null,this.options.duration,this.options.transition).css('height','0px');
	};

	//initialize options
    /** section: Zepto
     * zebedee.options -> Object
     *
     * Contains the configuration details for the current accordion
     **/
	this.options = this._merge({
        /** section: Zepto
         * zebedee.options.classNames -> Object
         *
         * Defines the default css classes for the accordion components.  Has 3 properties
         * - handle: Defines the css class for the clickable section headers
         * - handleActive: Defines the css class for the currently selected handle
         * - content: Defines the css class for the content blocks.
         **/
		classNames: {
			handle: 'zebedee-handle',
			handleActive: 'zebedee-active',
			content: 'zebedee-content'
		},
		linkElement:null,
		direction: 'vertical',
        /** section: Zepto
         * zebedee.options.duration -> Number
         *
         * Defines the duration of the opening/closing animation.
         **/
		duration:1,
		/** section: Zepto
         * zebedee.options.transition -> String
         *
         * Defines the animation effect used in the opening/closing animation.
         **/
		transition:'ease-out',
		/** section: Zepto
         * zebedee.options.trigger -> String
         *
         * Defines the event that triggers the opening/closing of blocks.
         **/
		trigger:'touchend'
	},options);

	//initialize accordion

	//set up handles
	$('#' + this._container.attr('id')+ '>.' + this.options.classNames.handle).bind(this.options.trigger,this.toggle);
	$('.' + this.options.classNames.content).each(function(i){
		$(i).attr('data-zebheight',$(i).height()).css('overflow','hidden');
	});
	$('.' + this.options.classNames.handle).each(function(i){_scope.close(i)});

	return this
});<commit_msg>Removed old zebedee file<commit_after><|endoftext|>


<commit_before>//META{"name":"ResizeX"}*//

var resizexDragging = false;
var resizexHandle;
var resizexWidth;
var resizexX;
var resizexY;
var resizexAspectRatio;

var ResizeX = function() {};

// unused
ResizeX.prototype.load = function() {};
ResizeX.prototype.unload = function() {};
ResizeX.prototype.onMessage = function() {};
// unused

ResizeX.prototype.start = function() {
	BdApi.injectCSS("resizex-style",'@font-face{font-family:Batch;src:url(https://cdn.rawgit.com/AdamWhitcroft/batch/a3640352/Webfont/batch-icons-webfont.ttf)}.resizex-icon::before{content:"\\F0A5";transform:scaleX(-1);display:inline-block;margin-top:8px;draggable:false!important}.resizex-handle{box-sizing:border-box;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:reverse;flex-direction:row-reverse;-webkit-box-pack:justify;justify-content:space-between;-webkit-box-align:center;align-items:center;cursor:nwse-resize;draggable:false!important;font-family:Batch;min-width:none!important}iframe.image{min-width:400px;max-width:none!important}');
};

ResizeX.prototype.stop = function() {
	BdApi.clearCSS("resizex-style");
};

ResizeX.prototype.observer = function(e) {
    if (e.addedNodes.length && e.addedNodes[0].classList && e.addedNodes[0].classList.contains("embed-thumbnail-video")) {

        $("iframe.image:not(:has(+ .resizex-handle))").after("

");

        $(document).add("*").off(".resizex");

        $(".resizex-handle").on("mousedown.resizex", function(e) {
            resizexDragging = true;
            resizexWidth = $(this).siblings().width();
            resizexX = e.pageX;
            resizexY = e.pageY;
            resizexHandle = this;
            resizexAspectRatio = $(this).siblings().height() / $(this).siblings().width();
            $(this).siblings().css("pointer-events", "none");
            BdApi.injectCSS("resizex-dragging","*{-webkit-user-select:none!important;cursor:nwse-resize!important;}");
		});

        $(document).on("mousemove.resizex", function(e) {
            if (resizexDragging) {
                $(resizexHandle).siblings().width(resizexWidth + (e.pageX - resizexX + e.pageY - resizexY));
                $(resizexHandle).siblings().height($(resizexHandle).siblings().width() * resizexAspectRatio);
            }
        }).on("mouseup.resizex", function() {
            resizexDragging = false;
            $(resizexHandle).siblings().css("pointer-events", "");
            BdApi.clearCSS("resizex-dragging");
        });
    }
};

ResizeX.prototype.getSettingsPanel = function() {
    return "";
};

ResizeX.prototype.getName = function() {
    return "ResizeX";
};

ResizeX.prototype.getDescription = function() {
    return "Makes videos (and images soon) resizable";
};

ResizeX.prototype.getVersion = function() {
    return "0.0.2";
};

ResizeX.prototype.getAuthor = function() {
    return "Anxeal";
};
<commit_msg>Only videos trigger ResizeX from now on<commit_after>//META{"name":"ResizeX"}*//

var resizexDragging = false;
var resizexHandle;
var resizexWidth;
var resizexX;
var resizexY;
var resizexAspectRatio;

var ResizeX = function() {};

// unused
ResizeX.prototype.load = function() {};
ResizeX.prototype.unload = function() {};
ResizeX.prototype.onMessage = function() {};
// unused

ResizeX.prototype.start = function() {
	BdApi.injectCSS("resizex-style",'@font-face{font-family:Batch;src:url(https://cdn.rawgit.com/AdamWhitcroft/batch/a3640352/Webfont/batch-icons-webfont.ttf)}.resizex-icon::before{content:"\\F0A5";transform:scaleX(-1);display:inline-block;margin-top:8px;draggable:false!important}.resizex-handle{box-sizing:border-box;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:reverse;flex-direction:row-reverse;-webkit-box-pack:justify;justify-content:space-between;-webkit-box-align:center;align-items:center;cursor:nwse-resize;draggable:false!important;font-family:Batch;min-width:none!important}iframe.image{min-width:400px;max-width:none!important}');
};

ResizeX.prototype.stop = function() {
	BdApi.clearCSS("resizex-style");
};

ResizeX.prototype.observer = function(e) {
    if (e.addedNodes.length && e.addedNodes[0].classList && e.addedNodes[0].classList.contains("embed-thumbnail-video")) {

        $(".embed-thumbnail-video iframe.image:not(:has(+ .resizex-handle))").after("

");

        $(document).add("*").off(".resizex");

        $(".resizex-handle").on("mousedown.resizex", function(e) {
            resizexDragging = true;
            resizexWidth = $(this).siblings().width();
            resizexX = e.pageX;
            resizexY = e.pageY;
            resizexHandle = this;
            resizexAspectRatio = $(this).siblings().height() / $(this).siblings().width();
            $(this).siblings().css("pointer-events", "none");
            BdApi.injectCSS("resizex-dragging","*{-webkit-user-select:none!important;cursor:nwse-resize!important;}");
		});

        $(document).on("mousemove.resizex", function(e) {
            if (resizexDragging) {
                $(resizexHandle).siblings().width(resizexWidth + (e.pageX - resizexX + e.pageY - resizexY));
                $(resizexHandle).siblings().height($(resizexHandle).siblings().width() * resizexAspectRatio);
            }
        }).on("mouseup.resizex", function() {
            resizexDragging = false;
            $(resizexHandle).siblings().css("pointer-events", "");
            BdApi.clearCSS("resizex-dragging");
        });
    }
};

ResizeX.prototype.getSettingsPanel = function() {
    return "";
};

ResizeX.prototype.getName = function() {
    return "ResizeX";
};

ResizeX.prototype.getDescription = function() {
    return "Makes videos (and images soon) resizable";
};

ResizeX.prototype.getVersion = function() {
    return "0.0.3";
};

ResizeX.prototype.getAuthor = function() {
    return "Anxeal";
};
<|endoftext|>