<commit_before>import React from 'react';
import Thumbnail from '../../common/Thumbnail';
import { NavLink } from 'fluxible-router';
import { timeSince } from '../../../common';
import { Microservices } from '../../../configs/microservices';

class DeckCard extends React.Component {

    componentDidMount() {}

    componentDidUpdate() {}

    render() {
        // console.log('DeckCard: cardContent', this.props);

        let thumbnailURL = Microservices.file.uri + '/slideThumbnail/';
        if (this.props.cardContent.firstSlide)
            thumbnailURL += this.props.cardContent.firstSlide + '.jpeg';
        else
            thumbnailURL = this.props.cardContent.picture;

        let description = (this.props.cardContent.description.length > 100) ? this.props.cardContent.description.slice(0,99) + '...' : this.props.cardContent.description;
        return (

                {this.props.newTab === true ? (

                        <Thumbnail url={thumbnailURL}
                            slideId={this.props.cardContent.deckID} />

                ) : (
                    <NavLink className="ui medium centered spaced image" aria-hidden={'true'}  tabIndex={'-1'} href={'/deck/' + this.props.cardContent.deckID}>
                        <Thumbnail url={thumbnailURL}
                            slideId={this.props.cardContent.deckID} />
                    </NavLink>
                )}

                        {this.props.newTab === true ? (
                            this.props.cardContent.title.length > 50 ? (
                                {this.props.cardContent.title.slice(0,49) + '...'}
                            ) : (
                                {this.props.cardContent.title}
                            )
                        ) : (
                            this.props.cardContent.title.length > 50 ? (
                                <NavLink href={'/deck/' + this.props.cardContent.deckID} data-tooltip={this.props.cardContent.title}>{this.props.cardContent.title.slice(0,49) + '...'}</NavLink>
                            ) : (
                                <NavLink href={'/deck/' + this.props.cardContent.deckID}>{this.props.cardContent.title}</NavLink>
                            )
                        )}

                        Last updated {timeSince((new Date(this.props.cardContent.updated)))} ago

                    <NavLink href={'/deck/' + this.props.cardContent.deckID} target='_blank' data-tooltip="open deck" className="ui basic lightGrey icon button" type="button" aria-label="Open deck">

                    </NavLink>

                    <NavLink href={'/presentation/' + this.props.cardContent.deckID + '/' + this.props.cardContent.deckID} target="_blank" className="ui basic lightGrey icon button" type="button" aria-label="Open slideshow in new tab" data-tooltip="Open slideshow in new tab">

                    </NavLink>

        );
    }
}

DeckCard.contextTypes = {
    executeAction: React.PropTypes.func.isRequired
};

export default DeckCard;
<commit_msg>improve button layout<commit_after>import React from 'react';
import Thumbnail from '../../common/Thumbnail';
import { NavLink } from 'fluxible-router';
import { timeSince } from '../../../common';
import { Microservices } from '../../../configs/microservices';

class DeckCard extends React.Component {

    componentDidMount() {}

    componentDidUpdate() {}

    render() {
        // console.log('DeckCard: cardContent', this.props);

        let thumbnailURL = Microservices.file.uri + '/slideThumbnail/';
        if (this.props.cardContent.firstSlide)
            thumbnailURL += this.props.cardContent.firstSlide + '.jpeg';
        else
            thumbnailURL = this.props.cardContent.picture;

        let description = (this.props.cardContent.description.length > 100) ? this.props.cardContent.description.slice(0,99) + '...' : this.props.cardContent.description;
        return (

                {this.props.newTab === true ? (

                        <Thumbnail url={thumbnailURL}
                            slideId={this.props.cardContent.deckID} />

                ) : (
                    <NavLink className="ui medium centered spaced image" aria-hidden={'true'}  tabIndex={'-1'} href={'/deck/' + this.props.cardContent.deckID}>
                        <Thumbnail url={thumbnailURL}
                            slideId={this.props.cardContent.deckID} />
                    </NavLink>
                )}

                        {this.props.newTab === true ? (
                            this.props.cardContent.title.length > 50 ? (
                                {this.props.cardContent.title.slice(0,49) + '...'}
                            ) : (
                                {this.props.cardContent.title}
                            )
                        ) : (
                            this.props.cardContent.title.length > 50 ? (
                                <NavLink href={'/deck/' + this.props.cardContent.deckID} data-tooltip={this.props.cardContent.title}>{this.props.cardContent.title.slice(0,49) + '...'}</NavLink>
                            ) : (
                                <NavLink href={'/deck/' + this.props.cardContent.deckID}>{this.props.cardContent.title}</NavLink>
                            )
                        )}

                        Last updated {timeSince((new Date(this.props.cardContent.updated)))} ago

                        <NavLink href={'/deck/' + this.props.cardContent.deckID} target='_blank' data-tooltip="open deck" className="ui basic lightGrey icon button" type="button" aria-label="Open deck">

                        </NavLink>
                        <NavLink href={'/presentation/' + this.props.cardContent.deckID + '/' + this.props.cardContent.deckID} target="_blank" className="ui basic lightGrey icon button" type="button" aria-label="Open slideshow in new tab" data-tooltip="Open slideshow in new tab">

                        </NavLink>

        );
    }
}

DeckCard.contextTypes = {
    executeAction: React.PropTypes.func.isRequired
};

export default DeckCard;
<|endoftext|>


<commit_before>var cdb = require('cartodb.js');
var FiltersView = require('./filters/view');
var ListView = require('./content/list/view');
var ContentView = require('./content/view');
var DatasetsCollection = require('./datasets_collection');
var DataLibraryHeader = require('./header/view');

module.exports = cdb.core.View.extend({

  events: {
    'click .js-more': '_onClickMore'
  },

  initialize: function() {
    this._initModels();
    this._initViews();

    this._initBindings();
  },

  _initViews: function() {
    this.controlledViews = {};  // All available views
    this.enabledViews = [];     // Visible views

    var dataLibraryHeader = new DataLibraryHeader({
      model: this.model
    });

    this.addView(dataLibraryHeader);
    $('.js-Header--datalibrary').append(dataLibraryHeader.render().el);
    dataLibraryHeader.load();

    var filtersView = new FiltersView({
      el: this.$('.Filters'),
      collection: this.collection,
      model: this.model
    });
    filtersView.render();
    this.addView(filtersView);

    var moreView = new ContentView({
      collection: this.collection,
      template: 'data_library/content/more_template',
    });
    this.$el.append(moreView.render().el);
    this.addView(moreView);

    var listView = new ListView({
      collection: this.collection
    });
    this.$('.js-DataLibrary-content').append(listView.render().el);
    this.addView(listView);
    this.controlledViews['list'] = listView;

    var noResultsView = new ContentView({
      collection: this.collection,
      template: 'data_library/content/no_results_template',
    });
    this.$el.append(noResultsView.render().el);
    this.addView(noResultsView);
    this.controlledViews['no_results'] = noResultsView;

    var errorView = new ContentView({
      collection: this.collection,
      template: 'data_library/content/error_template'
    });
    this.$el.append(errorView.render().el);
    this.addView(errorView);
    this.controlledViews['error'] = errorView;

    var mainLoaderView = new ContentView({
      collection: this.collection,
      template: 'data_library/content/loader_template'
    });
    this.$el.append(mainLoaderView.render().el);
    this.addView(mainLoaderView);
    this.controlledViews['main_loader'] = mainLoaderView;
  },

  _fetchCollection: function() {
    this.collection.fetch();
  },

  render: function() {
    this._fetchCollection();

    return this;
  },

  _initBindings: function() {
    this.model.bind('change:show_more', this._onChangeShowMore, this);
    this.model.bind('change:vis_count', this._onChangeVisCount, this);

    this.collection.options.bind('change:tags', function() {
      this.model.set({ vis_count: 0 });
    }, this);

    this.collection.options.bind('change', function() {
      this.model.set({ show_more: false });

      this._fetchCollection();
    }, this);
    this.collection.bind('reset', function() {
      this._onDataFetched();
    }, this);
    this.collection.bind('loading', function() {
      if (this.collection.options.get('page') === 1) {
        this._showLoader();
      } else {
        this._showLoaderOnly();
      }
    }, this);
    this.collection.bind('error', function() {
      this._onDataError();
    }, this);

    this.add_related_model(this.collection);
    this.add_related_model(this.collection.options);
  },

  _onChangeVisCount: function() {
    if (this.model.get('vis_count') >= this.collection.total_entries) {
      this.model.set({ show_more: false });
    } else {
      this.model.set({ show_more: true });
    }
  },

  _onChangeShowMore: function() {
    this.$('.js-more').toggleClass('is-hidden', !this.model.get('show_more'));
  },

  _onDataFetched: function() {
    var activeViews = [ ];

    if (this.collection.size() === 0) {
      activeViews.push('no_results');
    } else {
      this.model.set({ vis_count: this.model.get('vis_count') + this.collection.length, show_more: true });
      activeViews.push('list');
    }

    this._hideBlocks();
    this._showBlocks(activeViews);
  },

  _onDataError: function(e) {
    this._hideBlocks();
    this._showBlocks([ 'error' ]);
  },

  _showBlocks: function(views) {
    var self = this;

    if (views) {
      _.each(views, function(v){
        self.controlledViews[v].show();
        self.enabledViews.push(v);
      });
    } else {
      self.enabledViews = [];
      _.each(this.controlledViews, function(v){
        v.show();
        self.enabledViews.push(v);
      });
    }
  },

  _hideBlocks: function(views) {
    var self = this;
    if (views) {
      _.each(views, function(v){
        self.controlledViews[v].hide();
        self.enabledViews = _.without(self.enabledViews, v);
      });
    } else {
      _.each(this.controlledViews, function(v){
        v.hide();
      });
      self.enabledViews = [];
    }
  },

  _isBlockEnabled: function(name) {
    if (name) {
      return _.contains(this.enabledViews, name);
    }

    return false;
  },

  _showLoader: function() {
    this._hideBlocks();
    this._showBlocks([ 'main_loader' ]);
  },

  _showLoaderOnly: function() {
    this._showBlocks([ 'main_loader' ]);
  },

  _hideLoader: function() {
    this._hideBlocks([ 'main_loader' ]);
  },

  _initModels: function() {
    this.model = new cdb.core.Model({
      vis_count: 0,
      show_countries: false,
      is_searching: false
    });

    this.collection = new DatasetsCollection();

    this._resetOptions();
  },

  _resetOptions: function() {
    this.collection.options.set({
      q: '',
      order: 'updated_at',
      page: 1,
      tags: '',
      // bbox: '',
      source: [],
      type: 'table'
    });
  },

  _onClickMore: function(e) {
    this.killEvent(e);

    this.model.set({ show_more: false });

    this.collection.options.set({
      page: this.collection.options.get('page') + 1
    });
  }

});
<commit_msg>Adding abort error + tracking error when datasets collection fails<commit_after>var cdb = require('cartodb.js');
var FiltersView = require('./filters/view');
var ListView = require('./content/list/view');
var ContentView = require('./content/view');
var DatasetsCollection = require('./datasets_collection');
var DataLibraryHeader = require('./header/view');

