<commit_before>var representatives = {};
var lists = {};
var results = {};
var votes = {};
var projectData = {};

var projects = [
	'ley-26331',
	'ley-26425',
	'ley-26522',
	'ley-26571',
	'ley-26618',
	'ley-26637',
	'ley-26639',
	'ley-26649',
	'ley-26728',
	'ley-26729',
	'ley-26734',
	'ley-26736',
	'ley-26737',
	'ley-26739',
	'ley-26740',
	'ley-26741',
	'ley-26743',
	'ley-26761',
	'ley-26764',
	'ley-26773',
	'ley-26774',
	'ley-26784',
	'ley-26790',
	'ley-26831',
	'ley-26842',
	'ley-26843',
	'ley-26844',
	'ley-26853',
	'ley-26854',
	'ley-26855',
	'ley-26860',
	'proyecto-res-125'
];

function reset() {
	results = {};
	votes = {};
	$('#intro').css('display', 'block');
	$('#about').css('display', 'none');
	$('#voting').css('display', 'none');
	$('#results').css('display', 'none');

	$('#district').val('');
	$('#lists').empty();
}

function saveResults(items) {
	$.each(items, function (i, li) {
		var id = slugify(li.innerText);
		if (representatives[id]) {
			results[id] = representatives[id];
		}
	});
}

function showLists(district, house, callback) {
	var selectedLists = lists[district][house];
	if (!selectedLists) {
		showResults();
	}
	var root = $('#lists');
	root.empty();
	for (var i = 0; i < selectedLists.length; i++) {
		var list = selectedLists[i];
		var p = $(document.createElement('p')).text(list['lista']);
		var ol = $(document.createElement('ol'));
		for (var j = 0; j < list['candidatos'].length; j++) {
			var name = list['candidatos'][j];
			var li = $(document.createElement('li')).text(name);
			ol.append(li);
		}
		var li = $(document.createElement('li'));
		li.append(p).append(ol).addClass('list').click(callback);
		root.append(li);
	}
}

function showHouseLists(e) {
	var d = $('#district').val();
	if (!d) return;
	$('#selected-district').text(d);
	$('#intro').fadeOut(200, function () {
		$('#selected-house').text('Diputados Nacionales');
		showLists(d, 'Diputados', showSenateLists);
		$('#voting').fadeIn(100);
	});
}

function showSenateLists(e) {
	if (!e) showResults();
	var items = $(e.delegateTarget).find('li');
	saveResults(items);
	$('#voting').fadeOut(200, function () {
		$('#selected-house').text('Senadores Nacionales');
		showLists($('#district').val(), 'Senado', showResults);
		$('#voting').fadeIn(100);
	});
}

function showResults(e) {
	if (e) {
		var items = $(e.delegateTarget).find('li');
		saveResults(items);
	}
	$('#voting').stop(true);
	$('#voting').fadeOut(200, function () {
		$('#projects').empty();
		var n = 0;
		for (var i = 0; i < projects.length; i++) {
			var p = projectData[projects[i]];
			n += (printProjectResult(p) ? 1 : 0);
		}
		$(n ? '#available-notice' : '#not-available-notice').show();
		$(n ? '#not-available-notice' : '#available-notice').hide();
		$('#results').fadeIn(100);
	});
}

function printProjectResult(project) {
	var ul = $(document.createElement('ul'));
	var isValid = false;
	var votes = ['AFIRMATIVO', 'NEGATIVO', 'ABSTENCION', 'AUSENTE'];
	for (var i in results) {
		for (var j = 0; j < votes.length; j++) {
			var v = votes[j];
			var voters = project.votacion[v];
			if (voters && voters.indexOf(i) != -1) {
				isValid = true;
				var e = $(document.createElement('li'));
				var s = $(document.createElement('span'));
				s.text(votes[j]).addClass(v.toLowerCase());
				var t = $(document.createElement('span'));
				t.text(representatives[i].nombre);
				ul.append(e.append(s).append(t));
			}
		}
	}
	if (!isValid) return false;
	var li = $(document.createElement('li'));
	var p = $(document.createElement('p'));
	var a = $(document.createElement('a')).text(project.nombre)
		.attr({'href': project.url, 'target': '_blank'})				.css({'font-weight': 'bold'});
	var sub = $(document.createElement('p')).text(project.sumario)
		.addClass('shady');
	li.append(p.append(a)).append(sub).append(ul);
	$('#projects').append(li);
	return true;
}

function shareOnFacebook() {
	window.open('https://www.facebook.com/sharer/sharer.php?u='
		+ encodeURIComponent(location.href),
		'facebook-share-dialog', 'width=626,height=436');
}

function shareOnTwitter() {
	var tweet = '\u00bfNo sab\u00e9s a qui\u00e9n votar? '
		+ 'Prob\u00e1 este juego para elegir legisladores '
		+ 'que votan como vos: ';
	window.open('http://twitter.com/intent/tweet?text='
		+ encodeURIComponent(tweet) + '&url='
		+ encodeURIComponent(location.href)
		+ '&hashtags=opengov,elegilegi',
		'twitter-share-dialog', 'width=550,height=420');
}

function shareOnGooglePlus() {
	window.open('https://plus.google.com/share?url='
		+ encodeURIComponent(location.href),
		'google-share-dialog', 'width=600,height=600');
}

$(document).ready(function () {
	$(document).ajaxError(function (evnt, jqxhr, options, e) {
		alert('Error al cargar datos de: ' + options.url
			+ '\n\n' + JSON.stringify(jqxhr, null, 2)
			+ '\n\nPor favor, recarg\u00e1 la p\u00e1gina.');
	});

	$.each(projects, function (i, id) {
		$.getJSON('../data/' + id + '.json', function (data) {
			projectData[id] = data;
		});
	});

	$.getJSON('../data/legisladores.json', function (data) {
		representatives = data;
	});

	$.getJSON('listas.json', function (data) {
		lists = data;
		$('#start').click(showHouseLists);
	});

	$('.facebook').click(shareOnFacebook);
	$('.twitter').click(shareOnTwitter);
	$('.googleplus').click(shareOnGooglePlus);

	$('#info').click(function () { $('#about').slideToggle(500); });
	$('#back').click(function () { $('#about').slideToggle(500); });
	$('#reset').click(reset);
	reset();
});

var stripAccents = (function () {
  var in_chrs   = '\u00e0\u00e1\u00e2\u00e3\u00e4\u00e7\u00e8\u00e9\u00ea\u00eb\u00ec\u00ed\u00ee\u00ef\u00f1\u00f2\u00f3\u00f4\u00f5\u00f6\u00f9\u00fa\u00fb\u00fc\u00fd\u00ff\u00c0\u00c1\u00c2\u00c3\u00c4\u00c7\u00c8\u00c9\u00ca\u00cb\u00cc\u00cd\u00ce\u00cf\u00d1\u00d2\u00d3\u00d4\u00d5\u00d6\u00d9\u00da\u00db\u00dc\u00dd',
  //  in_chrs   = 'àáâãäçèéêëìíîïñòóôõöùúûüýÿÀÁÂÃÄÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝ',
      out_chrs  = 'aaaaaceeeeiiiinooooouuuuyyAAAAACEEEEIIIINOOOOOUUUUY',
      chars_rgx = new RegExp('[' + in_chrs + ']', 'g'),
      transl    = {},
      lookup    = function (m) { return transl[m] || m; };

  for (var i = 0; i < in_chrs.length; i++) {
    transl[in_chrs[i]] = out_chrs[i];
  }

  return function (s) { return s.replace(chars_rgx, lookup); }
})();

var slugify = function (s) {
	s = stripAccents(s).replace(/[^\w\s-]/g, ''); // normalize chars
	s = s.replace(/^\s+|\s+$/g, '').toLowerCase(); // trim and lower
	return s.replace(/[-\s]+/g, '-'); // join slug words
};

<commit_msg>Fixed DOM compatibility for Firefox<commit_after>var representatives = {};
var lists = {};
var results = {};
var votes = {};
var projectData = {};

var projects = [
	'ley-26331',
	'ley-26425',
	'ley-26522',
	'ley-26571',
	'ley-26618',
	'ley-26637',
	'ley-26639',
	'ley-26649',
	'ley-26728',
	'ley-26729',
	'ley-26734',
	'ley-26736',
	'ley-26737',
	'ley-26739',
	'ley-26740',
	'ley-26741',
	'ley-26743',
	'ley-26761',
	'ley-26764',
	'ley-26773',
	'ley-26774',
	'ley-26784',
	'ley-26790',
	'ley-26831',
	'ley-26842',
	'ley-26843',
	'ley-26844',
	'ley-26853',
	'ley-26854',
	'ley-26855',
	'ley-26860',
	'proyecto-res-125'
];

function reset() {
	results = {};
	votes = {};
	$('#intro').css('display', 'block');
	$('#about').css('display', 'none');
	$('#voting').css('display', 'none');
	$('#results').css('display', 'none');

	$('#district').val('');
	$('#lists').empty();
}

function saveResults(items) {
	$.each(items, function (i, li) {
		var id = slugify($(li).text());
		if (representatives[id]) {
			results[id] = representatives[id];
		}
	});
}

function showLists(district, house, callback) {
	var selectedLists = lists[district][house];
	if (!selectedLists) {
		showResults();
	}
	var root = $('#lists');
	root.empty();
	for (var i = 0; i < selectedLists.length; i++) {
		var list = selectedLists[i];
		var p = $(document.createElement('p')).text(list['lista']);
		var ol = $(document.createElement('ol'));
		for (var j = 0; j < list['candidatos'].length; j++) {
			var name = list['candidatos'][j];
			var li = $(document.createElement('li')).text(name);
			ol.append(li);
		}
		var li = $(document.createElement('li'));
		li.append(p).append(ol).addClass('list').click(callback);
		root.append(li);
	}
}

function showHouseLists(e) {
	var d = $('#district').val();
	if (!d) return;
	$('#selected-district').text(d);
	$('#intro').fadeOut(200, function () {
		$('#selected-house').text('Diputados Nacionales');
		showLists(d, 'Diputados', showSenateLists);
		$('#voting').fadeIn(100);
	});
}

function showSenateLists(e) {
	if (!e) showResults();
	var items = $(e.delegateTarget).find('li');
	saveResults(items);
	$('#voting').fadeOut(200, function () {
		$('#selected-house').text('Senadores Nacionales');
		showLists($('#district').val(), 'Senado', showResults);
		$('#voting').fadeIn(100);
	});
}

