added ability to switch what metacodes you are mapping with

This commit is contained in:
Connor Turland 2013-01-25 20:49:40 -05:00
parent 633e882aaa
commit a0f638c10c
17 changed files with 376 additions and 120 deletions

View file

@ -13,38 +13,6 @@
animate = !(iStuff || !nativeCanvasSupport);
})();
var imgArray = new Object();
imgArray['Group'] = new Image(); imgArray['Group'].src = '/assets/group.png';
imgArray['Person'] = new Image(); imgArray['Person'].src = '/assets/person.png';
imgArray['Bizarre'] = new Image(); imgArray['Bizarre'].src = '/assets/bizarre.png';
imgArray['Catalyst'] = new Image(); imgArray['Catalyst'].src = '/assets/catalyst.png';
imgArray['Closed'] = new Image(); imgArray['Closed'].src = '/assets/closed.png';
imgArray['Experience'] = new Image(); imgArray['Experience'].src = '/assets/experience.png';
imgArray['Future Dev'] = new Image(); imgArray['Future Dev'].src = '/assets/futuredev.png';
imgArray['Idea'] = new Image(); imgArray['Idea'].src = '/assets/idea.png';
imgArray['Implication'] = new Image(); imgArray['Implication'].src = '/assets/implication.png';
imgArray['Insight'] = new Image(); imgArray['Insight'].src = '/assets/insight.png';
imgArray['Intention'] = new Image(); imgArray['Intention'].src = '/assets/intention.png';
imgArray['Knowledge'] = new Image(); imgArray['Knowledge'].src = '/assets/knowledge.png';
imgArray['Location'] = new Image(); imgArray['Location'].src = '/assets/location.png';
imgArray['Open Issue'] = new Image(); imgArray['Open Issue'].src = '/assets/openissue.png';
imgArray['Opinion'] = new Image(); imgArray['Opinion'].src = '/assets/opinion.png';
imgArray['Opportunity'] = new Image(); imgArray['Opportunity'].src = '/assets/opportunity.png';
imgArray['Platform'] = new Image(); imgArray['Platform'].src = '/assets/platform.png';
imgArray['Problem'] = new Image(); imgArray['Problem'].src = '/assets/problem.png';
imgArray['Question'] = new Image(); imgArray['Question'].src = '/assets/question.png';
imgArray['Reference'] = new Image(); imgArray['Reference'].src = '/assets/reference.png';
imgArray['Requirement'] = new Image(); imgArray['Requirement'].src = '/assets/requirement.png';
imgArray['Resource'] = new Image(); imgArray['Resource'].src = '/assets/resource.png';
imgArray['Role'] = new Image(); imgArray['Role'].src = '/assets/role.png';
imgArray['Task'] = new Image(); imgArray['Task'].src = '/assets/task.png';
imgArray['Tool'] = new Image(); imgArray['Tool'].src = '/assets/tool.png';
imgArray['Trajectory'] = new Image(); imgArray['Trajectory'].src = '/assets/trajectory.png';
imgArray['Action'] = new Image(); imgArray['Action'].src = '/assets/action.png';
imgArray['Activity'] = new Image(); imgArray['Activity'].src = '/assets/activity.png';
// init custom node type
$jit.ForceDirected.Plot.NodeTypes.implement(nodeSettings);
//implement an edge type

View file

@ -243,7 +243,7 @@ function generateLittleHTML(node) {
//logged in, and owner of the topic, thus permission to delete
littleHTML += ' \
<span class="deleteTopic" \
onclick="deleteNode($_id_$)" \
onclick="var t = confirm(\'Are you sure you want to permanently delete this node and all synapses linking to it?\'); if (t) deleteNode($_id_$)" \
title="Click to delete this topic"> \
</span>';
}

View file