module.exports = cdb.core.View.extend({

  events: {
    'click .js-more': '_onClickMore'
  },

  initialize: function() {
    this._initModels();
    this._initViews();

    this._initBindings();
  },

  _initViews: function() {
    this.controlledViews = {};  // All available views
    this.enabledViews = [];     // Visible views

    var dataLibraryHeader = new DataLibraryHeader({
      model: this.model
    });

    this.addView(dataLibraryHeader);
    $('.js-Header--datalibrary').append(dataLibraryHeader.render().el);
    dataLibraryHeader.load();

    var filtersView = new FiltersView({
      el: this.$('.Filters'),
      collection: this.collection,
      model: this.model
    });
    filtersView.render();
    this.addView(filtersView);

    var moreView = new ContentView({
      collection: this.collection,
      template: 'data_library/content/more_template',
    });
    this.$el.append(moreView.render().el);
    this.addView(moreView);

    var listView = new ListView({
      collection: this.collection
    });
    this.$('.js-DataLibrary-content').append(listView.render().el);
    this.addView(listView);
    this.controlledViews['list'] = listView;

    var noResultsView = new ContentView({
      collection: this.collection,
      template: 'data_library/content/no_results_template',
    });
    this.$el.append(noResultsView.render().el);
    this.addView(noResultsView);
    this.controlledViews['no_results'] = noResultsView;

    var errorView = new ContentView({
      collection: this.collection,
      template: 'data_library/content/error_template'
    });
    this.$el.append(errorView.render().el);
    this.addView(errorView);
    this.controlledViews['error'] = errorView;

    var mainLoaderView = new ContentView({
      collection: this.collection,
      template: 'data_library/content/loader_template'
    });
    this.$el.append(mainLoaderView.render().el);
    this.addView(mainLoaderView);
    this.controlledViews['main_loader'] = mainLoaderView;
  },

  _fetchCollection: function() {
    this.collection.fetch();
  },

  render: function() {
    this._fetchCollection();

    return this;
  },

  _initBindings: function() {
    this.model.bind('change:show_more', this._onChangeShowMore, this);
    this.model.bind('change:vis_count', this._onChangeVisCount, this);

    this.collection.options.bind('change:tags', function() {
      this.model.set({ vis_count: 0 });
    }, this);

    this.collection.options.bind('change', function() {
      this.model.set({ show_more: false });
      this._fetchCollection();
    }, this);
    this.collection.bind('reset', function() {
      this._onDataFetched();
    }, this);
    this.collection.bind('loading', function() {
      if (this.collection.options.get('page') === 1) {
        this._showLoader();
      } else {
        this._showLoaderOnly();
      }
    }, this);
    this.collection.bind('error', function(coll, e, opts) {
      if (!e || (e && e.statusText !== "abort")) {
        this._onDataError(e);
      }
    }, this);

    this.add_related_model(this.collection);
    this.add_related_model(this.collection.options);
  },

  _onChangeVisCount: function() {
    if (this.model.get('vis_count') >= this.collection.total_entries) {
      this.model.set({ show_more: false });
    } else {
      this.model.set({ show_more: true });
    }
  },

  _onChangeShowMore: function() {
    this.$('.js-more').toggleClass('is-hidden', !this.model.get('show_more'));
  },

  _onDataFetched: function() {
    var activeViews = [ ];

    if (this.collection.size() === 0) {
      activeViews.push('no_results');
    } else {
      this.model.set({ vis_count: this.model.get('vis_count') + this.collection.length, show_more: true });
      activeViews.push('list');
    }

    this._hideBlocks();
    this._showBlocks(activeViews);
  },

  _onDataError: function(e) {
    // Send error to TrackJS
    if (window.trackJs && window.trackJs.track) {
      window.trackJs.track(e);
    }

    this._hideBlocks();
    this._showBlocks([ 'error' ]);
  },

  _showBlocks: function(views) {
    var self = this;

    if (views) {
      _.each(views, function(v){
        self.controlledViews[v].show();
        self.enabledViews.push(v);
      });
    } else {
      self.enabledViews = [];
      _.each(this.controlledViews, function(v){
        v.show();
        self.enabledViews.push(v);
      });
    }
  },

  _hideBlocks: function(views) {
    var self = this;
    if (views) {
      _.each(views, function(v){
        self.controlledViews[v].hide();
        self.enabledViews = _.without(self.enabledViews, v);
      });
    } else {
      _.each(this.controlledViews, function(v){
        v.hide();
      });
      self.enabledViews = [];
    }
  },

  _isBlockEnabled: function(name) {
    if (name) {
      return _.contains(this.enabledViews, name);
    }

    return false;
  },

  _showLoader: function() {
    this._hideBlocks();
    this._showBlocks([ 'main_loader' ]);
  },

  _showLoaderOnly: function() {
    this._showBlocks([ 'main_loader' ]);
  },

  _hideLoader: function() {
    this._hideBlocks([ 'main_loader' ]);
  },

  _initModels: function() {
    this.model = new cdb.core.Model({
      vis_count: 0,
      show_countries: false,
      is_searching: false
    });

    this.collection = new DatasetsCollection();

    this._resetOptions();
  },

  _resetOptions: function() {
    this.collection.options.set({
      q: '',
      order: 'updated_at',
      page: 1,
      tags: '',
      // bbox: '',
      source: [],
      type: 'table'
    });
  },

  _onClickMore: function(e) {
    this.killEvent(e);

    this.model.set({ show_more: false });

    this.collection.options.set({
      page: this.collection.options.get('page') + 1
    });
  }

});
<|endoftext|>


<commit_before>// app/routes.js

const debug = require("debug")("lncliweb:routes");
const logger = require("winston");
const request = require("request");

// expose the routes to our app with module.exports
module.exports = function (app, lightning, db) {

	// api ---------------------------------------------------------------------

	// get lnd network info
	app.get("/api/lnd/getnetworkinfo", function (req, res) {
		lightning.getNetworkInfo({}, function (err, response) {
			if (err) {
				logger.debug("GetNetworkInfo Error:", err);
				err.error = err.message;
				res.send(err);
			} else {
				logger.debug("GetNetworkInfo:", response);
				res.json(response);
			}
		});
	});

	// get lnd node info
	app.get("/api/lnd/getinfo", function (req, res) {
		lightning.getInfo({}, function (err, response) {
			if (err) {
				logger.debug("GetInfo Error:", err);
				err.error = err.message;
				res.send(err);
			} else {
				logger.debug("GetInfo:", response);
				res.json(response);
			}
		});
	});

	// get lnd node active channels list
	app.get("/api/lnd/listpeers", function (req, res) {
		lightning.listPeers({}, function (err, response) {
			if (err) {
				logger.debug("ListPeers Error:", err);
				err.error = err.message;
				res.send(err);
			} else {
				logger.debug("ListPeers:", response);
				res.json(response);
			}
		});
	});

	// get lnd node active channels list
	app.get("/api/lnd/listchannels", function (req, res) {
		lightning.listChannels({}, function (err, response) {
			if (err) {
				logger.debug("ListChannels Error:", err);
				err.error = err.message;
				res.send(err);
			} else {
				logger.debug("ListChannels:", response);
				res.json(response);
			}
		});
	});

	// get lnd node pending channels list
	app.get("/api/lnd/pendingchannels", function (req, res) {
		lightning.pendingChannels({}, function (err, response) {
			if (err) {
				logger.debug("PendingChannels Error:", err);
				err.error = err.message;
				res.send(err);
			} else {
				logger.debug("PendingChannels:", response);
				res.json(response);
			}
		});
	});

	// get lnd node payments list
	app.get("/api/lnd/listpayments", function (req, res) {
		lightning.listPayments({}, function (err, response) {
			if (err) {
				logger.debug("ListPayments Error:", err);
				err.error = err.message;
				res.send(err);
			} else {
				logger.debug("ListPayments:", response);
				res.json(response);
			}
		});
	});

	// get lnd node invoices list
	app.get("/api/lnd/listinvoices", function (req, res) {
		lightning.listInvoices({}, function (err, response) {
			if (err) {
				logger.debug("ListInvoices Error:", err);
				err.error = err.message;
				res.send(err);
			} else {
				logger.debug("ListInvoices:", response);
				res.json(response);
			}
		});
	});

	// get the lnd node wallet balance
	app.get("/api/lnd/walletbalance", function (req, res) {
		lightning.walletBalance({}, function (err, response) {
			if (err) {
				logger.debug("WalletBalance Error:", err);
				err.error = err.message;
				res.send(err);
			} else {
				logger.debug("WalletBalance:", response);
				res.json(response);
			}
		});
	});

	// get the lnd node channel balance
	app.get("/api/lnd/channelbalance", function (req, res) {
		lightning.channelBalance({}, function (err, response) {
			if (err) {
				logger.debug("ChannelBalance Error:", err);
				err.error = err.message;
				res.send(err);
			} else {
				logger.debug("ChannelBalance:", response);
				res.json(response);
			}
		});
	});

	// connect peer to lnd node
	app.post("/api/lnd/connectpeer", function (req, res) {
		if (req.limituser) {
			return res.sendStatus(403); // forbidden
		} else {
			var connectRequest = { addr: { pubkey: req.body.pubkey, host: req.body.host }, perm: true };
			logger.debug("ConnectPeer Request:", connectRequest);
			lightning.connectPeer(connectRequest, function (err, response) {
				if (err) {
					logger.debug("ConnectPeer Error:", err);
					err.error = err.message;
					res.send(err);
				} else {
					logger.debug("ConnectPeer:", response);
					res.json(response);
				}
			});
		}
	});

	// disconnect peer from lnd node
	app.post("/api/lnd/disconnectpeer", function (req, res) {
		if (req.limituser) {
			return res.sendStatus(403); // forbidden
		} else {
			var disconnectRequest = { pub_key: req.body.pubkey };
			logger.debug("DisconnectPeer Request:", disconnectRequest);
			lightning.disconnectPeer(disconnectRequest, function (err, response) {
				if (err) {
					logger.debug("DisconnectPeer Error:", err);
					err.error = err.message;
					res.send(err);
				} else {
					logger.debug("DisconnectPeer:", response);
					res.json(response);
				}
			});
		}
	});

	// addinvoice
	app.post("/api/lnd/addinvoice", function (req, res) {
		if (req.limituser) {
			return res.sendStatus(403); // forbidden
		} else {
			lightning.addInvoice({ memo: req.body.memo, value: req.body.value }, function (err, response) {
				if (err) {
					logger.debug("AddInvoice Error:", err);
					err.error = err.message;
					res.send(err);
				} else {
					logger.debug("AddInvoice:", response);
					res.json(response);
				}
			});
		}
	});

	// sendpayment
	app.post("/api/lnd/sendpayment", function (req, res) {
		if (req.limituser) {
			return res.sendStatus(403); // forbidden
		} else {
			var paymentRequest = { payment_request: req.body.payreq };
			logger.debug("Sending payment", paymentRequest);
			lightning.sendPaymentSync(paymentRequest, function (err, response) {
				if (err) {
					logger.debug("SendPayment Error:", err);
					err.error = err.message;
					res.send(err);
				} else {
					logger.debug("SendPayment:", response);
					res.json(response);
				}
			});
		}
	});

	// decodepayreq
	app.post("/api/lnd/decodepayreq", function (req, res) {
		lightning.decodePayReq({ pay_req: req.body.payreq }, function (err, response) {
			if (err) {
				logger.debug("DecodePayReq Error:", err);
				err.error = err.message;
				res.send(err);
			} else {
				logger.debug("DecodePayReq:", response);
				res.json(response);
			}
		});
	});

	// queryroute
	app.post("/api/lnd/queryroute", function (req, res) {
		lightning.queryRoutes({ pub_key: req.body.pubkey, amt: req.body.amt }, function (err, response) {
			if (err) {
				logger.debug("QueryRoute Error:", err);
				err.error = err.message;
				res.send(err);
			} else {
				logger.debug("QueryRoute:", response);
				res.json(response);
			}
		});
	});

	// newaddress
	app.post("/api/lnd/newaddress", function (req, res) {
		lightning.newAddress({ type: req.body.type }, function (err, response) {
			if (err) {
				logger.debug("NewAddress Error:", err);
				err.error = err.message;
				res.send(err);
			} else {
				logger.debug("NewAddress:", response);
				res.json(response);
			}
		});
	});

	// signmessage
	app.post("/api/lnd/signmessage", function (req, res) {
		if (req.limituser) {
			return res.sendStatus(403); // forbidden
		} else {
			lightning.signMessage({ msg: req.body.msg }, function (err, response) {
				if (err) {
					logger.debug("SignMessage Error:", err);
					err.error = err.message;
					res.send(err);
				} else {
					logger.debug("SignMessage:", response);
					res.json(response);
				}
			});
		}
	});

	// verifymessage
	app.post("/api/lnd/verifymessage", function (req, res) {
		lightning.verifyMessage({ msg: req.body.msg, signature: req.body.signature }, function (err, response) {
			if (err) {
				logger.debug("VerifyMessage Error:", err);
				err.error = err.message;
				res.send(err);
			} else {
				logger.debug("VerifyMessage:", response);
				res.json(response);
			}
		});
	});

	// application -------------------------------------------------------------
	app.get("*", function (req, res) {
		res.sendFile("lnd.html", { root: __dirname + "/../public/" }); // load the single view file (angular will handle the page changes on the front-end)
	});

};
<commit_msg>Message bytes encoding fix<commit_after>// app/routes.js