function showResults(e) {
	if (e) {
		var items = $(e.delegateTarget).find('li');
		saveResults(items);
	}
	$('#voting').stop(true);
	$('#voting').fadeOut(200, function () {
		$('#projects').empty();
		var n = 0;
		for (var i = 0; i < projects.length; i++) {
			var p = projectData[projects[i]];
			n += (printProjectResult(p) ? 1 : 0);
		}
		$(n ? '#available-notice' : '#not-available-notice').show();
		$(n ? '#not-available-notice' : '#available-notice').hide();
		$('#results').fadeIn(100);
	});
}

function printProjectResult(project) {
	var ul = $(document.createElement('ul'));
	var isValid = false;
	var votes = ['AFIRMATIVO', 'NEGATIVO', 'ABSTENCION', 'AUSENTE'];
	for (var i in results) {
		for (var j = 0; j < votes.length; j++) {
			var v = votes[j];
			var voters = project.votacion[v];
			if (voters && voters.indexOf(i) != -1) {
				isValid = true;
				var e = $(document.createElement('li'));
				var s = $(document.createElement('span'));
				s.text(votes[j]).addClass(v.toLowerCase());
				var t = $(document.createElement('span'));
				t.text(representatives[i].nombre);
				ul.append(e.append(s).append(t));
			}
		}
	}
	if (!isValid) return false;
	var li = $(document.createElement('li'));
	var p = $(document.createElement('p'));
	var a = $(document.createElement('a')).text(project.nombre)
		.attr({'href': project.url, 'target': '_blank'})				.css({'font-weight': 'bold'});
	var sub = $(document.createElement('p')).text(project.sumario)
		.addClass('shady');
	li.append(p.append(a)).append(sub).append(ul);
	$('#projects').append(li);
	return true;
}

function shareOnFacebook() {
	window.open('https://www.facebook.com/sharer/sharer.php?u='
		+ encodeURIComponent(location.href),
		'facebook-share-dialog', 'width=626,height=436');
}

function shareOnTwitter() {
	var tweet = '\u00bfNo sab\u00e9s a qui\u00e9n votar? '
		+ 'Prob\u00e1 este juego para elegir legisladores '
		+ 'que votan como vos: ';
	window.open('http://twitter.com/intent/tweet?text='
		+ encodeURIComponent(tweet) + '&url='
		+ encodeURIComponent(location.href)
		+ '&hashtags=opengov,elegilegi',
		'twitter-share-dialog', 'width=550,height=420');
}

function shareOnGooglePlus() {
	window.open('https://plus.google.com/share?url='
		+ encodeURIComponent(location.href),
		'google-share-dialog', 'width=600,height=600');
}

$(document).ready(function () {
	$(document).ajaxError(function (evnt, jqxhr, options, e) {
		alert('Error al cargar datos de: ' + options.url
			+ '\n\n' + JSON.stringify(jqxhr, null, 2)
			+ '\n\nPor favor, recarg\u00e1 la p\u00e1gina.');
	});

	$.each(projects, function (i, id) {
		$.getJSON('../data/' + id + '.json', function (data) {
			projectData[id] = data;
		});
	});

	$.getJSON('../data/legisladores.json', function (data) {
		representatives = data;
	});

	$.getJSON('listas.json', function (data) {
		lists = data;
		$('#start').click(showHouseLists);
	});

	$('.facebook').click(shareOnFacebook);
	$('.twitter').click(shareOnTwitter);
	$('.googleplus').click(shareOnGooglePlus);

	$('#info').click(function () { $('#about').slideToggle(500); });
	$('#back').click(function () { $('#about').slideToggle(500); });
	$('#reset').click(reset);
	reset();
});

var stripAccents = (function () {
  var in_chrs   = '\u00e0\u00e1\u00e2\u00e3\u00e4\u00e7\u00e8\u00e9\u00ea\u00eb\u00ec\u00ed\u00ee\u00ef\u00f1\u00f2\u00f3\u00f4\u00f5\u00f6\u00f9\u00fa\u00fb\u00fc\u00fd\u00ff\u00c0\u00c1\u00c2\u00c3\u00c4\u00c7\u00c8\u00c9\u00ca\u00cb\u00cc\u00cd\u00ce\u00cf\u00d1\u00d2\u00d3\u00d4\u00d5\u00d6\u00d9\u00da\u00db\u00dc\u00dd',
  //  in_chrs   = 'àáâãäçèéêëìíîïñòóôõöùúûüýÿÀÁÂÃÄÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝ',
      out_chrs  = 'aaaaaceeeeiiiinooooouuuuyyAAAAACEEEEIIIINOOOOOUUUUY',
      chars_rgx = new RegExp('[' + in_chrs + ']', 'g'),
      transl    = {},
      lookup    = function (m) { return transl[m] || m; };

  for (var i = 0; i < in_chrs.length; i++) {
    transl[in_chrs[i]] = out_chrs[i];
  }

  return function (s) { return s.replace(chars_rgx, lookup); }
})();

var slugify = function (s) {
	s = stripAccents(s).replace(/[^\w\s-]/g, ''); // normalize chars
	s = s.replace(/^\s+|\s+$/g, '').toLowerCase(); // trim and lower
	return s.replace(/[-\s]+/g, '-'); // join slug words
};

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014-2015, Wanadev <http://www.wanadev.fr/>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright notice, this
 *     list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the documentation
 *     and/or other materials provided with the distribution.
 *   * Neither the name of Wanadev nor the names of its contributors may be used
 *     to endorse or promote products derived from this software without specific
 *     prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authored by: Fabien LOISON <https://github.com/flozz>
 */

/**
 * PhotonUI - Javascript Web User Interface.
 *
 * @module PhotonUI
 * @submodule Container
 * @namespace photonui
 */

var Helpers = require("../helpers.js");
var Widget = require("../widget.js");
var BaseIcon = require("../visual/baseicon.js");
var Container = require("./container.js");

/**
 * Tab Item.
 *
 *  wEvents:
 *
 *   * click:
 *     - description: called when the tab was clicked.
 *     - callback:    function(widget, event)
 *
 * @class TabItem
 * @constructor
 * @extends photonui.Container
 * @param {Object} params An object that can contain any property of the widget (optional).
 */
var TabItem = Container.$extend({

    // Constructor
    __init__: function (params) {
        this._registerWEvents(["click"]);
        this.$super(params);
        this._updateProperties(["title", "leftIconName", "rightIconName"]);

        this._bindEvent("tab-click", this.__html.tab, "click", this.__onClick.bind(this));
        this._update();
    },

    //////////////////////////////////////////
    // Properties and Accessors             //
    //////////////////////////////////////////

    // ====== Public properties ======

    /**
     * Tab title.
     *
     * @property title
     * @type String
     * @default "Tab"
     */
    _title: "Tab",

    getTitle: function () {
        return this._title;
    },

    setTitle: function (title) {
        this._title = title;
        Helpers.cleanNode(this.__html.title);
        this.__html.title.appendChild(document.createTextNode(title));
    },

    /**
     * Definie if the tabItem title is displayed or hidden.
     *
     * @property titleVisible
     * @type Boolean
     * @default true
     */
    _titleVisible: true,

    isTitleVisible: function () {
        return this._titleVisible;
    },

    setTitleVisible: function (titleVisible) {
        this._titleVisible = titleVisible;
        this._update();
    },

    /**
     * Html outer element of the widget (if any).
     *
     * @property html
     * @type HTMLElement
     * @default null
     * @readOnly
     */
    getHtml: function () {
        return this.__html.div;
    },

    /**
     * Tab Html element.
     *
     * @property tabHtml
     * @type HTMLElement
     * @default null
     * @readOnly
     */
    getTabHtml: function () {
        return this.__html.tab;
    },

    /**
     * HTML Element that contain the child widget HTML.
     *
     * @property containerNode
     * @type HTMLElement
     * @readOnly
     */
    getContainerNode: function () {
        return this.__html.div;
    },

    /**
     * Is the widget visible or hidden.
     *
     * @property visible
     * @type Boolean
     * @default false
     */
    _visible: false,

    setVisible: function (visible, noParent) {
        this.$super(visible);

        if (visible) {
            if (this.parent) {
                var children = this.parent.children;
                for (var i = 0 ; i < children.length ; i++) {
                    if (!(children[i] instanceof TabItem)) {
                        continue;
                    }
                    if (children[i] === this) {
                        continue;
                    }
                    if (children[i].visible) {
                        children[i].setVisible(false, true);
                    }
                }
                this.parent._activeTabName = this.name;
            }

            this.addClass("photonui-tabitem-active");
            this.__html.tab.className = "photonui-tabitem-tab photonui-tabitem-active";
        } else {
            if (this.parent && !noParent) {
                this.parent.activeTab = null;
            }
            this.removeClass("photonui-tabitem-active");
            this.__html.tab.className = "photonui-tabitem-tab";
        }
    },

    /**
        * Left icon widget name
        *
        * @property leftIconName
        * @type String
        * @default null
        */
    _leftIconName: null,

    getLeftIconName: function () {
        return this._leftIconName;
    },

    setLeftIconName: function (leftIconName) {
        this._leftIconName = leftIconName;
        Helpers.cleanNode(this.__html.leftIcon);
        if (this._leftIconName) {
            this.__html.leftIcon.appendChild(this.leftIcon.html);
            this.leftIconVisible = true;
        }
    },

    /**
    * Left icon widget
    *
    * @property leftIcon
    * @type FAIcon
    * @default null
    */
    getLeftIcon: function () {
        return Widget.getWidget(this._leftIconName);
    },

    setLeftIcon: function (leftIcon) {
        if (leftIcon instanceof BaseIcon) {
            this.leftIconName = leftIcon.name;
        } else {
            this.leftIconName = null;
        }
    },

    /**
     * Define if the left icon is displayed or hidden.
     *
     * @property leftIconVisible
     * @type Boolean
     * @default true
     */
    _leftIconVisible: true,

    isLeftIconVisible: function () {
        return this._leftIconVisible;
    },

    setLeftIconVisible: function (leftIconVisible) {
        this._leftIconVisible = leftIconVisible;
        this._update();
    },

    /**
     * Right icon widget name
     *
     * @property rigthIconName
     * @type String
     * @default null
     */

    _rightIconName: null,

    getRightIconName: function () {
        return this._rightIconName;
    },

    setRightIconName: function (rightIconName) {
        this._rightIconName = rightIconName;
        Helpers.cleanNode(this.__html.rightIcon);
        if (this._rightIconName) {
            this.__html.rightIcon.appendChild(this.rightIcon.html);
            this.rightIconVisible = true;
        }
    },

    /**
     * Right icon widget
     *
     * @property rightIcon
     * @type FAIcon
     * @default null
     */
    getRightIcon: function () {
        return Widget.getWidget(this._rightIconName);
    },

    setRightIcon: function (rightIcon) {
        if (rightIcon instanceof BaseIcon) {
            this.rightIconName = rightIcon.name;
        } else {
            this.rightIconName = null;
        }
    },

    /**
     * Define if the right icon is displayed or hidden.
     *
     * @property rightIconVisible
     * @type Boolean
     * @default true
     */
    _rightIconVisible: true,

    isRightIconVisible: function () {
        return this._rightIconVisible;
    },

    setRightIconVisible: function (rightIconVisible) {
        this._rightIconVisible = rightIconVisible;
        this._update();
    },

    //////////////////////////////////////////
    // Methods                              //
    //////////////////////////////////////////

    // ====== Private methods ======

    _update: function () {
        if (this.__html.leftIcon.parentNode == this.__html.tab) {
            this.__html.tab.removeChild(this.__html.leftIcon);
        }
        if (this.__html.title.parentNode == this.__html.tab) {
            this.__html.tab.removeChild(this.__html.title);
        }
        if (this.__html.rightIcon.parentNode == this.__html.tab) {
            this.__html.tab.removeChild(this.__html.rightIcon);
        }

        if (this.leftIconName && this.leftIconVisible) {
            this.__html.tab.appendChild(this.__html.leftIcon);
        }

        if (this.title && this.titleVisible) {
            this.__html.tab.appendChild(this.__html.title);
        }

        if (this.rightIconName && this.rightIconVisible) {
            this.__html.tab.appendChild(this.__html.rightIcon);
        }
    },

    /**
     * Build the widget HTML.
     *
     * @method _buildHtml
     * @private
     */
    _buildHtml: function () {
        this.__html.div = document.createElement("div");
        this.__html.div.className = "photonui-widget photonui-tabitem photonui-container";

        this.__html.tab = document.createElement("div");
        this.__html.tab.className = "photonui-tabitem-tab";

        this.__html.leftIcon = document.createElement("span");
        this.__html.leftIcon.className = "photonui-tab-icon";
        this.__html.tab.appendChild(this.__html.leftIcon);

        this.__html.title = document.createElement("span");
        this.__html.title.className = "photonui-tabitem-title";
        this.__html.tab.appendChild(this.__html.title);

        this.__html.rightIcon = document.createElement("span");
        this.__html.rightIcon.className = "photon-ui-icon";
        this.__html.tab.appendChild(this.__html.rightIcon);

    },

    //////////////////////////////////////////
    // Internal Events Callbacks            //
    //////////////////////////////////////////

    /**
     * Called when the tab is clicked.
     *
     * @method __onClick
     * @private
     * @param event
     */
    __onClick: function (event) {
        this.show();
        this._callCallbacks("click", [event]);
    }

});

