<commit_before>/* eslint-disable no-unused-vars */
const $ = require('jquery');
const _ = require('lodash');
const qw = require('qw');
const ga = require('./ga.js');
const constants = require('./constants.js');
const moment = require('moment');

function getEntityId(href) {
    let entityId = getQueryArgs(href).entityId;
    if (entityId) {
        return entityId;
    }

    let navLink = $('.topNavLogo')[0].href;
    let query = navLink.substring(navLink.indexOf('?') + 1);
    entityId = getQueryArgs(query).entityId;
    if (entityId) {
        return entityId;
    }

    throw ga.merror('could not discover entityId');
}

function getCampaignId(href) {
    let campaignId = getQueryArgs(href).campaignId;
    if (campaignId) {
        return campaignId;
    }

    campaignId = $('input[name=campaignId]').val();
    if (campaignId) {
        return campaignId;
    }

    throw ga.merror('could not discover entityId');
}

function getSellerCampaignId(href) {
    let path = href.split('?')[0];
    let parts = path.split('/');
    let campaignIdx = parts.indexOf('campaign');
    let adGroupIdx = parts.indexOf('ad_group');
    return {
        campaignId: campaignIdx >= 0 ? parts[campaignIdx + 1] : undefined,
        adGroupId: adGroupIdx >= 0 ? parts[adGroupIdx + 1] : undefined,
    };
}

function getAsin(url) {
    let path = url.split('?')[0];
    let parts = path.split('/');

    // ASIN is 10 characters beginning with B. If there's only one of those,
    // return it immediately.
    let asinLookalikes = parts.filter(x => x.length == 10 && x[0] == 'B');
    if (!asinLookalikes.length)
        return undefined;
    if (asinLookalikes.length == 1)
        return asinLookalikes[0];

    // Look for url patterns like product/${ASIN}
    let productIdx = parts.indexOf('product');
    if (productIdx >= 0 && asinLookalikes.includes(parts[productIdx + 1]))
        return parts[productIdx + 1];

    // Look for url patterns like dp/${ASIN}
    let dpIdx = parts.indexOf('dp');
    if (dpIdx >= 0 && asinLookalikes.includes(parts[dpIdx + 1]))
        return parts[dpIdx + 1];

    // Just return the first ASIN-like thing and hope for the best. This returns
    // undefined if there were *no* ASINs found.
    return asinLookalikes[0];
}

function getQueryArgs(str) {
    let qstring = str || window.location.toString();
    qstring = qstring.split('?').pop();
    if (qstring.includes('#')) {
        qstring = qstring.substring(0, qstring.lastIndexOf('#'));
    }

    let qs = qstring.split('&');
    let args = {};
    for (let q of qs) {
        let parts = q.split('=');
        args[parts[0]] = parts[1];
    }
    return args;
}

function moneyFmt(val) {
    if (Number.isNaN(+val)) {
        return '--';
    }
    return `$${(+val).toFixed(2)}`;
}

function pctFmt(val) {
    if (Number.isNaN(+val)) {
        return '--';
    }
    return `${(+val).toFixed(2)}%`;
}

const cumulativeMetrics = qw`impressions clicks salesCount salesValue spend`;
const aggregateMetrics = qw`ctr acos avgCpc`;

// Convert a series of objects into a single object with a number of parallel
// arrays. All objects in the series should have the same keys; in any case,
// only the keys from the first object in the series are respected.
function parallelizeSeries(data) {
    let c = { timestamp: [] };
    if (!data || !data.length)
        return c;

    _.keys(data[0]).forEach(key => c[key] = []);

    for (let item of data) {
        for (let key of _.keys(c)) {
            if (key == 'timestamp')
                c[key].push(new Date(item[key]));
            else
                c[key].push(item[key]);
        }
    }

    return c;
}

// Convert a series of timestamped snapshots into a series of objects in which
// each key has the difference from the previous snapshot, ie. the rate of
// change between snapshots. Only the metrics found in `cumulativeMetrics` are
// converted into rates. The opt object has the following relevant keys:
//      chunk: round timestamps off to the nearest hour/day/etc. and only
//          compare values that cross a chunk boundary.
//      rate: the timespn over which to calculate rates. Should generally be the
//          same as chunk, when present.
//      startTimestamp: earliest timestamp to examine. Items outside of this
//          range are discarded.
//      endTimestamp: latest timestamp to examine. Items outside of this range
//          are discarded.
//      round: if true, then fractional values are rounded to the nearest whole
//          value
function convertSnapshotsToDeltas(data, opt) {
    let c = [];
    opt = opt || {};

    let lastItem = null;
    data = data.sort((a, b) => a.timestamp - b.timestamp);
    for (let item of data) {
        if (opt.chunk) {
            if (lastItem && moment(item.timestamp).isSame(moment(lastItem.timestamp), opt.chunk)) {
                continue;
            }
            item.timestamp = moment(item.timestamp).startOf(opt.chunk);
        }

        // Filter out things by date range
        if (opt.startTimestamp && item.timestamp < opt.startTimestamp) {
            continue;
        }
        if (opt.endTimestamp && item.timestamp > opt.endTimestamp) {
            continue;
        }

        // Skip this data point unless one of our metrics actually changed.
        if (lastItem && !cumulativeMetrics.some(metric => item[metric] != lastItem[metric])) {
            continue;
        }

        if (lastItem) {
            const delta = Object.assign({}, item);
            for (let metric of cumulativeMetrics) {
                let rateFactor = (item.timestamp - lastItem.timestamp)/constants.timespan[opt.rate];
                let normalized = (item[metric] - lastItem[metric])/rateFactor;
                if (opt.round)
                    normalized = Math.round(normalized);
                delta[metric] = normalized;
            }
            c.push(delta);
        }

        lastItem = item;
    }

    return c;
}

function getCampaignHistory(entityId, campaignId, cb) {
    chrome.runtime.sendMessage({
        action: 'getDataHistory',
        entityId: entityId,
        campaignId: campaignId,
    },
    ga.mcatch(response => {
        if (response.error) {
            ga.merror(response.status, response.error);
            return;
        }
        cb(response.data);
    }));
}

let allowedPromise = null;
function getAllowedCampaigns(entityId) {
    if (!allowedPromise) {
        allowedPromise = new Promise((resolve, reject) => {
            chrome.runtime.sendMessage({
                action: 'getAllowedCampaigns',
                entityId
            }, response => {
                if (response.error) {
                    return reject(response.error);
                }
                resolve(allowedCampaigns);
            });
        });
    }

    return allowedPromise;
}

function getCampaignAllowed(entityId, campaignId) {
    return getAllowedCampaigns(entityId).then(allowed => {
        if (allowed[0] == '*') {
            return true;
        }
        return allowed.includes(campaignId);
    });
}

if (window.location.href.includes('ams')) {
    chrome.runtime.sendMessage({
        action: 'setSession',
        entityId: getEntityId(),
    }, response => {});

    // Add in the Machete link to the top bar
    chrome.runtime.sendMessage({ action: 'getUser' }, response => {
        if (response.error) {
            ga.merror(response.error);
            return;
        }
        const user = response.data;
        let email = user.email;
        user.isAnon = email == 'anon-user-email';
        window.user = user;

        const desc = user.activeSubscription.name;
        let profileText = "Your Profile";
        let label = 'view-profile';
        if (user.isAnon) {
            email = '';
            profileText = 'Login/Register';
            label = 'login';
        }
        let links = $('.userBarLinksRight');
        if (links[0]) {
            let chunks = links[0].innerHTML.split(' | ');
            chunks.splice(-1, 0, `${desc} (<a data-mclick="machete-status ${label}" title="${email}" href="https://${constants.hostname}/profile" target="_blank">${profileText}</a>)`);
            links[0].innerHTML = chunks.join(' | ');
        }
        let logout = links.find('a');
        if (logout[1]) {
            $(logout[1]).click(() => {
                const result = confirm(
                    `Logging out of AMS will prevent Machete from monitoring your campaigns. Instead, you may close this tab without logging out.

                    Continue logging out?`);
                return result;
            });
        }

    });
}

module.exports = {
    getEntityId,
    getCampaignId,
    getSellerCampaignId,
    getQueryArgs,
    getAsin,
    getCampaignAllowed,
    moneyFmt,
    pctFmt,
    getCampaignHistory,
    parallelizeSeries,
    convertSnapshotsToDeltas,
};
<commit_msg>fixed a basic error in the the response data handler<commit_after>/* eslint-disable no-unused-vars */
const $ = require('jquery');
const _ = require('lodash');
const qw = require('qw');
const ga = require('./ga.js');
const constants = require('./constants.js');
const moment = require('moment');

function getEntityId(href) {
    let entityId = getQueryArgs(href).entityId;
    if (entityId) {
        return entityId;
    }

    let navLink = $('.topNavLogo')[0].href;
    let query = navLink.substring(navLink.indexOf('?') + 1);
    entityId = getQueryArgs(query).entityId;
    if (entityId) {
        return entityId;
    }

    throw ga.merror('could not discover entityId');
}

function getCampaignId(href) {
    let campaignId = getQueryArgs(href).campaignId;
    if (campaignId) {
        return campaignId;
    }

    campaignId = $('input[name=campaignId]').val();
    if (campaignId) {
        return campaignId;
    }

    throw ga.merror('could not discover entityId');
}

function getSellerCampaignId(href) {
    let path = href.split('?')[0];
    let parts = path.split('/');
    let campaignIdx = parts.indexOf('campaign');
    let adGroupIdx = parts.indexOf('ad_group');
    return {
        campaignId: campaignIdx >= 0 ? parts[campaignIdx + 1] : undefined,
        adGroupId: adGroupIdx >= 0 ? parts[adGroupIdx + 1] : undefined,
    };
}