const debug = require("debug")("lncliweb:routes");
const logger = require("winston");
const request = require("request");

// expose the routes to our app with module.exports
module.exports = function (app, lightning, db) {

	// api ---------------------------------------------------------------------

	// get lnd network info
	app.get("/api/lnd/getnetworkinfo", function (req, res) {
		lightning.getNetworkInfo({}, function (err, response) {
			if (err) {
				logger.debug("GetNetworkInfo Error:", err);
				err.error = err.message;
				res.send(err);
			} else {
				logger.debug("GetNetworkInfo:", response);
				res.json(response);
			}
		});
	});

	// get lnd node info
	app.get("/api/lnd/getinfo", function (req, res) {
		lightning.getInfo({}, function (err, response) {
			if (err) {
				logger.debug("GetInfo Error:", err);
				err.error = err.message;
				res.send(err);
			} else {
				logger.debug("GetInfo:", response);
				res.json(response);
			}
		});
	});

	// get lnd node active channels list
	app.get("/api/lnd/listpeers", function (req, res) {
		lightning.listPeers({}, function (err, response) {
			if (err) {
				logger.debug("ListPeers Error:", err);
				err.error = err.message;
				res.send(err);
			} else {
				logger.debug("ListPeers:", response);
				res.json(response);
			}
		});
	});

	// get lnd node active channels list
	app.get("/api/lnd/listchannels", function (req, res) {
		lightning.listChannels({}, function (err, response) {
			if (err) {
				logger.debug("ListChannels Error:", err);
				err.error = err.message;
				res.send(err);
			} else {
				logger.debug("ListChannels:", response);
				res.json(response);
			}
		});
	});

	// get lnd node pending channels list
	app.get("/api/lnd/pendingchannels", function (req, res) {
		lightning.pendingChannels({}, function (err, response) {
			if (err) {
				logger.debug("PendingChannels Error:", err);
				err.error = err.message;
				res.send(err);
			} else {
				logger.debug("PendingChannels:", response);
				res.json(response);
			}
		});
	});

	// get lnd node payments list
	app.get("/api/lnd/listpayments", function (req, res) {
		lightning.listPayments({}, function (err, response) {
			if (err) {
				logger.debug("ListPayments Error:", err);
				err.error = err.message;
				res.send(err);
			} else {
				logger.debug("ListPayments:", response);
				res.json(response);
			}
		});
	});

	// get lnd node invoices list
	app.get("/api/lnd/listinvoices", function (req, res) {
		lightning.listInvoices({}, function (err, response) {
			if (err) {
				logger.debug("ListInvoices Error:", err);
				err.error = err.message;
				res.send(err);
			} else {
				logger.debug("ListInvoices:", response);
				res.json(response);
			}
		});
	});

	// get the lnd node wallet balance
	app.get("/api/lnd/walletbalance", function (req, res) {
		lightning.walletBalance({}, function (err, response) {
			if (err) {
				logger.debug("WalletBalance Error:", err);
				err.error = err.message;
				res.send(err);
			} else {
				logger.debug("WalletBalance:", response);
				res.json(response);
			}
		});
	});

	// get the lnd node channel balance
	app.get("/api/lnd/channelbalance", function (req, res) {
		lightning.channelBalance({}, function (err, response) {
			if (err) {
				logger.debug("ChannelBalance Error:", err);
				err.error = err.message;
				res.send(err);
			} else {
				logger.debug("ChannelBalance:", response);
				res.json(response);
			}
		});
	});

	// connect peer to lnd node
	app.post("/api/lnd/connectpeer", function (req, res) {
		if (req.limituser) {
			return res.sendStatus(403); // forbidden
		} else {
			var connectRequest = { addr: { pubkey: req.body.pubkey, host: req.body.host }, perm: true };
			logger.debug("ConnectPeer Request:", connectRequest);
			lightning.connectPeer(connectRequest, function (err, response) {
				if (err) {
					logger.debug("ConnectPeer Error:", err);
					err.error = err.message;
					res.send(err);
				} else {
					logger.debug("ConnectPeer:", response);
					res.json(response);
				}
			});
		}
	});

	// disconnect peer from lnd node
	app.post("/api/lnd/disconnectpeer", function (req, res) {
		if (req.limituser) {
			return res.sendStatus(403); // forbidden
		} else {
			var disconnectRequest = { pub_key: req.body.pubkey };
			logger.debug("DisconnectPeer Request:", disconnectRequest);
			lightning.disconnectPeer(disconnectRequest, function (err, response) {
				if (err) {
					logger.debug("DisconnectPeer Error:", err);
					err.error = err.message;
					res.send(err);
				} else {
					logger.debug("DisconnectPeer:", response);
					res.json(response);
				}
			});
		}
	});

	// addinvoice
	app.post("/api/lnd/addinvoice", function (req, res) {
		if (req.limituser) {
			return res.sendStatus(403); // forbidden
		} else {
			lightning.addInvoice({ memo: req.body.memo, value: req.body.value }, function (err, response) {
				if (err) {
					logger.debug("AddInvoice Error:", err);
					err.error = err.message;
					res.send(err);
				} else {
					logger.debug("AddInvoice:", response);
					res.json(response);
				}
			});
		}
	});

	// sendpayment
	app.post("/api/lnd/sendpayment", function (req, res) {
		if (req.limituser) {
			return res.sendStatus(403); // forbidden
		} else {
			var paymentRequest = { payment_request: req.body.payreq };
			logger.debug("Sending payment", paymentRequest);
			lightning.sendPaymentSync(paymentRequest, function (err, response) {
				if (err) {
					logger.debug("SendPayment Error:", err);
					err.error = err.message;
					res.send(err);
				} else {
					logger.debug("SendPayment:", response);
					res.json(response);
				}
			});
		}
	});

	// decodepayreq
	app.post("/api/lnd/decodepayreq", function (req, res) {
		lightning.decodePayReq({ pay_req: req.body.payreq }, function (err, response) {
			if (err) {
				logger.debug("DecodePayReq Error:", err);
				err.error = err.message;
				res.send(err);
			} else {
				logger.debug("DecodePayReq:", response);
				res.json(response);
			}
		});
	});

	// queryroute
	app.post("/api/lnd/queryroute", function (req, res) {
		lightning.queryRoutes({ pub_key: req.body.pubkey, amt: req.body.amt }, function (err, response) {
			if (err) {
				logger.debug("QueryRoute Error:", err);
				err.error = err.message;
				res.send(err);
			} else {
				logger.debug("QueryRoute:", response);
				res.json(response);
			}
		});
	});

	// newaddress
	app.post("/api/lnd/newaddress", function (req, res) {
		lightning.newAddress({ type: req.body.type }, function (err, response) {
			if (err) {
				logger.debug("NewAddress Error:", err);
				err.error = err.message;
				res.send(err);
			} else {
				logger.debug("NewAddress:", response);
				res.json(response);
			}
		});
	});

	// signmessage
	app.post("/api/lnd/signmessage", function (req, res) {
		if (req.limituser) {
			return res.sendStatus(403); // forbidden
		} else {
			lightning.signMessage({ msg: Buffer.from(req.body.msg, "utf8") }, function (err, response) {
				if (err) {
					logger.debug("SignMessage Error:", err);
					err.error = err.message;
					res.send(err);
				} else {
					logger.debug("SignMessage:", response);
					res.json(response);
				}
			});
		}
	});

	// verifymessage
	app.post("/api/lnd/verifymessage", function (req, res) {
		lightning.verifyMessage({ msg: Buffer.from(req.body.msg, "utf8"), signature: req.body.signature }, function (err, response) {
			if (err) {
				logger.debug("VerifyMessage Error:", err);
				err.error = err.message;
				res.send(err);
			} else {
				logger.debug("VerifyMessage:", response);
				res.json(response);
			}
		});
	});

	// application -------------------------------------------------------------
	app.get("*", function (req, res) {
		res.sendFile("lnd.html", { root: __dirname + "/../public/" }); // load the single view file (angular will handle the page changes on the front-end)
	});

};
<|endoftext|>


<commit_before>'use strict'

var Err = require('./err')

var Node = module.exports = function(type, children, properties) {
	if (!Array.isArray(children)) {
		properties = children
		children = null
	}

	var node = properties || {}

	node.type = type

	if (children)
		node.children = children

	return node
}

Node.clone = function(node, deep) {
	if (Array.isArray(node))
		return node.map(function(node) {
			return Node.clone(node)
		})

	if (node === null || typeof node !== 'object')
		return node

	var clone = Object.create(node)

	if (deep === undefined)
		deep = true

	if (deep && node.children)
		clone.children = Node.clone(node.children)

	return clone
}

Node.equal = function(node1, node2) {
	if (Array.isArray(node1) || Array.isArray(node2)) {
		if (!Array.isArray(node1) || !Array.isArray(node2))
			return false

		if (node1.length !== node2.length)
			return false

		return node1.every(function(childNode1, i) {
			var childNode2 = node2[i]
			return Node.equal(childNode1, childNode2)
		})
	}

	if (node1 === null ||
	    typeof node1 !== 'object' ||
	    node2 === null ||
	    typeof node2 !== 'object'
	)
		return node1 === node2

	if (node1.type !== node2.type)
		return false

	if (!node1.children && !node2.children)
		return true

	if (!node1.children || !node2.children)
		return false

	return Node.equal(node1.children, node2.children)
}

Node.toNumber = function(node) {
	switch (node.type) {
	case 'number':
	case 'percentage':
	case 'dimension':
		return node.children[0]
	default:
		return null
	}
}