module.exports = TabItem;

<commit_msg>Update comment according to FLOZz remarks<commit_after>/*
 * Copyright (c) 2014-2015, Wanadev <http://www.wanadev.fr/>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright notice, this
 *     list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the documentation
 *     and/or other materials provided with the distribution.
 *   * Neither the name of Wanadev nor the names of its contributors may be used
 *     to endorse or promote products derived from this software without specific
 *     prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authored by: Fabien LOISON <https://github.com/flozz>
 */

/**
 * PhotonUI - Javascript Web User Interface.
 *
 * @module PhotonUI
 * @submodule Container
 * @namespace photonui
 */

var Helpers = require("../helpers.js");
var Widget = require("../widget.js");
var BaseIcon = require("../visual/baseicon.js");
var Container = require("./container.js");

/**
 * Tab Item.
 *
 *  wEvents:
 *
 *   * click:
 *     - description: called when the tab was clicked.
 *     - callback:    function(widget, event)
 *
 * @class TabItem
 * @constructor
 * @extends photonui.Container
 * @param {Object} params An object that can contain any property of the widget (optional).
 */
var TabItem = Container.$extend({

    // Constructor
    __init__: function (params) {
        this._registerWEvents(["click"]);
        this.$super(params);
        this._updateProperties(["title", "leftIconName", "rightIconName"]);

        this._bindEvent("tab-click", this.__html.tab, "click", this.__onClick.bind(this));
        this._update();
    },

    //////////////////////////////////////////
    // Properties and Accessors             //
    //////////////////////////////////////////

    // ====== Public properties ======

    /**
     * Tab title.
     *
     * @property title
     * @type String
     * @default "Tab"
     */
    _title: "Tab",

    getTitle: function () {
        return this._title;
    },

    setTitle: function (title) {
        this._title = title;
        Helpers.cleanNode(this.__html.title);
        this.__html.title.appendChild(document.createTextNode(title));
    },

    /**
     * Definie if the tabItem title is displayed or hidden.
     *
     * @property titleVisible
     * @type Boolean
     * @default true
     */
    _titleVisible: true,

    isTitleVisible: function () {
        return this._titleVisible;
    },

    setTitleVisible: function (titleVisible) {
        this._titleVisible = titleVisible;
        this._update();
    },

    /**
     * Html outer element of the widget (if any).
     *
     * @property html
     * @type HTMLElement
     * @default null
     * @readOnly
     */
    getHtml: function () {
        return this.__html.div;
    },

    /**
     * Tab Html element.
     *
     * @property tabHtml
     * @type HTMLElement
     * @default null
     * @readOnly
     */
    getTabHtml: function () {
        return this.__html.tab;
    },

    /**
     * HTML Element that contain the child widget HTML.
     *
     * @property containerNode
     * @type HTMLElement
     * @readOnly
     */
    getContainerNode: function () {
        return this.__html.div;
    },

    /**
     * Is the widget visible or hidden.
     *
     * @property visible
     * @type Boolean
     * @default false
     */
    _visible: false,

    setVisible: function (visible, noParent) {
        this.$super(visible);

        if (visible) {
            if (this.parent) {
                var children = this.parent.children;
                for (var i = 0 ; i < children.length ; i++) {
                    if (!(children[i] instanceof TabItem)) {
                        continue;
                    }
                    if (children[i] === this) {
                        continue;
                    }
                    if (children[i].visible) {
                        children[i].setVisible(false, true);
                    }
                }
                this.parent._activeTabName = this.name;
            }

            this.addClass("photonui-tabitem-active");
            this.__html.tab.className = "photonui-tabitem-tab photonui-tabitem-active";
        } else {
            if (this.parent && !noParent) {
                this.parent.activeTab = null;
            }
            this.removeClass("photonui-tabitem-active");
            this.__html.tab.className = "photonui-tabitem-tab";
        }
    },

    /**
        * Left icon widget name
        *
        * @property leftIconName
        * @type String
        * @default null
        */
    _leftIconName: null,

    getLeftIconName: function () {
        return this._leftIconName;
    },

    setLeftIconName: function (leftIconName) {
        this._leftIconName = leftIconName;
        Helpers.cleanNode(this.__html.leftIcon);
        if (this._leftIconName) {
            this.__html.leftIcon.appendChild(this.leftIcon.html);
            this.leftIconVisible = true;
        }
    },

    /**
    * Left icon widget
    *
    * @property leftIcon
    * @type photonui.Icon
    * @default null
    */
    getLeftIcon: function () {
        return Widget.getWidget(this._leftIconName);
    },

    setLeftIcon: function (leftIcon) {
        if (leftIcon instanceof BaseIcon) {
            this.leftIconName = leftIcon.name;
        } else {
            this.leftIconName = null;
        }
    },

    /**
     * Define if the left icon is displayed or hidden.
     *
     * @property leftIconVisible
     * @type Boolean
     * @default true
     */
    _leftIconVisible: true,

    isLeftIconVisible: function () {
        return this._leftIconVisible;
    },

    setLeftIconVisible: function (leftIconVisible) {
        this._leftIconVisible = leftIconVisible;
        this._update();
    },

    /**
     * Right icon widget name
     *
     * @property rigthIconName
     * @type String
     * @default null
     */

    _rightIconName: null,

    getRightIconName: function () {
        return this._rightIconName;
    },

    setRightIconName: function (rightIconName) {
        this._rightIconName = rightIconName;
        Helpers.cleanNode(this.__html.rightIcon);
        if (this._rightIconName) {
            this.__html.rightIcon.appendChild(this.rightIcon.html);
            this.rightIconVisible = true;
        }
    },

    /**
     * Right icon widget
     *
     * @property rightIcon
     * @type photonui.Icon
     * @default null
     */
    getRightIcon: function () {
        return Widget.getWidget(this._rightIconName);
    },

    setRightIcon: function (rightIcon) {
        if (rightIcon instanceof BaseIcon) {
            this.rightIconName = rightIcon.name;
        } else {
            this.rightIconName = null;
        }
    },

    /**
     * Define if the right icon is displayed or hidden.
     *
     * @property rightIconVisible
     * @type Boolean
     * @default true
     */
    _rightIconVisible: true,

    isRightIconVisible: function () {
        return this._rightIconVisible;
    },

    setRightIconVisible: function (rightIconVisible) {
        this._rightIconVisible = rightIconVisible;
        this._update();
    },

    //////////////////////////////////////////
    // Methods                              //
    //////////////////////////////////////////

    // ====== Private methods ======

    _update: function () {
        if (this.__html.leftIcon.parentNode == this.__html.tab) {
            this.__html.tab.removeChild(this.__html.leftIcon);
        }
        if (this.__html.title.parentNode == this.__html.tab) {
            this.__html.tab.removeChild(this.__html.title);
        }
        if (this.__html.rightIcon.parentNode == this.__html.tab) {
            this.__html.tab.removeChild(this.__html.rightIcon);
        }

        if (this.leftIconName && this.leftIconVisible) {
            this.__html.tab.appendChild(this.__html.leftIcon);
        }

        if (this.title && this.titleVisible) {
            this.__html.tab.appendChild(this.__html.title);
        }

        if (this.rightIconName && this.rightIconVisible) {
            this.__html.tab.appendChild(this.__html.rightIcon);
        }
    },

    /**
     * Build the widget HTML.
     *
     * @method _buildHtml
     * @private
     */
    _buildHtml: function () {
        this.__html.div = document.createElement("div");
        this.__html.div.className = "photonui-widget photonui-tabitem photonui-container";

        this.__html.tab = document.createElement("div");
        this.__html.tab.className = "photonui-tabitem-tab";

        this.__html.leftIcon = document.createElement("span");
        this.__html.leftIcon.className = "photonui-tab-icon";
        this.__html.tab.appendChild(this.__html.leftIcon);

        this.__html.title = document.createElement("span");
        this.__html.title.className = "photonui-tabitem-title";
        this.__html.tab.appendChild(this.__html.title);

        this.__html.rightIcon = document.createElement("span");
        this.__html.rightIcon.className = "photon-ui-icon";
        this.__html.tab.appendChild(this.__html.rightIcon);

    },

    //////////////////////////////////////////
    // Internal Events Callbacks            //
    //////////////////////////////////////////

    /**
     * Called when the tab is clicked.
     *
     * @method __onClick
     * @private
     * @param event
     */
    __onClick: function (event) {
        this.show();
        this._callCallbacks("click", [event]);
    }

});

