parsav  Check-in [d3fe1d11af]

Overview
Comment:add full relationship control screen, more timelines, minor fixes and cleanups
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: d3fe1d11afdd8440eb8b89506bde63da2235b9caeaf337d075a2995c223d5731
User & Date: lexi on 2021-01-13 00:04:54
Other Links: manifest | tags
Context
2021-01-13
13:57
implement some sanctions check-in: 60040f3ca3 user: lexi tags: trunk
00:04
add full relationship control screen, more timelines, minor fixes and cleanups check-in: d3fe1d11af user: lexi tags: trunk
2021-01-11
23:33
various cleanups, notices no longer originated from self check-in: 1ba4bbc92f user: lexi tags: trunk
Changes

Modified backend/pgsql.t from [c81652b018] to [bd352a7166].

  1515   1515   		post: uint64
  1516   1516   	): bool
  1517   1517   		var q = queries.post_reacts_fetch_uid.exec(src,uid,post,'like')
  1518   1518   		if q.sz > 0 then q:free() return true end
  1519   1519   		return false
  1520   1520   	end];
  1521   1521   
  1522         -	timeline_instance_fetch = [terra(src: &lib.store.source, rg: lib.store.range)
         1522  +	timeline_instance_fetch = [terra(
         1523  +		src: &lib.store.source,
         1524  +		rg: lib.store.range
         1525  +	): lib.mem.lstptr(lib.store.post)
  1523   1526   		var r = pqr { sz = 0 }
  1524   1527   		var A,B,C,D = rg:matrix() -- :/
  1525   1528   		r = queries.timeline_instance_fetch.exec(src,A,B,C,D)
         1529  +		
         1530  +		var ret: lib.mem.ptr(lib.mem.ptr(lib.store.post)) ret:init(r.sz)
         1531  +		for i=0,r.sz do
         1532  +			ret.ptr[i] = row_to_post(&r, i) -- MUST FREE ALL
         1533  +			ret.ptr[i].ptr.source = src
         1534  +		end
         1535  +
         1536  +		return ret
         1537  +	end];
         1538  +
         1539  +	timeline_actor_fetch_uid = [terra(
         1540  +		src: &lib.store.source,
         1541  +		uid: uint64,
         1542  +		rg: lib.store.range
         1543  +	): lib.mem.lstptr(lib.store.post)
         1544  +		var r = pqr { sz = 0 }
         1545  +		var A,B,C,D = rg:matrix() -- :/
         1546  +		r = queries.timeline_actor_fetch.exec(src,uid,A,B,C,D)
  1526   1547   		
  1527   1548   		var ret: lib.mem.ptr(lib.mem.ptr(lib.store.post)) ret:init(r.sz)
  1528   1549   		for i=0,r.sz do
  1529   1550   			ret.ptr[i] = row_to_post(&r, i) -- MUST FREE ALL
  1530   1551   			ret.ptr[i].ptr.source = src
  1531   1552   		end
  1532   1553   
................................................................................
  1608   1629   
  1609   1630   		var res = queries.actor_rel_enum.exec(src,relator,relatee)
  1610   1631   		var recip = queries.actor_rel_enum.exec(src,relatee,relator)
  1611   1632   
  1612   1633   		if res.sz > 0 then defer res:free()
  1613   1634   			for i = 0, res.sz do
  1614   1635   				var bit = res:int(uint16, i, 0)-1
  1615         -				if bit < [#lib.store.relation.members] then r.rel:setbit(bit, true)
         1636  +				if bit < [#lib.store.relation.members] then r.rel:setbit(bit,true)
  1616   1637   					else lib.warn('unknown relationship type in database') end
  1617   1638   			end
  1618   1639   		end
  1619   1640   
  1620   1641   		if recip.sz > 0 then defer recip:free()
  1621   1642   			for i = 0, recip.sz do
  1622   1643   				var bit = recip:int(uint16, i, 0)-1
  1623         -				if bit < [#lib.store.relation.members] then r.recip:setbit(bit, true)
         1644  +				if bit < [#lib.store.relation.members] then r.recip:setbit(bit,true)
  1624   1645   					else lib.warn('unknown relationship type in database') end
  1625   1646   			end
  1626   1647   		end
  1627   1648   
  1628   1649   		return r
  1629   1650   	end];
  1630   1651   

Modified doc/acl.md from [53956f184b] to [c0f2a21443].

    29     29   
    30     30   * `deny groupies allow +illuminati`: permits access to the illuminati, but excluding those members who are groupies
    31     31   * `+illuminati deny groupies`: allows access to everyone but groupies (unless they're in the illuminati)
    32     32   * `@eve @alice@nowhere.tld deny @bob @trent@witches.live`: grants access to eve and alice, but locks out bob and trent
    33     33   * `<grand duke> #4th-intl<comrade>`: restricts the post to the eyes of the Fourth International's secret cabal of anointed comrades and the grand dukes of the Empire
    34     34   * `deny ~%3`: blocks a post from being seen by anyone with a staff rank level below 3
    35     35   
    36         -**limitations:** to inhibit potential denial-of-service attacks, ACL expressions can be a maximum of 128 characters, can contain at most 16 words, and cannot trigger queries against other servers. all information needed to evaluate an ACL expression must be known locally. this is particularly relevant with respect to rooms.
           36  +**limitations:** to inhibit potential denial-of-service attacks, ACL expressions can be a maximum of 256 characters, can contain at most 16 words, and cannot trigger queries against other servers. all information needed to evaluate an ACL expression must be known locally. this is particularly relevant with respect to rooms.

Modified parsav.t from [392d24dbd5] to [d3351b7874].

   240    240   		}
   241    241   	}
   242    242   	n.name = string.format("stat<%s>", ty.name)
   243    243   	n.stat_basetype = ty
   244    244   	return n
   245    245   end)
   246    246   lib.enum = function(tbl)
          247  +	if type(tbl) == 'string' then -- shorthand syntax
          248  +		local t = {}
          249  +		for w in tbl:gmatch('(%g+)') do t[#t+1] = w end
          250  +		tbl = t
          251  +	end
   247    252   	local ty = uint8
   248    253   	if #tbl >= 2^32 then ty = uint64 -- hey, can't be too safe
   249    254   	elseif #tbl >= 2^16 then ty = uint32
   250    255   	elseif #tbl >= 2^8 then ty = uint16 end
   251    256   	local o = { t = ty, members = tbl }
   252    257   	local strings = {}
   253    258   	for i, name in ipairs(tbl) do
................................................................................
   265    270   	local o = {}
   266    271   	for i, name in ipairs(tbl) do o[name] = i end
   267    272   	local struct set { _store: uint8[bytes] }
   268    273   	local struct bit { _v: intptr _set: &set}
   269    274   	terra set:clear() for i=0,bytes do self._store[i] = 0 end end
   270    275   	terra set:fill() for i=0,bytes do self._store[i] = 0xFF end end
   271    276   	set.members = tbl
          277  +	set.idvmap = o
          278  +	set.null = quote var s: set s:clear() in s end
   272    279   	set.name = string.format('set<%s>', table.concat(tbl, '|'))
   273    280   	set.metamethods.__entrymissing = macro(function(val, obj)
   274    281   		if o[val] == nil then error('value ' .. val .. ' not in set') end
   275    282   		return `bit { _v=[o[val] - 1], _set = &(obj) }
   276    283   	end)
   277    284   	terra set:sz()
   278    285   		var ct: intptr = 0
................................................................................
   306    313   	terra set:setbit(i: intptr, val: bool)
   307    314   		if val then
   308    315   			self._store[i/8] = self._store[i/8] or (1 << (i % 8))
   309    316   		else
   310    317   			self._store[i/8] = self._store[i/8] and not (1 << (i % 8))
   311    318   		end
   312    319   	end
          320  +	local qksetexp = function(self,idx,rhs)
          321  +		local ch,bit
          322  +		if terralib.isconstant(idx) then
          323  +			ch = math.floor(idx/8)
          324  +			bit = idx%8
          325  +		else
          326  +			ch = `[idx]/8
          327  +			bit = `[idx]%8
          328  +		end
          329  +
          330  +		if terralib.isconstant(rhs) then
          331  +			local b = rhs:asvalue()
          332  +			if b == true then return quote
          333  +				self._store[ch] = self._store[ch] or (1 << bit)
          334  +			end elseif b == false then return quote
          335  +				self._store[ch] = self._store[ch] and not (1 << bit)
          336  +			end end
          337  +		else
          338  +			return quote self:setbit([ch], rhs) end
          339  +		end
          340  +	end
          341  +	set.metamethods.__update = macro(qksetexp)
          342  +	set.metamethods.__setentry = macro(function(field,self,rhs)
          343  +		return `self:setbit([o[field]-1],rhs)
          344  +		--return qksetexp(self, o[field], rhs)
          345  +	end)
   313    346   	set.bits = {}
   314         -	set.idvmap = {}
   315    347   	for i,v in ipairs(tbl) do
   316         -		set.idvmap[v] = i
   317    348   		set.bits[v] = quote var b: set b:clear() b:setbit([i-1], true) in b end
   318    349   	end
   319    350   	set.metamethods.__add = macro(function(self,other)
   320    351   		local new = symbol(set)
   321    352   		local q = quote var [new] new:clear() end
   322    353   		for i = 0, bytes - 1 do
   323    354   			q = quote [q]

Modified render/conf/users.t from [46d40d63a3] to [24aad61532].

   136    136   		terror fear blood slime slab warp waggle tit boob bird derp
   137    137   		birb goat horde masto mastodon social global tweet post
   138    138   		house home prison jail box pit hole haven town trump putin
   139    139   		truth liberty zone land ranch butt butts sex pimp cop mail
   140    140   		slut goblin goblins no good bad only gtfo electro electric
   141    141   		dragon space mars earth venus neptune pluto saturn star
   142    142   		moon lunar catastrophe catastro cuck honk war lap cuddle
   143         -		planet
          143  +		planet pride
   144    144   	]]
   145    145   	var tlds = splitwords [[
   146    146   		tld club town space xxx house land ranch horse com io online
   147    147   		shop site vip ltd win men lgbt cat adult army analytics art
   148    148   		associates bar bible biz black blog broker cam camp careers
   149    149   		catering church city coop dad date dating direct diy dog
   150    150   		duck dot enterprises esq estate expert express fail farm foo
................................................................................
   151    151   		forsale fun fund forum foundation gay global golf gop guru
   152    152   		group hangout hot industries international info investments
   153    153   		jobs land law life limited live lol mom network now party
   154    154   		porn productions pub rehab rocks school sex sexy singles
   155    155   		social software solutions spot store sucks supplies cuck
   156    156   		uwu systems university vacations ventures wang website work
   157    157   		wow wtf world xyz soy live gym park worship orb zone mail
   158         -		war honk derp planet
          158  +		war honk derp planet pride
   159    159   	]]
   160    160   	var sub = rnd(uint8,0,10) == 0
   161    161   	if sub then a:ppush(words[rnd(intptr,0,[words.type.N])]):lpush('.') end
   162    162   	a:ppush(words[rnd(intptr,0,[words.type.N])])
   163    163   	if rnd(uint8,0,3) == 0 or not sub then
   164    164   		a:ppush(words[rnd(intptr,0,[words.type.N])])
   165    165   	end

Modified render/docpage.t from [704653b9d0] to [2df16a2b60].

    30     30   	local par = 0
    31     31   	if t.meta.parent then par = topicidxt[t.meta.parent] end
    32     32   	local restrict = symbol(lib.store.powerset)
    33     33   	local setbits = quote restrict:clear() end
    34     34   	if t.meta.priv then
    35     35   		if type(t.meta.priv) ~= 'table' then t.meta.priv = {t.meta.priv} end
    36     36   		for _,v in pairs(t.meta.priv) do
    37         -			setbits = quote [setbits]; (restrict.[v] << true) end
           37  +			setbits = quote [setbits]; restrict.[v] = true end
    38     38   		end
    39     39   	end
    40     40   	allpages[i] = quote var [restrict]; [setbits] in pgpair {
    41     41   		name = [v];
    42     42   		parent = par;
    43     43   		priv = restrict;
    44     44   		title = [t.meta.title];

Modified render/media-gallery.t from [1f18c83945] to [880ce531e5].

     8      8   
     9      9   local terra 
    10     10   render_media_gallery(co: &lib.srv.convo, path: lib.mem.ptr(lib.mem.ref(int8)), uid: uint64, acc: &lib.str.acc)
    11     11    -- note that when calling this function, path must be adjusted so that path(0)
    12     12    -- eq "media"
    13     13   	var owner = false
    14     14   	if co.aid ~= 0 and co.who.id == uid then owner = true end
    15         -	var ou = co.srv:actor_fetch_uid(uid)
    16         -	if not ou then goto e404 end
    17         -	do defer ou:free()
           15  +	var ou = co:uid2actor(uid)
           16  +	if ou == nil then goto e404 end
           17  +	do -- defer ou:free()
    18     18   		var pfx = pstr.null()
    19     19   		if not owner then
    20     20   			var pa = co:stra(32)
    21     21   			pa:lpush('/')
    22         -			if ou(0).origin ~= 0 then pa:lpush('@') end
    23         -			pa:push(ou(0).xid,0)
           22  +			if ou.origin ~= 0 then pa:lpush('@') end
           23  +			pa:push(ou.xid,0)
    24     24   			pfx = pa:finalize()
    25     25   		end
    26     26   
    27     27   		if path.ct >= 3 and path(1):cmp('a') then
    28     28   			var id, idok = lib.math.shorthand.parse(path(2).ptr, path(2).ct)
    29     29   			if not idok then goto e404 end
    30     30   			var art = co.srv:artifact_fetch(uid, id)
................................................................................
   127    127   
   128    128   			if folders.ct > 0 then
   129    129   				var fa = co:stra(128)
   130    130   				var fldr = co:pgetv('folder')
   131    131   				for i=0,folders.ct do
   132    132   					var ule = lib.html.urlenc(&co.srv.pool,folders(i), true) -- defer ule:free()
   133    133   					var san = lib.html.sanitize(&co.srv.pool,folders(i), true) -- defer san:free()
   134         -					fa:lpush('<a href="'):ppush(pfx):lpush('/media?folder='):ppush(ule)
          134  +					fa:lpush('<a class="button" href="'):ppush(pfx):lpush('/media?folder='):ppush(ule)
   135    135   						:lpush('">'):ppush(san):lpush('</a>')
   136    136   					lib.dbg('checking folder ',{fldr.ptr,fldr.ct},' against ',{folders(i).ptr,folders(i).ct})
   137    137   					if fldr:ref() and folders(i):cmp(fldr)
   138    138   						then folder = folders(i) lib.dbg('folder match ',{fldr.ptr,fldr.ct})
   139    139   						else folders(i):free()
   140    140   					end
   141    141   				end
   142    142   				fa:lpush('<hr>')
   143    143   				view.folders = fa:finalize()
   144    144   				folders:free()
   145    145   			end
   146    146   
   147    147   			if owner then
   148         -				view.menu = '<a class="pos" href="/media/upload">upload</a><hr>'
          148  +				view.menu = '<a class="pos button" href="/media/upload">upload</a><hr>'
   149    149   			end
   150    150   
   151    151   			var md = co.srv:artifact_enum_uid(uid, folder)
   152    152   			var gallery: lib.str.acc gallery:pool(&co.srv.pool,256)
   153    153   			var files: lib.str.acc files:pool(&co.srv.pool,256) 
   154    154   			for i=0,md.ct do
   155    155   				var desc = lib.smackdown.html(&co.srv.pool,pstr{md(i)(0).desc,0}, true) --defer desc:free()

Modified render/profile.t from [4c6c4c1279] to [446c5d468d].

     1      1   -- vim: ft=terra
     2      2   local pstr = lib.mem.ptr(int8)
     3      3   local terra cs(s: rawstring)
     4      4   	return pstr { ptr = s, ct = lib.str.sz(s) }
     5      5   end
            6  +
            7  +local relkinds = {
            8  +	pos = {
            9  +		{ id = 'follow', start = {
           10  +			text = 'follow';
           11  +			desc = "this user's posts will appear in your timeline";
           12  +		}, stop = {
           13  +			text = 'unfollow';
           14  +			desc = "this user's posts will no longer appear in your timeline";
           15  +		}};
           16  +
           17  +		{ id = 'sub', start = {
           18  +			text = 'subscribe';
           19  +			desc = "you will get a notification whenever this user posts";
           20  +		}, stop = {
           21  +			text = 'unsubscribe';
           22  +			desc = "you will no longer get notifications when this user posts";
           23  +		}};
           24  +	};
           25  +	neg = {
           26  +		{ id = 'mute', start = {
           27  +			text = 'mute';
           28  +			desc = "this user's posts will no longer appear anywhere";
           29  +		}, stop = {
           30  +			text = 'unmute';
           31  +			desc = "this user's posts will once again be visible to you";
           32  +		}};
           33  +
           34  +		{ id = 'exclude', start = {
           35  +			text = 'exclude';
           36  +			desc = "this user will not be able to see your posts";
           37  +		}, stop = {
           38  +			text = 'reinclude';
           39  +			desc = "this user will again be able to see your posts";
           40  +		}};
           41  +
           42  +		{ id = 'avoid', start = {
           43  +			text = 'avoid';
           44  +			desc = "this user's posts will not appear on your timeline even if you follow them and you will not receive notices from them, but they will still be visible in threads";
           45  +		}, stop = {
           46  +			text = 'reconcile';
           47  +			desc = "this user will once again be able to originate notices to you, and will be shown on your timeline";
           48  +		}};
           49  +
           50  +		{ id = 'collapse', start = {
           51  +			text = 'collapse';
           52  +			desc = "this user's posts will still appear but will be collapsed by default, so you only see the text if you choose to expand each post";
           53  +		}, stop = {
           54  +			text = 'expand';
           55  +			desc = "this user's posts will no longer be collapsed";
           56  +		}};
           57  +
           58  +		{ id = 'disemvowel', start = {
           59  +			text = 'disemvowel'; -- translations should not translate this literally
           60  +			desc = "this user's posts will be ritually mutilated in a humorous fashion as appropriate to the script in which they are written; e.g. the removal of vowels in roman text and deletion of kana in japanese text";
           61  +		}, stop = {
           62  +			text = 're-emvowel';
           63  +			desc = "this user's posts will once again appear normally";
           64  +		}};
           65  +
           66  +		{ id = 'block', start = {
           67  +			text = 'block';
           68  +			desc = "this user will not be able to interact with you in any fashion and they will be forced to unfollow you";
           69  +		}, stop = {
           70  +			text = 'unblock';
           71  +			desc = "this user will once again be able to interact with you";
           72  +		}};
           73  +	};
           74  +}
           75  +
           76  +local function
           77  +btnhtml(kind)
           78  +	local function sb(class)
           79  +		local b = kind[class]
           80  +		return string.format('<div class="opt%s">' ..
           81  +			'<button name="act" value="%s">%s</button>' ..
           82  +			'<p>%s</p>' .. 
           83  +		'</div>',
           84  +			(class == 'stop' and ' on' or ''),
           85  +			(class == 'stop' and 'un' or '') .. kind.id,
           86  +			b.text, b.desc)
           87  +	end
           88  +	return sb('start'), sb('stop')
           89  +end
     6     90   
     7     91   local terra 
     8     92   render_profile(
     9     93   	co: &lib.srv.convo,
    10     94   	actor: &lib.store.actor,
    11     95   	relationship: &lib.store.relationship
    12     96   ): pstr
    13         -	var aux: lib.str.acc
           97  +	var aux = co:stra(128)
    14     98   	var followed = false -- FIXME
    15     99   	if co.aid ~= 0 and co.who.id == actor.id then
    16         -		aux:pcompose(&co.srv.pool,'<a accesskey="a" class="button" href="/conf/profile?go=/@',actor.handle,'">alter</a>')
          100  +		aux:lpush('<a accesskey="a" class="button" href="/conf/profile?go=/@'):push(actor.handle,0):lpush('">alter</a>')
    17    101   	elseif co.aid ~= 0 then
    18         -		if not relationship.rel.follow() then
    19         -			aux:pcompose(&co.srv.pool,'<button accesskey="f" method="post" class="pos" name="act" value="follow">follow</button>')
    20         -		elseif relationship.rel.follow() then
    21         -			aux:pcompose(&co.srv.pool,'<button accesskey="f" method="post" class="neg" name="act" value="unfollow">unfollow</button>')
    22         -		end
    23         -		aux:lpush(' <a accesskey="h" class="button" href="/'):push(actor.xid,0):lpush('/chat">chat</a>')
    24    102   		if co.who.rights.powers:affect_users() and co.who:overpowers(actor) then
    25    103   			aux:lpush(' <a accesskey="n" class="button" href="/conf/users/'):shpush(actor.id):lpush('">control</a>')
    26    104   		end
    27    105   	else
    28         -		aux:pcompose(&co.srv.pool,' <a accesskey="f" class="button" href="/', actor.xid, '/follow">remote follow</a>')
          106  +		aux:lpush(' <a accesskey="f" class="button" href="/'):push(actor.xid,0):lpush('/follow">remote follow</a>')
    29    107   	end
    30    108   	var auxp = aux:finalize()
    31    109   	var timestr: int8[26] lib.osclock.ctime_r(&actor.knownsince, &timestr[0])
          110  +
          111  +	var relbtns = co:stra(256)
          112  +	var sancbtns = co:stra(256)
          113  +	[(function()
          114  +		local allkinds = {}
          115  +		for kind, rels in pairs(relkinds) do
          116  +			for i,v in ipairs(rels) do
          117  +				v.kind = kind
          118  +				allkinds[#allkinds + 1] = v
          119  +			end
          120  +		end
          121  +		local br = {}
          122  +		for i,v in ipairs(allkinds) do
          123  +			local off, on = btnhtml(v)
          124  +			local target = v.kind == 'pos' and relbtns or sancbtns
          125  +			br[#br+1] = quote
          126  +				if relationship.rel.[v.id]()
          127  +					then target:ppush(lib.str.plit([on]))
          128  +					else target:ppush(lib.str.plit([off]))
          129  +				end
          130  +			end
          131  +		end
          132  +		return br
          133  +	end)()]
    32    134   
    33    135   	var strfbuf: int8[28*4]
    34    136   	var stats = co.srv:actor_stats(actor.id)
    35    137   		var sn_posts     = cs(lib.math.decstr_friendly(stats.posts, &strfbuf[ [strfbuf.type.N - 1] ]))
    36    138   		var sn_follows   = cs(lib.math.decstr_friendly(stats.follows, sn_posts.ptr - 1))
    37    139   		var sn_followers = cs(lib.math.decstr_friendly(stats.followers, sn_follows.ptr - 1))
    38    140   		var sn_mutuals   = cs(lib.math.decstr_friendly(stats.mutuals, sn_followers.ptr - 1))
................................................................................
    97    199   		nfollowers = sn_followers, nmutuals = sn_mutuals;
    98    200   		tweetday = cs(timestr);
    99    201   		timephrase = lib.trn(actor.origin == 0, pstr 'joined', pstr 'known since');
   100    202   
   101    203   		remarks = '';
   102    204   
   103    205   		auxbtn = auxp;
          206  +		relations = relbtns:finalize();
          207  +		sanctions = sancbtns:finalize();
   104    208   	}
   105    209   	if comments.sz > 0 then profile.remarks = comments:finalize() end
   106    210   
   107    211   	var ret = profile:poolstr(&co.srv.pool)
   108    212   	-- auxp:free() 
   109    213   	--if actor.bio ~= nil then bio:free() end
   110    214   	--if comments.sz > 0 then profile.remarks:free() end
   111    215   	return ret
   112    216   end
   113    217   
   114    218   return render_profile

Modified render/timeline.t from [9997258dca] to [91a054f52e].

     1      1   -- vim: ft=terra
     2         -local modes = lib.enum {'follow','mutual','srvlocal','fediglobal','circle'}
            2  +local pstr = lib.str.t
            3  +local modes = lib.enum [[follow mutual local fedi circle]]
            4  +local terra 
            5  +requires_login(m: modes.t): bool
            6  +	return m == modes.follow
            7  +	    or m == modes.mutual
            8  +	    or m == modes.circle
            9  +end
           10  +
     3     11   local terra 
     4     12   render_timeline(co: &lib.srv.convo, modestr: lib.mem.ref(int8))
     5         -	var mode = modes.srvlocal
           13  +	var mode = modes.follow
     6     14   	var circle: uint64 = 0
     7         -	-- if     modestr:cmpl('local') then mode = modes.srvlocal
     8         -	-- elseif modestr:cmpl('mutual') then mode = modes.mutual
     9         -	-- elseif modestr:cmpl('global') then mode = modes.fediglobal
    10         -	-- elseif modestr:cmpl('circle') then mode = modes.circle
    11         -	-- end
           15  +	if     modestr:cmp('local') then mode = [modes['local']]
           16  +	elseif modestr:cmp('mutual') then mode = modes.mutual
           17  +	elseif modestr:cmp('fedi') then mode = modes.fedi
           18  +	elseif modestr:cmp('circle') then mode = modes.circle
           19  +	end
           20  +	if requires_login(mode) and co.aid == 0 then mode = [modes['local']] end
           21  +
    12     22   
    13     23   	var stoptime = lib.osclock.time(nil)
    14     24   
    15     25   	var posts = [lib.mem.vec(lib.mem.ptr(lib.store.post))] { 
    16     26   		sz = 0, run = 0
    17     27   	}
    18         -	if mode == modes.follow then
    19         -	elseif mode == modes.srvlocal then
    20         -		posts = co.srv:timeline_instance_fetch(lib.store.range {
    21         -			mode = 1; -- T->I
    22         -			from_time = stoptime;
    23         -			to_idx = 64;
    24         -		})
    25         -	elseif mode == modes.fediglobal then
           28  +	var fetchmode = lib.store.range {
           29  +		mode = 1; -- T->I
           30  +		from_time = stoptime;
           31  +		to_idx = 64;
           32  +	}
           33  +	if mode == modes.follow or mode == modes.mutual then
           34  +		posts = co.srv:timeline_actor_fetch_uid(co.who.id,fetchmode)
           35  +	elseif mode == [modes['local']] then
           36  +		posts = co.srv:timeline_instance_fetch(fetchmode)
           37  +	elseif mode == modes.fedi then
    26     38   	elseif mode == modes.circle then
    27     39   	end
    28     40   
    29     41   	var acc = co:stra(1024)
           42  +	var modelabels = arrayof(pstr, 'followed', 'mutuals', 'local instance', 'fediverse', 'circle')
           43  +	var modelinks = arrayof(pstr, [modes.members])
           44  +	acc:lpush('<div style="text-align: right"><em>showing ')
           45  +	for i=0, [modelabels.type.N] do
           46  +		if co.aid ~= 0 or not requires_login(i) then
           47  +			if i > 0 then acc:lpush(' ยท ') end
           48  +			if i == mode then
           49  +				acc:lpush('<strong>'):ppush(modelabels[i]):lpush('</strong>')
           50  +			else
           51  +				acc:lpush('<a href="/tl/'):ppush(modelinks[i]):lpush('">'):ppush(modelabels[i]):lpush('</a>')
           52  +			end
           53  +		end
           54  +	end
           55  +	acc:lpush('</em></div>')
    30     56   	acc:lpush('<div id="tl" data-live="10">')
    31     57   	var newest: lib.store.timepoint = 0
    32     58   	for i = 0, posts.sz do
           59  +		if mode == modes.mutual and posts(i).ptr.author ~= co.who.id then
           60  +			var author = co:uid2actor(posts(i).ptr.author)
           61  +			if not author.relationship.recip.follow() then goto skip end
           62  +		end
    33     63   		lib.render.tweet(co, posts(i).ptr, &acc)
    34     64   		var t = lib.math.biggest(lib.math.biggest(posts(i).ptr.posted, posts(i).ptr.discovered),posts(i).ptr.edited)
    35     65   		if t > newest then newest = t end
    36         -		posts(i):free()
           66  +		::skip:: posts(i):free()
    37     67   	end
    38         -	posts:free()
           68  +	if posts.run > 0 then posts:free() end
    39     69   	acc:lpush('</div>')
    40     70   
    41     71   	var doc = [lib.srv.convo.page] {
    42     72   		title = 'timeline';
    43     73   		body = acc:finalize();
    44     74   		class = 'timeline';
    45     75   		cache = false;
    46     76   	}
    47     77   	co:livepage(doc,newest)
    48     78   	--doc.body:free()
    49     79   end
    50     80   return render_timeline

Modified render/tweet.t from [57f4f6bb5e] to [fad3f537df].

    24     24   		if p.author == co.actorcache(j).ptr.id then author    = co.actorcache(j).ptr end
    25     25   		if p.rtdby  == co.actorcache(j).ptr.id then retweeter = co.actorcache(j).ptr end
    26     26   		if author ~= nil and (p.rtdby == 0 or retweeter ~= nil) then
    27     27   			goto foundauth
    28     28   		end
    29     29   	end
    30     30   	if author == nil then
    31         -		author = co.actorcache:insert(co.srv:actor_fetch_uid(p.author)).ptr
           31  +		author = co.actorcache:insert(co:uid2actor_live(p.author)).ptr
    32     32   	end
    33     33   	if p.rtdby ~= 0 and retweeter == nil then
    34         -		retweeter = co.actorcache:insert(co.srv:actor_fetch_uid(p.rtdby)).ptr
           34  +		retweeter = co.actorcache:insert(co:uid2actor_live(p.rtdby)).ptr
    35     35   	end
    36     36   
    37     37   	::foundauth::
    38     38   	var timestr: int8[26] lib.osclock.ctime_r(&p.posted, &timestr[0])
    39     39   	for i=0,26 do if timestr[i] == @'\n' then timestr[i] = 0 break end end -- ๐Ÿ™„
    40     40   
    41     41   	var bhtml = lib.smackdown.html(&co.srv.pool, [lib.mem.ptr(int8)] {ptr=p.body,ct=0},false)

Modified render/user-page.t from [d4b538d774] to [b87f9f8b97].

     1      1   -- vim: ft=terra
     2      2   local terra 
     3      3   render_userpage(
     4      4   	co          : &lib.srv.convo,
     5      5   	actor       : &lib.store.actor,
     6      6   	relationship: &lib.store.relationship
     7      7   ): {}
     8         -	var ti: lib.str.acc 
            8  +	var ti: lib.str.t
     9      9   	if co.aid ~= 0 and co.who.id == actor.id then
    10         -		ti:compose('my profile')
           10  +		ti = 'my profile'
    11     11   	else
    12         -		ti:compose('profile :: ', actor.handle)
           12  +		ti = co:qstr('profile :: ', actor.handle)
    13     13   	end
    14         -	var tiptr = ti:finalize()
    15     14   
    16     15   	var acc: lib.str.acc acc:pool(&co.srv.pool, 1024)
    17     16   	var pftxt = lib.render.profile(co,actor,relationship) --defer pftxt:free()
    18     17   	acc:ppush(pftxt)
    19     18   
    20     19   	var stoptime = lib.osclock.time(nil)
    21     20   	var posts = co.srv:post_enum_author_uid(actor.id, lib.store.range {
................................................................................
    33     32   		posts(i):free()
    34     33   	end
    35     34   	posts:free()
    36     35   	acc:lpush('</div>')
    37     36   
    38     37   	var bdf = acc:finalize()
    39     38   	co:livepage([lib.srv.convo.page] {
    40         -		title = tiptr; body = bdf;
           39  +		title = ti; body = bdf;
    41     40   		class = 'profile';
    42     41   		cache = false;
    43     42   	}, newest)
    44     43   
    45         -	tiptr:free()
           44  +	--tiptr:free()
    46     45   	--bdf:free()
    47     46   end
    48     47   
    49     48   return render_userpage

Modified route.t from [57b2f599e2] to [cc19a11396].

    12     12   terra http.actor_profile(co: &lib.srv.convo, actor: &lib.store.actor, meth: method.t)
    13     13   	var rel: lib.store.relationship
    14     14   	if co.aid ~= 0 then
    15     15   		rel = co.srv:actor_rel_calc(co.who.id, actor.id)
    16     16   		if meth == method.post then
    17     17   			var act = co:ppostv('act')
    18     18   			if rel.recip.block() then
    19         -				if act:cmp( 'follow') or act:cmp( 'subscribe') then
           19  +				if act:cmp('follow') or act:cmp('subscribe') then
    20     20   					co:complain(403,'blocked','you cannot follow a user you are blocked by') return
    21     21   				end
    22     22   			end
    23         -			if act:cmp( 'block') and not rel.rel.block() then
    24         -				(rel.rel.block << true) ; (rel.recip.follow << false)
           23  +			if act:cmp('block') and not rel.rel.block() then
           24  +				rel.rel.block = true  rel.recip.follow = false
    25     25   				co.srv:actor_rel_create([lib.store.relation.idvmap.block], co.who.id, actor.id)
    26     26   				co.srv:actor_rel_destroy([lib.store.relation.idvmap.follow], actor.id, co.who.id)
    27         -			else
           27  +			elseif not act:cmp('report') then
    28     28   				[(function()
    29     29   					local tests = quote co:complain(400,'bad request','the action you have attempted on this user is not meaningful') return end
    30     30   					for i,v in ipairs(lib.store.relation.members) do
    31     31   						tests = quote
    32         -							if [v ~= 'block'] and act:cmp(([v])) and not rel.rel.[v]() then -- rely on dead code elimination :/
    33         -								(rel.rel.[v] << true)
           32  +							if [v ~= 'block'] and act:cmp(lib.str.plit([v])) and not rel.rel.[v]() then -- rely on dead code elimination :/
           33  +								rel.rel.[v] = true
    34     34   								co.srv:actor_rel_create([lib.store.relation.idvmap[v]], co.who.id, actor.id)
    35         -							elseif act:cmp((['un'..v])) and rel.rel.[v]() then
    36         -								(rel.rel.[v] << false)
           35  +							elseif act:cmp(lib.str.plit(['un'..v])) and rel.rel.[v]() then
           36  +								rel.rel.[v] = false
    37     37   								co.srv:actor_rel_destroy([lib.store.relation.idvmap[v]], co.who.id, actor.id)
    38     38   							else [tests] end
    39     39   						end
    40     40   					end
    41     41   					return tests
    42     42   				end)()]
    43     43   			end

Modified srv.t from [826b7b2edb] to [6a947d38ca].

    45     45   			for j=0, lst.ct do all:push(lst.ptr[j]) end
    46     46   			lst:free()
    47     47   		end
    48     48   	end
    49     49   	return all
    50     50   end
    51     51   
    52         -terra srv:timeline_instance_fetch(r: lib.store.range): lib.mem.vec(lib.mem.ptr(lib.store.post))
    53         -	var all: lib.mem.vec(lib.mem.ptr(lib.store.post)) all:init(64)
    54         -	for i=0,self.sources.ct do var src = self.sources.ptr + i
    55         -		if src.handle ~= nil and src.backend.timeline_instance_fetch ~= nil then
    56         -			var lst = src:timeline_instance_fetch(r)
    57         -			all:assure(all.sz + lst.ct)
    58         -			for j=0, lst.ct do all:push(lst.ptr[j]) end
    59         -			lst:free()
           52  +local function deftlfetch(fnname, ...)
           53  +	local args = {}
           54  +	for i,ty in ipairs{...} do args[#args + 1] = symbol(ty) end
           55  +	args[#args + 1] = symbol(lib.store.range)
           56  +	fnname = 'timeline_' .. fnname
           57  +	srv.methods[fnname] = terra(self: &srv, [args]): lib.mem.vec(lib.mem.ptr(lib.store.post))
           58  +		var all: lib.mem.vec(lib.mem.ptr(lib.store.post)) all:init(64)
           59  +		for i=0,self.sources.ct do var src = self.sources.ptr + i
           60  +			if src.handle ~= nil and src.backend.[fnname] ~= nil then
           61  +				var lst = src:[fnname]([args])
           62  +				all:assure(all.sz + lst.ct)
           63  +				for j=0, lst.ct do all:push(lst.ptr[j]) end
           64  +				lst:free()
           65  +			end
    60     66   		end
           67  +		return all
    61     68   	end
    62         -	return all
    63     69   end
    64     70   
           71  +deftlfetch('instance_fetch')
           72  +deftlfetch('actor_fetch_uid', uint64)
           73  +
    65     74   srv.metamethods.__methodmissing = macro(function(meth, self, ...)
    66     75   	local primary, ptr, stat, simple, oid = 0,1,2,3,4
    67     76   	local tk, rt = primary
    68     77   	local expr = {...}
    69     78   	for _,f in pairs(lib.store.backend.entries) do
    70     79   		local fn = f.field or f[1]
    71     80   		local ft = f.type or f[2]
................................................................................
   168    177   		mgr: &lib.net.mg_mgr
   169    178   		peer: lib.net.mg_addr
   170    179   	}
   171    180   	terra getpeer(con: &lib.net.mg_connection)
   172    181   		return [&strucheader](con).peer
   173    182   	end
   174    183   end
          184  +
          185  +terra convo:uid2actor_live(uid: uint64)
          186  +	var actor = self.srv:actor_fetch_uid(uid)
          187  +	if actor:ref() then
          188  +		if self.aid ~= 0 and self.who.id ~= uid then
          189  +			actor(0).relationship = self.srv:actor_rel_calc(self.who.id, uid)
          190  +		else -- defensive branch
          191  +			actor(0).relationship = lib.store.relationship {
          192  +				agent = 0, patient = uid;
          193  +				rel   = [lib.store.relation.null],
          194  +				recip = [lib.store.relation.null],
          195  +			}
          196  +		end
          197  +	end
          198  +	return actor
          199  +end
          200  +
          201  +terra convo:uid2actor(uid: uint64)
          202  +	var actor: &lib.store.actor = nil
          203  +	for j = 0, self.actorcache.top do
          204  +		if uid == self.actorcache(j).ptr.id then
          205  +			actor = self.actorcache(j).ptr
          206  +			break
          207  +		end
          208  +	end
          209  +	if actor == nil then
          210  +		actor = self.actorcache:insert(self:uid2actor_live(uid)).ptr
          211  +	end
          212  +	return actor
          213  +end
   175    214   
   176    215   terra convo:rawpage(code: uint16, pg: convo.page, hdrs: lib.mem.ptr(lib.http.header))
   177    216   	var doc = data.view.docskel {
   178    217   		instance = self.srv.cfg.instance;
   179    218   		title = pg.title;
   180    219   		body = pg.body;
   181    220   		class = pg.class;

Added static/followreq.svg version [8263feb69d].

            1  +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
            2  +<!-- Created with Inkscape (http://www.inkscape.org/) -->
            3  +
            4  +<svg
            5  +   xmlns:dc="http://purl.org/dc/elements/1.1/"
            6  +   xmlns:cc="http://creativecommons.org/ns#"
            7  +   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
            8  +   xmlns:svg="http://www.w3.org/2000/svg"
            9  +   xmlns="http://www.w3.org/2000/svg"
           10  +   xmlns:xlink="http://www.w3.org/1999/xlink"
           11  +   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
           12  +   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
           13  +   width="20"
           14  +   height="20"
           15  +   viewBox="0 0 5.2916664 5.2916665"
           16  +   version="1.1"
           17  +   id="svg8"
           18  +   inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
           19  +   sodipodi:docname="followreq.svg">
           20  +  <defs
           21  +     id="defs2">
           22  +    <linearGradient
           23  +       id="linearGradient1647"
           24  +       inkscape:collect="always">
           25  +      <stop
           26  +         id="stop1643"
           27  +         offset="0"
           28  +         style="stop-color:#9db3ff;stop-opacity:1" />
           29  +      <stop
           30  +         id="stop1645"
           31  +         offset="1"
           32  +         style="stop-color:#0036e4;stop-opacity:0.98431373" />
           33  +    </linearGradient>
           34  +    <linearGradient
           35  +       inkscape:collect="always"
           36  +       id="linearGradient1609">
           37  +      <stop
           38  +         style="stop-color:#f6f8ff;stop-opacity:1"
           39  +         offset="0"
           40  +         id="stop1605" />
           41  +      <stop
           42  +         style="stop-color:#3c6aff;stop-opacity:0.98431373"
           43  +         offset="1"
           44  +         id="stop1607" />
           45  +    </linearGradient>
           46  +    <linearGradient
           47  +       id="linearGradient1603"
           48  +       inkscape:collect="always">
           49  +      <stop
           50  +         id="stop1599"
           51  +         offset="0"
           52  +         style="stop-color:#557dff;stop-opacity:1" />
           53  +      <stop
           54  +         id="stop1601"
           55  +         offset="1"
           56  +         style="stop-color:#557dff;stop-opacity:0.97647059" />
           57  +    </linearGradient>
           58  +    <linearGradient
           59  +       id="linearGradient1597"
           60  +       inkscape:collect="always">
           61  +      <stop
           62  +         id="stop1591"
           63  +         offset="0"
           64  +         style="stop-color:#001868;stop-opacity:1" />
           65  +      <stop
           66  +         style="stop-color:#3565ff;stop-opacity:0.77254903"
           67  +         offset="0.30000001"
           68  +         id="stop1593" />
           69  +      <stop
           70  +         id="stop1595"
           71  +         offset="1"
           72  +         style="stop-color:#0032d4;stop-opacity:0" />
           73  +    </linearGradient>
           74  +    <linearGradient
           75  +       inkscape:collect="always"
           76  +       id="linearGradient1589">
           77  +      <stop
           78  +         style="stop-color:#557eff;stop-opacity:0.50980395"
           79  +         offset="0"
           80  +         id="stop1585" />
           81  +      <stop
           82  +         style="stop-color:#557dff;stop-opacity:0.02352941"
           83  +         offset="1"
           84  +         id="stop1587" />
           85  +    </linearGradient>
           86  +    <linearGradient
           87  +       inkscape:collect="always"
           88  +       id="linearGradient1054">
           89  +      <stop
           90  +         style="stop-color:#ff73e0;stop-opacity:1"
           91  +         offset="0"
           92  +         id="stop1050" />
           93  +      <stop
           94  +         style="stop-color:#ff00cb;stop-opacity:0.98431373"
           95  +         offset="1"
           96  +         id="stop1052" />
           97  +    </linearGradient>
           98  +    <linearGradient
           99  +       id="linearGradient1034"
          100  +       inkscape:collect="always">
          101  +      <stop
          102  +         id="stop1030"
          103  +         offset="0"
          104  +         style="stop-color:#ff55dd;stop-opacity:0.50869566" />
          105  +      <stop
          106  +         id="stop1032"
          107  +         offset="1"
          108  +         style="stop-color:#ff55dd;stop-opacity:0.02173913" />
          109  +    </linearGradient>
          110  +    <linearGradient
          111  +       id="linearGradient1019"
          112  +       inkscape:collect="always">
          113  +      <stop
          114  +         id="stop1013"
          115  +         offset="0"
          116  +         style="stop-color:#680054;stop-opacity:0.01304348" />
          117  +      <stop
          118  +         style="stop-color:#ff40d9;stop-opacity:0.23913044"
          119  +         offset="0.30000001"
          120  +         id="stop1015" />
          121  +      <stop
          122  +         id="stop1017"
          123  +         offset="1"
          124  +         style="stop-color:#d400aa;stop-opacity:0;" />
          125  +    </linearGradient>
          126  +    <linearGradient
          127  +       id="linearGradient1005"
          128  +       inkscape:collect="always">
          129  +      <stop
          130  +         id="stop1001"
          131  +         offset="0"
          132  +         style="stop-color:#fff6fd;stop-opacity:1" />
          133  +      <stop
          134  +         id="stop1003"
          135  +         offset="1"
          136  +         style="stop-color:#ff3cd7;stop-opacity:0.98260868" />
          137  +    </linearGradient>
          138  +    <linearGradient
          139  +       inkscape:collect="always"
          140  +       id="linearGradient979">
          141  +      <stop
          142  +         style="stop-color:#680054;stop-opacity:1"
          143  +         offset="0"
          144  +         id="stop975" />
          145  +      <stop
          146  +         id="stop983"
          147  +         offset="0.30000001"
          148  +         style="stop-color:#d400aa;stop-opacity:0.77254902;" />
          149  +      <stop
          150  +         style="stop-color:#d400aa;stop-opacity:0;"
          151  +         offset="1"
          152  +         id="stop977" />
          153  +    </linearGradient>
          154  +    <linearGradient
          155  +       inkscape:collect="always"
          156  +       id="linearGradient971">
          157  +      <stop
          158  +         style="stop-color:#ff55dd;stop-opacity:1;"
          159  +         offset="0"
          160  +         id="stop967" />
          161  +      <stop
          162  +         style="stop-color:#ff55dd;stop-opacity:0.97826087"
          163  +         offset="1"
          164  +         id="stop969" />
          165  +    </linearGradient>
          166  +    <linearGradient
          167  +       inkscape:collect="always"
          168  +       id="linearGradient963">
          169  +      <stop
          170  +         style="stop-color:#c839ac;stop-opacity:0.00392157"
          171  +         offset="0"
          172  +         id="stop959" />
          173  +      <stop
          174  +         style="stop-color:#852572;stop-opacity:1"
          175  +         offset="1"
          176  +         id="stop961" />
          177  +    </linearGradient>
          178  +    <linearGradient
          179  +       inkscape:collect="always"
          180  +       id="linearGradient943">
          181  +      <stop
          182  +         style="stop-color:#f4d7ee;stop-opacity:1;"
          183  +         offset="0"
          184  +         id="stop939" />
          185  +      <stop
          186  +         style="stop-color:#f4d7ee;stop-opacity:0;"
          187  +         offset="1"
          188  +         id="stop941" />
          189  +    </linearGradient>
          190  +    <linearGradient
          191  +       inkscape:collect="always"
          192  +       id="linearGradient954">
          193  +      <stop
          194  +         style="stop-color:#ffffff;stop-opacity:1;"
          195  +         offset="0"
          196  +         id="stop950" />
          197  +      <stop
          198  +         style="stop-color:#ffffff;stop-opacity:0;"
          199  +         offset="1"
          200  +         id="stop952" />
          201  +    </linearGradient>
          202  +    <linearGradient
          203  +       inkscape:collect="always"
          204  +       id="linearGradient938">
          205  +      <stop
          206  +         style="stop-color:#d9fff6;stop-opacity:1;"
          207  +         offset="0"
          208  +         id="stop934" />
          209  +      <stop
          210  +         style="stop-color:#d9fff6;stop-opacity:0;"
          211  +         offset="1"
          212  +         id="stop936" />
          213  +    </linearGradient>
          214  +    <linearGradient
          215  +       inkscape:collect="always"
          216  +       id="linearGradient1403">
          217  +      <stop
          218  +         style="stop-color:#ccaaff;stop-opacity:1;"
          219  +         offset="0"
          220  +         id="stop1399" />
          221  +      <stop
          222  +         style="stop-color:#ccaaff;stop-opacity:0;"
          223  +         offset="1"
          224  +         id="stop1401" />
          225  +    </linearGradient>
          226  +    <linearGradient
          227  +       id="linearGradient1395"
          228  +       inkscape:collect="always">
          229  +      <stop
          230  +         id="stop1391"
          231  +         offset="0"
          232  +         style="stop-color:#ff1616;stop-opacity:1" />
          233  +      <stop
          234  +         id="stop1393"
          235  +         offset="1"
          236  +         style="stop-color:#ff1d1d;stop-opacity:0" />
          237  +    </linearGradient>
          238  +    <linearGradient
          239  +       inkscape:collect="always"
          240  +       id="linearGradient1383">
          241  +      <stop
          242  +         style="stop-color:#980000;stop-opacity:1;"
          243  +         offset="0"
          244  +         id="stop1379" />
          245  +      <stop
          246  +         style="stop-color:#980000;stop-opacity:0;"
          247  +         offset="1"
          248  +         id="stop1381" />
          249  +    </linearGradient>
          250  +    <linearGradient
          251  +       inkscape:collect="always"
          252  +       id="linearGradient832">
          253  +      <stop
          254  +         style="stop-color:#ffcfcf;stop-opacity:1;"
          255  +         offset="0"
          256  +         id="stop828" />
          257  +      <stop
          258  +         style="stop-color:#ffcfcf;stop-opacity:0;"
          259  +         offset="1"
          260  +         id="stop830" />
          261  +    </linearGradient>
          262  +    <radialGradient
          263  +       inkscape:collect="always"
          264  +       xlink:href="#linearGradient832"
          265  +       id="radialGradient834"
          266  +       cx="3.2286437"
          267  +       cy="286.62921"
          268  +       fx="3.2286437"
          269  +       fy="286.62921"
          270  +       r="1.0866126"
          271  +       gradientTransform="matrix(1.8608797,0.8147617,-0.38242057,0.87343168,106.71446,33.692223)"
          272  +       gradientUnits="userSpaceOnUse" />
          273  +    <radialGradient
          274  +       inkscape:collect="always"
          275  +       xlink:href="#linearGradient1383"
          276  +       id="radialGradient1385"
          277  +       cx="4.1787109"
          278  +       cy="286.89261"
          279  +       fx="4.1787109"
          280  +       fy="286.89261"
          281  +       r="1.2260786"
          282  +       gradientTransform="matrix(1.7016464,0,0,1.6348586,-2.9319775,-182.10895)"
          283  +       gradientUnits="userSpaceOnUse" />
          284  +    <radialGradient
          285  +       inkscape:collect="always"
          286  +       xlink:href="#linearGradient1395"
          287  +       id="radialGradient1389"
          288  +       gradientUnits="userSpaceOnUse"
          289  +       gradientTransform="matrix(0.66230313,-1.6430738,1.0154487,0.40931507,-290.06307,177.39489)"
          290  +       cx="4.02069"
          291  +       cy="287.79269"
          292  +       fx="4.02069"
          293  +       fy="287.79269"
          294  +       r="1.0866126" />
          295  +    <linearGradient
          296  +       inkscape:collect="always"
          297  +       xlink:href="#linearGradient1403"
          298  +       id="linearGradient1405"
          299  +       x1="8.3939333"
          300  +       y1="288.1091"
          301  +       x2="7.0158253"
          302  +       y2="287.32819"
          303  +       gradientUnits="userSpaceOnUse" />
          304  +    <linearGradient
          305  +       inkscape:collect="always"
          306  +       xlink:href="#linearGradient938"
          307  +       id="linearGradient940"
          308  +       x1="7.609839"
          309  +       y1="288.73215"
          310  +       x2="7.609839"
          311  +       y2="283.78305"
          312  +       gradientUnits="userSpaceOnUse" />
          313  +    <linearGradient
          314  +       inkscape:collect="always"
          315  +       xlink:href="#linearGradient954"
          316  +       id="linearGradient956"
          317  +       x1="3.0150654"
          318  +       y1="285.94464"
          319  +       x2="3.0150654"
          320  +       y2="282.40109"
          321  +       gradientUnits="userSpaceOnUse" />
          322  +    <linearGradient
          323  +       inkscape:collect="always"
          324  +       xlink:href="#linearGradient954"
          325  +       id="linearGradient1138"
          326  +       gradientUnits="userSpaceOnUse"
          327  +       x1="3.0150654"
          328  +       y1="285.94464"
          329  +       x2="3.0150654"
          330  +       y2="284.62277" />
          331  +    <radialGradient
          332  +       inkscape:collect="always"
          333  +       xlink:href="#linearGradient1005"
          334  +       id="radialGradient945"
          335  +       cx="6.1517248"
          336  +       cy="285.09021"
          337  +       fx="6.1517248"
          338  +       fy="285.09021"
          339  +       r="1.3844374"
          340  +       gradientTransform="matrix(2.4674713,0,0,2.4674669,-5.8821073,-417.49152)"
          341  +       gradientUnits="userSpaceOnUse" />
          342  +    <radialGradient
          343  +       inkscape:collect="always"
          344  +       xlink:href="#linearGradient943"
          345  +       id="radialGradient953"
          346  +       gradientUnits="userSpaceOnUse"
          347  +       gradientTransform="matrix(2.4674713,0,0,2.4674669,-9.027479,-418.36044)"
          348  +       cx="6.1517248"
          349  +       cy="285.09021"
          350  +       fx="6.1517248"
          351  +       fy="285.09021"
          352  +       r="1.3844374" />
          353  +    <radialGradient
          354  +       inkscape:collect="always"
          355  +       xlink:href="#linearGradient963"
          356  +       id="radialGradient965"
          357  +       cx="6.1523438"
          358  +       cy="285.08984"
          359  +       fx="6.1523438"
          360  +       fy="285.08984"
          361  +       r="1.6679688"
          362  +       gradientTransform="matrix(1,0,0,0.99999775,0,6.4095141e-4)"
          363  +       gradientUnits="userSpaceOnUse" />
          364  +    <radialGradient
          365  +       inkscape:collect="always"
          366  +       xlink:href="#linearGradient971"
          367  +       id="radialGradient973"
          368  +       cx="4.6300988"
          369  +       cy="285.0715"
          370  +       fx="4.6300988"
          371  +       fy="285.0715"
          372  +       r="0.88396439"
          373  +       gradientTransform="matrix(3.5121044,0,0,4.5073949,-11.771195,-1000.0836)"
          374  +       gradientUnits="userSpaceOnUse" />
          375  +    <linearGradient
          376  +       inkscape:collect="always"
          377  +       xlink:href="#linearGradient979"
          378  +       id="linearGradient981"
          379  +       x1="6.3269596"
          380  +       y1="286.08289"
          381  +       x2="6.3263793"
          382  +       y2="288.44873"
          383  +       gradientUnits="userSpaceOnUse" />
          384  +    <linearGradient
          385  +       inkscape:collect="always"
          386  +       xlink:href="#linearGradient1019"
          387  +       id="linearGradient1009"
          388  +       gradientUnits="userSpaceOnUse"
          389  +       x1="6.3269596"
          390  +       y1="286.08289"
          391  +       x2="6.3263793"
          392  +       y2="288.44873" />
          393  +    <radialGradient
          394  +       inkscape:collect="always"
          395  +       xlink:href="#linearGradient1034"
          396  +       id="radialGradient1028"
          397  +       cx="7.8964839"
          398  +       cy="10.825195"
          399  +       fx="7.8964839"
          400  +       fy="10.825195"
          401  +       r="6.1388507"
          402  +       gradientTransform="matrix(1.5553588,0,0,2.1211746,-4.385382,-12.136934)"
          403  +       gradientUnits="userSpaceOnUse" />
          404  +    <radialGradient
          405  +       inkscape:collect="always"
          406  +       xlink:href="#linearGradient1034"
          407  +       id="radialGradient1038"
          408  +       gradientUnits="userSpaceOnUse"
          409  +       gradientTransform="matrix(-1.5553588,0,0,-1.3840186,20.178349,25.807467)"
          410  +       cx="7.8964839"
          411  +       cy="10.825195"
          412  +       fx="7.8964839"
          413  +       fy="10.825195"
          414  +       r="6.1388507" />
          415  +    <radialGradient
          416  +       inkscape:collect="always"
          417  +       xlink:href="#linearGradient1054"
          418  +       id="radialGradient1048"
          419  +       gradientUnits="userSpaceOnUse"
          420  +       gradientTransform="matrix(2.4674713,0,0,2.4674669,-5.8821075,-417.49152)"
          421  +       cx="6.1517248"
          422  +       cy="285.09021"
          423  +       fx="6.1517248"
          424  +       fy="285.09021"
          425  +       r="1.3844374" />
          426  +    <radialGradient
          427  +       inkscape:collect="always"
          428  +       xlink:href="#linearGradient1589"
          429  +       id="radialGradient1149"
          430  +       gradientUnits="userSpaceOnUse"
          431  +       gradientTransform="matrix(-1.5553588,0,0,-1.3840186,20.178349,25.807467)"
          432  +       cx="7.8964839"
          433  +       cy="10.825195"
          434  +       fx="7.8964839"
          435  +       fy="10.825195"
          436  +       r="6.1388507" />
          437  +    <linearGradient
          438  +       inkscape:collect="always"
          439  +       xlink:href="#linearGradient1597"
          440  +       id="linearGradient1151"
          441  +       gradientUnits="userSpaceOnUse"
          442  +       x1="6.3269596"
          443  +       y1="286.08289"
          444  +       x2="6.3263793"
          445  +       y2="288.44873" />
          446  +    <radialGradient
          447  +       inkscape:collect="always"
          448  +       xlink:href="#linearGradient1603"
          449  +       id="radialGradient1153"
          450  +       gradientUnits="userSpaceOnUse"
          451  +       gradientTransform="matrix(3.5121044,0,0,4.5073949,-11.771195,-1000.0836)"
          452  +       cx="4.6300988"
          453  +       cy="285.0715"
          454  +       fx="4.6300988"
          455  +       fy="285.0715"
          456  +       r="0.88396439" />
          457  +    <radialGradient
          458  +       inkscape:collect="always"
          459  +       xlink:href="#linearGradient1005"
          460  +       id="radialGradient1142-3"
          461  +       gradientUnits="userSpaceOnUse"
          462  +       gradientTransform="matrix(7.7743272,0,0,7.7743124,-43.463536,-2212.0183)"
          463  +       cx="6.1517248"
          464  +       cy="285.09021"
          465  +       fx="6.1517248"
          466  +       fy="285.09021"
          467  +       r="1.3844374" />
          468  +    <radialGradient
          469  +       inkscape:collect="always"
          470  +       xlink:href="#linearGradient1005"
          471  +       id="radialGradient1575"
          472  +       gradientUnits="userSpaceOnUse"
          473  +       gradientTransform="matrix(1.3440509,0,0,1.3440485,-0.7046247,-98.181012)"
          474  +       cx="5.6033692"
          475  +       cy="284.85327"
          476  +       fx="5.6033692"
          477  +       fy="284.85327"
          478  +       r="1.3844374" />
          479  +    <radialGradient
          480  +       inkscape:collect="always"
          481  +       xlink:href="#linearGradient1609"
          482  +       id="radialGradient1579"
          483  +       gradientUnits="userSpaceOnUse"
          484  +       gradientTransform="matrix(1.3440509,0,0,1.3440485,-7.5617585,-98.181012)"
          485  +       cx="5.6033692"
          486  +       cy="284.85327"
          487  +       fx="5.6033692"
          488  +       fy="284.85327"
          489  +       r="1.3844374" />
          490  +    <radialGradient
          491  +       inkscape:collect="always"
          492  +       xlink:href="#linearGradient1609"
          493  +       id="radialGradient1613"
          494  +       gradientUnits="userSpaceOnUse"
          495  +       gradientTransform="matrix(1.3440509,0,0,1.3440485,-0.62945515,-98.297942)"
          496  +       cx="5.6033692"
          497  +       cy="284.85327"
          498  +       fx="5.6033692"
          499  +       fy="284.85327"
          500  +       r="1.3844374" />
          501  +    <radialGradient
          502  +       inkscape:collect="always"
          503  +       xlink:href="#linearGradient1609"
          504  +       id="radialGradient1619"
          505  +       gradientUnits="userSpaceOnUse"
          506  +       gradientTransform="matrix(1.7810629,0,0,1.7810597,-2.9864585,-223.14925)"
          507  +       cx="5.3173594"
          508  +       cy="285.32516"
          509  +       fx="5.3173594"
          510  +       fy="285.32516"
          511  +       r="1.3844374" />
          512  +    <radialGradient
          513  +       inkscape:collect="always"
          514  +       xlink:href="#linearGradient1647"
          515  +       id="radialGradient1639"
          516  +       gradientUnits="userSpaceOnUse"
          517  +       gradientTransform="matrix(1.7810629,0,0,1.7810597,-2.9864585,-223.14925)"
          518  +       cx="5.3173594"
          519  +       cy="285.32516"
          520  +       fx="5.3173594"
          521  +       fy="285.32516"
          522  +       r="1.3844374" />
          523  +    <radialGradient
          524  +       inkscape:collect="always"
          525  +       xlink:href="#linearGradient1647"
          526  +       id="radialGradient1641"
          527  +       gradientUnits="userSpaceOnUse"
          528  +       gradientTransform="matrix(1.3440509,0,0,1.3440485,-0.62945515,-98.297942)"
          529  +       cx="5.6033692"
          530  +       cy="284.85327"
          531  +       fx="5.6033692"
          532  +       fy="284.85327"
          533  +       r="1.3844374" />
          534  +    <radialGradient
          535  +       inkscape:collect="always"
          536  +       xlink:href="#linearGradient1609"
          537  +       id="radialGradient1773"
          538  +       gradientUnits="userSpaceOnUse"
          539  +       gradientTransform="matrix(2.5551461,0,0,2.5551415,-7.1614394,-444.56578)"
          540  +       cx="5.3173594"
          541  +       cy="285.32516"
          542  +       fx="5.3173594"
          543  +       fy="285.32516"
          544  +       r="1.3844374" />
          545  +    <radialGradient
          546  +       inkscape:collect="always"
          547  +       xlink:href="#linearGradient1609"
          548  +       id="radialGradient1775"
          549  +       gradientUnits="userSpaceOnUse"
          550  +       gradientTransform="matrix(1.3440509,0,0,1.3440485,-0.62945515,-98.297942)"
          551  +       cx="5.6033692"
          552  +       cy="284.85327"
          553  +       fx="5.6033692"
          554  +       fy="284.85327"
          555  +       r="1.3844374" />
          556  +    <radialGradient
          557  +       inkscape:collect="always"
          558  +       xlink:href="#linearGradient1647"
          559  +       id="radialGradient1785"
          560  +       gradientUnits="userSpaceOnUse"
          561  +       gradientTransform="matrix(1.3440509,0,0,1.3440485,-0.62945515,-98.297942)"
          562  +       cx="5.6033692"
          563  +       cy="284.85327"
          564  +       fx="5.6033692"
          565  +       fy="284.85327"
          566  +       r="1.3844374" />
          567  +    <filter
          568  +       inkscape:collect="always"
          569  +       style="color-interpolation-filters:sRGB"
          570  +       id="filter1811"
          571  +       x="-0.10140134"
          572  +       width="1.2028027"
          573  +       y="-0.055816109"
          574  +       height="1.1116322">
          575  +      <feGaussianBlur
          576  +         inkscape:collect="always"
          577  +         stdDeviation="0.066236744"
          578  +         id="feGaussianBlur1813" />
          579  +    </filter>
          580  +    <filter
          581  +       inkscape:collect="always"
          582  +       style="color-interpolation-filters:sRGB"
          583  +       id="filter1889"
          584  +       x="-0.42250557"
          585  +       width="1.8450111"
          586  +       y="-0.23256712"
          587  +       height="1.4651342">
          588  +      <feGaussianBlur
          589  +         inkscape:collect="always"
          590  +         stdDeviation="0.27598643"
          591  +         id="feGaussianBlur1891" />
          592  +    </filter>
          593  +    <radialGradient
          594  +       inkscape:collect="always"
          595  +       xlink:href="#linearGradient1647"
          596  +       id="radialGradient1893"
          597  +       gradientUnits="userSpaceOnUse"
          598  +       gradientTransform="matrix(1.7810629,0,0,1.7810597,-2.9864585,-223.14925)"
          599  +       cx="5.3173594"
          600  +       cy="285.32516"
          601  +       fx="5.3173594"
          602  +       fy="285.32516"
          603  +       r="1.3844374" />
          604  +    <radialGradient
          605  +       inkscape:collect="always"
          606  +       xlink:href="#linearGradient1647"
          607  +       id="radialGradient1895"
          608  +       gradientUnits="userSpaceOnUse"
          609  +       gradientTransform="matrix(1.3440509,0,0,1.3440485,-0.62945515,-98.297942)"
          610  +       cx="5.6033692"
          611  +       cy="284.85327"
          612  +       fx="5.6033692"
          613  +       fy="284.85327"
          614  +       r="1.3844374" />
          615  +  </defs>
          616  +  <sodipodi:namedview
          617  +     id="base"
          618  +     pagecolor="#181818"
          619  +     bordercolor="#666666"
          620  +     borderopacity="1.0"
          621  +     inkscape:pageopacity="0"
          622  +     inkscape:pageshadow="2"
          623  +     inkscape:zoom="1.979899"
          624  +     inkscape:cx="-51.662731"
          625  +     inkscape:cy="-45.562994"
          626  +     inkscape:document-units="mm"
          627  +     inkscape:current-layer="layer1"
          628  +     showgrid="false"
          629  +     units="px"
          630  +     inkscape:window-width="1920"
          631  +     inkscape:window-height="1042"
          632  +     inkscape:window-x="0"
          633  +     inkscape:window-y="38"
          634  +     inkscape:window-maximized="0"
          635  +     showguides="true"
          636  +     fit-margin-top="0"
          637  +     fit-margin-left="0"
          638  +     fit-margin-right="0"
          639  +     fit-margin-bottom="0" />
          640  +  <metadata
          641  +     id="metadata5">
          642  +    <rdf:RDF>
          643  +      <cc:Work
          644  +         rdf:about="">
          645  +        <dc:format>image/svg+xml</dc:format>
          646  +        <dc:type
          647  +           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
          648  +        <dc:title></dc:title>
          649  +      </cc:Work>
          650  +    </rdf:RDF>
          651  +  </metadata>
          652  +  <g
          653  +     inkscape:label="Layer 1"
          654  +     inkscape:groupmode="layer"
          655  +     id="layer1"
          656  +     transform="translate(-2.6134661,-283.36966)">
          657  +    <g
          658  +       id="g1147"
          659  +       transform="matrix(0.9120087,0,0,0.9120087,0.33514277,25.128587)"
          660  +       style="stroke-width:1.09648085">
          661  +      <path
          662  +         transform="matrix(0.26458333,0,0,0.26458333,2.6134661,283.36966)"
          663  +         d="m 7.9257812,0.8359375 a 1.6178892,1.6178892 0 0 0 -0.2207031,0.009766 C 5.1410214,1.1501128 3.6301435,2.94586 3.1875,4.4550781 2.798777,5.7804512 2.9557893,6.822698 3.0019531,7.09375 c 0.045127,0.9218304 0.3822636,1.5885831 0.7910157,2.2910156 0.3127802,0.5375068 0.7335894,1.0229114 1.15625,1.4980464 0.028572,0.111047 0.050755,0.187185 0.082031,0.326172 0.0073,0.03244 0.00535,0.02259 0.011719,0.05664 -0.3761238,0.02572 -0.8216256,0.06774 -1.2910157,0.138672 -0.4857631,0.07341 -0.9830994,0.168253 -1.4765625,0.332031 -0.493463,0.163778 -1.0998654,0.233591 -1.6191406,1.203125 -0.23350107,0.435868 -0.24245693,0.654459 -0.2890625,0.923828 -0.0466056,0.269369 -0.0772406,0.547444 -0.10351562,0.84961 -0.0525501,0.604332 -0.0820372,1.293158 -0.0996094,1.955078 -0.0351443,1.323838 -0.0214844,2.544922 -0.0214844,2.544922 A 1.6178892,1.6178892 0 0 0 1.7597656,20.814453 H 14.033203 a 1.6178892,1.6178892 0 0 0 1.617188,-1.601562 c 0,0 0.01366,-1.221084 -0.02149,-2.544922 -0.01757,-0.661919 -0.04706,-1.350747 -0.09961,-1.955078 -0.02628,-0.302166 -0.05691,-0.580241 -0.103516,-0.84961 -0.04661,-0.269368 -0.05556,-0.487961 -0.289062,-0.923828 C 14.61759,11.970465 14.010855,11.900125 13.517578,11.736328 13.024302,11.572531 12.526554,11.477735 12.041016,11.404297 11.571088,11.33322 11.126348,11.28939 10.75,11.263672 c 0.0028,-0.01394 8.95e-4,-0.0098 0.0039,-0.02344 0.02862,-0.129185 0.05214,-0.210465 0.08008,-0.320312 0.433111,-0.472266 0.867515,-0.9510681 1.1875,-1.498047 0.424707,-0.7259885 0.791976,-1.4348115 0.777344,-2.4375 l -0.02734,0.3183594 c 0,0 0.276624,-1.338406 -0.166015,-2.8476563 C 12.162829,2.9458278 10.651988,1.1499497 8.0878906,0.84570312 A 1.6178892,1.6178892 0 0 0 7.9257812,0.8359375 Z M 10.701172,11.511719 c -0.0029,-0.0036 0.007,0.0064 0.0039,0.002 -0.04632,-0.06737 -0.0293,-0.353973 -0.0293,0.134766 0,0.04526 0.01972,-0.102408 0.02539,-0.136719 z m -5.6093751,0.002 c 0.00534,0.02911 0.025391,0.180144 0.025391,0.134766 0,-0.486237 0.016732,-0.199942 -0.029297,-0.132813 -0.00293,0.0043 0.00675,-0.0055 0.00391,-0.002 z"
          664  +         id="path1021"
          665  +         style="fill:url(#radialGradient1149);fill-opacity:1;stroke:none;stroke-width:1.09648073px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
          666  +         inkscape:original="M 7.8964844 2.453125 C 3.8572424 2.9326715 4.6113281 7.0078125 4.6113281 7.0078125 C 4.6485531 7.8381593 5.5094605 9.2817797 6.4453125 10.195312 C 6.4986525 10.392157 6.734375 11.271085 6.734375 11.648438 C 6.734375 12.069175 6.1908578 12.91084 5.8691406 12.861328 C 5.5474216 12.811888 2.4532451 13.010035 2.0820312 13.703125 C 1.7108136 14.396064 1.7597656 19.197266 1.7597656 19.197266 L 14.033203 19.197266 C 14.033203 19.197266 14.082152 14.396064 13.710938 13.703125 C 13.339721 13.010224 10.247498 12.811816 9.9257812 12.861328 C 9.6040608 12.910798 9.0585937 12.069174 9.0585938 11.648438 C 9.0585938 11.282797 9.2742792 10.466705 9.3378906 10.230469 C 10.300978 9.3271083 11.194239 7.8711535 11.181641 7.0078125 C 11.181641 7.0078125 11.935727 2.9324069 7.8964844 2.453125 z "
          667  +         inkscape:radius="1.6177274"
          668  +         sodipodi:type="inkscape:offset" />
          669  +      <path
          670  +         sodipodi:nodetypes="cccsccscccc"
          671  +         inkscape:connector-curvature="0"
          672  +         d="m 3.0792354,288.44873 c 0,0 -0.013096,-1.27028 0.085122,-1.45362 0.098217,-0.18338 0.9166976,-0.23571 1.0018191,-0.22263 0.085121,0.0131 0.2291744,-0.20953 0.2291744,-0.32085 0,-0.11131 -0.085123,-0.41905 -0.085123,-0.41905 h 0.7851589 c 0,0 -0.085122,0.30774 -0.085122,0.41905 0,0.11132 0.1440525,0.33394 0.2291744,0.32085 0.085121,-0.0131 0.9036015,0.0393 1.0018191,0.22263 0.098217,0.18334 0.085121,1.45362 0.085121,1.45362 z"
          673  +         style="fill:url(#linearGradient1151);fill-opacity:1;stroke:none;stroke-width:0.29011053px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
          674  +         id="path893" />
          675  +      <path
          676  +         sodipodi:nodetypes="cczcc"
          677  +         inkscape:connector-curvature="0"
          678  +         d="m 4.7028071,284.01884 c -1.0687161,0.12688 -0.8692216,1.20492 -0.8692216,1.20492 0.015116,0.33718 0.5431676,1.06402 0.8692218,1.06402 0.3260542,0 0.8742883,-0.71682 0.8692217,-1.06402 0,0 0.1994946,-1.07811 -0.8692216,-1.20492"
          679  +         style="fill:url(#radialGradient1153);fill-opacity:1;stroke:none;stroke-width:0.18091933;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
          680  +         id="path888" />
          681  +    </g>
          682  +    <g
          683  +       id="g1138"
          684  +       transform="matrix(0.83362971,0,0,0.83362961,-1.263316,47.635689)"
          685  +       style="stroke-width:1.1995734" />
          686  +    <path
          687  +       inkscape:connector-curvature="0"
          688  +       d="m -0.41544932,286.24407 -6e-7,0.0467 0.079412,0.0794 0.046709,2e-5 0.079411,-0.0794 -2.1e-5,-0.0467 -0.079412,-0.0794 h -0.046687 z m 0.1890431,-2.42429 c -0.050462,-5.4e-4 -0.099995,0.003 -0.1477672,0.0101 -0.0022,4.1e-4 -0.00479,5.4e-4 -0.00567,10e-4 a 0.03465606,0.03465606 0 0 1 -8.061e-4,0 c -0.1189057,0.0126 -0.2173312,0.0418 -0.2781267,0.085 -0.061644,0.0439 -0.097253,0.0941 -0.1089026,0.21092 -6.4e-6,2e-4 6.3e-6,2.1e-4 0,4.2e-4 -0.00108,0.0333 0.0017,0.0566 0.00486,0.0709 0.016269,-0.003 0.05438,-0.0179 0.097162,-0.0433 0.045262,-0.027 0.095547,-0.0636 0.1372414,-0.10242 a 0.03465606,0.03465606 0 0 1 0.01093,-0.006 c 2.279e-4,-2.1e-4 5.828e-4,-1.9e-4 8.061e-4,-4.2e-4 0.173871,-0.16094 0.4251415,-0.16698 0.6222422,-0.081 0.2022168,0.0882 0.3694383,0.29957 0.3214446,0.55544 -0.02942,0.25302 -0.2068773,0.42314 -0.3667866,0.56314 -0.1610552,0.14099 -0.3114891,0.26796 -0.3623339,0.38864 a 0.03465606,0.03465606 0 0 1 -8.062e-4,0.002 c -1.652e-4,4.1e-4 -7.68e-4,0.002 -0.00123,0.002 -0.011871,0.0255 -0.026525,0.0833 -0.033602,0.14534 -0.00708,0.062 -0.00747,0.12983 0.00243,0.18015 0.00958,0.0487 0.0298,0.0797 0.036841,0.087 2.695e-4,0 9.314e-4,10e-6 0.00123,0 0.0228,-0.0467 0.038064,-0.0971 0.059512,-0.18744 0.028951,-0.1219 0.091926,-0.27814 0.2586942,-0.41253 a 0.03465606,0.03465606 0 0 1 0.00162,-0.001 c 4.352e-4,-4.2e-4 7.68e-4,-10e-4 0.00123,-10e-4 a 0.03465606,0.03465606 0 0 1 4.145e-4,-4.2e-4 c 0.1472617,-0.11555 0.2995168,-0.24699 0.4032226,-0.38905 0.1044145,-0.14303 0.1602547,-0.28747 0.139266,-0.45707 -3.192e-4,-0.002 -5.992e-4,-0.004 -8.171e-4,-0.006 a 0.03465606,0.03465606 0 0 1 0,-0.002 l -0.00321,-0.0474 -0.00607,-0.0401 -4.042e-4,-10e-4 c -0.039415,-0.19025 -0.1654822,-0.32758 -0.3412823,-0.41821 -0.1316913,-0.0679 -0.2898916,-0.1043 -0.441278,-0.10606 z"
          689  +       style="opacity:1;vector-effect:none;fill:url(#radialGradient1579);fill-opacity:1;stroke:none;stroke-width:0.16500001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
          690  +       id="path1577" />
          691  +    <g
          692  +       id="g1783"
          693  +       transform="matrix(0.74111183,0.1038833,-0.1038833,0.74111183,31.405072,72.993613)"
          694  +       style="stroke-width:1.33626032">
          695  +      <g
          696  +         transform="translate(-0.33072917,0.20079985)"
          697  +         style="stroke-width:1.33626032;filter:url(#filter1811)"
          698  +         id="g1633">
          699  +        <path
          700  +           inkscape:connector-curvature="0"
          701  +           id="path1629"
          702  +           d="m 6.4834403,286.26988 -8e-7,0.0619 0.1052325,0.10522 0.061896,3e-5 0.1052311,-0.10522 -2.78e-5,-0.0619 -0.1052325,-0.10522 H 6.588672 Z"
          703  +           style="opacity:1;vector-effect:none;fill:url(#radialGradient1893);fill-opacity:1;stroke:none;stroke-width:0.22048296;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
          704  +        <path
          705  +           sodipodi:nodetypes="cccccccccccccccccccccscccccccccccccccccccccc"
          706  +           inkscape:connector-curvature="0"
          707  +           id="path1631"
          708  +           d="m 6.7087489,283.58994 c -0.050882,-5.4e-4 -0.10279,0.003 -0.1523438,0.01 -0.00506,6.7e-4 -0.010589,-7.5e-4 -0.015625,0 -3.981e-4,2e-5 -0.00193,0 -0.00195,0 -1.645e-4,2e-5 -0.038952,0.0117 -0.039063,0.0117 -0.1113928,0.0158 -0.2154498,0.0387 -0.2929688,0.0937 -5.9e-6,6.7e-4 -5.9e-6,0.001 0,0.002 -0.07796,0.0555 -0.1426172,0.15431 -0.15625,0.29102 -9.37e-5,0.003 -9.37e-5,0.005 0,0.008 -0.00142,0.0437 0.00283,0.079 0.00781,0.10156 0.013901,0.0597 0.07263,0.0977 0.1328125,0.0859 0.057973,-0.0107 0.084766,-0.0289 0.1347656,-0.0586 0.059414,-0.0359 0.1122747,-0.0811 0.1679671,-0.12224 0.094598,-0.0883 0.3547641,-0.16032 0.5,-0.0625 0.1617225,0.0705 0.2910221,0.23377 0.2539063,0.43164 -7.463e-4,0.003 -0.0014,0.005 -0.00195,0.008 -0.024015,0.20653 -0.170998,0.35267 -0.328125,0.49023 -0.1602903,0.14032 -0.3218459,0.26181 -0.3925782,0.42969 -0.00426,0.0106 -0.00689,0.0218 -0.00781,0.0332 -0.016089,0.0442 -0.028521,0.0883 -0.035156,0.14649 -0.00805,0.0705 -0.010059,0.14581 0.00391,0.21679 0.0069,0.0351 0.017881,0.0649 0.029297,0.0879 0.011416,0.023 0.017907,0.0348 0.037109,0.0547 0.054282,0.0565 0.1481054,0.0426 0.1835937,-0.0273 0.027599,-0.0565 0.048071,-0.11921 0.070312,-0.21289 0.025238,-0.10627 0.07465,-0.23075 0.2148438,-0.34571 0.00165,-10e-4 0.00223,-0.003 0.00391,-0.004 6.5e-4,10e-6 0.0013,10e-6 0.00195,0 0.1508326,-0.11835 0.3089707,-0.25673 0.4238281,-0.41407 0.1142535,-0.1565 0.1871609,-0.33467 0.1621093,-0.5371 2.34e-5,-10e-4 2.34e-5,-0.003 0,-0.004 -1.9e-6,-1e-5 -0.00195,3e-5 -0.00195,0 4.3e-6,4e-5 3.81e-5,-0.002 0,-0.002 -1.897e-4,-8.3e-4 4.685e-4,-0.004 0,-0.006 l -0.00195,-0.0332 c -1.92e-4,-0.006 -8.44e-4,-0.0118 -0.00195,-0.0176 l -0.00586,-0.0293 c -3.716e-4,-0.005 -0.00102,-0.009 -0.00195,-0.0137 -0.046881,-0.22629 -0.2005557,-0.39409 -0.3984375,-0.4961 -0.1502384,-0.0775 -0.3237824,-0.11523 -0.4921875,-0.11719 z m 0.6757812,0.72266 c -9.37e-5,0.003 -9.37e-5,0.005 0,0.008 -0.00407,-0.14371 -0.00305,0.0432 0,-0.008 z"
          709  +           style="opacity:1;vector-effect:none;fill:url(#radialGradient1895);fill-opacity:1;stroke:none;stroke-width:0.22048296;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
          710  +      </g>
          711  +      <g
          712  +         id="g1819"
          713  +         style="stroke-width:1.33626032;filter:url(#filter1889)"
          714  +         transform="translate(-0.33072917,0.20079985)">
          715  +        <path
          716  +           style="opacity:1;vector-effect:none;fill:url(#radialGradient1639);fill-opacity:1;stroke:none;stroke-width:0.22048296;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
          717  +           d="m 6.4834403,286.26988 -8e-7,0.0619 0.1052325,0.10522 0.061896,3e-5 0.1052311,-0.10522 -2.78e-5,-0.0619 -0.1052325,-0.10522 H 6.588672 Z"
          718  +           id="path1815"
          719  +           inkscape:connector-curvature="0" />
          720  +        <path
          721  +           style="opacity:1;vector-effect:none;fill:url(#radialGradient1785);fill-opacity:1;stroke:none;stroke-width:0.22048296;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
          722  +           d="m 6.7087489,283.58994 c -0.050882,-5.4e-4 -0.10279,0.003 -0.1523438,0.01 -0.00506,6.7e-4 -0.010589,-7.5e-4 -0.015625,0 -3.981e-4,2e-5 -0.00193,0 -0.00195,0 -1.645e-4,2e-5 -0.038952,0.0117 -0.039063,0.0117 -0.1113928,0.0158 -0.2154498,0.0387 -0.2929688,0.0937 -5.9e-6,6.7e-4 -5.9e-6,0.001 0,0.002 -0.07796,0.0555 -0.1426172,0.15431 -0.15625,0.29102 -9.37e-5,0.003 -9.37e-5,0.005 0,0.008 -0.00142,0.0437 0.00283,0.079 0.00781,0.10156 0.013901,0.0597 0.07263,0.0977 0.1328125,0.0859 0.057973,-0.0107 0.084766,-0.0289 0.1347656,-0.0586 0.059414,-0.0359 0.1122747,-0.0811 0.1679671,-0.12224 0.094598,-0.0883 0.3547641,-0.16032 0.5,-0.0625 0.1617225,0.0705 0.2910221,0.23377 0.2539063,0.43164 -7.463e-4,0.003 -0.0014,0.005 -0.00195,0.008 -0.024015,0.20653 -0.170998,0.35267 -0.328125,0.49023 -0.1602903,0.14032 -0.3218459,0.26181 -0.3925782,0.42969 -0.00426,0.0106 -0.00689,0.0218 -0.00781,0.0332 -0.016089,0.0442 -0.028521,0.0883 -0.035156,0.14649 -0.00805,0.0705 -0.010059,0.14581 0.00391,0.21679 0.0069,0.0351 0.017881,0.0649 0.029297,0.0879 0.011416,0.023 0.017907,0.0348 0.037109,0.0547 0.054282,0.0565 0.1481054,0.0426 0.1835937,-0.0273 0.027599,-0.0565 0.048071,-0.11921 0.070312,-0.21289 0.025238,-0.10627 0.07465,-0.23075 0.2148438,-0.34571 0.00165,-10e-4 0.00223,-0.003 0.00391,-0.004 6.5e-4,10e-6 0.0013,10e-6 0.00195,0 0.1508326,-0.11835 0.3089707,-0.25673 0.4238281,-0.41407 0.1142535,-0.1565 0.1871609,-0.33467 0.1621093,-0.5371 2.34e-5,-10e-4 2.34e-5,-0.003 0,-0.004 -1.9e-6,-1e-5 -0.00195,3e-5 -0.00195,0 4.3e-6,4e-5 3.81e-5,-0.002 0,-0.002 -1.897e-4,-8.3e-4 4.685e-4,-0.004 0,-0.006 l -0.00195,-0.0332 c -1.92e-4,-0.006 -8.44e-4,-0.0118 -0.00195,-0.0176 l -0.00586,-0.0293 c -3.716e-4,-0.005 -0.00102,-0.009 -0.00195,-0.0137 -0.046881,-0.22629 -0.2005557,-0.39409 -0.3984375,-0.4961 -0.1502384,-0.0775 -0.3237824,-0.11523 -0.4921875,-0.11719 z m 0.6757812,0.72266 c -9.37e-5,0.003 -9.37e-5,0.005 0,0.008 -0.00407,-0.14371 -0.00305,0.0432 0,-0.008 z"
          723  +           id="path1817"
          724  +           inkscape:connector-curvature="0"
          725  +           sodipodi:nodetypes="cccccccccccccccccccccscccccccccccccccccccccc" />
          726  +      </g>
          727  +      <g
          728  +         transform="translate(-0.33072916,0.20079985)"
          729  +         id="g1627"
          730  +         style="stroke-width:1.33626032">
          731  +        <path
          732  +           style="opacity:1;vector-effect:none;fill:url(#radialGradient1773);fill-opacity:1;stroke:none;stroke-width:0.22048296;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
          733  +           d="m 6.4242542,286.25641 -1.2e-6,0.0888 0.1509685,0.15095 0.088797,4e-5 0.1509666,-0.15095 -3.99e-5,-0.0888 -0.1509685,-0.15095 h -0.088755 z"
          734  +           id="path1617"
          735  +           inkscape:connector-curvature="0" />
          736  +        <path
          737  +           style="opacity:1;vector-effect:none;fill:url(#radialGradient1775);fill-opacity:1;stroke:none;stroke-width:0.22048296;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
          738  +           d="m 6.7087489,283.58994 c -0.050882,-5.4e-4 -0.10279,0.003 -0.1523438,0.01 -0.00506,6.7e-4 -0.010589,-7.5e-4 -0.015625,0 -3.981e-4,2e-5 -0.00193,0 -0.00195,0 -1.645e-4,2e-5 -0.038952,0.0117 -0.039063,0.0117 -0.1113928,0.0158 -0.2154498,0.0387 -0.2929688,0.0937 -5.9e-6,6.7e-4 -5.9e-6,0.001 0,0.002 -0.07796,0.0555 -0.1426172,0.15431 -0.15625,0.29102 -9.37e-5,0.003 -9.37e-5,0.005 0,0.008 -0.00142,0.0437 0.00283,0.079 0.00781,0.10156 0.013901,0.0597 0.07263,0.0977 0.1328125,0.0859 0.057973,-0.0107 0.084766,-0.0289 0.1347656,-0.0586 0.059414,-0.0359 0.1122747,-0.0811 0.1679671,-0.12224 0.094598,-0.0883 0.3547641,-0.16032 0.5,-0.0625 0.1617225,0.0705 0.2910221,0.23377 0.2539063,0.43164 -7.463e-4,0.003 -0.0014,0.005 -0.00195,0.008 -0.024015,0.20653 -0.170998,0.35267 -0.328125,0.49023 -0.1602903,0.14032 -0.3218459,0.26181 -0.3925782,0.42969 -0.00426,0.0106 -0.00689,0.0218 -0.00781,0.0332 -0.016089,0.0442 -0.028521,0.0883 -0.035156,0.14649 -0.00805,0.0705 -0.010059,0.14581 0.00391,0.21679 0.0069,0.0351 0.017881,0.0649 0.029297,0.0879 0.011416,0.023 0.017907,0.0348 0.037109,0.0547 0.054282,0.0565 0.1481054,0.0426 0.1835937,-0.0273 0.027599,-0.0565 0.048071,-0.11921 0.070312,-0.21289 0.025238,-0.10627 0.07465,-0.23075 0.2148438,-0.34571 0.00165,-10e-4 0.00223,-0.003 0.00391,-0.004 6.5e-4,10e-6 0.0013,10e-6 0.00195,0 0.1508326,-0.11835 0.3089707,-0.25673 0.4238281,-0.41407 0.1142535,-0.1565 0.1871609,-0.33467 0.1621093,-0.5371 2.34e-5,-10e-4 2.34e-5,-0.003 0,-0.004 -1.9e-6,-1e-5 -0.00195,3e-5 -0.00195,0 4.3e-6,4e-5 3.81e-5,-0.002 0,-0.002 -1.897e-4,-8.3e-4 4.685e-4,-0.004 0,-0.006 l -0.00195,-0.0332 c -1.92e-4,-0.006 -8.44e-4,-0.0118 -0.00195,-0.0176 l -0.00586,-0.0293 c -3.716e-4,-0.005 -0.00102,-0.009 -0.00195,-0.0137 -0.046881,-0.22629 -0.2005557,-0.39409 -0.3984375,-0.4961 -0.1502384,-0.0775 -0.3237824,-0.11523 -0.4921875,-0.11719 z m 0.6757812,0.72266 c -9.37e-5,0.003 -9.37e-5,0.005 0,0.008 -0.00407,-0.14371 -0.00305,0.0432 0,-0.008 z"
          739  +           id="path1611"
          740  +           inkscape:connector-curvature="0"
          741  +           sodipodi:nodetypes="cccccccccccccccccccccscccccccccccccccccccccc" />
          742  +      </g>
          743  +    </g>
          744  +  </g>
          745  +</svg>

Modified static/style.scss from [de5cdf2da4] to [d08e77f56c].

   268    268   	}
   269    269   	> .xid {
   270    270   		color: tone(20%,-0.1);
   271    271   		font-size: 80%;
   272    272   		vertical-align: text-top;
   273    273   	}
   274    274   }
          275  +
          276  +body.profile {
          277  +	#rel {
          278  +		menu {
          279  +			display: grid;
          280  +			grid-template-columns: 1fr 1fr;
          281  +			grid-template-rows: repeat(max-content);
          282  +			grid-gap: 0.1in;
          283  +			> .opt {
          284  +				padding: 0.1in;
          285  +				border-radius: 5px;
          286  +				border: 1px solid transparent;
          287  +				&.on {
          288  +					background-color: tone(-30%, -0.7);
          289  +					box-shadow: 0 0 10px tone(-30%);
          290  +					border-color: tone(-20%);
          291  +				}
          292  +				> button, > p { display: block; }
          293  +				> p { text-align: center; font-size: 80%; margin: 0; margin-top: 0.1in; }
          294  +				> button {
          295  +					margin: auto;
          296  +				}
          297  +				&:last-child:nth-child(2n-1) {
          298  +					grid-column: 1/3;
          299  +				}
          300  +			}
          301  +
          302  +		}
          303  +	}
          304  +}
   275    305   
   276    306   div.profile {
   277    307   	padding: 0.1in;
   278    308   	position: relative;
   279    309   	display: grid;
   280    310   	margin-bottom: 0.4in;
   281    311   	grid-template-columns: 2fr 1fr;
................................................................................
   290    320   		> .avatar {
   291    321   			display: block;
   292    322   			width: 1in; height: 1in;
   293    323   			object-fit: cover;
   294    324   			grid-column: 1 / 2;
   295    325   			grid-row: 1 / 3;
   296    326   			border: 1px solid black;
          327  +			background-color: tone(-57%);
   297    328   		}
   298    329   		> .id {
   299    330   			grid-column: 2 / 3;
   300    331   			grid-row: 1 / 2;
   301    332   		}
   302    333   		> .bio {
   303    334   			grid-column: 2 / 3;
................................................................................
   411    442   		> .msg:first-child { padding-top: 0; }
   412    443   		> .user {
   413    444   			width: max-content; margin: auto;
   414    445   			background: tone(-20%,-0.3);
   415    446   			border: 1px solid black;
   416    447   			color: tone(-50%);
   417    448   			padding: 0.1in;
   418         -			> img { display: block; width: 1in; height: 1in; margin: auto; border: 1px solid black; }
          449  +			> img {
          450  +				display: block;
          451  +				width: 1in; height: 1in;
          452  +				margin: auto;
          453  +				border: 1px solid black;
          454  +				background-color: tone(-50%);
          455  +			}
   419    456   			> .name { @extend %serif; text-align: center; font-size: 130%; font-weight: bold; margin-top: 0.08in; }
   420    457   		}
   421    458   		>form {
   422    459   			display: grid;
   423    460   			grid-template-columns: 1fr 1fr;
   424    461   			grid-template-rows: 1.2em max-content max-content;
   425    462   			grid-gap: 5px;
................................................................................
   473    510   		background: url(/s/padlock.svg) no-repeat, $grad-ui-focus;
   474    511   		background-size: 20pt;
   475    512   		background-position: 0.05in 50%;
   476    513   	};
   477    514   	padding-left: 0.40in;
   478    515   }
   479    516   
   480         -div.modal {
          517  +.modal {
   481    518   	@extend %box;
   482    519   	position: fixed;
   483    520   	display: none;
   484    521   	left: 0; right: 0; bottom: 0; top: 0;
   485    522   	max-width: 7in;
   486    523   	margin: 1in auto;
   487    524   	padding: 0.2in 0.3in;

Added static/sub.svg version [ed11a76c38].

            1  +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
            2  +<!-- Created with Inkscape (http://www.inkscape.org/) -->
            3  +
            4  +<svg
            5  +   xmlns:dc="http://purl.org/dc/elements/1.1/"
            6  +   xmlns:cc="http://creativecommons.org/ns#"
            7  +   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
            8  +   xmlns:svg="http://www.w3.org/2000/svg"
            9  +   xmlns="http://www.w3.org/2000/svg"
           10  +   xmlns:xlink="http://www.w3.org/1999/xlink"
           11  +   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
           12  +   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
           13  +   width="20"
           14  +   height="20"
           15  +   viewBox="0 0 5.2916664 5.2916665"
           16  +   version="1.1"
           17  +   id="svg8"
           18  +   inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
           19  +   sodipodi:docname="sub.svg">
           20  +  <defs
           21  +     id="defs2">
           22  +    <linearGradient
           23  +       inkscape:collect="always"
           24  +       id="linearGradient1080">
           25  +      <stop
           26  +         style="stop-color:#c2ff3c;stop-opacity:0.81568629"
           27  +         offset="0"
           28  +         id="stop1076" />
           29  +      <stop
           30  +         style="stop-color:#b6ff0d;stop-opacity:0.02173913"
           31  +         offset="1"
           32  +         id="stop1078" />
           33  +    </linearGradient>
           34  +    <linearGradient
           35  +       id="linearGradient1070"
           36  +       inkscape:collect="always">
           37  +      <stop
           38  +         id="stop1066"
           39  +         offset="0"
           40  +         style="stop-color:#f6ffe2;stop-opacity:0.81568629" />
           41  +      <stop
           42  +         id="stop1068"
           43  +         offset="1"
           44  +         style="stop-color:#b6ff0d;stop-opacity:1" />
           45  +    </linearGradient>
           46  +    <linearGradient
           47  +       inkscape:collect="always"
           48  +       id="linearGradient1054">
           49  +      <stop
           50  +         style="stop-color:#ff73e0;stop-opacity:1"
           51  +         offset="0"
           52  +         id="stop1050" />
           53  +      <stop
           54  +         style="stop-color:#ff00cb;stop-opacity:0.98431373"
           55  +         offset="1"
           56  +         id="stop1052" />
           57  +    </linearGradient>
           58  +    <linearGradient
           59  +       id="linearGradient1034"
           60  +       inkscape:collect="always">
           61  +      <stop
           62  +         id="stop1030"
           63  +         offset="0"
           64  +         style="stop-color:#ff55dd;stop-opacity:0.50869566" />
           65  +      <stop
           66  +         id="stop1032"
           67  +         offset="1"
           68  +         style="stop-color:#ff55dd;stop-opacity:0.02173913" />
           69  +    </linearGradient>
           70  +    <linearGradient
           71  +       id="linearGradient1019"
           72  +       inkscape:collect="always">
           73  +      <stop
           74  +         id="stop1013"
           75  +         offset="0"
           76  +         style="stop-color:#680054;stop-opacity:0.01304348" />
           77  +      <stop
           78  +         style="stop-color:#ff40d9;stop-opacity:0.23913044"
           79  +         offset="0.30000001"
           80  +         id="stop1015" />
           81  +      <stop
           82  +         id="stop1017"
           83  +         offset="1"
           84  +         style="stop-color:#d400aa;stop-opacity:0;" />
           85  +    </linearGradient>
           86  +    <linearGradient
           87  +       id="linearGradient1005"
           88  +       inkscape:collect="always">
           89  +      <stop
           90  +         id="stop1001"
           91  +         offset="0"
           92  +         style="stop-color:#fff6fd;stop-opacity:1" />
           93  +      <stop
           94  +         id="stop1003"
           95  +         offset="1"
           96  +         style="stop-color:#ff3cd7;stop-opacity:0.98260868" />
           97  +    </linearGradient>
           98  +    <linearGradient
           99  +       inkscape:collect="always"
          100  +       id="linearGradient979">
          101  +      <stop
          102  +         style="stop-color:#680054;stop-opacity:1"
          103  +         offset="0"
          104  +         id="stop975" />
          105  +      <stop
          106  +         id="stop983"
          107  +         offset="0.30000001"
          108  +         style="stop-color:#d400aa;stop-opacity:0.77254902;" />
          109  +      <stop
          110  +         style="stop-color:#d400aa;stop-opacity:0;"
          111  +         offset="1"
          112  +         id="stop977" />
          113  +    </linearGradient>
          114  +    <linearGradient
          115  +       inkscape:collect="always"
          116  +       id="linearGradient971">
          117  +      <stop
          118  +         style="stop-color:#ff55dd;stop-opacity:1;"
          119  +         offset="0"
          120  +         id="stop967" />
          121  +      <stop
          122  +         style="stop-color:#ff55dd;stop-opacity:0.97826087"
          123  +         offset="1"
          124  +         id="stop969" />
          125  +    </linearGradient>
          126  +    <linearGradient
          127  +       inkscape:collect="always"
          128  +       id="linearGradient963">
          129  +      <stop
          130  +         style="stop-color:#c839ac;stop-opacity:0.00392157"
          131  +         offset="0"
          132  +         id="stop959" />
          133  +      <stop
          134  +         style="stop-color:#852572;stop-opacity:1"
          135  +         offset="1"
          136  +         id="stop961" />
          137  +    </linearGradient>
          138  +    <linearGradient
          139  +       inkscape:collect="always"
          140  +       id="linearGradient943">
          141  +      <stop
          142  +         style="stop-color:#f4d7ee;stop-opacity:1;"
          143  +         offset="0"
          144  +         id="stop939" />
          145  +      <stop
          146  +         style="stop-color:#f4d7ee;stop-opacity:0;"
          147  +         offset="1"
          148  +         id="stop941" />
          149  +    </linearGradient>
          150  +    <linearGradient
          151  +       inkscape:collect="always"
          152  +       id="linearGradient954">
          153  +      <stop
          154  +         style="stop-color:#ffffff;stop-opacity:1;"
          155  +         offset="0"
          156  +         id="stop950" />
          157  +      <stop
          158  +         style="stop-color:#ffffff;stop-opacity:0;"
          159  +         offset="1"
          160  +         id="stop952" />
          161  +    </linearGradient>
          162  +    <linearGradient
          163  +       inkscape:collect="always"
          164  +       id="linearGradient938">
          165  +      <stop
          166  +         style="stop-color:#d9fff6;stop-opacity:1;"
          167  +         offset="0"
          168  +         id="stop934" />
          169  +      <stop
          170  +         style="stop-color:#d9fff6;stop-opacity:0;"
          171  +         offset="1"
          172  +         id="stop936" />
          173  +    </linearGradient>
          174  +    <linearGradient
          175  +       inkscape:collect="always"
          176  +       id="linearGradient1403">
          177  +      <stop
          178  +         style="stop-color:#ccaaff;stop-opacity:1;"
          179  +         offset="0"
          180  +         id="stop1399" />
          181  +      <stop
          182  +         style="stop-color:#ccaaff;stop-opacity:0;"
          183  +         offset="1"
          184  +         id="stop1401" />
          185  +    </linearGradient>
          186  +    <linearGradient
          187  +       id="linearGradient1395"
          188  +       inkscape:collect="always">
          189  +      <stop
          190  +         id="stop1391"
          191  +         offset="0"
          192  +         style="stop-color:#ff1616;stop-opacity:1" />
          193  +      <stop
          194  +         id="stop1393"
          195  +         offset="1"
          196  +         style="stop-color:#ff1d1d;stop-opacity:0" />
          197  +    </linearGradient>
          198  +    <linearGradient
          199  +       inkscape:collect="always"
          200  +       id="linearGradient1383">
          201  +      <stop
          202  +         style="stop-color:#980000;stop-opacity:1;"
          203  +         offset="0"
          204  +         id="stop1379" />
          205  +      <stop
          206  +         style="stop-color:#980000;stop-opacity:0;"
          207  +         offset="1"
          208  +         id="stop1381" />
          209  +    </linearGradient>
          210  +    <linearGradient
          211  +       inkscape:collect="always"
          212  +       id="linearGradient832">
          213  +      <stop
          214  +         style="stop-color:#ffcfcf;stop-opacity:1;"
          215  +         offset="0"
          216  +         id="stop828" />
          217  +      <stop
          218  +         style="stop-color:#ffcfcf;stop-opacity:0;"
          219  +         offset="1"
          220  +         id="stop830" />
          221  +    </linearGradient>
          222  +    <radialGradient
          223  +       inkscape:collect="always"
          224  +       xlink:href="#linearGradient832"
          225  +       id="radialGradient834"
          226  +       cx="3.2286437"
          227  +       cy="286.62921"
          228  +       fx="3.2286437"
          229  +       fy="286.62921"
          230  +       r="1.0866126"
          231  +       gradientTransform="matrix(1.8608797,0.8147617,-0.38242057,0.87343168,106.71446,33.692223)"
          232  +       gradientUnits="userSpaceOnUse" />
          233  +    <radialGradient
          234  +       inkscape:collect="always"
          235  +       xlink:href="#linearGradient1383"
          236  +       id="radialGradient1385"
          237  +       cx="4.1787109"
          238  +       cy="286.89261"
          239  +       fx="4.1787109"
          240  +       fy="286.89261"
          241  +       r="1.2260786"
          242  +       gradientTransform="matrix(1.7016464,0,0,1.6348586,-2.9319775,-182.10895)"
          243  +       gradientUnits="userSpaceOnUse" />
          244  +    <radialGradient
          245  +       inkscape:collect="always"
          246  +       xlink:href="#linearGradient1395"
          247  +       id="radialGradient1389"
          248  +       gradientUnits="userSpaceOnUse"
          249  +       gradientTransform="matrix(0.66230313,-1.6430738,1.0154487,0.40931507,-290.06307,177.39489)"
          250  +       cx="4.02069"
          251  +       cy="287.79269"
          252  +       fx="4.02069"
          253  +       fy="287.79269"
          254  +       r="1.0866126" />
          255  +    <linearGradient
          256  +       inkscape:collect="always"
          257  +       xlink:href="#linearGradient1403"
          258  +       id="linearGradient1405"
          259  +       x1="8.3939333"
          260  +       y1="288.1091"
          261  +       x2="7.0158253"
          262  +       y2="287.32819"
          263  +       gradientUnits="userSpaceOnUse" />
          264  +    <linearGradient
          265  +       inkscape:collect="always"
          266  +       xlink:href="#linearGradient938"
          267  +       id="linearGradient940"
          268  +       x1="7.609839"
          269  +       y1="288.73215"
          270  +       x2="7.609839"
          271  +       y2="283.78305"
          272  +       gradientUnits="userSpaceOnUse" />
          273  +    <linearGradient
          274  +       inkscape:collect="always"
          275  +       xlink:href="#linearGradient954"
          276  +       id="linearGradient956"
          277  +       x1="3.0150654"
          278  +       y1="285.94464"
          279  +       x2="3.0150654"
          280  +       y2="282.40109"
          281  +       gradientUnits="userSpaceOnUse" />
          282  +    <linearGradient
          283  +       inkscape:collect="always"
          284  +       xlink:href="#linearGradient954"
          285  +       id="linearGradient1138"
          286  +       gradientUnits="userSpaceOnUse"
          287  +       x1="3.0150654"
          288  +       y1="285.94464"
          289  +       x2="3.0150654"
          290  +       y2="284.62277" />
          291  +    <radialGradient
          292  +       inkscape:collect="always"
          293  +       xlink:href="#linearGradient1005"
          294  +       id="radialGradient945"
          295  +       cx="6.1517248"
          296  +       cy="285.09021"
          297  +       fx="6.1517248"
          298  +       fy="285.09021"
          299  +       r="1.3844374"
          300  +       gradientTransform="matrix(2.4674713,0,0,2.4674669,-5.8821073,-417.49152)"
          301  +       gradientUnits="userSpaceOnUse" />
          302  +    <radialGradient
          303  +       inkscape:collect="always"
          304  +       xlink:href="#linearGradient943"
          305  +       id="radialGradient953"
          306  +       gradientUnits="userSpaceOnUse"
          307  +       gradientTransform="matrix(2.4674713,0,0,2.4674669,-9.027479,-418.36044)"
          308  +       cx="6.1517248"
          309  +       cy="285.09021"
          310  +       fx="6.1517248"
          311  +       fy="285.09021"
          312  +       r="1.3844374" />
          313  +    <radialGradient
          314  +       inkscape:collect="always"
          315  +       xlink:href="#linearGradient963"
          316  +       id="radialGradient965"
          317  +       cx="6.1523438"
          318  +       cy="285.08984"
          319  +       fx="6.1523438"
          320  +       fy="285.08984"
          321  +       r="1.6679688"
          322  +       gradientTransform="matrix(1,0,0,0.99999775,0,6.4095141e-4)"
          323  +       gradientUnits="userSpaceOnUse" />
          324  +    <radialGradient
          325  +       inkscape:collect="always"
          326  +       xlink:href="#linearGradient971"
          327  +       id="radialGradient973"
          328  +       cx="4.6300988"
          329  +       cy="285.0715"
          330  +       fx="4.6300988"
          331  +       fy="285.0715"
          332  +       r="0.88396439"
          333  +       gradientTransform="matrix(3.5121044,0,0,4.5073949,-11.771195,-1000.0836)"
          334  +       gradientUnits="userSpaceOnUse" />
          335  +    <linearGradient
          336  +       inkscape:collect="always"
          337  +       xlink:href="#linearGradient979"
          338  +       id="linearGradient981"
          339  +       x1="6.3269596"
          340  +       y1="286.08289"
          341  +       x2="6.3263793"
          342  +       y2="288.44873"
          343  +       gradientUnits="userSpaceOnUse" />
          344  +    <linearGradient
          345  +       inkscape:collect="always"
          346  +       xlink:href="#linearGradient1019"
          347  +       id="linearGradient1009"
          348  +       gradientUnits="userSpaceOnUse"
          349  +       x1="6.3269596"
          350  +       y1="286.08289"
          351  +       x2="6.3263793"
          352  +       y2="288.44873" />
          353  +    <radialGradient
          354  +       inkscape:collect="always"
          355  +       xlink:href="#linearGradient1034"
          356  +       id="radialGradient1028"
          357  +       cx="7.8964839"
          358  +       cy="10.825195"
          359  +       fx="7.8964839"
          360  +       fy="10.825195"
          361  +       r="6.1388507"
          362  +       gradientTransform="matrix(1.5553588,0,0,2.1211746,-4.385382,-12.136934)"
          363  +       gradientUnits="userSpaceOnUse" />
          364  +    <radialGradient
          365  +       inkscape:collect="always"
          366  +       xlink:href="#linearGradient1034"
          367  +       id="radialGradient1038"
          368  +       gradientUnits="userSpaceOnUse"
          369  +       gradientTransform="matrix(-1.5553588,0,0,-1.3840186,20.178349,25.807467)"
          370  +       cx="7.8964839"
          371  +       cy="10.825195"
          372  +       fx="7.8964839"
          373  +       fy="10.825195"
          374  +       r="6.1388507" />
          375  +    <radialGradient
          376  +       inkscape:collect="always"
          377  +       xlink:href="#linearGradient1054"
          378  +       id="radialGradient1048"
          379  +       gradientUnits="userSpaceOnUse"
          380  +       gradientTransform="matrix(2.4674713,0,0,2.4674669,-5.8821075,-417.49152)"
          381  +       cx="6.1517248"
          382  +       cy="285.09021"
          383  +       fx="6.1517248"
          384  +       fy="285.09021"
          385  +       r="1.3844374" />
          386  +    <radialGradient
          387  +       inkscape:collect="always"
          388  +       xlink:href="#linearGradient863"
          389  +       id="radialGradient865"
          390  +       cx="2.5399754"
          391  +       cy="295.73944"
          392  +       fx="2.5399754"
          393  +       fy="295.91135"
          394  +       r="1.6620824"
          395  +       gradientTransform="matrix(2.9231275,0,0,2.7982783,-2.1662153,-540.00013)"
          396  +       gradientUnits="userSpaceOnUse" />
          397  +    <linearGradient
          398  +       inkscape:collect="always"
          399  +       id="linearGradient863">
          400  +      <stop
          401  +         style="stop-color:#b5ff0b;stop-opacity:0.81739128"
          402  +         offset="0"
          403  +         id="stop859" />
          404  +      <stop
          405  +         style="stop-color:#f5ffde;stop-opacity:0.88695651"
          406  +         offset="1"
          407  +         id="stop861" />
          408  +    </linearGradient>
          409  +    <radialGradient
          410  +       inkscape:collect="always"
          411  +       xlink:href="#linearGradient863"
          412  +       id="radialGradient865-3"
          413  +       cx="2.5399754"
          414  +       cy="295.73944"
          415  +       fx="2.5399754"
          416  +       fy="295.91135"
          417  +       r="1.6620824"
          418  +       gradientTransform="matrix(11.048041,0,0,10.57617,-21.779867,-3114.7234)"
          419  +       gradientUnits="userSpaceOnUse" />
          420  +    <radialGradient
          421  +       inkscape:collect="always"
          422  +       xlink:href="#linearGradient863"
          423  +       id="radialGradient1051"
          424  +       gradientUnits="userSpaceOnUse"
          425  +       gradientTransform="matrix(0.43493944,0,0,0.41636282,4.1537212,164.42622)"
          426  +       cx="1.4165958"
          427  +       cy="296.81403"
          428  +       fx="1.4165958"
          429  +       fy="296.81403"
          430  +       r="1.6620824" />
          431  +    <radialGradient
          432  +       inkscape:collect="always"
          433  +       xlink:href="#linearGradient1070"
          434  +       id="radialGradient1063"
          435  +       gradientUnits="userSpaceOnUse"
          436  +       gradientTransform="matrix(1.9675506,-0.52720423,0.47654978,1.778508,-133.90186,-239.39035)"
          437  +       cx="1.7406042"
          438  +       cy="296.20987"
          439  +       fx="1.7406042"
          440  +       fy="296.20987"
          441  +       r="1.6620824" />
          442  +    <radialGradient
          443  +       inkscape:collect="always"
          444  +       xlink:href="#linearGradient1080"
          445  +       id="radialGradient1074"
          446  +       gradientUnits="userSpaceOnUse"
          447  +       gradientTransform="matrix(1.9675506,-0.52720423,0.47654978,1.778508,-133.90186,-239.39035)"
          448  +       cx="1.7406042"
          449  +       cy="296.20987"
          450  +       fx="1.7406042"
          451  +       fy="296.20987"
          452  +       r="1.6620824" />
          453  +  </defs>
          454  +  <sodipodi:namedview
          455  +     id="base"
          456  +     pagecolor="#181818"
          457  +     bordercolor="#666666"
          458  +     borderopacity="1.0"
          459  +     inkscape:pageopacity="0"
          460  +     inkscape:pageshadow="2"
          461  +     inkscape:zoom="1.979899"
          462  +     inkscape:cx="106.19422"
          463  +     inkscape:cy="36.397286"
          464  +     inkscape:document-units="mm"
          465  +     inkscape:current-layer="layer1"
          466  +     showgrid="false"
          467  +     units="px"
          468  +     inkscape:window-width="1920"
          469  +     inkscape:window-height="1042"
          470  +     inkscape:window-x="0"
          471  +     inkscape:window-y="38"
          472  +     inkscape:window-maximized="0"
          473  +     showguides="true"
          474  +     fit-margin-top="0"
          475  +     fit-margin-left="0"
          476  +     fit-margin-right="0"
          477  +     fit-margin-bottom="0" />
          478  +  <metadata
          479  +     id="metadata5">
          480  +    <rdf:RDF>
          481  +      <cc:Work
          482  +         rdf:about="">
          483  +        <dc:format>image/svg+xml</dc:format>
          484  +        <dc:type
          485  +           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
          486  +        <dc:title></dc:title>
          487  +      </cc:Work>
          488  +    </rdf:RDF>
          489  +  </metadata>
          490  +  <g
          491  +     inkscape:label="Layer 1"
          492  +     inkscape:groupmode="layer"
          493  +     id="layer1"
          494  +     transform="translate(-2.6134661,-283.36966)">
          495  +    <path
          496  +       sodipodi:type="inkscape:offset"
          497  +       inkscape:radius="0.54500842"
          498  +       inkscape:original="M 10.669922 284.26953 C 10.335835 284.27753 10.318359 284.625 10.318359 284.625 C 9.3265928 284.99453 9.4746094 286.52344 9.4746094 286.52344 C 9.0235918 286.69884 9.0078125 287.27539 9.0078125 287.27539 C 10.093208 287.51331 11.202093 287.50516 12.332031 287.27539 C 12.332031 287.27539 12.314303 286.69884 11.863281 286.52344 C 11.863281 286.52344 12.011298 284.99453 11.019531 284.625 C 11.019531 284.625 11.004009 284.27789 10.669922 284.26953 z M 10.34375 287.5957 C 10.34375 287.5957 10.304813 288.0715 10.669922 288.0918 C 11.035034 288.0715 10.994141 287.5957 10.994141 287.5957 C 10.828305 287.6047 10.667343 287.6136 10.34375 287.5957 z "
          499  +       style="opacity:1;vector-effect:none;fill:url(#radialGradient1074);fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
          500  +       id="path1055"
          501  +       d="m 10.65625,283.72461 c -0.355601,0.009 -0.661267,0.26644 -0.7695312,0.47266 -0.040068,0.0763 -0.024426,0.0846 -0.041016,0.14843 -0.4844992,0.3329 -0.7685327,0.82955 -0.8554687,1.25782 -0.069301,0.34139 -0.044874,0.46468 -0.039063,0.63867 -0.4655292,0.3998 -0.4882813,1.01758 -0.4882813,1.01758 a 0.54506292,0.54506292 0 0 0 0.4277344,0.54882 c 0.3131979,0.0687 0.632618,0.0707 0.9492188,0.10157 0.00732,0.04 -0.00509,0.0364 0.00781,0.0801 0.035449,0.11995 0.097474,0.26806 0.2324218,0.40235 0.134948,0.13429 0.350907,0.23248 0.560547,0.24414 a 0.54506292,0.54506292 0 0 0 0.05859,0 c 0.209666,-0.0117 0.425592,-0.11128 0.560547,-0.2461 0.134954,-0.13481 0.197395,-0.28219 0.232422,-0.40234 0.01276,-0.0438 6.38e-4,-0.04 0.0078,-0.0801 0.3138,-0.0311 0.626443,-0.0356 0.941406,-0.0996 a 0.54506292,0.54506292 0 0 0 0.435547,-0.55078 c 0,0 -0.02416,-0.61828 -0.490234,-1.01758 0.0057,-0.17429 0.03003,-0.29636 -0.03906,-0.63671 -0.08686,-0.42789 -0.369921,-0.92484 -0.853515,-1.25782 -0.01631,-0.0633 -0.0018,-0.0711 -0.04102,-0.14648 -0.107556,-0.20696 -0.414125,-0.46572 -0.769531,-0.47461 a 0.54506292,0.54506292 0 0 0 -0.02734,0 z"
          502  +       transform="translate(-5.4106269,-0.16547988)" />
          503  +    <path
          504  +       id="path836"
          505  +       style="fill:url(#radialGradient865);fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
          506  +       d="m 6.9205392,287.11054 c 0,0 -0.016703,-0.57629 -0.4677217,-0.75169 0,0 0.1485135,-1.53033 -0.8432532,-1.89986 0,0 -0.017021,-0.34687 -0.3511075,-0.35523 -0.3340865,0.008 -0.3511075,0.35523 -0.3511075,0.35523 -0.9917668,0.36953 -0.8432532,1.89986 -0.8432532,1.89986 -0.4510176,0.1754 -0.4677216,0.75169 -0.4677216,0.75169 1.0853958,0.23792 2.1942267,0.22977 3.3241647,0 z"
          507  +       inkscape:connector-curvature="0"
          508  +       sodipodi:nodetypes="cccccccc" />
          509  +    <path
          510  +       id="path841"
          511  +       style="opacity:1;vector-effect:none;fill:url(#radialGradient1051);fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
          512  +       d="m 5.5830229,287.43002 c 0,0 0.040568,0.47666 -0.3245413,0.49696 -0.3651092,-0.0203 -0.3245412,-0.49696 -0.3245412,-0.49696 0.3235932,0.0179 0.4832471,0.009 0.6490825,0 z"
          513  +       inkscape:connector-curvature="0"
          514  +       sodipodi:nodetypes="cccc" />
          515  +  </g>
          516  +</svg>

Modified store.t from [bb9260aa8d] to [131fc4292b].

     2      2   local m = {
     3      3   	timepoint = lib.osclock.time_t;
     4      4   	scope = lib.enum {
     5      5   		'public', 'private', 'local';
     6      6   		'personal', 'direct', 'circle';
     7      7   	};
     8      8   	noticetype = lib.enum {
     9         -		'none', 'mention', 'reply', 'like', 'rt', 'react', 'follow'
            9  +	 -- only add new values to the end of this list! the numerical value
           10  +	 -- is stored in the database and must be kept synchronized across versions
           11  +		'none', 'mention', 'reply', 'like', 'rt', 'react', 'follow', 'followreq'
    10     12   	};
    11     13   
    12     14   	relation = lib.set {
    13     15   		'follow',
    14         -		'subscribe', -- get a notification for every post
           16  +		'sub', -- get a notification for every post
    15     17   		'mute', -- posts will be completely hidden at all times
    16     18   		'block', -- no interactions will be permitted, but posts will remain visible
    17     19   		'silence', -- messages will not be accepted
    18     20   		'collapse', -- posts will be collapsed by default
    19     21   		'disemvowel', -- posts will be ritually humiliated, but shown
    20     22   		'avoid', -- posts will be kept out of the timeline but will show on users' posts and in conversations
    21     23   		'exclude', -- own posts will not be visible to this user
................................................................................
    98    100   	(pow.propagate << true)
    99    101   	(pow.artifact  << true)
   100    102   	(pow.account   << true)
   101    103   	(pow.edit      << true)
   102    104   	(pow.snitch    << true)
   103    105   	return m.rights { rank = 0, quota = 1000, invites = 0, powers = pow; }
   104    106   end
          107  +
          108  +struct m.relationship {
          109  +	agent: uint64
          110  +	patient: uint64
          111  +	rel: m.relation -- agent โ†’ patient
          112  +	recip: m.relation -- patient โ†’ agent
          113  +}
   105    114   
   106    115   struct m.actor {
   107    116   	id: uint64
   108    117   	nym: str
   109    118   	handle: str
   110    119   	origin: uint64
   111    120   	bio: str
................................................................................
   115    124   	knownsince: m.timepoint
   116    125   	rights: m.rights
   117    126   	key: lib.mem.ptr(uint8)
   118    127   
   119    128   -- ephemera
   120    129   	xid: str
   121    130   	source: &m.source
          131  +	relationship: m.relationship -- relationship to the logged-in user, if any
   122    132   }
   123    133   
   124    134   terra m.actor:outranks(other: &m.actor)
   125    135    -- this predicate determines where two users stand relative to
   126    136    -- each other in the formal staff hierarchy. it is used in
   127    137    -- authority calculations, but this function should only be
   128    138    -- used directly in rendering code and by other predicates.
................................................................................
   330    340   	aname: str
   331    341   	comment: str
   332    342   	netmask: m.inet
   333    343   	privs: m.privset
   334    344   	blacklist: bool
   335    345   }
   336    346   
   337         -struct m.relationship {
   338         -	agent: uint64
   339         -	patient: uint64
   340         -	rel: m.relation -- agent โ†’ patient
   341         -	recip: m.relation -- patient โ†’ agent
   342         -}
   343         -
   344    347   -- backends only handle content on the local server
   345    348   struct m.backend { id: rawstring
   346    349   	open: &m.source -> &opaque
   347    350   	close: &m.source -> {}
   348    351   	dbsetup: &m.source -> bool -- creates the schema needed to call conprep (called only once per database e.g. with `parsav db init`)
   349    352   	conprep: {&m.source, m.prepmode.t} -> {} -- prepares queries and similar tasks that require the schema to already be in place
   350    353   	obliterate_everything: &m.source -> bool -- wipes everything parsav-related out of the database

Modified view/media-gallery.tpl from [18862037ee] to [898f5a4a48].

     1      1   <menu>@menu
     2         -	<a href="@pfx/media">new uploads</a>
     3         -	<a href="@pfx/media/unfiled">unfiled</a>
            2  +	<a class="button" href="@pfx/media">new uploads</a>
            3  +	<a class="button" href="@pfx/media/unfiled">unfiled</a>
     4      4   	<hr>
     5      5   	@folders
     6         -	<a href="@pfx/media/all">all uploads</a>
     7         -	<a href="@pfx/media/kind/img">all images</a>
     8         -	<a href="@pfx/media/kind/vid">all videos</a>
     9         -	<a href="@pfx/media/kind/txt">all text files</a>
    10         -	<a href="@pfx/media/kind/misc">all others</a>
            6  +	<a class="button" href="@pfx/media/all">all uploads</a>
            7  +	<a class="button" href="@pfx/media/kind/img">all images</a>
            8  +	<a class="button" href="@pfx/media/kind/vid">all videos</a>
            9  +	<a class="button" href="@pfx/media/kind/txt">all text files</a>
           10  +	<a class="button" href="@pfx/media/kind/misc">all others</a>
    11     11   </menu>
    12     12   
    13     13   <div class="dir">
    14     14   	@directory
    15     15   </div>
    16     16   
    17     17   <div class="gallery">
    18     18   	@images
    19     19   </div>

Modified view/profile.tpl from [1a1f71cc57] to [b073906391].

    21     21   		<div>
    22     22   			<a class="button" href="/@:xid">posts</a>
    23     23   			<a class="button" href="/@:xid/arc">archive</a>
    24     24   			<a class="button" href="/@:xid/media">media</a>
    25     25   			<a class="button" href="/@:xid/social">associates</a>
    26     26   		</div>
    27     27   		<div>
           28  +			<a class="button" href="#rel">options</a>
    28     29   			@auxbtn
    29     30   		</div>
    30     31   	</form>
    31     32   </div>
           33  +
           34  +<form id="rel" class="modal" method="post">
           35  +<a href="#0" class="button">close</a><div>
           36  +	<menu>@relations</menu>
           37  +	<details>
           38  +		<summary>circles</summary>
           39  +		<button name="act" value="encircle">commit</button>
           40  +	</details>
           41  +	<details>
           42  +		<summary>sanctions</summary>
           43  +		<menu>
           44  +			@sanctions
           45  +			<div class="opt">
           46  +				<button class="neg" name="act" value="report">report</button>
           47  +				<p>if this user is violating instance rules, you can report this behavior to moderation staff and ask them to take action. please do not report users simply because you dislike them; this is what the above options are for.</p>
           48  +			</div>
           49  +		</menu>
           50  +	</details>
           51  +</div></form>