Merge branch 'develop' of https://github.com/Connoropolous/metamaps_gen002
This commit is contained in:
commit
5725007e78
14 changed files with 282 additions and 196 deletions
6
LiveSiteUpdatesNotes.txt
Normal file
6
LiveSiteUpdatesNotes.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
make sure that root individuals have same 'joinedwithcode' as 'code'
|
||||
|
||||
User.all.each do |u|
|
||||
u.generation = u.get_generation
|
||||
u.save
|
||||
end
|
|
@ -2495,7 +2495,7 @@ Extras.Classes.Navigation = new Class({
|
|||
//START METAMAPS CODE
|
||||
var rightClick = e.button == 2 || (navigator.platform.indexOf("Mac") != -1 && e.ctrlKey);
|
||||
// TODO make sure this works across browsers
|
||||
if (!Metamaps.Mouse.boxStartCoordinates && ((e.button == 0 && e.shiftKey) || (e.button == 0 && e.ctrlKey) || (rightClick && e.ctrlKey))) {
|
||||
if (!Metamaps.Mouse.boxStartCoordinates && ((e.button == 0 && e.shiftKey) || (e.button == 0 && e.ctrlKey) || rightClick)) {
|
||||
Metamaps.Mouse.boxStartCoordinates = eventInfo.getPos();
|
||||
//console.log('mouse down');
|
||||
}
|
||||
|
@ -2525,13 +2525,13 @@ Extras.Classes.Navigation = new Class({
|
|||
|
||||
// START METAMAPS CODE
|
||||
var rightClick = e.button == 2 || (navigator.platform.indexOf("Mac") != -1 && e.ctrlKey);
|
||||
if (!Metamaps.Mouse.boxStartCoordinates && ((e.button == 0 && e.shiftKey) || (e.button == 0 && e.ctrlKey) || (rightClick && e.ctrlKey))) {
|
||||
if (!Metamaps.Mouse.boxStartCoordinates && ((e.button == 0 && e.shiftKey) || (e.button == 0 && e.ctrlKey) || rightClick)) {
|
||||
Metamaps.Visualize.mGraph.busy = true;
|
||||
Metamaps.boxStartCoordinates = eventInfo.getPos();
|
||||
//console.log('mouse move');
|
||||
return;
|
||||
}
|
||||
if (Metamaps.Mouse.boxStartCoordinates && ((e.button == 0 && e.shiftKey) || (e.button == 0 && e.ctrlKey) || (rightClick && e.ctrlKey))) {
|
||||
if (Metamaps.Mouse.boxStartCoordinates && ((e.button == 0 && e.shiftKey) || (e.button == 0 && e.ctrlKey) || rightClick)) {
|
||||
Metamaps.Visualize.mGraph.busy = true;
|
||||
Metamaps.JIT.drawSelectBox(eventInfo,e);
|
||||
//console.log('mouse move');
|
||||
|
|
|
@ -374,14 +374,14 @@ Metamaps.JIT = {
|
|||
$('.rightclickmenu').remove();
|
||||
|
||||
if (Metamaps.Mouse.boxStartCoordinates) {
|
||||
if(e.ctrlKey && e.shiftKey){
|
||||
if(e.ctrlKey){
|
||||
Metamaps.Visualize.mGraph.busy = false;
|
||||
Metamaps.Mouse.boxEndCoordinates = eventInfo.getPos();
|
||||
Metamaps.JIT.zoomToBox(e);
|
||||
//console.log('called zoom to box');
|
||||
return;
|
||||
}
|
||||
else if (e.ctrlKey || e.shiftKey) {
|
||||
else if (e.shiftKey) {
|
||||
Metamaps.Visualize.mGraph.busy = false;
|
||||
Metamaps.Mouse.boxEndCoordinates = eventInfo.getPos();
|
||||
Metamaps.JIT.selectWithBox(e);
|
||||
|
@ -410,10 +410,10 @@ Metamaps.JIT = {
|
|||
// remove the rightclickmenu
|
||||
$('.rightclickmenu').remove();
|
||||
|
||||
if (Metamaps.Mouse.boxStartCoordinates && e.ctrlKey) {
|
||||
if (Metamaps.Mouse.boxStartCoordinates) {
|
||||
Metamaps.Visualize.mGraph.busy = false;
|
||||
Metamaps.Mouse.boxEndCoordinates = eventInfo.getPos();
|
||||
Metamaps.JIT.zoomToBox(e);
|
||||
Metamaps.JIT.selectWithBox(e);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1097,7 +1097,7 @@ Metamaps.JIT = {
|
|||
eX = Metamaps.Mouse.boxEndCoordinates.x,
|
||||
eY = Metamaps.Mouse.boxEndCoordinates.y;
|
||||
|
||||
if(!(e.shiftKey) && !(e.ctrlKey)){
|
||||
if(!e.shiftKey){
|
||||
Metamaps.Control.deselectAllNodes();
|
||||
Metamaps.Control.deselectAllEdges();
|
||||
}
|
||||
|
@ -1108,7 +1108,7 @@ Metamaps.JIT = {
|
|||
y = n.pos.y;
|
||||
|
||||
if ((sX < x && x < eX && sY < y && y < eY) || (sX > x && x > eX && sY > y && y > eY) || (sX > x && x > eX && sY < y && y < eY) || (sX < x && x < eX && sY > y && y > eY)) {
|
||||
if(e.ctrlKey){
|
||||
if(e.shiftKey){
|
||||
if(n.selected){
|
||||
Metamaps.Control.deselectNode(n);
|
||||
}
|
||||
|
@ -1211,7 +1211,7 @@ Metamaps.JIT = {
|
|||
var node2id = synapse.get('edge').nodeTo.id;
|
||||
var edge = Metamaps.Visualize.mGraph.graph.getAdjacence(node1id, node2id);
|
||||
if(selectTest){
|
||||
if(e.ctrlKey){
|
||||
if(e.shiftKey){
|
||||
if(Metamaps.Selected.Edges.indexOf(synapse.get('edge')) != -1 ){
|
||||
Metamaps.Control.deselectEdge(synapse.get('edge'));
|
||||
}
|
||||
|
@ -1273,23 +1273,19 @@ Metamaps.JIT = {
|
|||
// wait a certain length of time, then check again, then run this code
|
||||
setTimeout(function () {
|
||||
if (!Metamaps.JIT.nodeWasDoubleClicked()) {
|
||||
if (!e.shiftKey && !e.ctrlKey) {
|
||||
|
||||
var nodeAlreadySelected = node.selected;
|
||||
|
||||
if (!e.shiftKey) {
|
||||
Metamaps.Control.deselectAllNodes();
|
||||
Metamaps.Control.deselectAllEdges();
|
||||
Metamaps.Control.selectNode(node,e);
|
||||
}
|
||||
else if(e.shiftKey && e.ctrlKey){
|
||||
//no result
|
||||
}
|
||||
else if(e.ctrlKey){
|
||||
if (node.selected) {
|
||||
|
||||
if (nodeAlreadySelected) {
|
||||
Metamaps.Control.deselectNode(node);
|
||||
} else {
|
||||
Metamaps.Control.selectNode(node,e);
|
||||
}
|
||||
}else if(e.shiftKey){
|
||||
Metamaps.Control.selectNode(node,e);
|
||||
}
|
||||
|
||||
//trigger animation to final styles
|
||||
Metamaps.Visualize.mGraph.fx.animate({
|
||||
|
@ -1531,24 +1527,19 @@ Metamaps.JIT = {
|
|||
// wait a certain length of time, then check again, then run this code
|
||||
setTimeout(function () {
|
||||
if (!Metamaps.JIT.nodeWasDoubleClicked()) {
|
||||
if (!e.shiftKey && !e.ctrlKey) {
|
||||
|
||||
var edgeAlreadySelected = Metamaps.Selected.Edges.indexOf(adj) !== -1;
|
||||
|
||||
if (!e.shiftKey) {
|
||||
Metamaps.Control.deselectAllNodes();
|
||||
Metamaps.Control.deselectAllEdges();
|
||||
Metamaps.Control.selectEdge(adj);
|
||||
}
|
||||
else if (e.shiftKey && e.ctrlKey){
|
||||
//no result
|
||||
}
|
||||
else if (e.ctrlKey){
|
||||
if (Metamaps.Selected.Edges.indexOf(adj) !== -1) {
|
||||
|
||||
if (edgeAlreadySelected) {
|
||||
Metamaps.Control.deselectEdge(adj);
|
||||
} else {
|
||||
Metamaps.Control.selectEdge(adj);
|
||||
}
|
||||
}
|
||||
else if (e.shiftKey){
|
||||
Metamaps.Control.selectEdge(adj);
|
||||
}
|
||||
|
||||
Metamaps.Visualize.mGraph.plot();
|
||||
}
|
||||
|
@ -1861,7 +1852,7 @@ Metamaps.JIT = {
|
|||
var x = n.pos.x,
|
||||
y = n.pos.y;
|
||||
|
||||
if (counter == 0){
|
||||
if (counter == 0 && n.getData('alpha') == 1){
|
||||
maxX = x;
|
||||
minX = x;
|
||||
maxY = y;
|
||||
|
@ -1880,12 +1871,15 @@ Metamaps.JIT = {
|
|||
}
|
||||
var width = Math.max.apply(null, lineWidths) + 8;
|
||||
|
||||
// only adjust these values if the node is not filtered
|
||||
if (n.getData('alpha') == 1) {
|
||||
maxX = Math.max(x + width /2,maxX);
|
||||
maxY = Math.max(y + n.getData("height") + 5 + height,maxY);
|
||||
minX = Math.min(x - width /2,minX);
|
||||
minY = Math.min(y - dim,minY);
|
||||
|
||||
counter++;
|
||||
}
|
||||
});
|
||||
|
||||
var spanX = maxX - minX;
|
||||
|
|
|
@ -1888,13 +1888,13 @@ Metamaps.Realtime = {
|
|||
turnOn: function (notify) {
|
||||
var self = Metamaps.Realtime;
|
||||
|
||||
if (!self.status) {
|
||||
if (notify) self.sendRealtimeOn();
|
||||
$(".rtMapperSelf").removeClass('littleRtOff').addClass('littleRtOn');
|
||||
$('.rtOn').addClass('active');
|
||||
$('.rtOff').removeClass('active');
|
||||
self.status = true;
|
||||
$(".sidebarCollaborateIcon").addClass("blue");
|
||||
$(".collabCompass").show();
|
||||
}
|
||||
},
|
||||
turnOff: function (silent) {
|
||||
var self = Metamaps.Realtime;
|
||||
|
@ -1902,6 +1902,8 @@ Metamaps.Realtime = {
|
|||
if (self.status) {
|
||||
if (!silent) self.sendRealtimeOff();
|
||||
$(".rtMapperSelf").removeClass('littleRtOn').addClass('littleRtOff');
|
||||
$('.rtOn').removeClass('active');
|
||||
$('.rtOff').addClass('active');
|
||||
self.status = false;
|
||||
$(".sidebarCollaborateIcon").removeClass("blue");
|
||||
$(".collabCompass").hide();
|
||||
|
@ -3111,6 +3113,8 @@ Metamaps.Filter = {
|
|||
$('#filter_by_metacode ul').empty();
|
||||
$('#filter_by_mapper ul').empty();
|
||||
$('#filter_by_synapse ul').empty();
|
||||
|
||||
$('.filterBox .showAll').addClass('active');
|
||||
},
|
||||
/*
|
||||
Most of this data essentially depends on the ruby function which are happening for filter inside view filterBox
|
||||
|
@ -3239,36 +3243,48 @@ Metamaps.Filter = {
|
|||
filterAllMetacodes: function (e) {
|
||||
var self = Metamaps.Filter;
|
||||
$('#filter_by_metacode ul li').addClass('toggledOff');
|
||||
$('.showAllMetacodes').removeClass('active');
|
||||
$('.hideAllMetacodes').addClass('active');
|
||||
self.visible.metacodes = [];
|
||||
self.passFilters();
|
||||
},
|
||||
filterNoMetacodes: function (e) {
|
||||
var self = Metamaps.Filter;
|
||||
$('#filter_by_metacode ul li').removeClass('toggledOff');
|
||||
$('.showAllMetacodes').addClass('active');
|
||||
$('.hideAllMetacodes').removeClass('active');
|
||||
self.visible.metacodes = self.filters.metacodes.slice();
|
||||
self.passFilters();
|
||||
},
|
||||
filterAllMappers: function (e) {
|
||||
var self = Metamaps.Filter;
|
||||
$('#filter_by_mapper ul li').addClass('toggledOff');
|
||||
$('.showAllMappers').removeClass('active');
|
||||
$('.hideAllMappers').addClass('active');
|
||||
self.visible.mappers = [];
|
||||
self.passFilters();
|
||||
},
|
||||
filterNoMappers: function (e) {
|
||||
var self = Metamaps.Filter;
|
||||
$('#filter_by_mapper ul li').removeClass('toggledOff');
|
||||
$('.showAllMappers').addClass('active');
|
||||
$('.hideAllMappers').removeClass('active');
|
||||
self.visible.mappers = self.filters.mappers.slice();
|
||||
self.passFilters();
|
||||
},
|
||||
filterAllSynapses: function (e) {
|
||||
var self = Metamaps.Filter;
|
||||
$('#filter_by_synapse ul li').addClass('toggledOff');
|
||||
$('.showAllSynapses').removeClass('active');
|
||||
$('.hideAllSynapses').addClass('active');
|
||||
self.visible.synapses = [];
|
||||
self.passFilters();
|
||||
},
|
||||
filterNoSynapses: function (e) {
|
||||
var self = Metamaps.Filter;
|
||||
$('#filter_by_synapse ul li').removeClass('toggledOff');
|
||||
$('.showAllSynapses').addClass('active');
|
||||
$('.hideAllSynapses').removeClass('active');
|
||||
self.visible.synapses = self.filters.synapses.slice();
|
||||
self.passFilters();
|
||||
},
|
||||
|
@ -3292,14 +3308,53 @@ Metamaps.Filter = {
|
|||
toggleMetacode: function () {
|
||||
var self = Metamaps.Filter;
|
||||
self.toggleLi.call(this, 'metacodes');
|
||||
|
||||
if (self.visible.metacodes.length === self.filters.metacodes.length) {
|
||||
$('.showAllMetacodes').addClass('active');
|
||||
$('.hideAllMetacodes').removeClass('active');
|
||||
}
|
||||
else if (self.visible.metacodes.length === 0) {
|
||||
$('.showAllMetacodes').removeClass('active');
|
||||
$('.hideAllMetacodes').addClass('active');
|
||||
}
|
||||
else {
|
||||
$('.showAllMetacodes').removeClass('active');
|
||||
$('.hideAllMetacodes').removeClass('active');
|
||||
}
|
||||
},
|
||||
toggleMapper: function () {
|
||||
var self = Metamaps.Filter;
|
||||
self.toggleLi.call(this, 'mappers');
|
||||
|
||||
if (self.visible.mappers.length === self.filters.mappers.length) {
|
||||
$('.showAllMappers').addClass('active');
|
||||
$('.hideAllMappers').removeClass('active');
|
||||
}
|
||||
else if (self.visible.mappers.length === 0) {
|
||||
$('.showAllMappers').removeClass('active');
|
||||
$('.hideAllMappers').addClass('active');
|
||||
}
|
||||
else {
|
||||
$('.showAllMappers').removeClass('active');
|
||||
$('.hideAllMappers').removeClass('active');
|
||||
}
|
||||
},
|
||||
toggleSynapse: function () {
|
||||
var self = Metamaps.Filter;
|
||||
self.toggleLi.call(this, 'synapses');
|
||||
|
||||
if (self.visible.synapses.length === self.filters.synapses.length) {
|
||||
$('.showAllSynapses').addClass('active');
|
||||
$('.hideAllSynapses').removeClass('active');
|
||||
}
|
||||
else if (self.visible.synapses.length === 0) {
|
||||
$('.showAllSynapses').removeClass('active');
|
||||
$('.hideAllSynapses').addClass('active');
|
||||
}
|
||||
else {
|
||||
$('.showAllSynapses').removeClass('active');
|
||||
$('.hideAllSynapses').removeClass('active');
|
||||
}
|
||||
},
|
||||
passFilters: function () {
|
||||
var self = Metamaps.Filter;
|
||||
|
@ -4204,6 +4259,7 @@ Metamaps.Map = {
|
|||
Metamaps.Create.newTopic.hide();
|
||||
Metamaps.Create.newSynapse.hide();
|
||||
Metamaps.Filter.close();
|
||||
Metamaps.Map.InfoBox.close();
|
||||
Metamaps.Realtime.endActiveMap();
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1007,7 +1007,7 @@ h3.filterBox {
|
|||
cursor: pointer;
|
||||
font-size:12px;
|
||||
}
|
||||
.sidebarFilterBox span:hover {
|
||||
.sidebarFilterBox span:hover, .sidebarFilterBox span.active {
|
||||
color: #00BCD4;
|
||||
}
|
||||
.sidebarFilterBox ul {
|
||||
|
@ -1104,7 +1104,7 @@ h3.realtimeBoxTitle {
|
|||
text-align: center;
|
||||
font-size:12px;
|
||||
}
|
||||
.sidebarCollaborateBox .realtimeOnOff:hover {
|
||||
.sidebarCollaborateBox .realtimeOnOff:hover, .sidebarCollaborateBox .realtimeOnOff.active {
|
||||
color: #00bcd4;
|
||||
}
|
||||
.sidebarCollaborateBox .rtOff {
|
||||
|
|
|
@ -760,7 +760,7 @@
|
|||
|
||||
/* infoAndHelp */
|
||||
|
||||
.mapPage .infoAndHelp, .topicPage .infoAndHelp{
|
||||
.mapPage .infoAndHelp, .topicPage .infoAndHelp {
|
||||
right: 70px;
|
||||
}
|
||||
.mapPage .openCheatsheet .tooltipsAbove, .topicPage .openCheatsheet .tooltipsAbove {
|
||||
|
@ -818,6 +818,10 @@
|
|||
right: 24px;
|
||||
}
|
||||
|
||||
.topicPage .zoomExtents {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mapControl {
|
||||
width:32px;
|
||||
height:32px;
|
||||
|
|
|
@ -10,6 +10,7 @@ module UsersHelper
|
|||
user['value'] = u.name
|
||||
user['profile'] = u.image.url(:square)
|
||||
user['mapCount'] = u.maps.count
|
||||
user['generation'] = u.generation
|
||||
user['created_at'] = u.created_at.strftime("%m/%d/%Y")
|
||||
user['rtype'] = "mapper"
|
||||
|
||||
|
|
|
@ -28,12 +28,7 @@ class User < ActiveRecord::Base
|
|||
validates_uniqueness_of :name # done by devise
|
||||
validates_uniqueness_of :email # done by devise
|
||||
|
||||
if ActiveRecord::Base.connection.table_exists? 'users'
|
||||
codes = ActiveRecord::Base.connection.execute("SELECT code FROM users").map {|user| user["code"] }
|
||||
else
|
||||
codes = []
|
||||
end
|
||||
validates :joinedwithcode, :presence => true, :inclusion => { :in => codes, :message => "%{value} is not valid" }, :on => :create
|
||||
validates :joinedwithcode, :presence => true, :inclusion => { :in => $codes, :message => "%{value} is not valid" }, :on => :create
|
||||
|
||||
# This method associates the attribute ":image" with a file attachment
|
||||
has_attached_file :image, :styles => {
|
||||
|
@ -54,6 +49,24 @@ class User < ActiveRecord::Base
|
|||
def generate_code
|
||||
#generate a random 8 letter/digit code that they can use to invite people
|
||||
self.code = rand(36**8).to_s(36)
|
||||
|
||||
$codes.push(self.code)
|
||||
|
||||
self.generation = self.get_generation
|
||||
end
|
||||
|
||||
def get_generation
|
||||
if self.joinedwithcode == self.code
|
||||
# if your joinedwithcode equals your code you must be GEN 0
|
||||
gen = 0
|
||||
elsif self.generation
|
||||
# if your generation has already been calculated then just return that value
|
||||
gen = self.generation
|
||||
else
|
||||
# if your generation hasn't been calculated, base it off the
|
||||
# generation of the person whose code you joined with + 1
|
||||
gen = User.find_by_code(self.joinedwithcode).get_generation + 1
|
||||
end
|
||||
end
|
||||
|
||||
def settings
|
||||
|
|
|
@ -149,7 +149,7 @@
|
|||
<p>Mapping since: {{created_at}}</p>
|
||||
</div>
|
||||
<div class="mapperGeneration">
|
||||
<p>Generation: 1</p>
|
||||
<p>Generation: {{generation}}</p>
|
||||
</div>
|
||||
<div class="mapCount">
|
||||
{{mapCount}}
|
||||
|
|
|
@ -91,7 +91,7 @@
|
|||
<div id="filter_by_mapper" class="filterBySection">
|
||||
<h3><%= @map ? "MAPPERS" : @topic ? "CREATORS" : "" %></h3>
|
||||
<span class="hideAll hideAllMappers">NONE</span>
|
||||
<span class="showAll showAllMappers">ALL</span>
|
||||
<span class="active showAll showAllMappers">ALL</span>
|
||||
<div class="clearfloat"></div>
|
||||
<ul>
|
||||
<%= @mapperlist.html_safe %>
|
||||
|
@ -102,7 +102,7 @@
|
|||
<div id="filter_by_metacode" class="filterBySection">
|
||||
<h3>METACODES</h3>
|
||||
<span class="hideAll hideAllMetacodes">NONE</span>
|
||||
<span class="showAll showAllMetacodes">ALL</span>
|
||||
<span class="active showAll showAllMetacodes">ALL</span>
|
||||
<div class="clearfloat"></div>
|
||||
<ul>
|
||||
<%= @metacodelist.html_safe %>
|
||||
|
@ -113,7 +113,7 @@
|
|||
<div id="filter_by_synapse" class="filterBySection">
|
||||
<h3>SYNAPSES</h3>
|
||||
<span class="hideAll hideAllSynapses">NONE</span>
|
||||
<span class="showAll showAllSynapses">ALL</span>
|
||||
<span class="active showAll showAllSynapses">ALL</span>
|
||||
<div class="clearfloat"></div>
|
||||
<ul>
|
||||
<%= @synapselist.html_safe %>
|
||||
|
|
4
config/initializers/access_codes.rb
Normal file
4
config/initializers/access_codes.rb
Normal file
|
@ -0,0 +1,4 @@
|
|||
$codes = []
|
||||
if ActiveRecord::Base.connection.table_exists? 'users'
|
||||
$codes = ActiveRecord::Base.connection.execute("SELECT code FROM users").map {|user| user["code"] }
|
||||
end
|
5
db/migrate/20141121204712_add_generation_to_users.rb
Normal file
5
db/migrate/20141121204712_add_generation_to_users.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
class AddGenerationToUsers < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :users, :generation, :integer
|
||||
end
|
||||
end
|
|
@ -11,7 +11,7 @@
|
|||
#
|
||||
# It's strongly recommended to check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(:version => 20140930013020) do
|
||||
ActiveRecord::Schema.define(:version => 20141121204712) do
|
||||
|
||||
create_table "in_metacode_sets", :force => true do |t|
|
||||
t.integer "metacode_id"
|
||||
|
@ -127,6 +127,7 @@ ActiveRecord::Schema.define(:version => 20140930013020) do
|
|||
t.string "image_content_type"
|
||||
t.integer "image_file_size"
|
||||
t.datetime "image_updated_at"
|
||||
t.integer "generation"
|
||||
end
|
||||
|
||||
add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true
|
||||
|
|
2
test/fixtures/users.yml
vendored
2
test/fixtures/users.yml
vendored
|
@ -5,6 +5,7 @@ user:
|
|||
email: user@user.com
|
||||
encrypted_password: $2a$10$psR68SWYNy5ZKQPs9FrFM.HuRMrTXO/YFzv.HaUmdCsQZsQrG1XAW
|
||||
code: qwertyui
|
||||
joinedwithcode: qwertyui
|
||||
admin: false
|
||||
|
||||
admin:
|
||||
|
@ -12,4 +13,5 @@ admin:
|
|||
email: admin@admin.com
|
||||
encrypted_password: $2a$10$psR68SWYNy5ZKQPs9FrFM.HuRMrTXO/YFzv.HaUmdCsQZsQrG1XAW
|
||||
code: iuytrewq
|
||||
joinedwithcode: iuytrewq
|
||||
admin: true
|
||||
|
|
Loading…
Reference in a new issue