module.exports = TabItem;

<|endoftext|>


<commit_before>import React, { PureComponent } from 'react';
// react-md
import FileInput from 'react-md/lib/FileInputs';
import TextField from 'react-md/lib/TextFields';
import Button from 'react-md/lib/Buttons';
import Subheader from 'react-md/lib/Subheaders';
import CircularProgress from 'react-md/lib/Progress/CircularProgress';
// redux
import { connect } from 'react-redux'
import { addJob } from '../actions'
import { subtypingDescription } from '../middleware/subtyping'
import { panseqDescription } from '../middleware/panseq'

// axios
import axios from 'axios'
import { API_ROOT } from '../middleware/api'
// router
import { Redirect } from 'react-router'
import Loading from '../components/Loading'

class Panseq extends PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      file: null,
      pi: 90,
      submitted: false,
      open: false,
      pan: true,
      msg: '',
      jobId: "",
      hasResult: false,
      progress: 0
    }
  }
  _selectFile = (file) => {
    console.log(file)
    if (!file) { return; }
    this.setState({ file });
  }

  _updateUploadProgress = ( progress ) => {
    this.setState({progress})
  }
  _handleSubmit = (e) => {
    e.preventDefault() // disable default HTML form behavior
    // open and msg are for Snackbar
    // uploading is to notify users
    this.setState({
      uploading: true
    });
    // configure a progress for axios
    const createConfig = (_updateUploadProgress) => {
      var config = {
        onUploadProgress: function(progressEvent) {
          var percentCompleted = Math.round( (progressEvent.loaded * 100) / progressEvent.total );
          _updateUploadProgress(percentCompleted)
        }
      }
      return config
    }
    // create form data with files```
    var data = new FormData()
    // eslint-disable-next-line
    this.state.file.map((f) => {
      data.append('file', f)
    })
    // append options
    // to match spfy(angular)'s format, we dont use a dict
    data.append('options.pi', this.state.pi)

    // POST
    axios.post(API_ROOT + 'panseq', data, createConfig(this._updateUploadProgress))
      .then(response => {
        console.log(response)
        // no longer uploading
        this.setState({
          uploading: false
        })
        let jobs = response.data
        // handle the return
        for(let job in jobs){
          // console.log(job)
          // console.log(jobs[job].analysis)
          // check filename
          let f = (this.state.file.length > 1 ?
          String(this.state.file.length + ' Files')
          :this.state.file[0].name)

            // regular subtyping uplods
            console.log(job.analysis)
            if(job.analysis === "Panseq"){
              this.props.dispatch(addJob(job,
              'Panseq',
              new Date().toLocaleTimeString(),
              panseqDescription(f, this.state.pi, this.state.pan)
              ))
              }

        }
        const hasResult = true
        this.setState({hasResult})
      })
  };
  render(){
    const { file, pi, amr, serotype, vf, groupresults, bulk, uploading, hasResult, progress } = this.state
    return (
      <div>
        {/* uploading bar */}
        {(uploading && !hasResult) ?
          <div>
            <CircularProgress key="progress" id="loading" value={progress} centered={false} />
            Uploading... {progress} %
          </div>
          : ""
        }
        {/* actual form */}
        {(!hasResult && !uploading)?
          <form className="md-text-container md-grid">
            <div className="md-cell md-cell--12">
              <FileInput
                id="inputFile"
                secondary
                label="Select File(s)"
                onChange={this._selectFile}
                multiple
              />

              <Button
                raised
                secondary
                type="submit"
                label="Submit"
                disabled={!file}
                onClick={this._handleSubmit}
              />
            </div>
            <div className="md-cell md-cell--12">
              {this.state.file ? this.state.file.map(f => (
                <TextField
                  key={f.name}
                  defaultValue={f.name}
                />
              )) : ''}
            </div>
          </form> :
          // if results are grouped, display the Loading page
          // else, results are separate and display the JobsList cards page
          (!uploading?(!groupresults?
            <Redirect to='/results' />:
            <Loading jobId={this.state.jobId} />
          ):"")

        }
      </div>
    )
  }
}

Panseq = connect()(Panseq)

export default Panseq
<commit_msg>DEBUG: Panseq job not dispatching<commit_after>import React, { PureComponent } from 'react';
// react-md
import FileInput from 'react-md/lib/FileInputs';
import TextField from 'react-md/lib/TextFields';
import Button from 'react-md/lib/Buttons';
import Subheader from 'react-md/lib/Subheaders';
import CircularProgress from 'react-md/lib/Progress/CircularProgress';
// redux
import { connect } from 'react-redux'
import { addJob } from '../actions'
import { subtypingDescription } from '../middleware/subtyping'
import { panseqDescription } from '../middleware/panseq'

// axios
import axios from 'axios'
import { API_ROOT } from '../middleware/api'
// router
import { Redirect } from 'react-router'
import Loading from '../components/Loading'

class Panseq extends PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      file: null,
      pi: 90,
      submitted: false,
      open: false,
      pan: true,
      msg: '',
      jobId: "",
      hasResult: false,
      progress: 0
    }
  }
  _selectFile = (file) => {
    console.log(file)
    if (!file) { return; }
    this.setState({ file });
  }

  _updateUploadProgress = ( progress ) => {
    this.setState({progress})
  }
  _handleSubmit = (e) => {
    e.preventDefault() // disable default HTML form behavior
    // open and msg are for Snackbar
    // uploading is to notify users
    this.setState({
      uploading: true
    });
    // configure a progress for axios
    const createConfig = (_updateUploadProgress) => {
      var config = {
        onUploadProgress: function(progressEvent) {
          var percentCompleted = Math.round( (progressEvent.loaded * 100) / progressEvent.total );
          _updateUploadProgress(percentCompleted)
        }
      }
      return config
    }
    // create form data with files```
    var data = new FormData()
    // eslint-disable-next-line
    this.state.file.map((f) => {
      data.append('file', f)
    })
    // append options
    // to match spfy(angular)'s format, we dont use a dict
    data.append('options.pi', this.state.pi)

    // POST
    axios.post(API_ROOT + 'panseq', data, createConfig(this._updateUploadProgress))
      .then(response => {
        console.log(response)
        // no longer uploading
        this.setState({
          uploading: false
        })
        let jobs = response.data
        // handle the return
        for(let job in jobs){
          console.log(job)
          // console.log(jobs[job].analysis)
          // check filename
          let f = (this.state.file.length > 1 ?
          String(this.state.file.length + ' Files')
          :this.state.file[0].name)

            // regular subtyping uplods
            console.log(jobs[job].analysis)
            if(jobs[job].analysis === "Panseq"){
              this.props.dispatch(addJob(job,
              'Panseq',
              new Date().toLocaleTimeString(),
              panseqDescription(f, this.state.pi, this.state.pan)
              ))
              }

        }
        const hasResult = true
        this.setState({hasResult})
      })
  };
  render(){
    const { file, pi, amr, serotype, vf, groupresults, bulk, uploading, hasResult, progress } = this.state
    return (

        {/* uploading bar */}
        {(uploading && !hasResult) ?

            <CircularProgress key="progress" id="loading" value={progress} centered={false} />
            Uploading... {progress} %

          : ""
        }
        {/* actual form */}
        {(!hasResult && !uploading)?
          <form className="md-text-container md-grid">

              <FileInput
                id="inputFile"
                secondary
                label="Select File(s)"
                onChange={this._selectFile}
                multiple
              />

              <Button
                raised
                secondary
                type="submit"
                label="Submit"
                disabled={!file}
                onClick={this._handleSubmit}
              />

              {this.state.file ? this.state.file.map(f => (
                <TextField
                  key={f.name}
                  defaultValue={f.name}
                />
              )) : ''}

          </form> :
          // if results are grouped, display the Loading page
          // else, results are separate and display the JobsList cards page
          (!uploading?(!groupresults?
            <Redirect to='/results' />:
            <Loading jobId={this.state.jobId} />
          ):"")

        }

    )
  }
}

Panseq = connect()(Panseq)

export default Panseq
<|endoftext|>