function getAsin(url) {
    let path = url.split('?')[0];
    let parts = path.split('/');

    // ASIN is 10 characters beginning with B. If there's only one of those,
    // return it immediately.
    let asinLookalikes = parts.filter(x => x.length == 10 && x[0] == 'B');
    if (!asinLookalikes.length)
        return undefined;
    if (asinLookalikes.length == 1)
        return asinLookalikes[0];

    // Look for url patterns like product/${ASIN}
    let productIdx = parts.indexOf('product');
    if (productIdx >= 0 && asinLookalikes.includes(parts[productIdx + 1]))
        return parts[productIdx + 1];

    // Look for url patterns like dp/${ASIN}
    let dpIdx = parts.indexOf('dp');
    if (dpIdx >= 0 && asinLookalikes.includes(parts[dpIdx + 1]))
        return parts[dpIdx + 1];

    // Just return the first ASIN-like thing and hope for the best. This returns
    // undefined if there were *no* ASINs found.
    return asinLookalikes[0];
}

function getQueryArgs(str) {
    let qstring = str || window.location.toString();
    qstring = qstring.split('?').pop();
    if (qstring.includes('#')) {
        qstring = qstring.substring(0, qstring.lastIndexOf('#'));
    }

    let qs = qstring.split('&');
    let args = {};
    for (let q of qs) {
        let parts = q.split('=');
        args[parts[0]] = parts[1];
    }
    return args;
}

function moneyFmt(val) {
    if (Number.isNaN(+val)) {
        return '--';
    }
    return `$${(+val).toFixed(2)}`;
}

function pctFmt(val) {
    if (Number.isNaN(+val)) {
        return '--';
    }
    return `${(+val).toFixed(2)}%`;
}

const cumulativeMetrics = qw`impressions clicks salesCount salesValue spend`;
const aggregateMetrics = qw`ctr acos avgCpc`;

// Convert a series of objects into a single object with a number of parallel
// arrays. All objects in the series should have the same keys; in any case,
// only the keys from the first object in the series are respected.
function parallelizeSeries(data) {
    let c = { timestamp: [] };
    if (!data || !data.length)
        return c;

    _.keys(data[0]).forEach(key => c[key] = []);

    for (let item of data) {
        for (let key of _.keys(c)) {
            if (key == 'timestamp')
                c[key].push(new Date(item[key]));
            else
                c[key].push(item[key]);
        }
    }

    return c;
}

// Convert a series of timestamped snapshots into a series of objects in which
// each key has the difference from the previous snapshot, ie. the rate of
// change between snapshots. Only the metrics found in `cumulativeMetrics` are
// converted into rates. The opt object has the following relevant keys:
//      chunk: round timestamps off to the nearest hour/day/etc. and only
//          compare values that cross a chunk boundary.
//      rate: the timespn over which to calculate rates. Should generally be the
//          same as chunk, when present.
//      startTimestamp: earliest timestamp to examine. Items outside of this
//          range are discarded.
//      endTimestamp: latest timestamp to examine. Items outside of this range
//          are discarded.
//      round: if true, then fractional values are rounded to the nearest whole
//          value
function convertSnapshotsToDeltas(data, opt) {
    let c = [];
    opt = opt || {};

    let lastItem = null;
    data = data.sort((a, b) => a.timestamp - b.timestamp);
    for (let item of data) {
        if (opt.chunk) {
            if (lastItem && moment(item.timestamp).isSame(moment(lastItem.timestamp), opt.chunk)) {
                continue;
            }
            item.timestamp = moment(item.timestamp).startOf(opt.chunk);
        }

        // Filter out things by date range
        if (opt.startTimestamp && item.timestamp < opt.startTimestamp) {
            continue;
        }
        if (opt.endTimestamp && item.timestamp > opt.endTimestamp) {
            continue;
        }

        // Skip this data point unless one of our metrics actually changed.
        if (lastItem && !cumulativeMetrics.some(metric => item[metric] != lastItem[metric])) {
            continue;
        }

        if (lastItem) {
            const delta = Object.assign({}, item);
            for (let metric of cumulativeMetrics) {
                let rateFactor = (item.timestamp - lastItem.timestamp)/constants.timespan[opt.rate];
                let normalized = (item[metric] - lastItem[metric])/rateFactor;
                if (opt.round)
                    normalized = Math.round(normalized);
                delta[metric] = normalized;
            }
            c.push(delta);
        }

        lastItem = item;
    }

    return c;
}

function getCampaignHistory(entityId, campaignId, cb) {
    chrome.runtime.sendMessage({
        action: 'getDataHistory',
        entityId: entityId,
        campaignId: campaignId,
    },
    ga.mcatch(response => {
        if (response.error) {
            ga.merror(response.status, response.error);
            return;
        }
        cb(response.data);
    }));
}

let allowedPromise = null;
function getAllowedCampaigns(entityId) {
    if (!allowedPromise) {
        allowedPromise = new Promise((resolve, reject) => {
            chrome.runtime.sendMessage({
                action: 'getAllowedCampaigns',
                entityId
            }, response => {
                if (response.error) {
                    return reject(response.error);
                }
                resolve(response.data);
            });
        });
    }

    return allowedPromise;
}

function getCampaignAllowed(entityId, campaignId) {
    return getAllowedCampaigns(entityId).then(allowed => {
        if (allowed[0] == '*') {
            return true;
        }
        return allowed.includes(campaignId);
    });
}

if (window.location.href.includes('ams')) {
    chrome.runtime.sendMessage({
        action: 'setSession',
        entityId: getEntityId(),
    }, response => {});

    // Add in the Machete link to the top bar
    chrome.runtime.sendMessage({ action: 'getUser' }, response => {
        if (response.error) {
            ga.merror(response.error);
            return;
        }
        const user = response.data;
        let email = user.email;
        user.isAnon = email == 'anon-user-email';
        window.user = user;

        const desc = user.activeSubscription.name;
        let profileText = "Your Profile";
        let label = 'view-profile';
        if (user.isAnon) {
            email = '';
            profileText = 'Login/Register';
            label = 'login';
        }
        let links = $('.userBarLinksRight');
        if (links[0]) {
            let chunks = links[0].innerHTML.split(' | ');
            chunks.splice(-1, 0, `${desc} (<a data-mclick="machete-status ${label}" title="${email}" href="https://${constants.hostname}/profile" target="_blank">${profileText}</a>)`);
            links[0].innerHTML = chunks.join(' | ');
        }
        let logout = links.find('a');
        if (logout[1]) {
            $(logout[1]).click(() => {
                const result = confirm(
                    `Logging out of AMS will prevent Machete from monitoring your campaigns. Instead, you may close this tab without logging out.

                    Continue logging out?`);
                return result;
            });
        }

    });
}

module.exports = {
    getEntityId,
    getCampaignId,
    getSellerCampaignId,
    getQueryArgs,
    getAsin,
    getCampaignAllowed,
    moneyFmt,
    pctFmt,
    getCampaignHistory,
    parallelizeSeries,
    convertSnapshotsToDeltas,
};
<|endoftext|>


<commit_before>import path from 'path'

const r = path.join(__dirname, '..', '..')
const env = process.env

const config = {
  root: r,
  env: env.NODE_ENV || 'dev',
  port: env.PORT || 8000,
  host: env.HOST || 'localhost',
  get baseUrl() {
    return `http://${this.host}:${this.port}`
  },
  get apiUrl() {
    return `https://api.github.com`
  },
}

export default config
<commit_msg>common configuration moved assets config from server/config to common/config added reactWrapperId<commit_after>import path from 'path'

const r = path.join(__dirname, '..', '..')
const env = process.env

const config = {
  root: r,
  env: env.NODE_ENV || 'dev',
  port: env.PORT || 8000,
  host: env.HOST || 'localhost',
  reactWrapperId: 'root',
  assets: {
    baseUrl: '/static',
    path: path.join(r, 'public'),
  },
  get baseUrl() {
    return `http://${this.host}:${this.port}`
  },
  get apiUrl() {
    return `https://api.github.com`
  },
}

export default config
<|endoftext|>


<commit_before>/* queue_manager.js
 * Backbone collection to manage queued_songs. Represents a user's queue.
 */

var winston = require('winston');
var _ = require('underscore');
var Backbone = require('backbone');
var queued_song_model = require('../../models/queued_song');
var QueuedSong = require('./queued_song');

module.exports = Backbone.Collection.extend({
  comparator: 'order',
  model: QueuedSong,

  initialize: function() {
    this.on('add', this.songAdded, this);
  },

  songAdded: function(queued_song) {
    queued_song.on('change:order', this.sort, this);
    queued_song.on('change', function() {
      this.trigger('songChanged', queued_song);
    }, this);
  },

  getNextSong: function() {
    return this.first();
  },

  addSongEntity: function(song_entity, callback) {
    var queued_song = new QueuedSong({
      song: song_entity,
      song_id: song_entity.id,
      user_id: this.user_id,
      order: this.length + 1
    });
    queued_song.on('save', function() {
      this.add(queued_song);
      callback(queued_song);
    }, this);
    queued_song.save();
  },

  rotate: function() {
    this.updateSongOrder(this.getNextSong().id, this.length);
  },

  updateSongOrder: function(queued_song_id, order) {
    var target_queued_song = this.get(queued_song_id);
    var original_order = target_queued_song.get('order');
    var moved_down = order > original_order; // directionally, not numerically

    if (order === original_order)
      return;

    this.forEach(function(queued_song) {
      if (
          !moved_down &&
          queued_song.id !== queued_song_id &&
          queued_song.get('order') >= order &&
          queued_song.get('order') < original_order) {
        queued_song.incrementOrder();
      } else if (
          moved_down &&
          queued_song.id !== queued_song_id &&
          queued_song.get('order') <= order &&
          queued_song.get('order') > original_order) {
        queued_song.decrementOrder();
      }
    });
    this.get(queued_song_id).set({ order: order });
  },

  sync: function(method, model) {
    if (!this.user_id) {
      winston.error('Can\'t fetch queue; no user_id set.');
      this.trigger('error', new Error('No user ID specified.'));
      return;
    }

    queued_song_model.QueuedSong.find({
      user_id: this.user_id
    }, _.bind(function(err, queued_songs) {
      this.reset();
      var songs_left = queued_songs.length;
      if (songs_left === 0) {
        this.trigger('load');
        return;
      }
      queued_songs.forEach(_.bind(function(queued_song) {

        // Because autoFetch doesn't seem to work (godammit), we'll manually
        // fetch the artwork file entity.
        queued_song.song.getArtwork(_.bind(function(err, artwork) {
          if (artwork && !err)
            queued_song.song.artwork = artwork;
          var new_queued_song = new QueuedSong({ entity: queued_song });
          this.add(new_queued_song);
          if (--songs_left <= 0) {
            this.trigger('load');
          }
        }, this));
      }, this));
    }, this));
  },

  toJSON: function() {
    var songs = [];

    this.models.forEach(function(queued_song) {
      songs.push(queued_song.toJSON());
    });

    return songs;
  }
});