@ -226,9 +226,11 @@ function fetchRelatives(node) {
url: "/topics/" + node.id + "?format=json",
success: function(data) {
if (gType == "centered") {
Mconsole.busy = true;
Mconsole.op.sum(data, {
type: 'fade',
duration: 500
duration: 500,
hideLabels: false
});
Mconsole.graph.eachNode(function (n) {
n.eachAdjacency(function (a) {
@ -239,6 +241,7 @@ function fetchRelatives(node) {
}
});
});
Mconsole.busy = false;
}
else {
Mconsole.op.sum(data, {

View file

@ -111,7 +111,6 @@ a {
.new_session,
.new_user,
.new_map,
.edit_user,
.edit_topic,
.edit_synapse,
.edit_map,
@ -129,6 +128,20 @@ a {
border:2px solid #000;
}
.edit_user{
display: block;
width: 800px;
position:absolute;
left:50%;
top:0;
margin:50px 0 0 -420px;
background: url('bg.png');
padding: 20px;
border-radius: 15px;
color: #000;
border:2px solid #000;
}
.onConsole .new_map {
display:none;
}

View file

@ -1,3 +1,65 @@
// Place all the styles related to the users controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
.allMetacodes {
float:left;
}
.allMetacodes span {
margin:4px 8px;
color:#67AF9F;
}
.editMetacodes {
z-index:12;
width:auto;
color: #67AF9F;
padding:10px;
float:left;
}
.editMetacodes ul {
display:block;
}
.editMetacodes ul li {
clear:both;
list-style-type:none;
display:block;
padding:3px;
}
.editMetacodes ul img {
width:40px;
height:40px;
float:left;
}
.editMetacodes ul p {
float:left;
display: block;
margin: 0;
background: none;
padding: 10px 4px 2px 4px;
}
.editMetacodes #filters-one {
float:left;
}
.editMetacodes #filters-two {
float:left;
}
.editMetacodes #filters-three {
float:left;
}
.editMetacodes #filters-four {
float:left;
}
.editMetacodes li.toggledOff {
opacity: 0.4;
}

View file

@ -64,6 +64,9 @@ class UsersController < ApplicationController
@user = current_user
@user.attributes = params[:user]
@m = params[:metacodes][:value]
@user.settings.metacodes=@m.split(',')
@user.save
respond_with(@user, location: user_url(@user)) do |format|

View file

@ -2,4 +2,9 @@ class Metacode < ActiveRecord::Base
has_many :topics
def hasSelected(user)
return true if user.settings.metacodes.include? self.id.to_s
return false
end
end

View file

@ -15,6 +15,8 @@ has_many :mappings
configuration.merge_validates_length_of_email_field_options unless: Proc.new { |user| user.email.blank? and user.authed? }
end
serialize :settings, UserPreference
validates :password, :presence => true,
:length => {
:maximum => 20,
@ -27,5 +29,18 @@ has_many :mappings
:on => :update
validates :joinedwithcode, :presence => true, :inclusion => { :in => User.all.map(&:code), :message => "%{value} is not a valid code" }, :on => :create
def settings
# make sure we always return a UserPreference instance
if read_attribute(:settings).nil?
write_attribute :settings, UserPreference.new
read_attribute :settings
else
read_attribute :settings
end
end
def settings=(val)
write_attribute :settings, val
end
end

View file

@ -0,0 +1,11 @@
class UserPreference
attr_accessor :metacodes
def initialize
array = []
Metacode.all.each do |m|
array.push(m.id.to_s)
end
@metacodes = array
end
end

View file

@ -20,6 +20,13 @@
var username = null;
</script>
<% end %>
<script>
var imgArray = new Object();
<% Metacode.all.each do |m| %>
imgArray['<%= m.name %>'] = new Image(); imgArray['<%= m.name %>'].src = '/assets/<%= m.icon %>';
<% end %>
</script>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<script type="text/javascript" src="//use.typekit.net/tki2nyo.js"></script>

View file

@ -4,7 +4,13 @@
#%>
<div class="anypage">
<%= form_for Topic.new, url: topics_url, remote: true do |form| %>
<div id="metacodeImg"><img class="cloudcarousel" width="40" height="40" src="/assets/action.png" alt="Action" title="Action"/><img class="cloudcarousel" width="40" height="40" src="/assets/activity.png" alt="Activity" title="Activity"/><img class="cloudcarousel" width="40" height="40" src="/assets/bizarre.png" alt="Bizarre" title="Bizarre"/><img class="cloudcarousel" width="40" height="40" src="/assets/catalyst.png" alt="Catalyst" title="Catalyst"/><img class="cloudcarousel" width="40" height="40" src="/assets/closed.png" alt="Closed" title="Closed"/><img class="cloudcarousel" width="40" height="40" src="/assets/experience.png" alt="Experience" title="Experience"/><img class="cloudcarousel" width="40" height="40" src="/assets/futuredev.png" alt="Future Dev" title="Future Dev"/><img class="cloudcarousel" width="40" height="40" src="/assets/group.png" alt="Group" title="Group"/><img class="cloudcarousel" width="40" height="40" src="/assets/idea.png" alt="Idea" title="Idea"/><img class="cloudcarousel" width="40" height="40" src="/assets/implication.png" alt="Implication" title="Implication"/><img class="cloudcarousel" width="40" height="40" src="/assets/insight.png" alt="Insight" title="Insight"/><img class="cloudcarousel" width="40" height="40" src="/assets/intention.png" alt="Intention" title="Intention"/><img class="cloudcarousel" width="40" height="40" src="/assets/knowledge.png" alt="Knowledge" title="Knowledge"/><img class="cloudcarousel" width="40" height="40" src="/assets/location.png" alt="Location" title="Location"/><img class="cloudcarousel" width="40" height="40" src="/assets/openissue.png" alt="Open Issue" title="Open Issue"/><img class="cloudcarousel" width="40" height="40" src="/assets/opinion.png" alt="Opinion" title="Opinion"/><img class="cloudcarousel" width="40" height="40" src="/assets/opportunity.png" alt="Opportunity" title="Opportunity"/><img class="cloudcarousel" width="40" height="40" src="/assets/person.png" alt="Person" title="Person"/><img class="cloudcarousel" width="40" height="40" src="/assets/platform.png" alt="Platform" title="Platform"/><img class="cloudcarousel" width="40" height="40" src="/assets/problem.png" alt="Problem" title="Problem"/><img class="cloudcarousel" width="40" height="40" src="/assets/question.png" alt="Question" title="Question"/><img class="cloudcarousel" width="40" height="40" src="/assets/reference.png" alt="Reference" title="Reference"/><img class="cloudcarousel" width="40" height="40" src="/assets/requirement.png" alt="Requirement" title="Requirement"/><img class="cloudcarousel" width="40" height="40" src="/assets/resource.png" alt="Resource" title="Resource"/><img class="cloudcarousel" width="40" height="40" src="/assets/role.png" alt="Role" title="Role"/><img class="cloudcarousel" width="40" height="40" src="/assets/task.png" alt="Task" title="Task"/><img class="cloudcarousel" width="40" height="40" src="/assets/tool.png" alt="Tool" title="Tool"/><img class="cloudcarousel" width="40" height="40" src="/assets/trajectory.png" alt="Trajectory" title="Trajectory"/></div>
<div id="metacodeImg">
<% @m = user.settings.metacodes %>
<% @m.each do |m| %>
<% metacode = Metacode.find(m.to_i) %>
<img class="cloudcarousel" width="40" height="40" src="/assets/<%= metacode.icon %>" alt="<%= metacode.name %>" title="<%= metacode.name %>"/>
<% end %>
</div>
<%= form.autocomplete_field :name, autocomplete_topic_name_topics_path, :placeholder => "What is the name of your topic?" %>
<%= form.hidden_field :metacode, :value => "Action" %>
<%= form.hidden_field :x, :value => 0 %>

View file

@ -6,7 +6,13 @@
<div class="anypage">
<%= form_for Topic.new, url: topics_url, remote: true do |form| %>
<div id="metacodeImg"><img class="cloudcarousel" width="40" height="40" src="/assets/action.png" alt="Action" title="Action"/><img class="cloudcarousel" width="40" height="40" src="/assets/activity.png" alt="Activity" title="Activity"/><img class="cloudcarousel" width="40" height="40" src="/assets/bizarre.png" alt="Bizarre" title="Bizarre"/><img class="cloudcarousel" width="40" height="40" src="/assets/catalyst.png" alt="Catalyst" title="Catalyst"/><img class="cloudcarousel" width="40" height="40" src="/assets/closed.png" alt="Closed" title="Closed"/><img class="cloudcarousel" width="40" height="40" src="/assets/experience.png" alt="Experience" title="Experience"/><img class="cloudcarousel" width="40" height="40" src="/assets/futuredev.png" alt="Future Dev" title="Future Dev"/><img class="cloudcarousel" width="40" height="40" src="/assets/group.png" alt="Group" title="Group"/><img class="cloudcarousel" width="40" height="40" src="/assets/idea.png" alt="Idea" title="Idea"/><img class="cloudcarousel" width="40" height="40" src="/assets/implication.png" alt="Implication" title="Implication"/><img class="cloudcarousel" width="40" height="40" src="/assets/insight.png" alt="Insight" title="Insight"/><img class="cloudcarousel" width="40" height="40" src="/assets/intention.png" alt="Intention" title="Intention"/><img class="cloudcarousel" width="40" height="40" src="/assets/knowledge.png" alt="Knowledge" title="Knowledge"/><img class="cloudcarousel" width="40" height="40" src="/assets/location.png" alt="Location" title="Location"/><img class="cloudcarousel" width="40" height="40" src="/assets/openissue.png" alt="Open Issue" title="Open Issue"/><img class="cloudcarousel" width="40" height="40" src="/assets/opinion.png" alt="Opinion" title="Opinion"/><img class="cloudcarousel" width="40" height="40" src="/assets/opportunity.png" alt="Opportunity" title="Opportunity"/><img class="cloudcarousel" width="40" height="40" src="/assets/person.png" alt="Person" title="Person"/><img class="cloudcarousel" width="40" height="40" src="/assets/platform.png" alt="Platform" title="Platform"/><img class="cloudcarousel" width="40" height="40" src="/assets/problem.png" alt="Problem" title="Problem"/><img class="cloudcarousel" width="40" height="40" src="/assets/question.png" alt="Question" title="Question"/><img class="cloudcarousel" width="40" height="40" src="/assets/reference.png" alt="Reference" title="Reference"/><img class="cloudcarousel" width="40" height="40" src="/assets/requirement.png" alt="Requirement" title="Requirement"/><img class="cloudcarousel" width="40" height="40" src="/assets/resource.png" alt="Resource" title="Resource"/><img class="cloudcarousel" width="40" height="40" src="/assets/role.png" alt="Role" title="Role"/><img class="cloudcarousel" width="40" height="40" src="/assets/task.png" alt="Task" title="Task"/><img class="cloudcarousel" width="40" height="40" src="/assets/tool.png" alt="Tool" title="Tool"/><img class="cloudcarousel" width="40" height="40" src="/assets/trajectory.png" alt="Trajectory" title="Trajectory"/></div>
<div id="metacodeImg">
<% @m = user.settings.metacodes %>
<% @m.each do |m| %>
<% metacode = Metacode.find(m.to_i) %>
<img class="cloudcarousel" width="40" height="40" src="/assets/<%= metacode.icon %>" alt="<%= metacode.name %>" title="<%= metacode.name %>"/>
<% end %>
</div>
<%= form.autocomplete_field :name, autocomplete_topic_name_topics_path, :placeholder => "What is the name of your topic?" %>
<%= form.hidden_field :metacode, :value => "Action" %>
<%= form.hidden_field :x, :value => 0 %>

View file

@ -1,12 +1,110 @@
<%#
# @file
# TODO: What URL is this?
# /users/:id/edit
# User edit form
#%>
<%= formula_form_for @user, url: user_url do |form| %>
<h3>Choose Active Metacodes</h3>
<div class="allMetacodes"><span id="showAll">Show All</span><span id="hideAll">Hide All</span></div>
<div class="clearfloat"></div>
<div class="editMetacodes">
<ul id="filters-one">
<% $i = 0 %>
<% @m = Metacode.order("name").all %>
<% while $i < 10 do %>
<li id="<%= @m[$i].id %>" <% if not @m[$i].hasSelected(@user) %>class="toggledOff"<% end %> >
<img src="/assets/<%= @m[$i].icon %>" alt="<%= @m[$i].name %>" />
<p><%= @m[$i].name.downcase %></p>
<div class="clearfloat"></div>
</li>
<% $i += 1 %>
<% end %>
</ul>
<ul id="filters-two">
<% while $i < 20 do %>
<li id="<%= @m[$i].id %>" <% if not @m[$i].hasSelected(@user) %>class="toggledOff"<% end %> >
<img src="/assets/<%= @m[$i].icon %>" alt="<%= @m[$i].name %>" />
<p><%= @m[$i].name.downcase %></p>
<div class="clearfloat"></div>
</li>
<% $i += 1 %>
<% end %>
</ul>
<ul id="filters-three">
<% while $i < 30 do %>
<li id="<%= @m[$i].id %>" <% if not @m[$i].hasSelected(@user) %>class="toggledOff"<% end %> >
<img src="/assets/<%= @m[$i].icon %>" alt="<%= @m[$i].name %>" />
<p><%= @m[$i].name.downcase %></p>
<div class="clearfloat"></div>
</li>
<% $i += 1 %>
<% end %>
</ul>
<ul id="filters-four">
<% while $i < 40 do %>
<li id="<%= @m[$i].id %>" <% if not @m[$i].hasSelected(@user) %>class="toggledOff"<% end %> >
<img src="/assets/<%= @m[$i].icon %>" alt="<%= @m[$i].name %>" />
<p><%= @m[$i].name.downcase %></p>
<div class="clearfloat"></div>
</li>
<% $i += 1 %>
<% end %>
</ul>
<div class="clearfloat"></div>
</div>
<h3>Edit Account</h3>
<%= form.input :name, label: "Name", class: "name" %>
<%= form.input :email, label: "Email", class: "email" %>
<%= form.input :password, label: "Password", class: "password" %>
<%= hidden_field(:metacodes, :value, {:value => 0}) %>
<%= form.submit "Update", class: "update" %>
<% end %>
<script>
var selectMetacodes = new Array;
var allMetacodes = new Array;
<% Metacode.all.each do |m| %>
<% if m.hasSelected(@user) %>
selectMetacodes.push("<%= m.id %>");
<% end %>
allMetacodes.push("<%= m.id %>");
<% end %>
$(document).ready(function() {
$('#metacodes_0').val(selectMetacodes.toString());
$('.editMetacodes li').click(function() {
if ($(this).attr('class') != 'toggledOff') {
$(this).addClass('toggledOff');
var value_to_remove = $(this).attr('id');
selectMetacodes.splice(selectMetacodes.indexOf(value_to_remove), 1);
$('#metacodes_value').val(selectMetacodes.toString());
}
else if ($(this).attr('class') == 'toggledOff') {
$(this).removeClass('toggledOff');
selectMetacodes.push($(this).attr('id'));
$('#metacodes_value').val(selectMetacodes.toString());
}
});
$('#showAll').click(function() {
$('.editMetacodes li').removeClass('toggledOff');
selectMetacodes = allMetacodes;
$('#metacodes_value').val(selectMetacodes.toString());
});
$('#hideAll').click(function() {
$('.editMetacodes li').addClass('toggledOff');
selectMetacodes = [];
$('#metacodes_value').val(0);
});
$('.edit_user').bind('submit', function(event) {
if (selectMetacodes.length == 0) {
alert('Would you pretty please select at least one metacode to map with?');
return false;
}
});
});
</script>

View file

@ -3,6 +3,7 @@ class CreateUsers < ActiveRecord::Migration
create_table :users do |t|
t.string :name
t.string :email
t.text :settings
t.string :code, :limit => 8
t.string :joinedwithcode, :limit => 8
t.string :crypted_password

View file

@ -0,0 +1,9 @@
class AddMetacodesToUser < ActiveRecord::Migration
def self.up
add_column :users, :settings, :text
end
def self.down
remove_column :users, :settings
end
end

View file

@ -1,81 +1,82 @@
# encoding: UTF-8
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20130101194424) do
create_table "mappings", :force => true do |t|
t.text "category"
t.integer "xloc"
t.integer "yloc"
t.integer "topic_id"
t.integer "synapse_id"
t.integer "map_id"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "maps", :force => true do |t|
t.text "name"
t.boolean "arranged"
t.text "desc"
t.text "permission"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "metacodes", :force => true do |t|
t.text "name"
t.string "icon"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "synapses", :force => true do |t|
t.text "desc"
t.text "category"
t.text "weight"
t.text "permission"
t.integer "node1_id"
t.integer "node2_id"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "topics", :force => true do |t|
t.text "name"
t.text "desc"
t.text "link"
t.text "permission"
t.integer "user_id"
t.integer "metacode_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "users", :force => true do |t|
t.string "name"
t.string "email"
t.string "code", :limit => 8
t.string "joinedwithcode", :limit => 8
t.string "crypted_password"
t.string "password_salt"
t.string "persistence_token"
t.string "perishable_token"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
end
# encoding: UTF-8
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20130125210014) do
create_table "mappings", :force => true do |t|
t.text "category"
t.integer "xloc"
t.integer "yloc"
t.integer "topic_id"
t.integer "synapse_id"
t.integer "map_id"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "maps", :force => true do |t|
t.text "name"
t.boolean "arranged"
t.text "desc"
t.text "permission"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "metacodes", :force => true do |t|
t.text "name"
t.string "icon"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "synapses", :force => true do |t|
t.text "desc"
t.text "category"
t.text "weight"
t.text "permission"
t.integer "node1_id"
t.integer "node2_id"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "topics", :force => true do |t|
t.text "name"
t.text "desc"
t.text "link"
t.text "permission"
t.integer "user_id"
t.integer "metacode_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "users", :force => true do |t|
t.string "name"
t.string "email"
t.string "code", :limit => 8
t.string "joinedwithcode", :limit => 8
t.string "crypted_password"
t.string "password_salt"
t.string "persistence_token"
t.string "perishable_token"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.text "settings"
end
end

View file

@ -115,3 +115,51 @@ twenty-seven:
twenty-eight:
name: Trajectory
icon: trajectory.png
twenty-nine:
name: Argument
icon: argument.png
thirty:
name: Con
icon: con_icon.png
thirty-one:
name: Decision
icon: decision.png
thirty-two:
name: Example
icon: example.png
thirty-three:
name: Foresight
icon: foresight.png
thirty-four:
name: Good Practice
icon: goodpractice.png
thirty-five:
name: List
icon: list.png
thirty-six:
name: Movie Map
icon: moviemap.png
thirty-seven:
name: Note
icon: note.png
thirty-eight:
name: Pro
icon: pro.png
thirty-nine:
name: Research
icon: research.png
forty:
name: Wildcard
icon: wildcard.png