<commit_before>(function(){

// Shortcuts
var C = Crypto,
    util = C.util,
    charenc = C.charenc,
    UTF8 = charenc.UTF8,
    Binary = charenc.Binary;

// Precomputed SBOX
var SBOX = [ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
             0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
             0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
             0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
             0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
             0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
             0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
             0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
             0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
             0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
             0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
             0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
             0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
             0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
             0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
             0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
             0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
             0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
             0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
             0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
             0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
             0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
             0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
             0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
             0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
             0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
             0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
             0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
             0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
             0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
             0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
             0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ];

// Compute inverse SBOX lookup table
for (var INVSBOX = [], i = 0; i < 256; i++) INVSBOX[SBOX[i]] = i;

// Compute mulitplication in GF(2^8) lookup tables
var MULT2 = [],
    MULT3 = [],
    MULT9 = [],
    MULTB = [],
    MULTD = [],
    MULTE = [];

function xtime(a, b) {
	for (var result = 0, i = 0; i < 8; i++) {
		if (b & 1) result ^= a;
		var hiBitSet = a & 0x80;
		a = (a << 1) & 0xFF;
		if (hiBitSet) a ^= 0x1b;
		b >>>= 1;
	}
	return result;
}

for (var i = 0; i < 256; i++) {
	MULT2[i] = xtime(i,2);
	MULT3[i] = xtime(i,3);
	MULT9[i] = xtime(i,9);
	MULTB[i] = xtime(i,0xB);
	MULTD[i] = xtime(i,0xD);
	MULTE[i] = xtime(i,0xE);
}

// Precomputed RCon lookup
var RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36];

// Inner state
var state = [[], [], [], []],
    keylength,
    nrounds,
    keyschedule;

var AES = C.AES = {

	/**
	 * Public API
	 */

	encrypt: function (message, password, options) {

		var

		    // Convert to bytes
		    m = UTF8.stringToBytes(message),

		    // Generate random IV
		    iv = util.randomBytes(AES._blocksize * 4),

		    // Generate key
		    k = password.constructor == String ?
		        // Derive key from passphrase
		        C.PBKDF2(password, iv, 32, { asBytes: true }) :
		        // else, assume byte array representing cryptographic key
		        password;

		// Determine mode
		mode = options && options.mode || C.mode.OFB;

		// Encrypt
		AES._init(k);
		mode.encrypt(AES, m, iv);

		// Return ciphertext
		return util.bytesToBase64(iv.concat(m));

	},

	decrypt: function (ciphertext, password, options) {

		var

		    // Convert to bytes
		    c = util.base64ToBytes(ciphertext),

		    // Separate IV and message
		    iv = c.splice(0, AES._blocksize * 4),

		    // Generate key
		    k = password.constructor == String ?
		        // Derive key from passphrase
		        C.PBKDF2(password, iv, 32, { asBytes: true }) :
		        // else, assume byte array representing cryptographic key
		        password;

		// Determine mode
		mode = options && options.mode || C.mode.OFB;

		// Decrypt
		AES._init(k);
		mode.decrypt(AES, c, iv);

		// Return plaintext
		return UTF8.bytesToString(c);

	},

	/**
	 * Package private methods and properties
	 */

	_blocksize: 4,

	_encryptblock: function (m, offset) {

		// Set input
		for (var row = 0; row < AES._blocksize; row++) {
			for (var col = 0; col < 4; col++)
				state[row][col] = m[offset + col * 4 + row];
		}

		// Add round key
		for (var row = 0; row < 4; row++) {
			for (var col = 0; col < 4; col++)
				state[row][col] ^= keyschedule[col][row];
		}

		for (var round = 1; round < nrounds; round++) {

			// Sub bytes
			for (var row = 0; row < 4; row++) {
				for (var col = 0; col < 4; col++)
					state[row][col] = SBOX[state[row][col]];
			}

			// Shift rows
			state[1].push(state[1].shift());
			state[2].push(state[2].shift());
			state[2].push(state[2].shift());
			state[3].unshift(state[3].pop());

			// Mix columns
			for (var col = 0; col < 4; col++) {

				var s0 = state[0][col],
				    s1 = state[1][col],
				    s2 = state[2][col],
				    s3 = state[3][col];

				state[0][col] = MULT2[s0] ^ MULT3[s1] ^ s2 ^ s3;
				state[1][col] = s0 ^ MULT2[s1] ^ MULT3[s2] ^ s3;
				state[2][col] = s0 ^ s1 ^ MULT2[s2] ^ MULT3[s3];
				state[3][col] = MULT3[s0] ^ s1 ^ s2 ^ MULT2[s3];

			}

			// Add round key
			for (var row = 0; row < 4; row++) {
				for (var col = 0; col < 4; col++)
					state[row][col] ^= keyschedule[round * 4 + col][row];
			}

		}

		// Sub bytes
		for (var row = 0; row < 4; row++) {
			for (var col = 0; col < 4; col++)
				state[row][col] = SBOX[state[row][col]];
		}

		// Shift rows
		state[1].push(state[1].shift());
		state[2].push(state[2].shift());
		state[2].push(state[2].shift());
		state[3].unshift(state[3].pop());

		// Add round key
		for (var row = 0; row < 4; row++) {
			for (var col = 0; col < 4; col++)
				state[row][col] ^= keyschedule[nrounds * 4 + col][row];
		}

		// Set output
		for (var row = 0; row < AES._blocksize; row++) {
			for (var col = 0; col < 4; col++)
				m[offset + col * 4 + row] = state[row][col];
		}

	},

	_decryptblock: function (c, offset) {

		// Set input
		for (var row = 0; row < AES._blocksize; row++) {
			for (var col = 0; col < 4; col++)
				state[row][col] = c[offset + col * 4 + row];
		}

		// Add round key
		for (var row = 0; row < 4; row++) {
			for (var col = 0; col < 4; col++)
				state[row][col] ^= keyschedule[nrounds * 4 + col][row];
		}

		for (var round = 1; round < nrounds; round++) {

			// Inv shift rows
			state[1].unshift(state[1].pop());
			state[2].push(state[2].shift());
			state[2].push(state[2].shift());
			state[3].push(state[3].shift());

			// Inv sub bytes
			for (var row = 0; row < 4; row++) {
				for (var col = 0; col < 4; col++)
					state[row][col] = INVSBOX[state[row][col]];
			}

			// Add round key
			for (var row = 0; row < 4; row++) {
				for (var col = 0; col < 4; col++)
					state[row][col] ^= keyschedule[(nrounds - round) * 4 + col][row];
			}

			// Inv mix columns
			for (var col = 0; col < 4; col++) {

				var s0 = state[0][col],
				    s1 = state[1][col],
				    s2 = state[2][col],
				    s3 = state[3][col];

				state[0][col] = MULTE[s0] ^ MULTB[s1] ^ MULTD[s2] ^ MULT9[s3];
				state[1][col] = MULT9[s0] ^ MULTE[s1] ^ MULTB[s2] ^ MULTD[s3];
				state[2][col] = MULTD[s0] ^ MULT9[s1] ^ MULTE[s2] ^ MULTB[s3];
				state[3][col] = MULTB[s0] ^ MULTD[s1] ^ MULT9[s2] ^ MULTE[s3];

			}

		}

		// Inv shift rows
		state[1].unshift(state[1].pop());
		state[2].push(state[2].shift());
		state[2].push(state[2].shift());
		state[3].push(state[3].shift());

		// Inv sub bytes
		for (var row = 0; row < 4; row++) {
			for (var col = 0; col < 4; col++)
				state[row][col] = INVSBOX[state[row][col]];
		}

		// Add round key
		for (var row = 0; row < 4; row++) {
			for (var col = 0; col < 4; col++)
				state[row][col] ^= keyschedule[col][row];
		}

		// Set output
		for (var row = 0; row < AES._blocksize; row++) {
			for (var col = 0; col < 4; col++)
				c[offset + col * 4 + row] = state[row][col];
		}

	},

	/**
	 * Private methods
	 */

	_init: function (k) {
		keylength = k.length / 4;
		nrounds = keylength + 6;
		AES._keyexpansion(k);
	},

	// Generate a key schedule
	_keyexpansion: function (k) {

		keyschedule = [];

		for (var row = 0; row < keylength; row++) {
			keyschedule[row] = [
				k[row * 4],
				k[row * 4 + 1],
				k[row * 4 + 2],
				k[row * 4 + 3]
			];
		}

		for (var row = keylength; row < AES._blocksize * (nrounds + 1); row++) {

			var temp = [
				keyschedule[row - 1][0],
				keyschedule[row - 1][1],
				keyschedule[row - 1][2],
				keyschedule[row - 1][3]
			];

			if (row % keylength == 0) {

				// Rot word
				temp.push(temp.shift());

				// Sub word
				temp[0] = SBOX[temp[0]];
				temp[1] = SBOX[temp[1]];
				temp[2] = SBOX[temp[2]];
				temp[3] = SBOX[temp[3]];

				temp[0] ^= RCON[row / keylength];

			} else if (keylength > 6 && row % keylength == 4) {

				// Sub word
				temp[0] = SBOX[temp[0]];
				temp[1] = SBOX[temp[1]];
				temp[2] = SBOX[temp[2]];
				temp[3] = SBOX[temp[3]];

			}

			keyschedule[row] = [
				keyschedule[row - keylength][0] ^ temp[0],
				keyschedule[row - keylength][1] ^ temp[1],
				keyschedule[row - keylength][2] ^ temp[2],
				keyschedule[row - keylength][3] ^ temp[3]
			];

		}

	}

};

})();
<commit_msg>K-weight optimization.<commit_after>(function(){

// Shortcuts
var C = Crypto,
    util = C.util,
    charenc = C.charenc,
    UTF8 = charenc.UTF8,
    Binary = charenc.Binary;

// Compute Sbox
var SBOX = [],
    INVSBOX = [];

// Compute double table
for (var d = [], i = 0; i < 256; i++) {
	d[i] = i >= 128 ? i << 1 ^ 0x11b : i << 1
}

// Walk GF(2^8)
var x = 0, xi = 0;
while (1) {

	var sx = xi ^ xi << 1 ^ xi << 2 ^ xi << 3 ^ xi << 4;
	sx = sx >>> 8 ^ sx & 0xFF ^ 0x63;

	SBOX[x] = sx;
	INVSBOX[sx] = x;

	var x2 = d[x],
	    x4 = d[x2],
	    x8 = d[x4];

	if (x == 5) {
		break;
	}
	else if (x) {
		x = x2 ^ d[d[d[x8 ^ x2]]];
		xi ^= d[d[xi]];
	}
	else {
		x = xi = 1;
	}

}

// Compute mulitplication in GF(2^8) lookup tables
var MULT2 = [],
    MULT3 = [],
    MULT9 = [],
    MULTB = [],
    MULTD = [],
    MULTE = [];

function xtime(a, b) {
	for (var result = 0, i = 0; i < 8; i++) {
		if (b & 1) result ^= a;
		var hiBitSet = a & 0x80;
		a = (a << 1) & 0xFF;
		if (hiBitSet) a ^= 0x1b;
		b >>>= 1;
	}
	return result;
}

for (var i = 0; i < 256; i++) {
	MULT2[i] = xtime(i,2);
	MULT3[i] = xtime(i,3);
	MULT9[i] = xtime(i,9);
	MULTB[i] = xtime(i,0xB);
	MULTD[i] = xtime(i,0xD);
	MULTE[i] = xtime(i,0xE);
}

// Precomputed RCon lookup
var RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36];

// Inner state
var state = [[], [], [], []],
    keylength,
    nrounds,
    keyschedule;

var AES = C.AES = {

	/**
	 * Public API
	 */

	encrypt: function (message, password, options) {

		var

		    // Convert to bytes
		    m = UTF8.stringToBytes(message),

		    // Generate random IV
		    iv = util.randomBytes(AES._blocksize * 4),

		    // Generate key
		    k = password.constructor == String ?
		        // Derive key from passphrase
		        C.PBKDF2(password, iv, 32, { asBytes: true }) :
		        // else, assume byte array representing cryptographic key
		        password;

		// Determine mode
		mode = options && options.mode || C.mode.OFB;

		// Encrypt
		AES._init(k);
		mode.encrypt(AES, m, iv);

		// Return ciphertext
		return util.bytesToBase64(iv.concat(m));

	},

	decrypt: function (ciphertext, password, options) {

		var

		    // Convert to bytes
		    c = util.base64ToBytes(ciphertext),

		    // Separate IV and message
		    iv = c.splice(0, AES._blocksize * 4),

		    // Generate key
		    k = password.constructor == String ?
		        // Derive key from passphrase
		        C.PBKDF2(password, iv, 32, { asBytes: true }) :
		        // else, assume byte array representing cryptographic key
		        password;

		// Determine mode
		mode = options && options.mode || C.mode.OFB;

		// Decrypt
		AES._init(k);
		mode.decrypt(AES, c, iv);

		// Return plaintext
		return UTF8.bytesToString(c);

	},

	/**
	 * Package private methods and properties
	 */

	_blocksize: 4,

	_encryptblock: function (m, offset) {

		// Set input
		for (var row = 0; row < AES._blocksize; row++) {
			for (var col = 0; col < 4; col++)
				state[row][col] = m[offset + col * 4 + row];
		}

		// Add round key
		for (var row = 0; row < 4; row++) {
			for (var col = 0; col < 4; col++)
				state[row][col] ^= keyschedule[col][row];
		}

		for (var round = 1; round < nrounds; round++) {

			// Sub bytes
			for (var row = 0; row < 4; row++) {
				for (var col = 0; col < 4; col++)
					state[row][col] = SBOX[state[row][col]];
			}

			// Shift rows
			state[1].push(state[1].shift());
			state[2].push(state[2].shift());
			state[2].push(state[2].shift());
			state[3].unshift(state[3].pop());

			// Mix columns
			for (var col = 0; col < 4; col++) {

				var s0 = state[0][col],
				    s1 = state[1][col],
				    s2 = state[2][col],
				    s3 = state[3][col];

				state[0][col] = MULT2[s0] ^ MULT3[s1] ^ s2 ^ s3;
				state[1][col] = s0 ^ MULT2[s1] ^ MULT3[s2] ^ s3;
				state[2][col] = s0 ^ s1 ^ MULT2[s2] ^ MULT3[s3];
				state[3][col] = MULT3[s0] ^ s1 ^ s2 ^ MULT2[s3];

			}

			// Add round key
			for (var row = 0; row < 4; row++) {
				for (var col = 0; col < 4; col++)
					state[row][col] ^= keyschedule[round * 4 + col][row];
			}

		}

		// Sub bytes
		for (var row = 0; row < 4; row++) {
			for (var col = 0; col < 4; col++)
				state[row][col] = SBOX[state[row][col]];
		}

		// Shift rows
		state[1].push(state[1].shift());
		state[2].push(state[2].shift());
		state[2].push(state[2].shift());
		state[3].unshift(state[3].pop());

		// Add round key
		for (var row = 0; row < 4; row++) {
			for (var col = 0; col < 4; col++)
				state[row][col] ^= keyschedule[nrounds * 4 + col][row];
		}

		// Set output
		for (var row = 0; row < AES._blocksize; row++) {
			for (var col = 0; col < 4; col++)
				m[offset + col * 4 + row] = state[row][col];
		}

	},

	_decryptblock: function (c, offset) {

		// Set input
		for (var row = 0; row < AES._blocksize; row++) {
			for (var col = 0; col < 4; col++)
				state[row][col] = c[offset + col * 4 + row];
		}

		// Add round key
		for (var row = 0; row < 4; row++) {
			for (var col = 0; col < 4; col++)
				state[row][col] ^= keyschedule[nrounds * 4 + col][row];
		}

		for (var round = 1; round < nrounds; round++) {

			// Inv shift rows
			state[1].unshift(state[1].pop());
			state[2].push(state[2].shift());
			state[2].push(state[2].shift());
			state[3].push(state[3].shift());

			// Inv sub bytes
			for (var row = 0; row < 4; row++) {
				for (var col = 0; col < 4; col++)
					state[row][col] = INVSBOX[state[row][col]];
			}

			// Add round key
			for (var row = 0; row < 4; row++) {
				for (var col = 0; col < 4; col++)
					state[row][col] ^= keyschedule[(nrounds - round) * 4 + col][row];
			}

			// Inv mix columns
			for (var col = 0; col < 4; col++) {

				var s0 = state[0][col],
				    s1 = state[1][col],
				    s2 = state[2][col],
				    s3 = state[3][col];

				state[0][col] = MULTE[s0] ^ MULTB[s1] ^ MULTD[s2] ^ MULT9[s3];
				state[1][col] = MULT9[s0] ^ MULTE[s1] ^ MULTB[s2] ^ MULTD[s3];
				state[2][col] = MULTD[s0] ^ MULT9[s1] ^ MULTE[s2] ^ MULTB[s3];
				state[3][col] = MULTB[s0] ^ MULTD[s1] ^ MULT9[s2] ^ MULTE[s3];

			}

		}

		// Inv shift rows
		state[1].unshift(state[1].pop());
		state[2].push(state[2].shift());
		state[2].push(state[2].shift());
		state[3].push(state[3].shift());

		// Inv sub bytes
		for (var row = 0; row < 4; row++) {
			for (var col = 0; col < 4; col++)
				state[row][col] = INVSBOX[state[row][col]];
		}

		// Add round key
		for (var row = 0; row < 4; row++) {
			for (var col = 0; col < 4; col++)
				state[row][col] ^= keyschedule[col][row];
		}

		// Set output
		for (var row = 0; row < AES._blocksize; row++) {
			for (var col = 0; col < 4; col++)
				c[offset + col * 4 + row] = state[row][col];
		}

	},

	/**
	 * Private methods
	 */

	_init: function (k) {
		keylength = k.length / 4;
		nrounds = keylength + 6;
		AES._keyexpansion(k);
	},

	// Generate a key schedule
	_keyexpansion: function (k) {

		keyschedule = [];

		for (var row = 0; row < keylength; row++) {
			keyschedule[row] = [
				k[row * 4],
				k[row * 4 + 1],
				k[row * 4 + 2],
				k[row * 4 + 3]
			];
		}

		for (var row = keylength; row < AES._blocksize * (nrounds + 1); row++) {

			var temp = [
				keyschedule[row - 1][0],
				keyschedule[row - 1][1],
				keyschedule[row - 1][2],
				keyschedule[row - 1][3]
			];

			if (row % keylength == 0) {

				// Rot word
				temp.push(temp.shift());

				// Sub word
				temp[0] = SBOX[temp[0]];
				temp[1] = SBOX[temp[1]];
				temp[2] = SBOX[temp[2]];
				temp[3] = SBOX[temp[3]];

				temp[0] ^= RCON[row / keylength];

			} else if (keylength > 6 && row % keylength == 4) {

				// Sub word
				temp[0] = SBOX[temp[0]];
				temp[1] = SBOX[temp[1]];
				temp[2] = SBOX[temp[2]];
				temp[3] = SBOX[temp[3]];

			}

			keyschedule[row] = [
				keyschedule[row - keylength][0] ^ temp[0],
				keyschedule[row - keylength][1] ^ temp[1],
				keyschedule[row - keylength][2] ^ temp[2],
				keyschedule[row - keylength][3] ^ temp[3]
			];

		}

	}

};

})();
<|endoftext|>