<commit_msg>Adding song adds it to the top of queue.<commit_after>/* queue_manager.js
 * Backbone collection to manage queued_songs. Represents a user's queue.
 */

var winston = require('winston');
var _ = require('underscore');
var Backbone = require('backbone');
var queued_song_model = require('../../models/queued_song');
var QueuedSong = require('./queued_song');

module.exports = Backbone.Collection.extend({
  comparator: 'order',
  model: QueuedSong,

  initialize: function() {
    this.on('add', this.songAdded, this);
  },

  songAdded: function(queued_song) {
    queued_song.on('change:order', this.sort, this);
    queued_song.on('change', function() {
      this.trigger('songChanged', queued_song);
    }, this);
  },

  getNextSong: function() {
    return this.first();
  },

  getPlayingSong: function() {
    return this.findWhere({ playing: true });
  },

  addSongEntity: function(song_entity, callback) {
    var queued_song = new QueuedSong({
      song: song_entity,
      song_id: song_entity.id,
      user_id: this.user_id,
      order: this.length + 1
    });
    queued_song.on('save', function() {
      this.add(queued_song);
      callback(queued_song);
      this.updateSongOrder(
        queued_song.id, this.getPlayingSong() ? 2 : 1);
    }, this);
    queued_song.save();
  },

  rotate: function() {
    this.updateSongOrder(this.getNextSong().id, this.length);
  },

  updateSongOrder: function(queued_song_id, order) {
    var target_queued_song = this.get(queued_song_id);
    var original_order = target_queued_song.get('order');
    var moved_down = order > original_order; // directionally, not numerically

    if (order === original_order)
      return;

    this.forEach(function(queued_song) {
      if (
          !moved_down &&
          queued_song.id !== queued_song_id &&
          queued_song.get('order') >= order &&
          queued_song.get('order') < original_order) {
        queued_song.incrementOrder();
      } else if (
          moved_down &&
          queued_song.id !== queued_song_id &&
          queued_song.get('order') <= order &&
          queued_song.get('order') > original_order) {
        queued_song.decrementOrder();
      }
    });
    this.get(queued_song_id).set({ order: order });
  },

  sync: function(method, model) {
    if (!this.user_id) {
      winston.error('Can\'t fetch queue; no user_id set.');
      this.trigger('error', new Error('No user ID specified.'));
      return;
    }

    queued_song_model.QueuedSong.find({
      user_id: this.user_id
    }, _.bind(function(err, queued_songs) {
      this.reset();
      var songs_left = queued_songs.length;
      if (songs_left === 0) {
        this.trigger('load');
        return;
      }
      queued_songs.forEach(_.bind(function(queued_song) {

        // Because autoFetch doesn't seem to work (godammit), we'll manually
        // fetch the artwork file entity.
        queued_song.song.getArtwork(_.bind(function(err, artwork) {
          if (artwork && !err)
            queued_song.song.artwork = artwork;
          var new_queued_song = new QueuedSong({ entity: queued_song });
          this.add(new_queued_song);
          if (--songs_left <= 0) {
            this.trigger('load');
          }
        }, this));
      }, this));
    }, this));
  },

  toJSON: function() {
    var songs = [];

    this.models.forEach(function(queued_song) {
      songs.push(queued_song.toJSON());
    });

    return songs;
  }
});

<|endoftext|>


<commit_before>function onliner_by_utils_install(doc)
{
	doc.execXPath = function (xpath, ctx, nsResolver)
	{
		var d = this;
		if(d.wrappedJSObject != null)
			d = d.wrappedJSObject;

		if(ctx == null)
			ctx = d;

		var xs = d.evaluate(
			xpath,
			ctx,
			nsResolver,
			XPathResult.ANY_TYPE,
			null);

		var ret = Array();
		var x = xs.iterateNext();
		while(x != null)
		{
			ret.push(x);
			x = xs.iterateNext();
		}
		return ret;
	};

	doc.execXPathOne = function (xpath, ctx, nsResolver)
	{
		var d = this;
		if(d.wrappedJSObject != null)
			d = d.wrappedJSObject;
		var res = d.execXPath(xpath, ctx, nsResolver);
		if(res.length != 1)
			return null;
		return res[0];
	}

	doc.addEventListener("OnGetClipboardText", phpBBx_onGetClipboardText, false);
}

function phpBBx_onGetClipboardText(e)
{
	var clip = Components.classes["@mozilla.org/widget/clipboard;1"]
		.getService(Components.interfaces.nsIClipboard);

	var trans = Components.classes["@mozilla.org/widget/transferable;1"].
		createInstance(Components.interfaces.nsITransferable);
	trans.addDataFlavor("text/unicode");

	clip.getData(trans, clip.kGlobalClipboard);
	var str = new Object();
	var strLength = new Object();
	trans.getTransferData("text/unicode", str, strLength);

	var dataHolder = e.target.getElementById('phpBBx_clipboard');
	if(dataHolder == null)
	{
		dataHolder = e.target.createElement('OLBYClipboard');
		dataHolder.id = 'phpBBx_clipboard';
		e.target.documentElement.appendChild(dataHolder);
	}

	dataHolder.textContent = "";

	if (str)
	{
		str = str.value.QueryInterface(Components.interfaces.nsISupportsString);
		dataHolder.textContent = str.data.substring(0, strLength.value / 2);
	}
}

function phpBBx_install_script(doc, funct)
{
	var body = doc.execXPathOne("/html/body");
	if(body == null)
		return;
	var script = doc.createElement("script");
	script.type = "text/javascript";
	script.language = "javascript";
	script.text = funct.toString();
	body.appendChild(script);
}<commit_msg><commit_after>function phpBBx_utils_install(doc)
{
	doc.execXPath = function (xpath, ctx, nsResolver)
	{
		var d = this;
		if(d.wrappedJSObject != null)
			d = d.wrappedJSObject;

		if(ctx == null)
			ctx = d;

		var xs = d.evaluate(
			xpath,
			ctx,
			nsResolver,
			XPathResult.ANY_TYPE,
			null);

		var ret = Array();
		var x = xs.iterateNext();
		while(x != null)
		{
			ret.push(x);
			x = xs.iterateNext();
		}
		return ret;
	};

	doc.execXPathOne = function (xpath, ctx, nsResolver)
	{
		var d = this;
		if(d.wrappedJSObject != null)
			d = d.wrappedJSObject;
		var res = d.execXPath(xpath, ctx, nsResolver);
		if(res.length != 1)
			return null;
		return res[0];
	}

	doc.addEventListener("OnGetClipboardText", phpBBx_onGetClipboardText, false);
}

function phpBBx_onGetClipboardText(e)
{
	var clip = Components.classes["@mozilla.org/widget/clipboard;1"]
		.getService(Components.interfaces.nsIClipboard);

	var trans = Components.classes["@mozilla.org/widget/transferable;1"].
		createInstance(Components.interfaces.nsITransferable);
	trans.addDataFlavor("text/unicode");

	clip.getData(trans, clip.kGlobalClipboard);
	var str = new Object();
	var strLength = new Object();
	trans.getTransferData("text/unicode", str, strLength);

	var dataHolder = e.target.getElementById('phpBBx_clipboard');
	if(dataHolder == null)
	{
		dataHolder = e.target.createElement('phpBBxClipboard');
		dataHolder.id = 'phpBBx_clipboard';
		e.target.documentElement.appendChild(dataHolder);
	}

	dataHolder.textContent = "";

	if (str)
	{
		str = str.value.QueryInterface(Components.interfaces.nsISupportsString);
		dataHolder.textContent = str.data.substring(0, strLength.value / 2);
	}
}

function phpBBx_install_script(doc, funct)
{
	var body = doc.execXPathOne("/html/body");
	if(body == null)
		return;
	var script = doc.createElement("script");
	script.type = "text/javascript";
	script.language = "javascript";
	script.text = funct.toString();
	body.appendChild(script);
}<|endoftext|>


<commit_before>/* eslint-disable import/no-extraneous-dependencies */

const crypto = require('crypto');
const url = require('url');
const path = require('path');

const _ = require('lodash');
const Koa = require('koa');
const jose = require('node-jose');
const Router = require('koa-router');
const body = require('koa-body');
const session = require('koa-session');
const render = require('koa-ejs');
const LRU = require('lru-cache')();

const PRESETS = require('./presets');

const SESSION_KEY = 'rp:sess';