Node.toBoolean = function(node) {
	switch (node.type) {
	case 'boolean':
		return node.children[0]
	case 'number':
	case 'percentage':
	case 'dimension':
		return !!node.children[0]
	case 'identifier':
	case 'string':
		return node.children.length !== 1 || !!node.children[0]
	}

	return true
}

Node.toListNode = function(rangeNode) {
	var fromNode = rangeNode.children[0]
	var fromNumber = fromNode.children[0]

	var toNode = rangeNode.children[1]
	var toNumber = toNode.children[0]

	var stepNumber = fromNumber < toNumber ? 1 : -1

	var exclusive = rangeNode.exclusive

	var itemNodes = []
	var i = 0
	while (
		exclusive ?
			stepNumber > 0 && fromNumber < toNumber ||
			stepNumber < 0 && fromNumber > toNumber
		:
			stepNumber > 0 && fromNumber <= toNumber ||
			stepNumber < 0 && fromNumber >= toNumber
	) {
		if (i++)
			itemNodes.push(Node('separator', [' '], {loc: rangeNode.loc}))

		var fromClone = Node.clone(fromNode)
		fromClone.children[0] = fromNumber
		itemNodes.push(fromClone)

		fromNumber += stepNumber
	}

	if (!itemNodes.length)
		return Node('null', {loc: rangeNode.loc})

	if (itemNodes.length === 1)
		return itemNodes[0]

	return Node('list', itemNodes, {loc: rangeNode.loc})
}<commit_msg>no need to require Err in Node<commit_after>'use strict'

var Node = module.exports = function(type, children, properties) {
	if (!Array.isArray(children)) {
		properties = children
		children = null
	}

	var node = properties || {}

	node.type = type

	if (children)
		node.children = children

	return node
}

Node.clone = function(node, deep) {
	if (Array.isArray(node))
		return node.map(function(node) {
			return Node.clone(node)
		})

	if (node === null || typeof node !== 'object')
		return node

	var clone = Object.create(node)

	if (deep === undefined)
		deep = true

	if (deep && node.children)
		clone.children = Node.clone(node.children)

	return clone
}

Node.equal = function(node1, node2) {
	if (Array.isArray(node1) || Array.isArray(node2)) {
		if (!Array.isArray(node1) || !Array.isArray(node2))
			return false

		if (node1.length !== node2.length)
			return false

		return node1.every(function(childNode1, i) {
			var childNode2 = node2[i]
			return Node.equal(childNode1, childNode2)
		})
	}

	if (node1 === null ||
	    typeof node1 !== 'object' ||
	    node2 === null ||
	    typeof node2 !== 'object'
	)
		return node1 === node2

	if (node1.type !== node2.type)
		return false

	if (!node1.children && !node2.children)
		return true

	if (!node1.children || !node2.children)
		return false

	return Node.equal(node1.children, node2.children)
}

Node.toNumber = function(node) {
	switch (node.type) {
	case 'number':
	case 'percentage':
	case 'dimension':
		return node.children[0]
	default:
		return null
	}
}

Node.toBoolean = function(node) {
	switch (node.type) {
	case 'boolean':
		return node.children[0]
	case 'number':
	case 'percentage':
	case 'dimension':
		return !!node.children[0]
	case 'identifier':
	case 'string':
		return node.children.length !== 1 || !!node.children[0]
	}

	return true
}

Node.toListNode = function(rangeNode) {
	var fromNode = rangeNode.children[0]
	var fromNumber = fromNode.children[0]

	var toNode = rangeNode.children[1]
	var toNumber = toNode.children[0]

	var stepNumber = fromNumber < toNumber ? 1 : -1

	var exclusive = rangeNode.exclusive

	var itemNodes = []
	var i = 0
	while (
		exclusive ?
			stepNumber > 0 && fromNumber < toNumber ||
			stepNumber < 0 && fromNumber > toNumber
		:
			stepNumber > 0 && fromNumber <= toNumber ||
			stepNumber < 0 && fromNumber >= toNumber
	) {
		if (i++)
			itemNodes.push(Node('separator', [' '], {loc: rangeNode.loc}))

		var fromClone = Node.clone(fromNode)
		fromClone.children[0] = fromNumber
		itemNodes.push(fromClone)

		fromNumber += stepNumber
	}

	if (!itemNodes.length)
		return Node('null', {loc: rangeNode.loc})

	if (itemNodes.length === 1)
		return itemNodes[0]

	return Node('list', itemNodes, {loc: rangeNode.loc})
}<|endoftext|>


<commit_before>/*
 *
 * Home
 *
 */

import React from 'react';
import Helmet from 'react-helmet';
import {Link} from "react-router"; /* allow us to link to different pages in project folder*/

export default class Home extends React.PureComponent {
  render() {

    const titleStyle = {
        display: "flex",
        flexDirection: "column",
        padding: "13.5%",
        background:"url(https://68.media.tumblr.com/8ba6be52a6cb41fe964cd7fbb94a3e02/tumblr_on2pafGDUw1vieawno1_1280.jpg)",
        backgroundSize:"cover",
        width:"100%",
        height:"300px",
    }

    const titlePage = {
        color: "#eeeeee",
        fontSize: "5em",
        fontFamily: "Source Sans Pro",
        fontStyle: "light",
        fontWeight: "400",
        textTransform: "uppercase",
        letterSpacing: "6px",
        textAlign: "center",
        marginTop: "160px",

    }

    const screenshotStyle = {
        display: "flex",
        justifyContent: "center",
        background: " #BED9F6",
        height: "30vh"
        /* #B4CFEC*/

    }
    /*const picBox = {
        display: "flex",
        justifyContent: "center",
        flexDirection: "column",
        width: "13%",
        height: "150px",
        background: "red"
    }*/

        const picBox = {
        display: "flex",
        justifyContent: "center",
        flexDirection: "column",
        width: "13%",
        height: "150px",
        margin: "5px",
    }

       const thumbNails = {

            width: "100%",
            height: "128px"
        }

        const placeHoldertext = {
            textDecoration: "none",
            display: "flex",
            textAlign: "center",
            justifyContent: "center",
            fontFamily: "Merriweather",
            color:"000000"
        }

    /*
        const thirdPic = {
        width: "13%",
        height: "150px",
        background:"#0000ff"
    }

        const fourthPic = {
        width: "13%",
        height: "150px",
        background:"#ff0000"
    }*/

    return (

        <Helmet title="Home" meta={[ { name: 'description', content: 'Description of Home' }]}/>

                <Link to= "/">Home</Link>
                <Link to= "/About">About</Link>

<Link to= "/">Home</Link>

Dos

Tres

Quatro

    );
  }
}
<commit_msg>added color to footer<commit_after>/*
 *
 * Home
 *
 */

import React from 'react';
import Helmet from 'react-helmet';
import {Link} from "react-router"; /* allow us to link to different pages in project folder*/

export default class Home extends React.PureComponent {
  render() {

    const titleStyle = {
        display: "flex",
        flexDirection: "column",
        padding: "13.5%",
        background:"url(https://68.media.tumblr.com/8ba6be52a6cb41fe964cd7fbb94a3e02/tumblr_on2pafGDUw1vieawno1_1280.jpg)",
        backgroundSize:"cover",
        width:"100%",
        height:"300px",
    }

    const titlePage = {
        color: "#eeeeee",
        fontSize: "5em",
        fontFamily: "Source Sans Pro",
        fontStyle: "light",
        fontWeight: "400",
        textTransform: "uppercase",
        letterSpacing: "6px",
        textAlign: "center",
        /*marginBottom: "160px"*/

    }

    const screenshotStyle = {
        display: "flex",
        justifyContent: "center",
        background: " #BED9F6",
        height: "30vh"
        /* #B4CFEC*/

    }
    /*const picBox = {
        display: "flex",
        justifyContent: "center",
        flexDirection: "column",
        width: "13%",
        height: "150px",
        background: "red"
    }*/

        const picBox = {
        display: "flex",
        justifyContent: "center",
        flexDirection: "column",
        width: "13%",
        height: "150px",
        margin: "5px",
    }

       const thumbNails = {

            width: "100%",
            height: "128px"
        }

        const placeHoldertext = {
            display: "flex",
            textAlign: "center",
            justifyContent: "center",
            fontFamily: "Merriweather",
            color:"#000000"
        }

        const footStyle = {
            display: "flex",
            flexDirection: "column",
            background: "#9E9E9E",
            height: "100vh",
            width: "100%"
        }

    /*
        const thirdPic = {
        width: "13%",
        height: "150px",
        background:"#0000ff"
    }

        const fourthPic = {
        width: "13%",
        height: "150px",
        background:"#ff0000"
    }*/

    return (

        <Helmet title="Home" meta={[ { name: 'description', content: 'Description of Home' }]}/>

                    Cinema, so blue...

                            <Link to= "/" style={{
                            textDecoration:'none',
                            fontFamily: 'Merriweather',
                            color:'black'
                            }}>Home</Link>

                            <Link to= "/About" style={{
                            textDecoration:'none',
                            fontFamily: 'Merriweather',
                            color:'black'
                            }}>About</Link>

Tres

Quatro

    );
  }
}
<|endoftext|>


<commit_before>var util = require('util'),
    twitter = require('twitter');
var twit;
var merge = require('merge');
var fs = require('fs')
var colors = require('colors');

var DUMMY_SEARCH = false;
var DUMMY_TWEET = false;
var WAIT_SECONDS = 120;
var QUERY = "";
var TWEET_CALLBACK = null;
var DB = null;

var COUNTDOWN_OUTPUT = false;

var TWITTER_ACCOUNT_NAME = "weathermcr";

var DEFAULT_STREAM_SLEEP_SECONDS = 5;

// --- SQL ---
var sql = [];
sql['createSeenTweets'] = 'CREATE TABLE IF NOT EXISTS seen_tweets ' +
                          '(id INTEGER PRIMARY KEY, time DATETIME DEFAULT current_timestamp, text TEXT, user_id INTEGER,' +
                          ' username TEXT, action_taken TEXT, streamed BOOLEAN)';
sql['createSentTweets'] = 'CREATE TABLE IF NOT EXISTS sent_tweets ' +
                          '(id INTEGER PRIMARY KEY AUTOINCREMENT, text TEXT, related_tweet_id INTEGER)';
sql['createAPILogin'] =   'CREATE TABLE IF NOT EXISTS api_login ' +
                          '(id INTEGER PRIMARY KEY AUTOINCREMENT, access_token_key TEXT, access_token_secret TEXT)';

sql['selectNewestAPI'] =     'SELECT * FROM api_login ORDER BY id DESC LIMIT 1';
sql['selectNewestTweet'] =   'SELECT id FROM seen_tweets WHERE streamed = 0 ORDER BY id DESC LIMIT 1';
sql['selectExistingTweet'] = "SELECT 1 as 'exist' FROM seen_tweets WHERE id = $tweet_id LIMIT 1";

sql['updateActionTaken'] = 'UPDATE seen_tweets SET action_taken = $action WHERE id = $id';

sql['insertSeenTweet'] = 'INSERT INTO seen_tweets (id, text, user_id, username, streamed) ' +
                         'VALUES ($id, $text, $user_id, $username, $streamed)';
sql['logSentTweet'] =    'INSERT INTO sent_tweets (text, related_tweet_id) VALUES ($text, $related_id)';
sql['insertAPILogin'] =  'INSERT INTO api_login (access_token_key, access_token_secret) VALUES ($key, $secret)';

// --- public
exports.config = function(config, wait_seconds, database) {
    twit = new twitter(config);
    WAIT_SECONDS = wait_seconds;
    DB = database;
}