<commit_before>import React from 'react'
import { prefetch } from 'react-fetcher'
import { connect } from 'react-redux'
import { connectedListProps, fetchWithCache, refetch } from '../util/caching'
import { navigate, search } from '../actions'
import { debounce, get, isEmpty, pick, some } from 'lodash'
import Select from '../components/Select'
import Comment from '../components/Comment'
import Avatar from '../components/Avatar'
import A from '../components/A'
import Post from '../components/Post'
import ScrollListener from '../components/ScrollListener'
import Tags from '../components/Tags'
import CoverImagePage from '../components/CoverImagePage'
import { commentUrl } from '../routes'
import decode from 'ent/decode'
const { array, bool, func, number, object } = React.PropTypes

const types = [
  {name: 'Everything'},
  {name: 'Posts', id: 'post'},
  {name: 'People', id: 'person'},
  {name: 'Comments', id: 'comment'}
]

const subject = 'search'
const fetch = fetchWithCache(search)

@prefetch(({ dispatch, query }) => query.q && dispatch(fetch(subject, null, query)))
@connect((state, { location: { query } }) => ({
  ...connectedListProps(state, {subject, query}, 'searchResults'),
  currentUser: state.people.current
}))
export default class Search extends React.Component {
  static propTypes = {
    dispatch: func,
    location: object,
    searchResults: array,
    total: number,
    pending: bool
  }

  static childContextTypes = {
    dispatch: func,
    currentUser: object
  }

  constructor (props) {
    super(props)
    this.state = {textInput: get(props, 'location.query.q')}
  }

  getChildContext () {
    return pick(this.props, 'currentUser', 'dispatch')
  }

  updateSearch = debounce(opts => {
    let { dispatch, location } = this.props
    return dispatch(refetch(opts, location))
  }, 500)

  render () {
    let { dispatch, location, searchResults, total, pending } = this.props
    if (pending && !searchResults) {
      return
Loading...

    }

    let { q, type } = location.query
    let selectedType = types.find(t => t.id === type) || types[0]

    let loadMore = () => {
      let offset = searchResults.length
      if (!pending && offset < total) {
        dispatch(fetch(subject, null, {q, type, offset}))
      }
    }

    let updateTextInput = text => {
      this.setState({textInput: text})
      this.updateSearch({q: text})
    }

    return <CoverImagePage id='search'>

        <input type='text' className='form-control search'
          value={this.state.textInput}
          onChange={event => updateTextInput(event.target.value)}/>
        <Select className='type' choices={types} selected={selectedType}
          onChange={t => this.updateSearch({type: t.id})} alignRight={true}/>

      <Results results={searchResults}
        dispatch={dispatch}
        onTagClick={tag => updateTextInput(tag)}
        loadMore={loadMore}/>
      {pending
        ?
Loading...

        : isEmpty(searchResults) && (q
          ?
No results match your search term.

        :
Type a search term to search posts, comments, and people.
)}
    </CoverImagePage>
  }
}