module.exports = (issuer) => {
  const app = new Koa();

  if (process.env.NODE_ENV === 'production') {
    app.proxy = true;

    app.use(async (ctx, next) => {
      if (ctx.secure) {
        await next();
      } else {
        ctx.redirect(ctx.href.replace(/^http:\/\//i, 'https://'));
      }
    });
  }

  app.keys = ['some secret hurr'];
  app.use(session({
    key: SESSION_KEY,
    store: {
      get(key) {
        return LRU.get(key);
      },
      set(key, sess, maxAge) {
        LRU.set(key, sess, maxAge);
      },
      destroy(key) {
        LRU.del(key);
      },
    },
  }, app));

  render(app, {
    cache: true,
    layout: '_layout',
    root: path.join(__dirname, 'views'),
  });

  app.use(async (ctx, next) => {
    try {
      await next();
    } catch (error) {
      await ctx.render('error', { issuer, error, session: ctx.session });
    }
  });

  app.use(async (ctx, next) => {
    if (!ctx.session.client && !ctx.path.startsWith('/setup')) {
      ctx.redirect('/setup');
    }
    await next();
  });

  const router = new Router();

  router.get('/', async (ctx, next) => {
    await ctx.render('index', { session: ctx.session, issuer });
    return next();
  });

  router.get('/rpframe', async (ctx, next) => {
    const clientId = ctx.session.client.client_id;
    const sessionState = ctx.session.tokenset.session_state;
    await ctx.render('rp_frame', {
      session: ctx.session, layout: false, issuer, clientId, sessionState,
    });
    return next();
  });

  router.get('/setup', async (ctx, next) => {
    await ctx.render('setup', { session: ctx.session, presets: PRESETS, issuer });
    return next();
  });

  router.post('/setup/:preset', async (ctx, next) => {
    let keystore;
    const preset = PRESETS[ctx.params.preset];
    const metadata = {};

    if (preset.keystore) {
      keystore = jose.JWK.createKeyStore();
      await keystore.generate(...preset.keystore);
      ctx.session.keystore = keystore;
      if (process.env.NODE_ENV === 'production') {
        Object.assign(metadata, {
          jwks_uri: url.resolve(ctx.href, router.url('jwks', { session_id: ctx.cookies.get(SESSION_KEY) })),
        });
      }
    } else {
      ctx.session.keystore = undefined;
    }

    Object.assign(metadata, {
      post_logout_redirect_uris: [url.resolve(ctx.href, '/')],
      redirect_uris: [url.resolve(ctx.href, '/cb')],
    }, preset.registration);

    const client = await issuer.Client.register(metadata, { keystore });
    client.CLOCK_TOLERANCE = 5;
    ctx.session.tokenset = undefined;
    ctx.session.client = client;
    ctx.session.authorization_params = preset.authorization_params;

    ctx.redirect('/client');
    return next();
  });

  router.get('/issuer', async (ctx, next) => {
    await ctx.render('issuer', {
      issuer,
      keystore: (await issuer.keystore()),
      session: ctx.session,
    });
    return next();
  });

  router.get('/client', async (ctx, next) => {
    await ctx.render('client', { client: ctx.session.client, session: ctx.session, issuer });
    return next();
  });

  router.get('/logout', async (ctx, next) => {
    const { client, tokenset: tokens } = ctx.session;

    if (tokens) {
      try {
        await Promise.all([
          tokens.access_token ? client.revoke(tokens.access_token, 'access_token') : undefined,
          tokens.refresh_token ? client.revoke(tokens.refresh_token, 'refresh_token') : undefined,
        ]);
      } catch (err) {}
      ctx.redirect(url.format(Object.assign(url.parse(issuer.end_session_endpoint), {
        search: null,
        query: {
          id_token_hint: tokens.id_token,
          post_logout_redirect_uri: url.resolve(ctx.href, '/'),
        },
      })));
    } else {
      ctx.redirect('/');
    }
    ctx.session = null;

    return next();
  });

  router.get('/login', async (ctx, next) => {
    ctx.session.state = crypto.randomBytes(16).toString('hex');
    ctx.session.nonce = crypto.randomBytes(16).toString('hex');

    const { client } = ctx.session;

    const authorizationRequest = Object.assign({
      redirect_uri: url.resolve(ctx.href, 'cb'),
      scope: 'openid profile email address phone',
      state: ctx.session.state,
      nonce: ctx.session.nonce,
      response_type: client.response_types[0],
    }, ctx.session.authorization_params);

    ctx.redirect(client.authorizationUrl(authorizationRequest));
    return next();
  });

  router.get('/refresh', async (ctx, next) => {
    if (!ctx.session.tokenset) {
      ctx.session = null;
      ctx.redirect('/');
    } else {
      const tokens = ctx.session.tokenset;
      const { client } = ctx.session;

      const refreshed = await client.refresh(tokens);
      refreshed.session_state = tokens.session_state;

      ctx.session.tokenset = refreshed;

      ctx.redirect('/user');
    }

    return next();
  });

  router.get('/cb', async (ctx, next) => {
    const { client } = ctx.session;
    const params = client.callbackParams(ctx.request.req);

    if (_.isEmpty(params)) { // probably a fragment response
      return ctx.render('repost', { layout: false });
    }

    const { state, nonce } = ctx.session;
    delete ctx.session.state;
    delete ctx.session.nonce;

    ctx.session.tokenset = await client.authorizationCallback(url.resolve(ctx.href, 'cb'), params, { nonce, state });

    ctx.redirect('/user');

    return next();
  });

  router.post('/cb', body({ patchNode: true }), async (ctx, next) => {
    const { state, nonce } = ctx.session;
    delete ctx.session.state;
    delete ctx.session.nonce;
    const { client } = ctx.session;
    const params = client.callbackParams(ctx.request.req);

    ctx.session.tokenset = await client.authorizationCallback(url.resolve(ctx.href, 'cb'), params, { nonce, state });

    ctx.redirect('/user');

    return next();
  });

  router.get('jwks', '/:session_id/jwks.json', async (ctx) => {
    const { keystore } = LRU.get(ctx.params.session_id) || {};
    if (keystore) {
      ctx.body = keystore.toJSON();
    } else {
      ctx.status = 404;
      ctx.body = {
        error: 'invalid_request',
        error_description: 'jwks for this client not found',
      };
    }
  });

  function rejectionHandler(error) {
    if (error.name === 'OpenIdConnectError') {
      return error;
    }

    throw error;
  }

  router.get('/user', async (ctx, next) => {
    const tokens = ctx.session.tokenset;
    if (!tokens) {
      return ctx.redirect('/client');
    }
    const { client } = ctx.session;

    const context = {
      tokens,
      userinfo: undefined,
      id_token: tokens.id_token ? tokens.claims : undefined,
      session: ctx.session,
      introspections: {},
      issuer,
    };

    const promises = [];

    _.forEach(tokens, (value, key) => {
      if (key.endsWith('token') && key !== 'id_token') {
        const p = client.introspect(value, key)
          .then((result) => {
            context.introspections[key] = result;
          })
          .catch(rejectionHandler);
        promises.push(p);
      }
      return undefined;
    });

    if (tokens.access_token) {
      const p = client.userinfo(tokens)
        .then(userinfo => client.fetchDistributedClaims(userinfo))
        .then(userinfo => client.unpackAggregatedClaims(userinfo))
        .then((result) => {
          context.userinfo = result;
        })
        .catch(rejectionHandler);
      promises.push(p);
    }

    await Promise.all(promises);
    await ctx.render('user', context);

    return next();
  });

  app.use(router.routes());
  app.use(router.allowedMethods());

  return app;
};
<commit_msg>no really, fix it<commit_after>/* eslint-disable import/no-extraneous-dependencies */

const crypto = require('crypto');
const url = require('url');
const path = require('path');

const _ = require('lodash');
const Koa = require('koa');
const jose = require('node-jose');
const Router = require('koa-router');
const body = require('koa-body');
const session = require('koa-session');
const render = require('koa-ejs');
const LRU = require('lru-cache')();

const PRESETS = require('./presets');

const SESSION_KEY = 'rp:sess';

module.exports = (issuer) => {
  const app = new Koa();

  if (process.env.NODE_ENV === 'production') {
    app.proxy = true;

    app.use(async (ctx, next) => {
      if (ctx.secure) {
        await next();
      } else {
        ctx.redirect(ctx.href.replace(/^http:\/\//i, 'https://'));
      }
    });
  }

  app.keys = ['some secret hurr'];
  app.use(session({
    key: SESSION_KEY,
    store: {
      get(key) {
        return LRU.get(key);
      },
      set(key, sess, maxAge) {
        LRU.set(key, sess, maxAge);
      },
      destroy(key) {
        LRU.del(key);
      },
    },
  }, app));
  app.use((ctx, next) => {
    ctx.session.save(); // save this session no matter whether it is populated
    return next();
  });

  render(app, {
    cache: true,
    layout: '_layout',
    root: path.join(__dirname, 'views'),
  });

  app.use(async (ctx, next) => {
    try {
      await next();
    } catch (error) {
      await ctx.render('error', { issuer, error, session: ctx.session });
    }
  });

  app.use(async (ctx, next) => {
    if (!ctx.session.client && !ctx.path.startsWith('/setup') && !ctx.path.endsWith('/jwks.json')) {
      ctx.redirect('/setup');
    }
    await next();
  });

  const router = new Router();

  router.get('/', async (ctx, next) => {
    await ctx.render('index', { session: ctx.session, issuer });
    return next();
  });

  router.get('/rpframe', async (ctx, next) => {
    const clientId = ctx.session.client.client_id;
    const sessionState = ctx.session.tokenset.session_state;
    await ctx.render('rp_frame', {
      session: ctx.session, layout: false, issuer, clientId, sessionState,
    });
    return next();
  });

  router.get('/setup', async (ctx, next) => {
    await ctx.render('setup', { session: ctx.session, presets: PRESETS, issuer });
    return next();
  });

  router.post('/setup/:preset', async (ctx, next) => {
    let keystore;
    const preset = PRESETS[ctx.params.preset];
    const metadata = {};

    if (preset.keystore) {
      keystore = jose.JWK.createKeyStore();
      await keystore.generate(...preset.keystore);
      ctx.session.keystore = keystore;
      if (process.env.NODE_ENV === 'production') {
        Object.assign(metadata, {
          jwks_uri: url.resolve(ctx.href, router.url('jwks', { session_id: ctx.cookies.get(SESSION_KEY) })),
        });
      }
    } else {
      ctx.session.keystore = undefined;
    }

    Object.assign(metadata, {
      post_logout_redirect_uris: [url.resolve(ctx.href, '/')],
      redirect_uris: [url.resolve(ctx.href, '/cb')],
    }, preset.registration);

    const client = await issuer.Client.register(metadata, { keystore });
    client.CLOCK_TOLERANCE = 5;
    ctx.session.tokenset = undefined;
    ctx.session.client = client;
    ctx.session.authorization_params = preset.authorization_params;

    ctx.redirect('/client');
    return next();
  });

  router.get('/issuer', async (ctx, next) => {
    await ctx.render('issuer', {
      issuer,
      keystore: (await issuer.keystore()),
      session: ctx.session,
    });
    return next();
  });

  router.get('/client', async (ctx, next) => {
    await ctx.render('client', { client: ctx.session.client, session: ctx.session, issuer });
    return next();
  });

  router.get('/logout', async (ctx, next) => {
    const { client, tokenset: tokens } = ctx.session;

    if (tokens) {
      try {
        await Promise.all([
          tokens.access_token ? client.revoke(tokens.access_token, 'access_token') : undefined,
          tokens.refresh_token ? client.revoke(tokens.refresh_token, 'refresh_token') : undefined,
        ]);
      } catch (err) {}
      ctx.redirect(url.format(Object.assign(url.parse(issuer.end_session_endpoint), {
        search: null,
        query: {
          id_token_hint: tokens.id_token,
          post_logout_redirect_uri: url.resolve(ctx.href, '/'),
        },
      })));
    } else {
      ctx.redirect('/');
    }
    ctx.session = null;

    return next();
  });

  router.get('/login', async (ctx, next) => {
    ctx.session.state = crypto.randomBytes(16).toString('hex');
    ctx.session.nonce = crypto.randomBytes(16).toString('hex');

    const { client } = ctx.session;

    const authorizationRequest = Object.assign({
      redirect_uri: url.resolve(ctx.href, 'cb'),
      scope: 'openid profile email address phone',
      state: ctx.session.state,
      nonce: ctx.session.nonce,
      response_type: client.response_types[0],
    }, ctx.session.authorization_params);

    ctx.redirect(client.authorizationUrl(authorizationRequest));
    return next();
  });

  router.get('/refresh', async (ctx, next) => {
    if (!ctx.session.tokenset) {
      ctx.session = null;
      ctx.redirect('/');
    } else {
      const tokens = ctx.session.tokenset;
      const { client } = ctx.session;

      const refreshed = await client.refresh(tokens);
      refreshed.session_state = tokens.session_state;

      ctx.session.tokenset = refreshed;

      ctx.redirect('/user');
    }

    return next();
  });

  router.get('/cb', async (ctx, next) => {
    const { client } = ctx.session;
    const params = client.callbackParams(ctx.request.req);

    if (_.isEmpty(params)) { // probably a fragment response
      return ctx.render('repost', { layout: false });
    }

    const { state, nonce } = ctx.session;
    delete ctx.session.state;
    delete ctx.session.nonce;

    ctx.session.tokenset = await client.authorizationCallback(url.resolve(ctx.href, 'cb'), params, { nonce, state });

    ctx.redirect('/user');

    return next();
  });

  router.post('/cb', body({ patchNode: true }), async (ctx, next) => {
    const { state, nonce } = ctx.session;
    delete ctx.session.state;
    delete ctx.session.nonce;
    const { client } = ctx.session;
    const params = client.callbackParams(ctx.request.req);

    ctx.session.tokenset = await client.authorizationCallback(url.resolve(ctx.href, 'cb'), params, { nonce, state });

    ctx.redirect('/user');

    return next();
  });

  router.get('jwks', '/:session_id/jwks.json', async (ctx) => {
    const { keystore } = LRU.get(ctx.params.session_id) || {};
    if (keystore) {
      ctx.body = keystore.toJSON();
    } else {
      ctx.status = 404;
      ctx.body = {
        error: 'invalid_request',
        error_description: 'jwks for this client not found',
      };
    }
  });

  function rejectionHandler(error) {
    if (error.name === 'OpenIdConnectError') {
      return error;
    }

    throw error;
  }

  router.get('/user', async (ctx, next) => {
    const tokens = ctx.session.tokenset;
    if (!tokens) {
      return ctx.redirect('/client');
    }
    const { client } = ctx.session;

    const context = {
      tokens,
      userinfo: undefined,
      id_token: tokens.id_token ? tokens.claims : undefined,
      session: ctx.session,
      introspections: {},
      issuer,
    };

    const promises = [];

    _.forEach(tokens, (value, key) => {
      if (key.endsWith('token') && key !== 'id_token') {
        const p = client.introspect(value, key)
          .then((result) => {
            context.introspections[key] = result;
          })
          .catch(rejectionHandler);
        promises.push(p);
      }
      return undefined;
    });

    if (tokens.access_token) {
      const p = client.userinfo(tokens)
        .then(userinfo => client.fetchDistributedClaims(userinfo))
        .then(userinfo => client.unpackAggregatedClaims(userinfo))
        .then((result) => {
          context.userinfo = result;
        })
        .catch(rejectionHandler);
      promises.push(p);
    }

    await Promise.all(promises);
    await ctx.render('user', context);

    return next();
  });

  app.use(router.routes());
  app.use(router.allowedMethods());

  return app;
};
<|endoftext|>


<commit_before>(function() {
  "use strict";
  var answers;

  // This following code is taken from
  // https://github.com/thieman/github-selfies/blob/master/chrome/selfie.js
  var allowedPaths = [
    // New issues
    /github.com\/[\w\-]+\/[\w\-]+\/issues\/new/,
    // Existing issues (comment)
    /github.com\/[\w\-]+\/[\w\-]+\/issues\/\d+/,
    // New pull request
    /github.com\/[\w\-]+\/[\w\-]+\/compare/,
    // Existing pull requests (comment)
    /github.com\/[\w\-]+\/[\w\-]+\/pull\/\d+/
  ];

  // Inject the code from fn into the page, in an IIFE.
  function inject(fn) {
    var script = document.createElement('script');
    var parent = document.documentElement;
    script.textContent = '('+ fn +')();';
    parent.appendChild(script);
    parent.removeChild(script);
  }

  // Post a message whenever history.pushState is called. GitHub uses
  // pushState to implement page transitions without full page loads.
  // This needs to be injected because content scripts run in a sandbox.
  inject(function() {
    var pushState = history.pushState;
    history.pushState = function on_pushState() {
      window.postMessage('extension:pageUpdated', '*');
      return pushState.apply(this, arguments);
    };
    var replaceState = history.replaceState;
    history.replaceState = function on_replaceState() {
      window.postMessage('extension:pageUpdated', '*');
      return replaceState.apply(this, arguments);
    };
  });

  // Do something when the extension is loaded into the page,
  // and whenever we push/pop new pages.
  window.addEventListener("message", function(event) {
    if (event.data === 'extension:pageUpdated') {
      load();
    }
  });

  window.addEventListener("popstate", load);
  load();

  // End of code from https://github.com/thieman/github-selfies/blob/master/chrome/selfie.js

  function load() {
    chrome.runtime.sendMessage('load', function(response) {
      answers = response.answers;
      addAnswerButton();
    });
  }

  function any(array, predicate) {
    for (var i = 0; i < array.length; i++) {
      if (predicate(array[i])) {
        return true;
      }
    }
    return false;
  }

  function addAnswerButton() {
    if (!any(allowedPaths, (path) => path.test(window.location.href))) {
      // NOPE.
      return;
    }

    // If there's already a button nuke it so we can start fresh.
    var b = document.querySelector('.github-canned-response-item');
    if (b) {
      b.parentNode.removeChild(b);
    }

    var targets = document.querySelectorAll('.js-toolbar.toolbar-commenting');

    for (var i = 0; i < targets.length; i++) {
      var target = createNodeWithClass('div', 'toolbar-group');
      targets[i].insertBefore(target, targets[i].childNodes[0]);

      var item = createNodeWithClass('div', 'select-menu js-menu-container js-select-menu label-select-menu github-canned-response-item');
      target.appendChild(item);

      var button = createButton();
      item.appendChild(button);

      if (targets[i]) {
        var dropdown = createDropdown(answers, targets[i]);
        item.appendChild(dropdown);
      }
    }
  }

  function createNodeWithClass(nodeType, className) {
    var element = document.createElement(nodeType);
    element.className = className;
    return element;
  }

  function createButton() {
    var button = createNodeWithClass('button', 'toolbar-item tooltipped tooltipped-n js-menu-target menu-target');

    button.setAttribute('aria-label', 'Insert canned response');
    button.style.display = 'inline-block';

    //var text = document.createTextNode('Canned Response');
    //button.appendChild(text);

    var span = createNodeWithClass('span', 'octicon octicon-mail-read');
    button.appendChild(span);

    var span = createNodeWithClass('span', 'dropdown-caret');
    button.appendChild(span);

    return button;
  }

  function createDropdown(answers, toolbar) {
    // This should use the fuzzy search instead (see labels)
    var outer = createNodeWithClass('div', 'select-menu-modal-holder js-menu-content js-navigation-container');
    var inner = createNodeWithClass('div', 'select-menu-modal');
    outer.appendChild(inner);

    var header = createNodeWithClass('div', 'select-menu-header');
    var headerText = createNodeWithClass('span', 'select-menu-title');
    headerText.innerHTML = 'Insert response';
    header.appendChild(headerText);
    inner.appendChild(header);

    var main = createNodeWithClass('div', 'js-select-menu-deferred-content');
    inner.appendChild(main);

    var filter = createNodeWithClass('div', 'select-menu-filters');
    var filterText = createNodeWithClass('div', 'select-menu-text-filter');
    var filterInput = createNodeWithClass('input', 'js-filterable-field js-navigation-enable form-control');
    filterInput.id = 'canned-response-filter-field';
    filterInput.type = 'text';
    filterInput.placeholder = 'Filter responses';
    filterInput.autocomplete = 'off';
    filterInput.setAttribute('aria-label', 'Type or choose an answer');

    filterText.appendChild(filterInput);
    filter.appendChild(filterText);
    main.appendChild(filter);

    var itemList = createNodeWithClass('div', 'select-menu-list');
    itemList.setAttribute('data-filterable-for', 'canned-response-filter-field');
    itemList.setAttribute('data-filterable-type', 'fuzzy');

    main.appendChild(itemList);

    for (var i = 0; i < answers.length; i++) {
      var item = createDropdownItem(answers[i].name);
      itemList.appendChild(item);
      item.toolbar = toolbar;
      item.answer = answers[i].description;
      item.addEventListener('click', insertAnswer);

      // Gigantic hack because the PR page is not setting up mouse events correctly.
      item.addEventListener('mouseenter', function() {
        this.className += ' navigation-focus';
      });
      item.addEventListener('mouseleave', function() {
        this.className = this.className.replace(/ navigation-focus/g, '');
      });
    }

    return outer;
  }

  function createDropdownItem(text) {
    var item = createNodeWithClass('div', 'select-menu-item js-navigation-item');
    item.textContent = text;
    return item;
  }

  function insertAnswer(event) {
    var item = event.target;
    var textarea = item.toolbar.parentNode.parentNode.querySelector('textarea');
    textarea.value += item.answer + '\n';

    // Scroll down.
    textarea.focus();
    textarea.scrollTop = textarea.scrollHeight;
  }
})();
<commit_msg>actually delete nodes correctly<commit_after>(function() {
  "use strict";
  var answers;

  // This following code is taken from
  // https://github.com/thieman/github-selfies/blob/master/chrome/selfie.js
  var allowedPaths = [
    // New issues
    /github.com\/[\w\-]+\/[\w\-]+\/issues\/new/,
    // Existing issues (comment)
    /github.com\/[\w\-]+\/[\w\-]+\/issues\/\d+/,
    // New pull request
    /github.com\/[\w\-]+\/[\w\-]+\/compare/,
    // Existing pull requests (comment)
    /github.com\/[\w\-]+\/[\w\-]+\/pull\/\d+/
  ];

  // Inject the code from fn into the page, in an IIFE.
  function inject(fn) {
    var script = document.createElement('script');
    var parent = document.documentElement;
    script.textContent = '('+ fn +')();';
    parent.appendChild(script);
    parent.removeChild(script);
  }

  // Post a message whenever history.pushState is called. GitHub uses
  // pushState to implement page transitions without full page loads.
  // This needs to be injected because content scripts run in a sandbox.
  inject(function() {
    var pushState = history.pushState;
    history.pushState = function on_pushState() {
      window.postMessage('extension:pageUpdated', '*');
      return pushState.apply(this, arguments);
    };
    var replaceState = history.replaceState;
    history.replaceState = function on_replaceState() {
      window.postMessage('extension:pageUpdated', '*');
      return replaceState.apply(this, arguments);
    };
  });

  // Do something when the extension is loaded into the page,
  // and whenever we push/pop new pages.
  window.addEventListener("message", function(event) {
    if (event.data === 'extension:pageUpdated') {
      addAnswerButton();
    }
  });

  window.addEventListener("popstate", load);
  load();

  // End of code from https://github.com/thieman/github-selfies/blob/master/chrome/selfie.js

  function load() {
    chrome.runtime.sendMessage('load', function(response) {
      answers = response.answers;
      addAnswerButton();
    });
  }

  function any(array, predicate) {
    for (var i = 0; i < array.length; i++) {
      if (predicate(array[i])) {
        return true;
      }
    }
    return false;
  }

  function addAnswerButton() {
    if (!any(allowedPaths, (path) => path.test(window.location.href))) {
      // NOPE.
      return;
    }

    // If there's already a button nuke it so we can start fresh.
    var existingButtons = document.querySelectorAll('.github-canned-response-item');
    if (existingButtons && existingButtons.length !== 0) {
      for (var i = 0; i < existingButtons.length; i++) {
        existingButtons[i].parentNode.removeChild(existingButtons[i]);
      }
    }

    var targets = document.querySelectorAll('.js-toolbar.toolbar-commenting');

    for (var i = 0; i < targets.length; i++) {
      var target = createNodeWithClass('div', 'toolbar-group github-canned-response-item');
      targets[i].insertBefore(target, targets[i].childNodes[0]);

      var item = createNodeWithClass('div', 'select-menu js-menu-container js-select-menu label-select-menu');
      target.appendChild(item);

      var button = createButton();
      item.appendChild(button);

      if (targets[i]) {
        var dropdown = createDropdown(answers, targets[i]);
        item.appendChild(dropdown);
      }
    }
  }

  function createNodeWithClass(nodeType, className) {
    var element = document.createElement(nodeType);
    element.className = className;
    return element;
  }

  function createButton() {
    var button = createNodeWithClass('button', 'toolbar-item tooltipped tooltipped-n js-menu-target menu-target');

    button.setAttribute('aria-label', 'Insert canned response');
    button.style.display = 'inline-block';

    //var text = document.createTextNode('Canned Response');
    //button.appendChild(text);

    var span = createNodeWithClass('span', 'octicon octicon-mail-read');
    button.appendChild(span);

    var span = createNodeWithClass('span', 'dropdown-caret');
    button.appendChild(span);

    return button;
  }

  function createDropdown(answers, toolbar) {
    // This should use the fuzzy search instead (see labels)
    var outer = createNodeWithClass('div', 'select-menu-modal-holder js-menu-content js-navigation-container');
    var inner = createNodeWithClass('div', 'select-menu-modal');
    outer.appendChild(inner);

    var header = createNodeWithClass('div', 'select-menu-header');
    var headerText = createNodeWithClass('span', 'select-menu-title');
    headerText.innerHTML = 'Insert response';
    header.appendChild(headerText);
    inner.appendChild(header);

    var main = createNodeWithClass('div', 'js-select-menu-deferred-content');
    inner.appendChild(main);

    var filter = createNodeWithClass('div', 'select-menu-filters');
    var filterText = createNodeWithClass('div', 'select-menu-text-filter');
    var filterInput = createNodeWithClass('input', 'js-filterable-field js-navigation-enable form-control');
    filterInput.id = 'canned-response-filter-field';
    filterInput.type = 'text';
    filterInput.placeholder = 'Filter responses';
    filterInput.autocomplete = 'off';
    filterInput.setAttribute('aria-label', 'Type or choose an answer');

    filterText.appendChild(filterInput);
    filter.appendChild(filterText);
    main.appendChild(filter);

    var itemList = createNodeWithClass('div', 'select-menu-list');
    itemList.setAttribute('data-filterable-for', 'canned-response-filter-field');
    itemList.setAttribute('data-filterable-type', 'fuzzy');

    main.appendChild(itemList);

    for (var i = 0; i < answers.length; i++) {
      var item = createDropdownItem(answers[i].name);
      itemList.appendChild(item);
      item.toolbar = toolbar;
      item.answer = answers[i].description;
      item.addEventListener('click', insertAnswer);

      // Gigantic hack because the PR page is not setting up mouse events correctly.
      item.addEventListener('mouseenter', function() {
        this.className += ' navigation-focus';
      });
      item.addEventListener('mouseleave', function() {
        this.className = this.className.replace(/ navigation-focus/g, '');
      });
    }

    return outer;
  }

  function createDropdownItem(text) {
    var item = createNodeWithClass('div', 'select-menu-item js-navigation-item');
    item.textContent = text;
    return item;
  }

  function insertAnswer(event) {
    var item = event.target;
    var textarea = item.toolbar.parentNode.parentNode.querySelector('textarea');
    textarea.value += item.answer + '\n';

    // Scroll down.
    textarea.focus();
    textarea.scrollTop = textarea.scrollHeight;
  }
})();
<|endoftext|>


<commit_before>'use strict';

/**
 * @ngdoc function
 * @name frontendApp.controller:AboutCtrl
 * @description
 * # AboutCtrl
 * Controller of the frontendApp
 */
angular.module('frontendApp')
  .controller('AboutCtrl', function () {
    this.awesomeThings = [
      'HTML5 Boilerplate',
      'AngularJS',
      'Karma'
    ];
  });
<commit_msg>equation<commit_after>'use strict';

/**
 * @ngdoc function
 * @name frontendApp.controller:AboutCtrl
 * @description
 * # AboutCtrl
 * Controller of the frontendApp
 */
angular.module('frontendApp')
  .controller('AboutCtrl', function () {
    this.awesomeThings = [
      'HTML5 Boilerplate',
      'AngularJS',
      'Karma'
    ];
    var damageIndex = parseInt(storm.direct_injuries) * 2 + parseInt(storm.indirect_injuries) * 2 +
      parseInt(storm.direct_deaths) * 5 + parseInt(storm.indirect_deaths) * 5 +
      parseFloat(storm.property_damage) * 1.5 + parseFloat(storm.crops_damage) * 2;
  });
<|endoftext|>


<commit_before>import React, {Component, PropTypes} from 'react';

import formatCurrency from '../lib/format_currency';
import { resizeImage, getGroupCustomStyles } from '../lib/utils';

const DEFAULT_LOGOS = [
  '/static/images/code.svg',
  '/static/images/rocket.svg',
  '/static/images/repo.svg',
];

export default class CollectiveCard extends Component {

  constructor(props) {
    super(props);
  }

  mapCollectiveCardProps() {
    const { i18n, group } = this.props;

    const stats = [];
    if (group.contributorsCount)
      stats.push({ label: i18n.getString('coreContributors'), value: group.contributorsCount});
    else if (group.membersCount) {
      stats.push({ label: i18n.getString('members'), value: group.membersCount });
    }

    if (group.backersAndSponsorsCount) {
      stats.push({ label: i18n.getString('backers'), value: group.backersAndSponsorsCount });
    }

    stats.push({ label: i18n.getString('annualIncome'), value: formatCurrency(group.yearlyIncome/100, group.currency, { compact: true, precision: 0 }) });
    return stats;
  }

  mapCollectiveCardOnProfileProps() {
    const { group, i18n } = this.props;
    const stats = [];
    stats.push({label: i18n.getString('backers'), value: group.backersCount});
    stats.push({label: i18n.getString('sponsors'), value: group.sponsorsCount});
    stats.push({label: i18n.getString('annualIncome'), value: formatCurrency(group.yearlyIncome/100, group.currency, { compact: true, precision: 0 })});
    return stats;
  }

  mapSponsorsCardProps() {
    const { collectives, totalDonations, currency } = this.props;

    const stats = [
      {
        label: ' ',
        value: ' '
      },{
        label: 'collectives',
        value: collectives
      },{
        label: 'donations',
        value: formatCurrency(totalDonations, currency, { compact: true, precision: 0 })
      }];
    return stats;
  }

  render() {
    const { i18n, key, group } = this.props;

    const {
      backgroundImage,
      logo,
      name,
      description,
      mission,
      publicUrl,
      isSponsor,
      isCollectiveOnProfile
    } = this.props.group;

    let stats = [];
    let className = '';

    if (isSponsor) {
      className = 'sponsor';
      stats = this.mapSponsorsCardProps();
    } else if (isCollectiveOnProfile) {
      stats = this.mapCollectiveCardOnProfileProps();
    } else {
      stats = this.mapCollectiveCardProps();
    }

    group.settings = group.settings || {};
    group.settings.style = getGroupCustomStyles(group);
    if (backgroundImage) {
      group.settings.style.hero.cover.backgroundImage = `url(${resizeImage(backgroundImage, { width: 320 })})`;
    }

    return (
      <div className={`CollectiveCard ${className}`}>

              <div className='CollectiveCard-image' style={{backgroundImage: `url(${logo || DEFAULT_LOGOS[key%DEFAULT_LOGOS.length]})`}}>

{name}

{i18n.getString('missionTo')} {mission || description}

              { stats.map((stat) =>
                <div key={stat.label} className={`col col-${12/(stats.length||1)}`}>

{stat.value}

{stat.label}

              ) }

    );
  }

}

CollectiveCard.propTypes = {
  name: PropTypes.string.isRequired,
  description: PropTypes.string,
  logo: PropTypes.string,
  url: PropTypes.string
};
<commit_msg>fix sponsors on collective-card (#524)<commit_after>import React, {Component, PropTypes} from 'react';

import formatCurrency from '../lib/format_currency';
import { resizeImage, getGroupCustomStyles } from '../lib/utils';

const DEFAULT_LOGOS = [
  '/static/images/code.svg',
  '/static/images/rocket.svg',
  '/static/images/repo.svg',
];

export default class CollectiveCard extends Component {

  constructor(props) {
    super(props);
  }

  mapCollectiveCardProps() {
    const { i18n, group } = this.props;

    const stats = [];
    if (group.contributorsCount)
      stats.push({ label: i18n.getString('coreContributors'), value: group.contributorsCount});
    else if (group.membersCount) {
      stats.push({ label: i18n.getString('members'), value: group.membersCount });
    }

    if (group.backersAndSponsorsCount) {
      stats.push({ label: i18n.getString('backers'), value: group.backersAndSponsorsCount });
    }

    stats.push({ label: i18n.getString('annualIncome'), value: formatCurrency(group.yearlyIncome/100, group.currency, { compact: true, precision: 0 }) });
    return stats;
  }

  mapCollectiveCardOnProfileProps() {
    const { group, i18n } = this.props;
    const stats = [];
    stats.push({label: i18n.getString('backers'), value: group.backersCount});
    stats.push({label: i18n.getString('sponsors'), value: group.sponsorsCount});
    stats.push({label: i18n.getString('annualIncome'), value: formatCurrency(group.yearlyIncome/100, group.currency, { compact: true, precision: 0 })});
    return stats;
  }

  mapSponsorsCardProps() {
    const { collectives, totalDonations, currency } = this.props.group;

    const stats = [
      {
        label: ' ',
        value: ' '
      },{
        label: 'collectives',
        value: collectives
      },{
        label: 'donations',
        value: formatCurrency(totalDonations, currency, { compact: true, precision: 0 })
      }];
    return stats;
  }

  render() {
    const { i18n, key, group, isSponsor } = this.props;

    const {
      backgroundImage,
      logo,
      name,
      description,
      mission,
      publicUrl,
      isCollectiveOnProfile
    } = this.props.group;

    let stats = [];
    let className = '';

    if (isSponsor) {
      className = 'sponsor';
      stats = this.mapSponsorsCardProps();
    } else if (isCollectiveOnProfile) {
      stats = this.mapCollectiveCardOnProfileProps();
    } else {
      stats = this.mapCollectiveCardProps();
    }

    group.settings = group.settings || {};
    group.settings.style = getGroupCustomStyles(group);
    if (backgroundImage) {
      group.settings.style.hero.cover.backgroundImage = `url(${resizeImage(backgroundImage, { width: 320 })})`;
    }

    return (
      <div className={`CollectiveCard ${className}`}>

              <div className='CollectiveCard-image' style={{backgroundImage: `url(${logo || DEFAULT_LOGOS[key%DEFAULT_LOGOS.length]})`}}>

{name}

{i18n.getString('missionTo')} {mission || description}

              { stats.map((stat) =>
                <div key={stat.label} className={`col col-${12/(stats.length||1)}`}>

{stat.value}

{stat.label}

              ) }

    );
  }

}

CollectiveCard.propTypes = {
  name: PropTypes.string.isRequired,
  description: PropTypes.string,
  logo: PropTypes.string,
  url: PropTypes.string
};
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { withRouter } from 'react-router-dom'
import { injectIntl, defineMessages, FormattedMessage } from 'react-intl'

import Paper from 'material-ui/Paper'
import Typography from 'material-ui/Typography'
import AppBar from 'material-ui/AppBar'

import Card from 'material-ui/Card'
import CardActions from 'material-ui/Card/CardActions'
import CardContent from 'material-ui/Card/CardContent'
import CardMedia from 'material-ui/Card/CardMedia'

import Tabs, { Tab } from 'material-ui/Tabs'

import { withStyles } from 'material-ui/styles'

import RedeemIcon from 'material-ui-icons/Redeem'
import ShoppingBasket from 'material-ui-icons/ShoppingBasket'

import AssignIcon from 'material-ui-icons/Assignment'
import ActionIcon from 'material-ui-icons/CallToAction'

import CustomPaginationActionsTable from './task-table'
import TaskStatusFilter from './task-status-filter'
import Button from 'material-ui/Button'

const logoGithub = require('../../images/github-logo.png')
const logoBitbucket = require('../../images/bitbucket-logo.png')

const imageGettingStarted = require('../../images/octodex.png')

import api from '../../consts'

const styles = theme => ({
  icon: {
    backgroundColor: 'black'
  },
  card: {},
  gutterLeft: {
    marginLeft: 10
  },
  media: {
    width: 600
  },
  rootTabs: {
    backgroundColor: theme.palette.primary.light
  }
})

const messages = defineMessages({
  allTasks: {
    id: 'task.list.lable.allTasks',
    defaultMessage: 'All tasks'
  },
  createdByMeTasks: {
    id: 'task.status.createdByMe',
    defaultMessage: 'Created by me'
  },
  interestedTasks: {
    id: 'tasks.status.interested',
    defaultMessage: 'I\'m interested'
  },
  assignedToMeTasks: {
    id: 'task.status.assigned',
    defaultMessage: 'Assigned to me'
  }
})

class TaskList extends Component {
  constructor (props) {
    super(props)
    this.state = {
      tab: 0,
      loading: true
    }
  }

  componentDidMount () {
    this.props.listTasks().then(t => {
      let pathName = this.props.history.location.pathname
      this.handleRoutePath(pathName)
      this.setState({ loading: false })
    })
  }

  handleRoutePath = (path) => {
    switch (path) {
      case '/tasks/explore':
        this.handleTabChange(0, 0)
        break
      case '/tasks/createdbyme':
        this.handleTabChange(0, 1)
        break
      case '/tasks/interested':
        this.handleTabChange(0, 2)
        break
      case '/tasks/assignedtome':
        this.handleTabChange(0, 3)
        break
      default:
        // this.props.filterTasks()
    }
  }

  handleTabChange = (event, value) => {
    this.setState({ tab: value })
    switch (value) {
      case 0:
        this.props.history.push('/tasks/explore')
        this.props.filterTasks('open')
        break
      case 1:
        this.props.history.push('/tasks/createdbyme')
        this.props.filterTasks('userId')
        break
      case 2:
        this.props.history.push('/tasks/interested')
        this.props.filterTasks('Assigns')
        break
      case 3:
        this.props.history.push('/tasks/assignedtome')
        this.props.filterTasks('assigned')
        break
      default:
        // this.props.filterTasks()
    }
  }

  render () {
    const { classes, user } = this.props

    const TabContainer = props => {
      return (
        <Typography component='div' style={ { padding: 8 * 3 } }>
          { props.children }
        </Typography>
      )
    }

    return (
      <Paper elevation={ 0 }>
        <Typography variant='headline' component='h2'>
          <FormattedMessage
            id='task.list.headline'
            defaultMessage='Task list'
          />
        </Typography>
        <Typography component='p' style={ { marginBottom: 20 } }>
          <FormattedMessage
            id='task.list.description'
            defaultMessage='Available tasks for development'
          />
        </Typography>

          <TaskStatusFilter onFilter={ this.props.filterTasks } loading={ this.state.loading } />

          <AppBar position='static' color='default'>
            <Tabs
              value={ this.state.tab }
              onChange={ this.handleTabChange }
              scrollable
              scrollButtons='on'
              indicatorColor='primary'
              textColor='primary'
            >
              <Tab
                value={ 0 }
                label={ this.props.intl.formatMessage(messages.allTasks) }
                icon={ <RedeemIcon /> }
              />
              <Tab
                value={ 1 }
                label={ this.props.intl.formatMessage(messages.createdByMeTasks) }
                icon={ <ShoppingBasket /> }
              />
              <Tab
                value={ 2 }
                label={ this.props.intl.formatMessage(messages.interestedTasks) }
                icon={ <AssignIcon /> }
              />
              <Tab
                value={ 3 }
                label={ this.props.intl.formatMessage(
                  messages.assignedToMeTasks
                ) }
                icon={ <ActionIcon /> }
              />
            </Tabs>
          </AppBar>
          <TabContainer>
            { !user.id && this.state.tab !== 0 ? (
              <Card className={ classes.card }>
                <CardMedia
                  className={ classes.media }
                  src={ imageGettingStarted }
                  title='Teste'
                />
                <CardContent>
                  <Typography gutterBottom variant='headline' component='h2'>
                    <FormattedMessage
                      id='task.user.account.create.headline'
                      defaultMessage='Login / signup to work in our tasks'
                    />
                    ,
                  </Typography>
                  <Typography component='p'>
                    <FormattedMessage
                      id='task.user.account.create.description'
                      defaultMessage='Creating your account, you can be assigned to a task and receive bounties'
                    />
                    ,
                  </Typography>
                </CardContent>
                <CardActions>
                  <Button
                    style={ { marginRight: 10 } }
                    href={ `${api.API_URL}/authorize/github` }
                    variant='raised'
                    size='small'
                    color='secondary'
                    className={ classes.logButtons }
                  >

                    Github
                  </Button>

                  <Button
                    href={ `${api.API_URL}/authorize/bitbucket` }
                    variant='raised'
                    size='small'
                    color='secondary'
                    className={ classes.logButtons }
                  >

                    Bitbucket
                  </Button>
                </CardActions>
              </Card>
            ) : (
              <CustomPaginationActionsTable tasks={ this.props.tasks } />
            ) }
          </TabContainer>

      </Paper>
    )
  }
}

TaskList.propTypes = {
  classes: PropTypes.object.isRequired,
  listTasks: PropTypes.func,
  filterTasks: PropTypes.func,
  tasks: PropTypes.object,
  user: PropTypes.object
}

export default injectIntl(withRouter(withStyles(styles)(TaskList)))
<commit_msg>fixing merge of claudio changes about the task filter router (#315)<commit_after>import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { withRouter } from 'react-router-dom'
import { injectIntl, defineMessages, FormattedMessage } from 'react-intl'

import Paper from 'material-ui/Paper'
import Typography from 'material-ui/Typography'
import AppBar from 'material-ui/AppBar'

import Card from 'material-ui/Card'
import CardActions from 'material-ui/Card/CardActions'
import CardContent from 'material-ui/Card/CardContent'
import CardMedia from 'material-ui/Card/CardMedia'

import Tabs, { Tab } from 'material-ui/Tabs'

import { withStyles } from 'material-ui/styles'

import RedeemIcon from 'material-ui-icons/Redeem'
import ShoppingBasket from 'material-ui-icons/ShoppingBasket'

import AssignIcon from 'material-ui-icons/Assignment'
import ActionIcon from 'material-ui-icons/CallToAction'

import CustomPaginationActionsTable from './task-table'
import TaskStatusFilter from './task-status-filter'
import Button from 'material-ui/Button'

const logoGithub = require('../../images/github-logo.png')
const logoBitbucket = require('../../images/bitbucket-logo.png')

const imageGettingStarted = require('../../images/octodex.png')

import api from '../../consts'

const styles = theme => ({
  icon: {
    backgroundColor: 'black'
  },
  card: {},
  gutterLeft: {
    marginLeft: 10
  },
  media: {
    width: 600
  },
  rootTabs: {
    backgroundColor: theme.palette.primary.light
  }
})

const messages = defineMessages({
  allTasks: {
    id: 'task.list.lable.allTasks',
    defaultMessage: 'All tasks'
  },
  createdByMeTasks: {
    id: 'task.status.createdByMe',
    defaultMessage: 'Created by me'
  },
  interestedTasks: {
    id: 'tasks.status.interested',
    defaultMessage: 'I\'m interested'
  },
  assignedToMeTasks: {
    id: 'task.status.assigned',
    defaultMessage: 'Assigned to me'
  }
})

class TaskList extends Component {
  constructor (props) {
    super(props)
    this.state = {
      tab: 0,
      loading: true
    }
  }

  componentDidMount () {
    this.props.listTasks().then(t => {
      let pathName = this.props.history.location.pathname
      this.handleRoutePath(pathName)
      this.setState({ loading: false })
    })
  }

  handleRoutePath = (path) => {
    switch (path) {
      case '/tasks/explore':
        this.handleTabChange(0, 0)
        break
      case '/tasks/createdbyme':
        this.handleTabChange(0, 1)
        break
      case '/tasks/interested':
        this.handleTabChange(0, 2)
        break
      case '/tasks/assignedtome':
        this.handleTabChange(0, 3)
        break
      default:
        // this.props.filterTasks()
    }
  }

  handleTabChange = (event, value) => {
    this.setState({ tab: value })
    Promise.all([this.props.listTasks()]).then(() => {
      this.props.filterTasks('Assigns')

      switch (value) {
        case 0:
          this.props.filterTasks()
          this.props.history.push('/tasks/explore')
          break
        case 1:
          this.props.filterTasks('userId')
          this.props.history.push('/tasks/createdbyme')
          break
        case 2:
          this.props.filterTasks('Assigns')
          this.props.history.push('/tasks/interested')
          break
        case 3:
          this.props.filterTasks('assigned')
          this.props.history.push('/tasks/assignedtome')
          break
        default:
          this.props.filterTasks()
      }
    })
  }

  render () {
    const { classes, user } = this.props
    const TabContainer = props => {
      return (
        <Typography component='div' style={ { padding: 8 * 3 } }>
          { props.children }
        </Typography>
      )
    }

    return (
      <Paper elevation={ 0 }>
        <Typography variant='headline' component='h2'>
          <FormattedMessage
            id='task.list.headline'
            defaultMessage='Task list'
          />
        </Typography>
        <Typography component='p' style={ { marginBottom: 20 } }>
          <FormattedMessage
            id='task.list.description'
            defaultMessage='Available tasks for development'
          />
        </Typography>

          <TaskStatusFilter onFilter={ this.props.filterTasks } loading={ this.state.loading } />

          <AppBar position='static' color='default'>
            <Tabs
              value={ this.state.tab }
              onChange={ this.handleTabChange }
              scrollable
              scrollButtons='on'
              indicatorColor='primary'
              textColor='primary'
            >
              <Tab
                value={ 0 }
                label={ this.props.intl.formatMessage(messages.allTasks) }
                icon={ <RedeemIcon /> }
              />
              <Tab
                value={ 1 }
                label={ this.props.intl.formatMessage(messages.createdByMeTasks) }
                icon={ <ShoppingBasket /> }
              />
              <Tab
                value={ 2 }
                label={ this.props.intl.formatMessage(messages.interestedTasks) }
                icon={ <AssignIcon /> }
              />
              <Tab
                value={ 3 }
                label={ this.props.intl.formatMessage(
                  messages.assignedToMeTasks
                ) }
                icon={ <ActionIcon /> }
              />
            </Tabs>
          </AppBar>
          <TabContainer>
            { !user.id && this.state.tab !== 0 ? (
              <Card className={ classes.card }>
                <CardMedia
                  className={ classes.media }
                  src={ imageGettingStarted }
                  title='Teste'
                />
                <CardContent>
                  <Typography gutterBottom variant='headline' component='h2'>
                    <FormattedMessage
                      id='task.user.account.create.headline'
                      defaultMessage='Login / signup to work in our tasks'
                    />
                    ,
                  </Typography>
                  <Typography component='p'>
                    <FormattedMessage
                      id='task.user.account.create.description'
                      defaultMessage='Creating your account, you can be assigned to a task and receive bounties'
                    />
                    ,
                  </Typography>
                </CardContent>
                <CardActions>
                  <Button
                    style={ { marginRight: 10 } }
                    href={ `${api.API_URL}/authorize/github` }
                    variant='raised'
                    size='small'
                    color='secondary'
                    className={ classes.logButtons }
                  >

                    Github
                  </Button>

                  <Button
                    href={ `${api.API_URL}/authorize/bitbucket` }
                    variant='raised'
                    size='small'
                    color='secondary'
                    className={ classes.logButtons }
                  >

                    Bitbucket
                  </Button>
                </CardActions>
              </Card>
            ) : (
              <CustomPaginationActionsTable tasks={ this.props.tasks } />
            ) }
          </TabContainer>

      </Paper>
    )
  }
}

TaskList.propTypes = {
  classes: PropTypes.object.isRequired,
  listTasks: PropTypes.func,
  filterTasks: PropTypes.func,
  tasks: PropTypes.object,
  user: PropTypes.object
}

export default injectIntl(withRouter(withStyles(styles)(TaskList)))
<|endoftext|>


<commit_before>import React from 'react';
import ReactTooltip from 'react-tooltip';
import { Glyphicon } from 'react-bootstrap';

const clientStatusTextColor = {
    xcomplete: 'text-success',
    xrunning: 'text-info',
    xlost: 'text-warning',
    xfailed: 'text-danger',
};

const clientStatusIcon = {
    complete: <Glyphicon glyph="ok" />,
    running: <Glyphicon glyph="cog" />,
    lost: <Glyphicon glyph="remove" />,
    failed: <Glyphicon glyph="exclamation-sign" />,
};

export function renderDesiredStatus(allocation) {
    if (allocation.DesiredDescription) {
        return (

            <ReactTooltip id={ `tooltip-${allocation.ID}` }>{allocation.DesiredDescription}</ReactTooltip>
            <span data-tip data-for={ `tooltip-${allocation.ID}` } className="dotted">
              {allocation.DesiredStatus}

        );
    }

    return
{allocation.DesiredStatus}
;
}

export function renderClientStatus(allocation) {
    let textColor = null;
    let icon = null;

    if (allocation.ClientStatus in clientStatusTextColor) {
        textColor = clientStatusTextColor[allocation.ClientStatus];
    }

    if (allocation.ClientStatus in clientStatusIcon) {
        icon = clientStatusIcon[allocation.ClientStatus];
    }

    return {icon} {allocation.ClientStatus};
}
<commit_msg>change allocation status into icon only with tooltip<commit_after>import React from 'react';
import ReactTooltip from 'react-tooltip';
import { Glyphicon } from 'react-bootstrap';

const clientStatusTextColor = {
    xcomplete: 'text-success',
    xrunning: 'text-info',
    xlost: 'text-warning',
    xfailed: 'text-danger',
};

const clientStatusIcon = {
    complete: <Glyphicon glyph="ok" />,
    running: <Glyphicon glyph="cog" />,
    lost: <Glyphicon glyph="remove" />,
    failed: <Glyphicon glyph="exclamation-sign" />,
};

export function renderDesiredStatus(allocation) {
    if (allocation.DesiredDescription) {
        return (

            <ReactTooltip id={ `tooltip-${allocation.ID}` }>{allocation.DesiredDescription}</ReactTooltip>
            <span data-tip data-for={ `tooltip-${allocation.ID}` } className="dotted">
              {allocation.DesiredStatus}

        );
    }

    return
{allocation.DesiredStatus}
;
}

export function renderClientStatus(allocation) {
    let textColor = null;
    let icon = null;

    if (allocation.ClientStatus in clientStatusTextColor) {
        textColor = clientStatusTextColor[allocation.ClientStatus];
    }

    if (allocation.ClientStatus in clientStatusIcon) {
        icon = clientStatusIcon[allocation.ClientStatus];
    }

    return (

        <ReactTooltip id={ `client-status-${allocation.ID}` }>{allocation.ClientStatus}</ReactTooltip>
        <span data-tip data-for={ `client-status-${allocation.ID}` } className={ textColor }>{icon}

    );
}
<|endoftext|>