exports.dummy = function(search, tweets) {
    DUMMY_SEARCH = search;
    DUMMY_TWEET = tweets;
    if(DUMMY_SEARCH)
      console.log("Using dummy twitter search");
    if(DUMMY_TWEET)
      console.log("Using dummy twitter tweet");
}

exports.start = function(query, tweet_callback, callback) {
    QUERY = query;
    TWEET_CALLBACK = tweet_callback;

    // Ensure the database is ready for use
    DB.serialize(function() {
      DB.run(sql['createSeenTweets']);
      DB.run(sql['createSentTweets']);
      DB.run(sql['createAPILogin']);
    });

    DB.get(sql['selectNewestAPI'], function(err, result) {

      if(result) {
          console.info("Using stored authentication");
          params = { 'since_id': (result.id - 1500) } // for some reason this needs to be done...

          twit.options.access_token_key = result.access_token_key;
          twit.options.access_token_secret = result.access_token_secret;

          start(callback);
      } else {
          console.info("Authentication is needed before bot can start.");
          requireAuthentication(function() {
              //reusable API access
              var insert = DB.prepare(sql['insertAPILogin']);
              insert.run({ $key: twit.options.access_token_key, $secret: twit.options.access_token_secret });

              start(callback);
          });

      }

    });
}

exports.updateActionTaken = function(tweet, actionTaken) {
    var update = DB.prepare(sql['updateActionTaken']);
    update.bind({$id: tweet.id, $action: actionTaken });
    update.run();
}

exports.sendReply = function(reply_to, message, callback, disable_dummy_tweet) {
    if(typeof disable_dummy_tweet === 'undefined')
        disable_dummy_tweet = false;

    // Must include @ for reply, else twitter rejects it
    if(reply_to.user.screen_name)
      message = "@" + reply_to.user.screen_name + " " + message;

    // Twitter rejects us if we provide an incorrect reply_to.id
    params = {}
    if(reply_to.id)
      params.in_reply_to_status_id = reply_to.id;

    if(message.length > 140)
        console.error("Message over 140 letters: " + message);

    console.log("Attempting to send", message);

    if(DUMMY_TWEET && !disable_dummy_tweet) {
      var dummy = { text: message };
      logSentTweet(dummy, params, false);
      callback(dummy);
    } else {
      twit.updateStatus(message, params, function(reply) {
          if(reply.id) {
            logSentTweet(reply, params);
            callback(reply);
          } else {
            console.error("Error sending tweet", reply);
          }
      });
    }

}

// --- private
function start(callback) {
    updateTweets();
    streamWeatherTweets();
    streamUserReplies();
    callback();
}

function requireAuthentication(callback) {
    var express = require('express');
    var app = express();
    var server;

    app.get('/', twit.gatekeeper('/login'), function(req, res){
      res.send('Authentification successfull');
      console.log("Auth complete, closing authentication server.");
      server.close();
      callback();
    });
    app.get('/twauth', twit.login());

    console.log('Listening on 1200 for auth requests to Twitter');
    server = app.listen(1200);
}

function logSentTweet(tweet, params, real) {
    if(typeof params === 'undefined')
      params = {};

    if(typeof real === 'undefined')
      real = true;

    var insert = DB.prepare(sql['logSentTweet']);
    insert.run({ $text: tweet.text, $related_id: params.in_reply_to_status_id });
    console.log("Tweet sent successfully" + (real ? "" : " (Mock)"));
}

function selectTweets(params, callback) {
    defaultParams = {
        'q': QUERY,
        'lang': 'en',
        'result_type': 'recent', //mixed, recent, popular
        'f': 'realtime',
        'include_entities': 'false',
        'count': 100
    };

    params = merge(defaultParams, params);

    if(DUMMY_SEARCH) callback();
    else twit.get('/search/tweets.json', params, callback);
}

function updateTweets() {
    console.log("Querying twitter for updates using polling");
    DB.get(sql['selectNewestTweet'], function(err, result) {
        if(result) params = { 'since_id': (result.id + 1)  }
        else params = {}

        selectTweets(params, function(data) {
            if(!data || !data.statuses) {
                console.warn("No data received from Twitter from search poll");
            }
            else
            {
                var count = data.statuses.length;
                if(count < 1) {
                    console.warn("No tweets received from Twitter from search poll");
                }

                for(i=0;i<count;i++) {
                    var tweet = data.statuses[i];
                    seenTweet(tweet);
                }
            }

            updateComplete();
        });
    });
}

// Connect to a twitter stream
function streamTweets(type, params, dataCallback, reconnectSleepSeconds) {
    if(typeof reconnectSleepSeconds === 'undefined')
        reconnectSleepSeconds = DEFAULT_STREAM_SLEEP_SECONDS;

    twit.stream(type, params, function(stream) {
        console.info("Connected to twitter "+type+" stream");

        var resetStream = setTimeout(function() {
            console.info("Restarting "+type+" stream as it has been open for 30 minutes");
            stream.destroy();
        }, 30 * 60 * 1000);

        stream.on('data', function(data) {

            // reset done here as 'connect' fires even on rejection
            reconnectSleepSeconds = DEFAULT_STREAM_SLEEP_SECONDS;

            dataCallback(data);

        });

        stream.on('error', function(error) {
            if(error.errorSource) console.error("Twitter "+type+" stream error:", error);
            else console.error("Other Twitter "+type+" stream error");
        });

        stream.on('end', function(end) {
            console.info("Stream "+type+" ended, will attempt to reconnect in "+reconnectSleepSeconds+" seconds");
            clearTimeout(resetStream);
            setTimeout(function() {
              streamTweets(type, params, dataCallback, reconnectSleepSeconds * 2);
            }, reconnectSleepSeconds * 1000);
        });

    });

}

// Twitter side
var weather_keywords = ['weather', 'forecast', 'sunny', ' rain', 'sunshine', 'thunder', 'lightning',
                        'umbrella', ' snow', 'hail', ' warm', 'cold', 'brolly', 'boiling',
                        '#snow', '#rain', '#hail', '#sun', '#thunder'];

// Local
var ignored_users = ['galgateweather', 'mennewsdesk', 'metoffice', 'chadWeather', 'myweather_man',
                     'uk_storms', 'wx_manchester', 'widdop_weather', 'weather', TWITTER_ACCOUNT_NAME,
                     'LordChapman'];

var ignored_keywords = ['rt @', '[Manchester Weather] Your Weekend Forecast', 'weatherspoons',
                        'manchester, nh', 'train', '@MetOffice', '@coldplay', 'Cold cave'];

function isWeatherTweet(tweet) {
    return arrayInString(tweet.text, weather_keywords, true)
           && !arrayInString(tweet.user.screen_name, ignored_users)
           && !arrayInString(tweet.text, ignored_keywords)
}

function highlightMatches(string, array) {
    text = string;
    for(i=0;i<array.length;i++) {
      text = text.replace(new RegExp('(' + array[i] + ')','ig'), "$1".red);
    }
}

// Get tweets about the weather
function streamWeatherTweets() {

    // Bounding boxes do not act as filters for other filter parameters.
    // For example track=twitter&locations=-122.75,36.8,-121.75,37.8 would match
    // any tweets containing the term Twitter (even non-geo tweets) OR coming from the San Francisco area.
    track = []

    for(i=0;i<weather_keywords.length;i++) {
      track.push(weather_keywords[i] + ' manchester');
      track.push(weather_keywords[i] + ' #mcr');
    }

    streamTweets('filter',
        {
            track: track,
            locations: '-2.275,53.45,-2.2,53.5' // bottom right, top left - lon/lat
        },
        function(data) {

            // @todo should probably validate data, twitter might return a none tweet
            // the steam may contain "non weather" tweets we must filter first
            if(isWeatherTweet(data)) {

                textWithMatches = highlightMatches(data.text, weather_keywords);
                console.info("Matched streamed weather tweet @", data.user.screen_name, " ", textWithMatches);
                seenTweet(data, true);

            } else {
                fs.appendFile('ignoredTweets.txt', data.user.screen_name
                                                    + ":\t"
                                                    + data.text.replace(/(\r\n|\n|\r)/gm," \\ ")
                                                    + "\n");
            }

        }
    );
}

function streamUserReplies() {
    streamTweets('user',
        {
            replies: 'all', // By default @replies are only sent if the current user follows the sender and receiver
            with: 'users' // When set to "users", only messages targeted directly at a user will be delivered
        },
        function(data) {
            // Upon establishing a User Stream connection Twitter will send
            // a preamble before starting regular message delivery
            if(data.friends) {
                return;
            }

            else if(data.text && data.text.toLowerCase().indexOf(TWITTER_ACCOUNT_NAME) != -1) {
                console.log("Recieved mention in user stream @", data.user.screen_name, data.text);

                // Avoid loops, if we sent the message and it was a reply to US
                if(data.in_reply_to_screen_name
                    && data.in_reply_to_screen_name.toLowerCase() == TWITTER_ACCOUNT_NAME
                    && data.user.screen_name.toLowerCase() == TWITTER_ACCOUNT_NAME) {
                    console.warn('Ignored self reply message');
                    return;
                }

                seenTweet(data, true, true);
            }
        }
    );
}

function arrayInString(string, array, ignore_mentions) {
    if(typeof string !== 'string')
        throw new Error('The term to search must be a string');

    if(typeof ignore_mentions === 'undefined')
        ignore_mentions = false;

    for(i=0;i<array.length;i++) {
        if(string.toLowerCase().indexOf(array[i].toLowerCase()) != -1) {
            if(!ignore_mentions) return true;
            else {
              // note double escape and trim due to trailing spaces
              var re = new RegExp('@\\w*'+array[i].trim(),'i');
              if(!re.test(string))
                  return true;
            }
        }
    }

    return false;

}

function seenTweet(tweet, streamed, mention) {
    if(typeof streamed === 'undefined')
        streamed = false;

    if(typeof mention === 'undefined')
        mention = tweet.text.toLowerCase().indexOf(TWITTER_ACCOUNT_NAME) != -1;

    var select = DB.prepare(sql['selectExistingTweet']);
    select.get({$tweet_id: tweet.id}, function(err, row) {
        if(!row) { // If the result set is empty, the second parameter is undefined
            var insert = DB.prepare(sql['insertSeenTweet']);
            insert.run({
              $id: tweet.id,
              $text: tweet.text,
              $user_id: tweet.user.id,
              $username: tweet.user.screen_name,
              $streamed: streamed ? 1 : 0  // 0/1 as SQLlite has no boolean support
            });
            TWEET_CALLBACK(tweet, mention);
            console.info("Logged: ", tweet.text, tweet.created_at);
        } else {
            console.info("Ignored duplicate: ", tweet.text, tweet.created_at);
            // @todo if streamed == false, I might need to mark this as non-streamed
            // to prevent the non-stream falling behind if the stream is capturing everything
        }
    });
}

function updateComplete() {
    console.info("\n"+'Update complete, waiting '+WAIT_SECONDS+' seconds before the next update');
    countdown(WAIT_SECONDS, updateTweets, "seconds until next search...");
}