const Results = ({ results, dispatch, onTagClick, loadMore }) => {
  return

    {results.map(({ type, data }) => <div key={`${type}${data.id}`}>
      {type === 'post'
        ? <PostResult post={data} dispatch={dispatch}/>
        : type === 'person'
          ? <PersonResult person={data} onTagClick={onTagClick}/>
        : <CommentResult comment={data} dispatch={dispatch}/>}

)}
    <ScrollListener onBottom={loadMore}/>

}

const PostResult = ({ post, dispatch }) => {
  return <Post post={post}/>
}

const PersonResult = ({ person, onTagClick }) => {
  let { bio, work, intention, skills, organizations } = person
  return

      <Avatar person={person}/>

      <A to={`/u/${person.id}`}>{person.name}

      {bio &&
About me: {bio}
}
      {work &&
What I'm doing: {work}
}
      {intention &&
What I'd like to do: {intention}
}
      {some(skills) &&

        Skills:
        <Tags onClick={onTagClick}>{skills}</Tags>

}
      {some(organizations) &&

        Groups:
        <Tags onClick={onTagClick}>{organizations}</Tags>

}

}

const CommentResult = ({ comment, dispatch }) => {
  const { post } = comment
  const welcomedPerson = get(post, 'relatedUsers.0')
  const url = commentUrl(comment)
  const visit = () => dispatch(navigate(url))
  return

      Comment on

        {post.type === 'welcome'
          ? `${welcomedPerson.name}'s welcome post`
          : `"${decode(post.name)}"`}

    <Comment comment={comment} truncate={true} expand={visit}/>

}
<commit_msg>remove skills & orgs from search results<commit_after>import React from 'react'
import { prefetch } from 'react-fetcher'
import { connect } from 'react-redux'
import { connectedListProps, fetchWithCache, refetch } from '../util/caching'
import { navigate, search } from '../actions'
import { debounce, get, isEmpty, pick } from 'lodash'
import Select from '../components/Select'
import Comment from '../components/Comment'
import Avatar from '../components/Avatar'
import A from '../components/A'
import Post from '../components/Post'
import ScrollListener from '../components/ScrollListener'
import CoverImagePage from '../components/CoverImagePage'
import { commentUrl } from '../routes'
import decode from 'ent/decode'
const { array, bool, func, number, object } = React.PropTypes

const types = [
  {name: 'Everything'},
  {name: 'Posts', id: 'post'},
  {name: 'People', id: 'person'},
  {name: 'Comments', id: 'comment'}
]

const subject = 'search'
const fetch = fetchWithCache(search)

@prefetch(({ dispatch, query }) => query.q && dispatch(fetch(subject, null, query)))
@connect((state, { location: { query } }) => ({
  ...connectedListProps(state, {subject, query}, 'searchResults'),
  currentUser: state.people.current
}))
export default class Search extends React.Component {
  static propTypes = {
    dispatch: func,
    location: object,
    searchResults: array,
    total: number,
    pending: bool
  }

  static childContextTypes = {
    dispatch: func,
    currentUser: object
  }

  constructor (props) {
    super(props)
    this.state = {textInput: get(props, 'location.query.q')}
  }

  getChildContext () {
    return pick(this.props, 'currentUser', 'dispatch')
  }

  updateSearch = debounce(opts => {
    let { dispatch, location } = this.props
    return dispatch(refetch(opts, location))
  }, 500)

  render () {
    let { dispatch, location, searchResults, total, pending } = this.props
    if (pending && !searchResults) {
      return
Loading...

    }

    let { q, type } = location.query
    let selectedType = types.find(t => t.id === type) || types[0]

    let loadMore = () => {
      let offset = searchResults.length
      if (!pending && offset < total) {
        dispatch(fetch(subject, null, {q, type, offset}))
      }
    }

    let updateTextInput = text => {
      this.setState({textInput: text})
      this.updateSearch({q: text})
    }

    return <CoverImagePage id='search'>

        <input type='text' className='form-control search'
          value={this.state.textInput}
          onChange={event => updateTextInput(event.target.value)}/>
        <Select className='type' choices={types} selected={selectedType}
          onChange={t => this.updateSearch({type: t.id})} alignRight={true}/>

      <Results results={searchResults}
        dispatch={dispatch}
        onTagClick={tag => updateTextInput(tag)}
        loadMore={loadMore}/>
      {pending
        ?
Loading...

        : isEmpty(searchResults) && (q
          ?
No results match your search term.

        :
Type a search term to search posts, comments, and people.
)}
    </CoverImagePage>
  }
}

const Results = ({ results, dispatch, onTagClick, loadMore }) => {
  return

    {results.map(({ type, data }) => <div key={`${type}${data.id}`}>
      {type === 'post'
        ? <PostResult post={data} dispatch={dispatch}/>
        : type === 'person'
          ? <PersonResult person={data} onTagClick={onTagClick}/>
        : <CommentResult comment={data} dispatch={dispatch}/>}

)}
    <ScrollListener onBottom={loadMore}/>

}

const PostResult = ({ post, dispatch }) => {
  return <Post post={post}/>
}

const PersonResult = ({ person, onTagClick }) => {
  let { bio, work, intention } = person
  return

      <Avatar person={person}/>

      <A to={`/u/${person.id}`}>{person.name}

      {bio &&
About me: {bio}
}
      {work &&
What I'm doing: {work}
}
      {intention &&
What I'd like to do: {intention}
}

}

const CommentResult = ({ comment, dispatch }) => {
  const { post } = comment
  const welcomedPerson = get(post, 'relatedUsers.0')
  const url = commentUrl(comment)
  const visit = () => dispatch(navigate(url))
  return

      Comment on

        {post.type === 'welcome'
          ? `${welcomedPerson.name}'s welcome post`
          : `"${decode(post.name)}"`}

    <Comment comment={comment} truncate={true} expand={visit}/>

}
<|endoftext|>


<commit_before>import React from 'react'
import {
  Provider,
  Banner,
  Heading,
  Lead,
  Container,
  Flex,
  Box,
  Text,
  Subhead,
  Absolute,
  Link as A
} from 'rebass'
import theme, { colors, mx } from '../theme'
import { Head } from 'react-static'
import { withFormik } from 'formik'
import yup from 'yup'
import axios from 'axios'
import Nav from '../components/Nav'
import { Field, Submit } from '../components/Forms'
import Footer from '../components/Footer'

const Header = Box.extend.attrs({
  is: 'header',
  align: 'center',
  justify: 'center',
  direction: 'column',
  bg: 'primary',
  p: 3
})`text-align: center;`

const Base = Container.extend.attrs({
  is: 'form',
  py: 4,
  px: 3,
  maxWidth: 40 * 16
})`
  display: grid;
  grid-gap: 1rem;
  ${mx[1]} {
    grid-template-columns: repeat(2, 1fr);
    h2, .textarea { grid-column: 1 / -1; }
  }
`

const Subheading = Heading.extend.attrs({
  f: 4,
  mt: 2,
  mb: 0,
  color: 'primary'
})``

const next12Months = () => {
  const monthNames = [
    'January',
    'February',
    'March',
    'April',
    'May',
    'June',
    'July',
    'August',
    'September',
    'October',
    'November',
    'December'
  ]
  const genMonth = date => {
    const month = monthNames[date.getMonth()]
    const label = `${month} ${date.getFullYear()}`
    const iso = date.toISOString()
    return { label, iso }
  }
  const months = []
  const today = new Date()
  const asap = genMonth(today)
  asap.label = 'ASAP'
  months.push(asap)
  for (let i = 0; i < 12; i++) {
    today.setMonth(today.getMonth() + 1)
    months.push(genMonth(today))
  }
  return months
}

const statusMessage = status =>
  status
    ? {
        success: 'Submitted—you’re all set! 🎈',
        error: 'Something went wrong 😰'
      }[status]
    : 'Submit application 📝'
const InnerForm = ({
  values,
  errors,
  touched,
  handleChange,
  handleBlur,
  handleSubmit,
  isSubmitting,
  status
}) => (
  <Base onSubmit={handleSubmit}>
    <Subheading>About you</Subheading>
    <Field
      label="First name"
      name="first_name"
      p="Cat"
      onChange={handleChange}
      onBlur={handleBlur}
      value={values.first_name}
      error={touched.first_name && errors.first_name}
    />
    <Field
      label="Last name"
      name="last_name"
      value={values.last_name}
      p="Hackworth"
      onChange={handleChange}
      onBlur={handleBlur}
      error={touched.last_name && errors.last_name}
    />
    <Field
      label="Email"
      name="email"
      type="email"
      p="cat@hackclub.com"
      value={values.email}
      onChange={handleChange}
      onBlur={handleBlur}
      error={touched.email && errors.email}
    />
    <Field
      label="Phone number"
      name="phone"
      type="phone"
      p="(555) 555-5555"
      value={values.phone}
      onChange={handleChange}
    />
    <Field
      label="GitHub"
      name="github"
      p="cathackworth"
      value={values.github}
      onChange={handleChange}
      onBlur={handleBlur}
    />
    <Field
      label="Twitter"
      name="twitter"
      p="cathackworth"
      value={values.twitter}
      onChange={handleChange}
      onBlur={handleBlur}
    />
    <Field
      label="High school name"
      name="high_school"
      p="Hacking High School"
      value={values.high_school}
      onChange={handleChange}
      onBlur={handleBlur}
      error={touched.high_school && errors.high_school}
    />
    <Field
      label="When do you graduate?"
      name="graduate"
      type="select"
      value={values.graduate}
      onChange={handleChange}
      onBlur={handleBlur}
      error={touched.graduate && errors.graduate}
    >
      <option value="9010">Other</option>
      <option value="9001">2022</option>
      <option value="9002">2021</option>
      <option value="9003">2020</option>
      <option value="9004">2019</option>
      <option value="9005">2018</option>
      <option value="9006">2017</option>
      <option value="9007">2016</option>
      <option value="9009">Teacher</option>
      <option value="9008">Graduated</option>
    </Field>
    <Subheading>Your club</Subheading>
    <Field
      label="When do you want to start?"
      name="start"
      type="select"
      children={next12Months().map(({ iso, label }) => (
        <option value={iso} key={iso} children={label} />
      ))}
      value={values.start}
      onChange={handleChange}
      onBlur={handleBlur}
      error={touched.start && errors.start}
    />
    <Field
      label="How did you hear about us?"
      name="referer"
      type="text"
      value={values.referer}
      onChange={handleChange}
      onBlur={handleBlur}
      error={touched.referer && errors.referer}
    />
    <Field
      label="Please tell us about an interesting project, preferably outside of class, that you created or worked on."
      name="interesting_project"
      type="textarea"
      value={values.interesting_project}
      onChange={handleChange}
      onBlur={handleBlur}
      error={touched.interesting_project && errors.interesting_project}
    />
    <Field
      label={

          Please tell us about the time you most successfully hacked some
          (non-computer) system to your advantage. (
            See some kinds of responses we’re looking for.
          )

      }
      name="systems_hacked"
      type="textarea"
      value={values.systems_hacked}
      onChange={handleChange}
      onBlur={handleBlur}
      error={touched.systems_hacked && errors.systems_hacked}
    />
    <Field
      label="What steps have you taken so far in starting your club?"
      name="steps_taken"
      type="textarea"
      value={values.steps_taken}
      onChange={handleChange}
      onBlur={handleBlur}
      error={touched.steps_taken && errors.steps_taken}
    />
    <Submit
      disabled={isSubmitting}
      onClick={handleSubmit}
      value={statusMessage(status)}
    />
  </Base>
)