function countdown(seconds, callback, message) {
    var countdownInterval;
    var countdownSecondsLeft;
    var countdownCallback;

    countdownInterval = setInterval(function(){
        if(COUNTDOWN_OUTPUT) {
            process.stdout.clearLine();  // clear current text
            process.stdout.cursorTo(0);  // move cursor to beginning of line
            process.stdout.write(countdownSecondsLeft-- + " " + message);
        }

        if(countdownSecondsLeft <= 0) {
            clearInterval(countdownInterval);
            process.stdout.write("\n");
            if(countdownCallback) {
                temp = countdownCallback;
                countdownCallback = null;
                temp();
            }
        }
    }, 1000);

    countdownSecondsLeft = seconds;
    if(typeof callback !== 'undefined') {
        countdownCallback = callback;
    }
}<commit_msg>Both methods now share the same filter<commit_after>var util = require('util'),
    twitter = require('twitter');
var twit;
var merge = require('merge');
var fs = require('fs')
var colors = require('colors');

var DUMMY_SEARCH = false;
var DUMMY_TWEET = false;
var WAIT_SECONDS = 120;
var QUERY = "";
var TWEET_CALLBACK = null;
var DB = null;

var COUNTDOWN_OUTPUT = false;

var TWITTER_ACCOUNT_NAME = "weathermcr";

var DEFAULT_STREAM_SLEEP_SECONDS = 5;

// --- SQL ---
var sql = [];
sql['createSeenTweets'] = 'CREATE TABLE IF NOT EXISTS seen_tweets ' +
                          '(id INTEGER PRIMARY KEY, time DATETIME DEFAULT current_timestamp, text TEXT, user_id INTEGER,' +
                          ' username TEXT, action_taken TEXT, streamed BOOLEAN)';
sql['createSentTweets'] = 'CREATE TABLE IF NOT EXISTS sent_tweets ' +
                          '(id INTEGER PRIMARY KEY AUTOINCREMENT, text TEXT, related_tweet_id INTEGER)';
sql['createAPILogin'] =   'CREATE TABLE IF NOT EXISTS api_login ' +
                          '(id INTEGER PRIMARY KEY AUTOINCREMENT, access_token_key TEXT, access_token_secret TEXT)';

sql['selectNewestAPI'] =     'SELECT * FROM api_login ORDER BY id DESC LIMIT 1';
sql['selectNewestTweet'] =   'SELECT id FROM seen_tweets WHERE streamed = 0 ORDER BY id DESC LIMIT 1';
sql['selectExistingTweet'] = "SELECT 1 as 'exist' FROM seen_tweets WHERE id = $tweet_id LIMIT 1";

sql['updateActionTaken'] = 'UPDATE seen_tweets SET action_taken = $action WHERE id = $id';

sql['insertSeenTweet'] = 'INSERT INTO seen_tweets (id, text, user_id, username, streamed) ' +
                         'VALUES ($id, $text, $user_id, $username, $streamed)';
sql['logSentTweet'] =    'INSERT INTO sent_tweets (text, related_tweet_id) VALUES ($text, $related_id)';
sql['insertAPILogin'] =  'INSERT INTO api_login (access_token_key, access_token_secret) VALUES ($key, $secret)';

// --- public
exports.config = function(config, wait_seconds, database) {
    twit = new twitter(config);
    WAIT_SECONDS = wait_seconds;
    DB = database;
}

exports.dummy = function(search, tweets) {
    DUMMY_SEARCH = search;
    DUMMY_TWEET = tweets;
    if(DUMMY_SEARCH)
      console.log("Using dummy twitter search");
    if(DUMMY_TWEET)
      console.log("Using dummy twitter tweet");
}

exports.start = function(query, tweet_callback, callback) {
    QUERY = query;
    TWEET_CALLBACK = tweet_callback;

    // Ensure the database is ready for use
    DB.serialize(function() {
      DB.run(sql['createSeenTweets']);
      DB.run(sql['createSentTweets']);
      DB.run(sql['createAPILogin']);
    });

    DB.get(sql['selectNewestAPI'], function(err, result) {

      if(result) {
          console.info("Using stored authentication");
          params = { 'since_id': (result.id - 1500) } // for some reason this needs to be done...

          twit.options.access_token_key = result.access_token_key;
          twit.options.access_token_secret = result.access_token_secret;

          start(callback);
      } else {
          console.info("Authentication is needed before bot can start.");
          requireAuthentication(function() {
              //reusable API access
              var insert = DB.prepare(sql['insertAPILogin']);
              insert.run({ $key: twit.options.access_token_key, $secret: twit.options.access_token_secret });

              start(callback);
          });

      }

    });
}

exports.updateActionTaken = function(tweet, actionTaken) {
    var update = DB.prepare(sql['updateActionTaken']);
    update.bind({$id: tweet.id, $action: actionTaken });
    update.run();
}

exports.sendReply = function(reply_to, message, callback, disable_dummy_tweet) {
    if(typeof disable_dummy_tweet === 'undefined')
        disable_dummy_tweet = false;

    // Must include @ for reply, else twitter rejects it
    if(reply_to.user.screen_name)
      message = "@" + reply_to.user.screen_name + " " + message;

    // Twitter rejects us if we provide an incorrect reply_to.id
    params = {}
    if(reply_to.id)
      params.in_reply_to_status_id = reply_to.id;

    if(message.length > 140)
        console.error("Message over 140 letters: " + message);

    console.log("Attempting to send", message);

    if(DUMMY_TWEET && !disable_dummy_tweet) {
      var dummy = { text: message };
      logSentTweet(dummy, params, false);
      callback(dummy);
    } else {
      twit.updateStatus(message, params, function(reply) {
          if(reply.id) {
            logSentTweet(reply, params);
            callback(reply);
          } else {
            console.error("Error sending tweet", reply);
          }
      });
    }

}

// --- private
function start(callback) {
    updateTweets();
    streamWeatherTweets();
    streamUserReplies();
    callback();
}

function requireAuthentication(callback) {
    var express = require('express');
    var app = express();
    var server;

    app.get('/', twit.gatekeeper('/login'), function(req, res){
      res.send('Authentification successfull');
      console.log("Auth complete, closing authentication server.");
      server.close();
      callback();
    });
    app.get('/twauth', twit.login());

    console.log('Listening on 1200 for auth requests to Twitter');
    server = app.listen(1200);
}

function logSentTweet(tweet, params, real) {
    if(typeof params === 'undefined')
      params = {};

    if(typeof real === 'undefined')
      real = true;

    var insert = DB.prepare(sql['logSentTweet']);
    insert.run({ $text: tweet.text, $related_id: params.in_reply_to_status_id });
    console.log("Tweet sent successfully" + (real ? "" : " (Mock)"));
}

function selectTweets(params, callback) {
    defaultParams = {
        'q': QUERY,
        'lang': 'en',
        'result_type': 'recent', //mixed, recent, popular
        'f': 'realtime',
        'include_entities': 'false',
        'count': 100
    };

    params = merge(defaultParams, params);

    if(DUMMY_SEARCH) callback();
    else twit.get('/search/tweets.json', params, callback);
}

function updateTweets() {
    console.log("Querying twitter for updates using polling");
    DB.get(sql['selectNewestTweet'], function(err, result) {
        if(result) params = { 'since_id': (result.id + 1)  }
        else params = {}

        selectTweets(params, function(data) {
            if(!data || !data.statuses) {
                console.warn("No data received from Twitter from search poll");
            }
            else
            {
                var count = data.statuses.length;
                if(count < 1) {
                    console.warn("No tweets received from Twitter from search poll");
                }

                for(i=0;i<count;i++) {
                    var tweet = data.statuses[i];

                    if(isWeatherTweet(data)) {
                        seenTweet(tweet);
                    } else {
                        fs.appendFile('ignoredTweets.txt', data.user.screen_name
                                       + ":\t"
                                       + data.text.replace(/(\r\n|\n|\r)/gm," \\\ ")
                                       + "\n");
                    }

                }
            }

            updateComplete();
        });
    });
}

// Connect to a twitter stream
function streamTweets(type, params, dataCallback, reconnectSleepSeconds) {
    if(typeof reconnectSleepSeconds === 'undefined')
        reconnectSleepSeconds = DEFAULT_STREAM_SLEEP_SECONDS;

    twit.stream(type, params, function(stream) {
        console.info("Connected to twitter "+type+" stream");

        var resetStream = setTimeout(function() {
            console.info("Restarting "+type+" stream as it has been open for 30 minutes");
            stream.destroy();
        }, 30 * 60 * 1000);

        stream.on('data', function(data) {

            // reset done here as 'connect' fires even on rejection
            reconnectSleepSeconds = DEFAULT_STREAM_SLEEP_SECONDS;

            dataCallback(data);

        });

        stream.on('error', function(error) {
            if(error.errorSource) console.error("Twitter "+type+" stream error:", error);
            else console.error("Other Twitter "+type+" stream error");
        });

        stream.on('end', function(end) {
            console.info("Stream "+type+" ended, will attempt to reconnect in "+reconnectSleepSeconds+" seconds");
            clearTimeout(resetStream);
            setTimeout(function() {
              streamTweets(type, params, dataCallback, reconnectSleepSeconds * 2);
            }, reconnectSleepSeconds * 1000);
        });

    });

}

// Twitter side
var weather_keywords = ['weather', 'forecast', 'sunny', ' rain', 'sunshine', 'thunder', 'lightning',
                        'umbrella', ' snow', 'hail', ' warm', 'cold', 'brolly', 'boiling',
                        '#snow', '#rain', '#hail', '#sun', '#thunder'];

// Local
var ignored_users = ['galgateweather', 'mennewsdesk', 'metoffice', 'chadWeather', 'myweather_man',
                     'uk_storms', 'wx_manchester', 'widdop_weather', 'weather', TWITTER_ACCOUNT_NAME,
                     'LordChapman'];

var ignored_keywords = ['rt @', '[Manchester Weather] Your Weekend Forecast', 'weatherspoons',
                        'manchester, nh', 'train', '@MetOffice', '@coldplay', 'Cold cave'];

function isWeatherTweet(tweet) {
    return arrayInString(tweet.text, weather_keywords, true)
           && !arrayInString(tweet.user.screen_name, ignored_users)
           && !arrayInString(tweet.text, ignored_keywords)
}

function highlightMatches(string, array) {
    text = string;
    for(i=0;i<array.length;i++) {
      text = text.replace(new RegExp('(' + array[i] + ')','ig'), "$1".red);
    }
}

// Get tweets about the weather
function streamWeatherTweets() {

    // Bounding boxes do not act as filters for other filter parameters.
    // For example track=twitter&locations=-122.75,36.8,-121.75,37.8 would match
    // any tweets containing the term Twitter (even non-geo tweets) OR coming from the San Francisco area.
    track = []

    for(i=0;i<weather_keywords.length;i++) {
      track.push(weather_keywords[i] + ' manchester');
      track.push(weather_keywords[i] + ' #mcr');
    }

    streamTweets('filter',
        {
            track: track,
            locations: '-2.275,53.45,-2.2,53.5' // bottom right, top left - lon/lat
        },
        function(data) {

            // @todo should probably validate data, twitter might return a none tweet
            // the steam may contain "non weather" tweets we must filter first
            if(isWeatherTweet(data)) {

                textWithMatches = highlightMatches(data.text, weather_keywords);
                console.info("Matched streamed weather tweet @", data.user.screen_name, " ", textWithMatches);
                seenTweet(data, true);

            } else {
                fs.appendFile('ignoredTweets.txt', data.user.screen_name
                                                    + ":\t"
                                                    + data.text.replace(/(\r\n|\n|\r)/gm," \\ ")
                                                    + "\n");
            }

        }
    );
}