const r = 'required'
const ApplicationForm = withFormik({
  mapPropsToValues: ({ params }) => ({ ...params }),
  validationSchema: yup.object().shape({
    first_name: yup.string().required(r),
    last_name: yup.string().required(r),
    email: yup.string().email('invalid email address').required(r),
    high_school: yup.string().required(r),
    graduate: yup.string().required(r),
    referer: yup.string().required(r),
    interesting_project: yup.string().required(r),
    systems_hacked: yup.string().required(r),
    steps_taken: yup.string().required(r)
  }),
  handleSubmit: (data, { setSubmitting, setStatus }) => {
    console.log(data)
    axios
      .post('https://hackclub.com/v1/club_applications', data)
      .then(res => {
        console.log(res)
        setSubmitting(false)
        setStatus('success')
      })
      .catch(e => {
        console.error(e)
        setSubmitting(false)
        setStatus('error')
      })
  },
  displayName: 'ApplicationForm'
})(InnerForm)

const systems_hacked =
  'https://www.quora.com/When-have-you-most-successfully-hacked-a-non-computer-system-to-your-advantage'
export default () => (
  <Provider theme={theme}>

      <title>Sign up – Hack Club</title>

      <Heading is="h1" color="white" f={[5, 6]} mt={4}>
        Submit your application
      </Heading>

    <ApplicationForm />

  </Provider>
)
<commit_msg>Fix start select menu<commit_after>import React from 'react'
import {
  Provider,
  Banner,
  Heading,
  Lead,
  Container,
  Flex,
  Box,
  Text,
  Subhead,
  Absolute,
  Link as A
} from 'rebass'
import theme, { colors, mx } from '../theme'
import { Head } from 'react-static'
import { withFormik } from 'formik'
import yup from 'yup'
import axios from 'axios'
import Nav from '../components/Nav'
import { Field, Submit } from '../components/Forms'
import Footer from '../components/Footer'

const Header = Box.extend.attrs({
  is: 'header',
  align: 'center',
  justify: 'center',
  direction: 'column',
  bg: 'primary',
  p: 3
})`text-align: center;`

const Base = Container.extend.attrs({
  is: 'form',
  py: 4,
  px: 3,
  maxWidth: 40 * 16
})`
  display: grid;
  grid-gap: 1rem;
  ${mx[1]} {
    grid-template-columns: repeat(2, 1fr);
    h2, .textarea { grid-column: 1 / -1; }
  }
`

const Subheading = Heading.extend.attrs({
  f: 4,
  mt: 2,
  mb: 0,
  color: 'primary'
})``

const next12Months = () => {
  const monthNames = [
    'January',
    'February',
    'March',
    'April',
    'May',
    'June',
    'July',
    'August',
    'September',
    'October',
    'November',
    'December'
  ]
  const genMonth = date => {
    const month = monthNames[date.getMonth()]
    const label = `${month} ${date.getFullYear()}`
    const iso = date.toISOString()
    return { label, iso }
  }
  const months = []
  const today = new Date()
  const asap = genMonth(today)
  asap.label = 'ASAP'
  months.push(asap)
  for (let i = 0; i < 12; i++) {
    today.setMonth(today.getMonth() + 1)
    months.push(genMonth(today))
  }
  return months
}

const statusMessage = status =>
  status
    ? {
        success: 'Submitted—you’re all set! 🎈',
        error: 'Something went wrong 😰'
      }[status]
    : 'Submit application 📝'
const InnerForm = ({
  values,
  errors,
  touched,
  handleChange,
  handleBlur,
  handleSubmit,
  isSubmitting,
  status,
  months
}) => (
  <Base onSubmit={handleSubmit}>
    <Subheading>About you</Subheading>
    <Field
      label="First name"
      name="first_name"
      p="Cat"
      onChange={handleChange}
      onBlur={handleBlur}
      value={values.first_name}
      error={touched.first_name && errors.first_name}
    />
    <Field
      label="Last name"
      name="last_name"
      value={values.last_name}
      p="Hackworth"
      onChange={handleChange}
      onBlur={handleBlur}
      error={touched.last_name && errors.last_name}
    />
    <Field
      label="Email"
      name="email"
      type="email"
      p="cat@hackclub.com"
      value={values.email}
      onChange={handleChange}
      onBlur={handleBlur}
      error={touched.email && errors.email}
    />
    <Field
      label="Phone number"
      name="phone"
      type="phone"
      p="(555) 555-5555"
      value={values.phone}
      onChange={handleChange}
    />
    <Field
      label="GitHub"
      name="github"
      p="cathackworth"
      value={values.github}
      onChange={handleChange}
      onBlur={handleBlur}
    />
    <Field
      label="Twitter"
      name="twitter"
      p="cathackworth"
      value={values.twitter}
      onChange={handleChange}
      onBlur={handleBlur}
    />
    <Field
      label="High school name"
      name="high_school"
      p="Hacking High School"
      value={values.high_school}
      onChange={handleChange}
      onBlur={handleBlur}
      error={touched.high_school && errors.high_school}
    />
    <Field
      label="When do you graduate?"
      name="graduate"
      type="select"
      value={values.graduate}
      onChange={handleChange}
      onBlur={handleBlur}
      error={touched.graduate && errors.graduate}
    >
      <option value="9010">Other</option>
      <option value="9001">2022</option>
      <option value="9002">2021</option>
      <option value="9003">2020</option>
      <option value="9004">2019</option>
      <option value="9005">2018</option>
      <option value="9006">2017</option>
      <option value="9007">2016</option>
      <option value="9009">Teacher</option>
      <option value="9008">Graduated</option>
    </Field>
    <Subheading>Your club</Subheading>
    <Field
      label="When do you want to start?"
      name="start"
      type="select"
      value={values.start}
      onChange={handleChange}
      onBlur={handleBlur}
      error={touched.start && errors.start}
    >
      {months.map(({ iso, label }, i) => (
        <option value={iso} key={`start-${i}`} children={label} />
      ))}
    </Field>
    <Field
      label="How did you hear about us?"
      name="referer"
      type="text"
      value={values.referer}
      onChange={handleChange}
      onBlur={handleBlur}
      error={touched.referer && errors.referer}
    />
    <Field
      label="Please tell us about an interesting project, preferably outside of class, that you created or worked on."
      name="interesting_project"
      type="textarea"
      value={values.interesting_project}
      onChange={handleChange}
      onBlur={handleBlur}
      error={touched.interesting_project && errors.interesting_project}
    />
    <Field
      label={

          Please tell us about the time you most successfully hacked some
          (non-computer) system to your advantage. (
            See some kinds of responses we’re looking for.
          )

      }
      name="systems_hacked"
      type="textarea"
      value={values.systems_hacked}
      onChange={handleChange}
      onBlur={handleBlur}
      error={touched.systems_hacked && errors.systems_hacked}
    />
    <Field
      label="What steps have you taken so far in starting your club?"
      name="steps_taken"
      type="textarea"
      value={values.steps_taken}
      onChange={handleChange}
      onBlur={handleBlur}
      error={touched.steps_taken && errors.steps_taken}
    />
    <Submit
      disabled={isSubmitting}
      onClick={handleSubmit}
      value={statusMessage(status)}
    />
  </Base>
)

const r = 'required'
const ApplicationForm = withFormik({
  mapPropsToValues: ({ params }) => ({ ...params }),
  validationSchema: yup.object().shape({
    first_name: yup.string().required(r),
    last_name: yup.string().required(r),
    email: yup.string().email('invalid email address').required(r),
    high_school: yup.string().required(r),
    graduate: yup.string().required(r),
    referer: yup.string().required(r),
    interesting_project: yup.string().required(r),
    systems_hacked: yup.string().required(r),
    steps_taken: yup.string().required(r)
  }),
  handleSubmit: (data, { setSubmitting, setStatus }) => {
    console.log(data)
    axios
      .post('https://hackclub.com/v1/club_applications', data)
      .then(res => {
        console.log(res)
        setSubmitting(false)
        setStatus('success')
      })
      .catch(e => {
        console.error(e)
        setSubmitting(false)
        setStatus('error')
      })
  },
  displayName: 'ApplicationForm'
})(InnerForm)

const systems_hacked =
  'https://www.quora.com/When-have-you-most-successfully-hacked-a-non-computer-system-to-your-advantage'
export default () => (
  <Provider theme={theme}>

      <title>Sign up – Hack Club</title>

      <Heading is="h1" color="white" f={[5, 6]} mt={4}>
        Submit your application
      </Heading>

    <ApplicationForm months={next12Months()} />

  </Provider>
)
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { connect } from 'react-redux';
import * as actions from '../actions/index';
import IceboxList from '../components/iceboxList';

class Icebox extends Component {
	render(){
		return (

        <IceboxList />

		);
	}
}

export default Icebox;<commit_msg>[setup] adds iceboxToolbar to Icebox container<commit_after>import React, { Component } from 'react';
import { connect } from 'react-redux';
import * as actions from '../actions/index';
import IceboxToolbar from '../components/iceboxToolbar';
import IceboxList from '../components/iceboxList';

class Icebox extends Component {
	render(){
		return (

				<IceboxToolbar />
        <IceboxList />

		);
	}
}

export default Icebox;<|endoftext|>