function streamUserReplies() {
    streamTweets('user',
        {
            replies: 'all', // By default @replies are only sent if the current user follows the sender and receiver
            with: 'users' // When set to "users", only messages targeted directly at a user will be delivered
        },
        function(data) {
            // Upon establishing a User Stream connection Twitter will send
            // a preamble before starting regular message delivery
            if(data.friends) {
                return;
            }

            else if(data.text && data.text.toLowerCase().indexOf(TWITTER_ACCOUNT_NAME) != -1) {
                console.log("Recieved mention in user stream @", data.user.screen_name, data.text);

                // Avoid loops, if we sent the message and it was a reply to US
                if(data.in_reply_to_screen_name
                    && data.in_reply_to_screen_name.toLowerCase() == TWITTER_ACCOUNT_NAME
                    && data.user.screen_name.toLowerCase() == TWITTER_ACCOUNT_NAME) {
                    console.warn('Ignored self reply message');
                    return;
                }

                seenTweet(data, true, true);
            }
        }
    );
}

function arrayInString(string, array, ignore_mentions) {
    if(typeof string !== 'string')
        throw new Error('The term to search must be a string');

    if(typeof ignore_mentions === 'undefined')
        ignore_mentions = false;

    for(i=0;i<array.length;i++) {
        if(string.toLowerCase().indexOf(array[i].toLowerCase()) != -1) {
            if(!ignore_mentions) return true;
            else {
              // note double escape and trim due to trailing spaces
              var re = new RegExp('@\\w*'+array[i].trim(),'i');
              if(!re.test(string))
                  return true;
            }
        }
    }

    return false;

}

function seenTweet(tweet, streamed, mention) {
    if(typeof streamed === 'undefined')
        streamed = false;

    if(typeof mention === 'undefined')
        mention = tweet.text.toLowerCase().indexOf(TWITTER_ACCOUNT_NAME) != -1;

    var select = DB.prepare(sql['selectExistingTweet']);
    select.get({$tweet_id: tweet.id}, function(err, row) {
        if(!row) { // If the result set is empty, the second parameter is undefined
            var insert = DB.prepare(sql['insertSeenTweet']);
            insert.run({
              $id: tweet.id,
              $text: tweet.text,
              $user_id: tweet.user.id,
              $username: tweet.user.screen_name,
              $streamed: streamed ? 1 : 0  // 0/1 as SQLlite has no boolean support
            });
            TWEET_CALLBACK(tweet, mention);
            console.info("Logged: ", tweet.text, tweet.created_at);
        } else {
            console.info("Ignored duplicate: ", tweet.text, tweet.created_at);
            // @todo if streamed == false, I might need to mark this as non-streamed
            // to prevent the non-stream falling behind if the stream is capturing everything
        }
    });
}

function updateComplete() {
    console.info("\n"+'Update complete, waiting '+WAIT_SECONDS+' seconds before the next update');
    countdown(WAIT_SECONDS, updateTweets, "seconds until next search...");
}

function countdown(seconds, callback, message) {
    var countdownInterval;
    var countdownSecondsLeft;
    var countdownCallback;

    countdownInterval = setInterval(function(){
        if(COUNTDOWN_OUTPUT) {
            process.stdout.clearLine();  // clear current text
            process.stdout.cursorTo(0);  // move cursor to beginning of line
            process.stdout.write(countdownSecondsLeft-- + " " + message);
        }

        if(countdownSecondsLeft <= 0) {
            clearInterval(countdownInterval);
            process.stdout.write("\n");
            if(countdownCallback) {
                temp = countdownCallback;
                countdownCallback = null;
                temp();
            }
        }
    }, 1000);

    countdownSecondsLeft = seconds;
    if(typeof callback !== 'undefined') {
        countdownCallback = callback;
    }
}<|endoftext|>


<commit_before>var restify = require('restify');
var models = require('./models.js');

module.exports = {
  create: function (req, res, next) {
    res.send(models.createCode(req.params));
    return next();
  },

  verify: function (req, res, next) {
    return models.verifyCode(req.params, function (err, code) {
      var httpError = null;
      next.ifError(err);
      if (code == null) {
        httpError = new restify.errors.ResourceNotFoundError("Code not found.");
      }
      else if (code == false) {
        httpError = new restify.errors.BadRequestError("Code already verified");
      }
      else {
        res.send(code);
      }
      return next(httpError);
    });
  }
};
<commit_msg>french please<commit_after>var restify = require('restify');
var models = require('./models.js');

module.exports = {
  create: function (req, res, next) {
    res.send(models.createCode(req.params));
    return next();
  },

  verify: function (req, res, next) {
    return models.verifyCode(req.params, function (err, code) {
      var httpError = null;
      next.ifError(err);
      if (code == null) {
        httpError = new restify.errors.ResourceNotFoundError("Code invalide, inconnu.");
      }
      else if (code == false) {
        httpError = new restify.errors.BadRequestError("Code déjà vérifié.");
      }
      else {
        res.send(code);
      }
      return next(httpError);
    });
  }
};
<|endoftext|>


<commit_before>import React from 'react';
import { render } from 'enzyme';
import Icon from '..';
import ReactIcon from '@ant-design/icons-react';
import { getThemeFromTypeName, withThemeSuffix } from '../utils';

describe('Icon', () => {
  it('should render to a <svg>...</svg>', () => {
    const wrapper = render(
      <Icon type="message" className="my-icon-classname" />
    );
    expect(wrapper).toMatchSnapshot();
  });

  it('should support basic usage', () => {
    const wrapper = render(

        <Icon type="home" />
        <Icon type="setting" theme="filled" />
        <Icon type="smile" theme="outlined" />
        <Icon type="sync" spin />
        <Icon type="loading" />

    );
    expect(wrapper).toMatchSnapshot();
  });

  it('should support older usage', () => {
    const wrapper = render(

        <Icon type="home-o" />
        <Icon type="setting-fill" />
        <Icon type="smile-o" />
        <Icon type="check-circle-twotone" />

    );
    expect(wrapper).toMatchSnapshot();
  });

  it('should support two-tone icon', () => {
    const wrapper = render(
      <Icon type="check-circle" theme="twoTone" twoToneColor="#f5222d" />
    );
    expect(wrapper).toMatchSnapshot();
  });

  it('should support config global two-tone primary color', () => {
    const colors = ReactIcon.getTwoToneColors();
    Icon.setTwoToneColor('#1890ff');
    expect(Icon.getTwoToneColor()).toBe('#1890ff');
    const wrapper = render(
      <Icon type="check-circle" theme="twoTone" />
    );
    expect(wrapper).toMatchSnapshot();
    ReactIcon.setTwoToneColors(colors);
  });

  it('should support pass svg paths as children', () => {
    const wrapper = render(
      <Icon viewBox="0 0 24 24">
        <title>Cool Home</title>
        <path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" />
      </Icon>
    );
    expect(wrapper).toMatchSnapshot();
  });

  it('should give warning and render {null}', () => {
    const wrapper = render(
      <Icon viewBox="0 0 24 24" />
    );
    expect(wrapper).toMatchSnapshot();
  });

  describe('`component` prop', () => {
    it('can access to svg defs if has children', () => {
      const wrapper = render(
        <Icon
          className="my-home-icon"
          component={svgProps => (
            <svg {...svgProps}>
              <defs>
                <linearGradient id="gradient">
                  <stop offset="20%" stopColor="#39F" />
                  <stop offset="90%" stopColor="#F3F" />
                </linearGradient>
              </defs>
              {
                React.Children.map(
                  svgProps.children,
                  child => React.cloneElement(
                    child,
                    child.type === 'path' ? { fill: 'scriptUrl(#gradient)' } : {}
                  )
                )
              }
            </svg>
          )}
        >
          <title>Cool Home</title>
          <path d="'M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z'" />
        </Icon>
      );
      expect(wrapper).toMatchSnapshot();
    });
  });

  it('should support svg react component', () => {
    const SvgComponent = props => (
      <svg viewBox="0 0 24 24" {...props}>
        <title>Cool Home</title>
        <path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" />
      </svg>
    );

    const wrapper = render(
      <Icon
        className="my-home-icon"
        component={SvgComponent}
      >
        <title>Cool Home</title>
        <path d="'M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z'" />
      </Icon>
    );
    expect(wrapper).toMatchSnapshot();
  });
});

describe('Icon.createFromIconfontCN()', () => {
  const IconFont = Icon.createFromIconfontCN({
    scriptUrl: '//at.alicdn.com/t/font_8d5l8fzk5b87iudi.js',
  });

  it('should support iconfont.cn', () => {
    const wrapper = render(

        <IconFont type="icon-tuichu" />
        <IconFont type="icon-facebook" />
        <IconFont type="icon-twitter" />

    );
    expect(wrapper).toMatchSnapshot();
  });
});

describe('utils', () => {
  it('getThemeFromTypeName() should work', () => {
    const testCases = ['check-circle', 'check-circle-o', 'check-circle-fill', 'check-circle-twotone'];
    const result = testCases.map(type => getThemeFromTypeName(type));
    expect(result).toEqual(
      [null, 'outlined', 'filled', 'twoTone']
    );
  });

  it('withThemeSuffix() should work', () => {
    const testCases = [
      { type: 'home', theme: 'filled' },
      { type: 'home', theme: 'outlined' },
      { type: 'home', theme: 'twoTone' },
      { type: 'home', theme: 'This-is-the-secret' },
      { type: 'home-o', theme: 'filled' },
      { type: 'home-fill', theme: 'outlined' },
      { type: 'home-o', theme: 'twoTone' },
      { type: 'home-o', theme: 'This-is-the-secret' },
    ];
    const result = testCases.map(({ type, theme }) => withThemeSuffix(type, theme));
    expect(result).toEqual(
      ['home-fill', 'home-o', 'home-twotone', 'home',
        'home-o-fill', 'home-fill-o', 'home-o-twotone', 'home-o']
    );
  });
});
<commit_msg>Add test case for Tooltip and Icon<commit_after>import React from 'react';
import { render, mount } from 'enzyme';
import Icon from '..';
import ReactIcon from '@ant-design/icons-react';
import Tooltip from '../../tooltip';
import { getThemeFromTypeName, withThemeSuffix } from '../utils';

describe('Icon', () => {
  it('should render to a <svg>...</svg>', () => {
    const wrapper = render(
      <Icon type="message" className="my-icon-classname" />
    );
    expect(wrapper).toMatchSnapshot();
  });

  it('should support basic usage', () => {
    const wrapper = render(

        <Icon type="home" />
        <Icon type="setting" theme="filled" />
        <Icon type="smile" theme="outlined" />
        <Icon type="sync" spin />
        <Icon type="loading" />

    );
    expect(wrapper).toMatchSnapshot();
  });

  it('should support older usage', () => {
    const wrapper = render(

        <Icon type="home-o" />
        <Icon type="setting-fill" />
        <Icon type="smile-o" />
        <Icon type="check-circle-twotone" />

    );
    expect(wrapper).toMatchSnapshot();
  });

  it('should support two-tone icon', () => {
    const wrapper = render(
      <Icon type="check-circle" theme="twoTone" twoToneColor="#f5222d" />
    );
    expect(wrapper).toMatchSnapshot();
  });

  it('should support config global two-tone primary color', () => {
    const colors = ReactIcon.getTwoToneColors();
    Icon.setTwoToneColor('#1890ff');
    expect(Icon.getTwoToneColor()).toBe('#1890ff');
    const wrapper = render(
      <Icon type="check-circle" theme="twoTone" />
    );
    expect(wrapper).toMatchSnapshot();
    ReactIcon.setTwoToneColors(colors);
  });

  it('should support pass svg paths as children', () => {
    const wrapper = render(
      <Icon viewBox="0 0 24 24">
        <title>Cool Home</title>
        <path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" />
      </Icon>
    );
    expect(wrapper).toMatchSnapshot();
  });

  it('should give warning and render {null}', () => {
    const wrapper = render(
      <Icon viewBox="0 0 24 24" />
    );
    expect(wrapper).toMatchSnapshot();
  });

  it('should support wrapped by Tooltip', () => {
    const onVisibleChange = jest.fn();
    const wrapper = mount(
      <Tooltip
        title="xxxxx"
        mouseEnterDelay={0}
        mouseLeaveDelay={0}
        onVisibleChange={onVisibleChange}
      >
        <Icon type="home" />
      </Tooltip>
    );
    expect(wrapper.find('i')).toHaveLength(1);
    const icon = wrapper.find('i').at(0);
    icon.simulate('mouseenter');
    expect(onVisibleChange).toBeCalledWith(true);
    expect(wrapper.instance().tooltip.props.visible).toBe(true);

    icon.simulate('mouseleave');
    expect(onVisibleChange).toBeCalledWith(false);
    expect(wrapper.instance().tooltip.props.visible).toBe(false);
  });

  describe('`component` prop', () => {
    it('can access to svg defs if has children', () => {
      const wrapper = render(
        <Icon
          className="my-home-icon"
          component={svgProps => (
            <svg {...svgProps}>
              <defs>
                <linearGradient id="gradient">
                  <stop offset="20%" stopColor="#39F" />
                  <stop offset="90%" stopColor="#F3F" />
                </linearGradient>
              </defs>
              {
                React.Children.map(
                  svgProps.children,
                  child => React.cloneElement(
                    child,
                    child.type === 'path' ? { fill: 'scriptUrl(#gradient)' } : {}
                  )
                )
              }
            </svg>
          )}
        >
          <title>Cool Home</title>
          <path d="'M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z'" />
        </Icon>
      );
      expect(wrapper).toMatchSnapshot();
    });
  });

  it('should support svg react component', () => {
    const SvgComponent = props => (
      <svg viewBox="0 0 24 24" {...props}>
        <title>Cool Home</title>
        <path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" />
      </svg>
    );

    const wrapper = render(
      <Icon
        className="my-home-icon"
        component={SvgComponent}
      >
        <title>Cool Home</title>
        <path d="'M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z'" />
      </Icon>
    );
    expect(wrapper).toMatchSnapshot();
  });
});

describe('Icon.createFromIconfontCN()', () => {
  const IconFont = Icon.createFromIconfontCN({
    scriptUrl: '//at.alicdn.com/t/font_8d5l8fzk5b87iudi.js',
  });

  it('should support iconfont.cn', () => {
    const wrapper = render(

        <IconFont type="icon-tuichu" />
        <IconFont type="icon-facebook" />
        <IconFont type="icon-twitter" />

    );
    expect(wrapper).toMatchSnapshot();
  });
});

describe('utils', () => {
  it('getThemeFromTypeName() should work', () => {
    const testCases = ['check-circle', 'check-circle-o', 'check-circle-fill', 'check-circle-twotone'];
    const result = testCases.map(type => getThemeFromTypeName(type));
    expect(result).toEqual(
      [null, 'outlined', 'filled', 'twoTone']
    );
  });

  it('withThemeSuffix() should work', () => {
    const testCases = [
      { type: 'home', theme: 'filled' },
      { type: 'home', theme: 'outlined' },
      { type: 'home', theme: 'twoTone' },
      { type: 'home', theme: 'This-is-the-secret' },
      { type: 'home-o', theme: 'filled' },
      { type: 'home-fill', theme: 'outlined' },
      { type: 'home-o', theme: 'twoTone' },
      { type: 'home-o', theme: 'This-is-the-secret' },
    ];
    const result = testCases.map(({ type, theme }) => withThemeSuffix(type, theme));
    expect(result).toEqual(
      ['home-fill', 'home-o', 'home-twotone', 'home',
        'home-o-fill', 'home-fill-o', 'home-o-twotone', 'home-o']
    );
  });
});
<|endoftext|>


<commit_before>var DashboardController = Ember.ObjectController.extend({
  needs: ['user'],
  user: Ember.computed.alias('controllers.user'),
  repositoryName: Ember.computed.alias('id'),
  hidePanes: false,
  isPerformingReorder: false,
  cardManager: null,

  scheduleSetupCardManager: function() {
    Ember.run.once(this, this.setupCardManager);
  }.observes('content', 'isPerformingReorder'),

  contentWillChange: function() {
    if (this.cardManager) {
      this.cardManager.destroy();
      this.cardManager = null;
    }
  }.observesBefore('content'),

  setupCardManager: function() {
    if (this.get('content')) {
      this.cardManager = this.container.lookup('cardManager:main');
      this.cardManager.setProviderCardCatalog(this.get('content'));
    }
  },

  isAdmin: function() {
    var user = this.get('user.content'),
      repositoryName = this.get('repositoryName'),
      repos = user && user.editable_repositories;
    return repos && repos.indexOf(repositoryName) !== -1;
  }.property('user.content', 'repositoryName'),

  removePane: function(pane) {
    if (window.confirm('Are you sure you want to remove ' + pane.get('displayName') + '?')) {
      pane.get('dashboard.panes').removeObject(pane);
      pane.deleteRecord();
      pane.store.commit();
      this.cardManager.unload(pane);
    }
  },

  addPane: function(paneType, repository, paneEntries) {
    var store = this.get('store');
    var dependencies = this.paneTypesToAdd(paneType);
    var transaction = store.transaction();
    // TODO: make recursively handle dependencies. (YAGNI?)
    var dashboard = this.get('content');

    repository = repository || this.get('id'); // default to dashboard id
    paneEntries = paneEntries || {};

    if (dependencies) {
      dependencies.forEach(function(paneType) {
        transaction.createRecord(Glazier.Pane, {
          dashboard: dashboard,
          paneType: paneType,
          position: dashboard.get('nextPanePosition')
        });
      }, this);
    }

    transaction.createRecord(Glazier.Pane, {
      dashboard: dashboard,
      paneType: paneType,
      repository: repository,
      position: dashboard.get('nextPanePosition'),
      paneEntries: paneEntries
    });

    transaction.commit();
    this.send('hideModal');

    this.scrollLastPaneIntoView();
  },

  scrollLastPaneIntoView: function() {
    // Scroll the new pane into view after for modal-close animation is done
    // Doing it sooner results in an odd scroll position
    Ember.run.later(this, function() {
      var lastPane = $('.pane').last();
      var scrollTop = lastPane.offset().top + lastPane.height();
      $('body').scrollTop(scrollTop);
    }, 500);
  },

  paneTypesToAdd: function(paneType) {
    var consumes = paneType.get('manifest.consumes');
    var conductorServices = Conductor.services;

    var paneProvides = [];
    this.get('panes').forEach(function(pane) {
      var provides = pane.get('manifest.provides');
      if (provides && provides.length) {
        paneProvides = paneProvides.concat(provides);
      }
    });
    var dep, dependencies = [];
    var paneTypes = this.get('paneTypes');

    consumes.forEach(function(consume) {
      if (!paneProvides.contains(consume) && !conductorServices.hasOwnProperty(consume)) {
        dep = paneTypes.find(function(paneType) {
          var provides = paneType.get('manifest.provides');
          if (provides) {
            return provides.contains(consume);
          }
        });
        if (dep) {
          dependencies.push(dep);
        }
      }
    }, this);

    return dependencies;
  }
});
export default DashboardController;
<commit_msg>fix adding a card that has consumes<commit_after>var DashboardController = Ember.ObjectController.extend({
  needs: ['user', 'paneTypes'],
  user: Ember.computed.alias('controllers.user'),
  repositoryName: Ember.computed.alias('id'),
  hidePanes: false,
  isPerformingReorder: false,
  cardManager: null,
  paneTypes: Ember.computed.alias('controllers.paneTypes'),

  scheduleSetupCardManager: function() {
    Ember.run.once(this, this.setupCardManager);
  }.observes('content', 'isPerformingReorder'),

  contentWillChange: function() {
    if (this.cardManager) {
      this.cardManager.destroy();
      this.cardManager = null;
    }
  }.observesBefore('content'),

  setupCardManager: function() {
    if (this.get('content')) {
      this.cardManager = this.container.lookup('cardManager:main');
      this.cardManager.setProviderCardCatalog(this.get('content'));
    }
  },

  isAdmin: function() {
    var user = this.get('user.content'),
      repositoryName = this.get('repositoryName'),
      repos = user && user.editable_repositories;
    return repos && repos.indexOf(repositoryName) !== -1;
  }.property('user.content', 'repositoryName'),

  removePane: function(pane) {
    if (window.confirm('Are you sure you want to remove ' + pane.get('displayName') + '?')) {
      pane.get('dashboard.panes').removeObject(pane);
      pane.deleteRecord();
      pane.store.commit();
      this.cardManager.unload(pane);
    }
  },

  addPane: function(paneType, repository, paneEntries) {
    var store = this.get('store');
    var dependencies = this.paneTypesToAdd(paneType);
    var transaction = store.transaction();
    // TODO: make recursively handle dependencies. (YAGNI?)
    var dashboard = this.get('content');

    repository = repository || this.get('id'); // default to dashboard id
    paneEntries = paneEntries || {};

    if (dependencies) {
      dependencies.forEach(function(paneType) {
        transaction.createRecord(Glazier.Pane, {
          dashboard: dashboard,
          paneType: paneType,
          position: dashboard.get('nextPanePosition')
        });
      }, this);
    }

    transaction.createRecord(Glazier.Pane, {
      dashboard: dashboard,
      paneType: paneType,
      repository: repository,
      position: dashboard.get('nextPanePosition'),
      paneEntries: paneEntries
    });

    transaction.commit();
    this.send('hideModal');

    this.scrollLastPaneIntoView();
  },

  scrollLastPaneIntoView: function() {
    // Scroll the new pane into view after for modal-close animation is done
    // Doing it sooner results in an odd scroll position
    Ember.run.later(this, function() {
      var lastPane = $('.pane').last();
      var scrollTop = lastPane.offset().top + lastPane.height();
      $('body').scrollTop(scrollTop);
    }, 500);
  },

  paneTypesToAdd: function(paneType) {
    var consumes = paneType.get('manifest.consumes');
    var conductorServices = Conductor.services;

    var paneProvides = [];
    this.get('panes').forEach(function(pane) {
      var provides = pane.get('manifest.provides');
      if (provides && provides.length) {
        paneProvides = paneProvides.concat(provides);
      }
    });
    var dep, dependencies = [];
    var paneTypes = this.get('paneTypes');

    consumes.forEach(function(consume) {
      if (!paneProvides.contains(consume) && !conductorServices.hasOwnProperty(consume)) {
        dep = paneTypes.find(function(paneType) {
          var provides = paneType.get('manifest.provides');
          if (provides) {
            return provides.contains(consume);
          }
        });
        if (dep) {
          dependencies.push(dep);
        }
      }
    }, this);

    return dependencies;
  }
});
export default DashboardController;
<|endoftext|>