parsav  Check-in [1ba4bbc92f]

Overview
Comment:various cleanups, notices no longer originated from self
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 1ba4bbc92f8d9564ff4b2cb308d012d72c8cae34121c97725dd9b27fc6a78c11
User & Date: lexi on 2021-01-11 23:33:55
Other Links: manifest | tags
Context
2021-01-13
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
02:17
enable revoking credentials check-in: 41cbbca855 user: lexi tags: trunk
Changes

Modified backend/pgsql.t from [05f7cb1a74] to [c81652b018].

   831    831   local con = symbol(&lib.pq.PGconn)
   832    832   local function sqlsquash(s) return s
   833    833   	:gsub('%%include (.-)%%',function(f)
   834    834   		return sqlsquash(lib.util.ingest('backend/schema/' .. f))
   835    835   	end) -- include dependencies
   836    836   	:gsub('%-%-.-\n','') -- remove disruptive line comments
   837    837   	:gsub('%-%-.-$','') -- remove unnecessary terminal comments
   838         -	:gsub('<(%g-)>',function(r) return tostring(sqlvars[r]) end)
          838  +	:gsub('<(%g%g-)>',function(r) return tostring(sqlvars[r]) end)
   839    839   	:gsub('%s+',' ') -- remove whitespace
   840    840   	:gsub('^%s*(.-)%s*$','%1') -- chomp
   841    841   end
   842    842   
   843    843   -- to simplify queries and reduce development headaches in general, we
   844    844   -- offload as much logic as possible into views. to avoid versioning
   845    845   -- difficulties, these views are not part of the schema, but are rather

Modified backend/schema/pgsql-views.sql from [0fea8fa8b6] to [ac2cb76c4f].

   226    226   		from parsav_rels as r
   227    227   			left  join ntimes as nt on nt.uid = r.relatee
   228    228   		where
   229    229   			r.since >= coalesce(nt.when,0) and
   230    230   			r.kind = <rel:follow>
   231    231   	), allnotices as (table acts union table replies union table follows)
   232    232   
   233         -	table allnotices order by (notice).when desc
          233  +	select * from allnotices where rcpt <> (notice).who
          234  +	order by (notice).when desc
   234    235   );
   235    236   

Modified render/conf.t from [a292c2030a] to [fa9db8630d].

    50     50   local terra 
    51     51   render_conf([co], [path], notify: pstr)
    52     52   	var menu = co:stra(256)
    53     53   	menu:lpush('<hr>') 
    54     54   
    55     55   	-- build menu
    56     56   	do var p = co.who.rights.powers
    57         -		if p:affect_users() then menu:lpush '<a href="/conf/users">users</a>' end
    58         -		if p.censor() then menu:lpush '<a href="/conf/censor">badthink alerts</a>' end
           57  +		if p:affect_users() then menu:lpush '<a class="button" href="/conf/users">users</a>' end
           58  +		if p.censor() then menu:lpush '<a class="button" href="/conf/censor">badthink alerts</a>' end
    59     59   		if p.config() then menu:lpush([
    60         -			'<a href="/conf/srv">server &amp; policy</a>' ..
    61         -			'<a href="/conf/badge">badges</a>' ..
    62         -			'<a href="/conf/emoji">emoji packs</a>'
           60  +			'<a class="button" href="/conf/srv">server &amp; policy</a>' ..
           61  +			'<a class="button" href="/conf/badge">badges</a>' ..
           62  +			'<a class="button" href="/conf/emoji">emoji packs</a>'
    63     63   		]) end
    64         -		if p.rebrand() then menu:lpush '<a href="/conf/brand">instance branding</a>' end
           64  +		if p.rebrand() then menu:lpush '<a class="button" href="/conf/brand">instance branding</a>' end
    65     65   	end
    66     66   
    67     67   	-- select the appropriate panel
    68     68   	var [panel] = pstr { ptr = ''; ct = 0 }
    69     69   	if path.ct >= 2 then [invoker] end
    70     70   
    71     71   	-- avoid the hr if we didn't add any elements

Modified render/conf/users.t from [88e528c638] to [46d40d63a3].

    25     25   end)
    26     26   
    27     27   local rnd = lib.crypt.random
    28     28   local terra 
    29     29   suggest_handle(a: &lib.str.acc)
    30     30   	var start = a.sz
    31     31   	var puncts = array('.','_','-')
    32         -	var xXx = rnd(uint8, 0, 9) == 0
           32  +	var xXx = rnd(uint8, 0, 30) == 0
    33     33   	var leet = rnd(uint8, 0, 8) == 0
    34     34   	var caps = rnd(uint8, 0, 10)
    35     35   	var punct: rawstring = nil
    36     36   	var useadj = rnd(uint8, 0, 4) == 0
    37     37   	if rnd(uint8, 0, 4) == 0 then
    38     38   		punct = puncts[rnd(intptr,0,[puncts.type.N])]
    39     39   	end
................................................................................
    48     48   		killer murderer thief arson fire ice frost hack
    49     49   		hacker god master mistress slave rage freeze flayer
    50     50   		pirate ninja shadow fog mist misery glory bear
    51     51   		king queen empress emperor majesty space martian
    52     52   		winter fall monk katana 420 warrior banana demon
    53     53   		devil ghost wraith cuck legend hero heroine goblin
    54     54   		gremlin troll dragon evil overlord radiance slop
    55         -		operator rage hog bog roach wizard
           55  +		operator rage hog bog roach wizard steel madness
           56  +		reign
    56     57   	]]
    57     58   	var adjs = splitwords [[
    58     59   		dark super supreme ultra ultimate total infinite
    59     60   		omnipotent crazy final deathless immortal elite
    60     61   		leet 1337 bloody fearless headless screaming insane
    61         -		brutal legendary space frozen flaming burning
           62  +		brutal legendary space frozen flaming burning lazy
    62     63   		mighty flayed hidden secret lost mystery glorious
    63     64   		nude naked bare first radiant martian fallen bog
    64     65   		wandering dank demonic satanic invisible based woke
    65     66   		deadly lethal heroic evil majestic luminous ethereal
           67  +		perfect first fantastic special great steel insane
           68  +		royal imperial celestial cosmic mystic sublime
    66     69   	]]
    67     70   
    68     71   	if xXx then a:lpush('xXx_') end
    69     72   
    70     73   	if useadj then
    71     74   		var len = rnd(uint8,1,3) 
    72     75   		for i = 0, len do
................................................................................
   125    128   		wank fae weird woke slurp spine skull fail elf elves mom
   126    129   		dad dog cat kitten snake troll top bottom chungus dong wang
   127    130   		420 hog lover lovers best worst love hate big bigger tiny
   128    131   		little teeny spunky jazz wrack rump kink kinky crack meth
   129    132   		whore cam live over under turbo pizza rat rats crotch crank
   130    133   		chunky funky butt grab grabber grabbers thief steal slave
   131    134   		slaves hug hugs hag hags hogs wimp thieves wizard wizards
   132         -		pussy pansy dark doom stank spunk dumb rage
          135  +		pussy pansy dark doom stank spunk dumb rage worship orb
          136  +		terror fear blood slime slab warp waggle tit boob bird derp
          137  +		birb goat horde masto mastodon social global tweet post
          138  +		house home prison jail box pit hole haven town trump putin
          139  +		truth liberty zone land ranch butt butts sex pimp cop mail
          140  +		slut goblin goblins no good bad only gtfo electro electric
          141  +		dragon space mars earth venus neptune pluto saturn star
          142  +		moon lunar catastrophe catastro cuck honk war lap cuddle
          143  +		planet
   133    144   	]]
   134    145   	var tlds = splitwords [[
   135    146   		tld club town space xxx house land ranch horse com io online
   136    147   		shop site vip ltd win men lgbt cat adult army analytics art
   137    148   		associates bar bible biz black blog broker cam camp careers
   138    149   		catering church city coop dad date dating direct diy dog
   139    150   		duck dot enterprises esq estate expert express fail farm foo
   140    151   		forsale fun fund forum foundation gay global golf gop guru
   141    152   		group hangout hot industries international info investments
   142    153   		jobs land law life limited live lol mom network now party
   143    154   		porn productions pub rehab rocks school sex sexy singles
   144         -		social software solutions space spot store sucks supplies
   145         -		systems university vacations ventures wang website work
   146         -		wow wtf world xyz soy live gym park 
          155  +		social software solutions spot store sucks supplies cuck
          156  +		uwu systems university vacations ventures wang website work
          157  +		wow wtf world xyz soy live gym park worship orb zone mail
          158  +		war honk derp planet
   147    159   	]]
   148    160   	var sub = rnd(uint8,0,10) == 0
   149    161   	if sub then a:ppush(words[rnd(intptr,0,[words.type.N])]):lpush('.') end
   150    162   	a:ppush(words[rnd(intptr,0,[words.type.N])])
   151    163   	if rnd(uint8,0,3) == 0 or not sub then
   152    164   		a:ppush(words[rnd(intptr,0,[words.type.N])])
   153    165   	end

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

    16     16   		aux:pcompose(&co.srv.pool,'<a accesskey="a" class="button" href="/conf/profile?go=/@',actor.handle,'">alter</a>')
    17     17   	elseif co.aid ~= 0 then
    18     18   		if not relationship.rel.follow() then
    19     19   			aux:pcompose(&co.srv.pool,'<button accesskey="f" method="post" class="pos" name="act" value="follow">follow</button>')
    20     20   		elseif relationship.rel.follow() then
    21     21   			aux:pcompose(&co.srv.pool,'<button accesskey="f" method="post" class="neg" name="act" value="unfollow">unfollow</button>')
    22     22   		end
    23         -		aux:lpush('<a accesskey="h" class="button" href="/'):push(actor.xid,0):lpush('/chat">chat</a>')
           23  +		aux:lpush(' <a accesskey="h" class="button" href="/'):push(actor.xid,0):lpush('/chat">chat</a>')
    24     24   		if co.who.rights.powers:affect_users() and co.who:overpowers(actor) then
    25         -			aux:lpush('<a accesskey="n" class="button" href="/'):push(actor.xid,0):lpush('/ctl">control</a>')
           25  +			aux:lpush(' <a accesskey="n" class="button" href="/conf/users/'):shpush(actor.id):lpush('">control</a>')
    26     26   		end
    27     27   	else
    28         -		aux:pcompose(&co.srv.pool,'<a accesskey="f" class="button" href="/', actor.xid, '/follow">remote follow</a>')
           28  +		aux:pcompose(&co.srv.pool,' <a accesskey="f" class="button" href="/', actor.xid, '/follow">remote follow</a>')
    29     29   	end
    30     30   	var auxp = aux:finalize()
    31     31   	var timestr: int8[26] lib.osclock.ctime_r(&actor.knownsince, &timestr[0])
    32     32   
    33     33   	var strfbuf: int8[28*4]
    34     34   	var stats = co.srv:actor_stats(actor.id)
    35     35   		var sn_posts     = cs(lib.math.decstr_friendly(stats.posts, &strfbuf[ [strfbuf.type.N - 1] ]))
................................................................................
    73     73   		if co.who.rights.rank ~= 0 then
    74     74   			if co.who:outranks(actor) then
    75     75   				comments:lpush('<li style="--co:50">underling</li>')
    76     76   			elseif actor:outranks(co.who) then
    77     77   				comments:lpush('<li style="--co:-50">outranks you</li>')
    78     78   			end
    79     79   		end
           80  +	end
           81  +
           82  +	if relationship.rel.block() then
           83  +		comments:lpush('<li style="--co:80">blocked</li>')
           84  +	end
    80     85   
    81         -		if relationship.recip.follow() then
    82         -			comments:lpush('<li style="--co:30">follows you</li>')
    83         -		end
           86  +	if relationship.recip.follow() then
           87  +		comments:lpush('<li style="--co:30">follows you</li>')
    84     88   	end
    85     89   
    86     90   	var profile = data.view.profile {
    87     91   		nym = fullname;
    88     92   		bio = bio;
    89     93   		xid = cs(actor.xid);
    90     94   		avatar = cs(actor.avatar);

Modified static/style.scss from [048cf30682] to [de5cdf2da4].

    33     33   	text-underline-offset: 0.1em;
    34     34   	&:hover, &:focus {
    35     35   		color: white;
    36     36   		text-shadow: 0 0 15px tone(20%);
    37     37   		text-decoration-color: tone(10%,-0.1);
    38     38   		outline: none;
    39     39   	}
    40         -	&.button { @extend %button; }
    41     40   }
    42     41   a[href^="//"],
    43     42   a[href^="http://"],
    44     43   a[href^="https://"] { // external link
    45     44   	&:hover::after {
    46     45   		color: black;
    47     46   		background-color: white;
................................................................................
    65     64   	margin: auto;
    66     65   }
    67     66   
    68     67   %glow {
    69     68   	box-shadow: 0 0 20px tone(0%,-0.8);
    70     69   }
    71     70   
    72         -%button {
           71  +.button, a[href].button { // 🙄
    73     72   	@extend %sans;
    74     73   	font-size: 14pt;
    75     74   	box-sizing: border-box;
    76     75   	padding: 0.1in 0.2in;
    77     76   	border: 1px solid black;
    78     77   	color: otone(25%);
    79     78   	text-shadow: 1px 1px black;
................................................................................
   111    110   			otone(-30%) 15%,
   112    111   			otone(-30%) 75%,
   113    112   			otone(-35%)
   114    113   		);
   115    114   	}
   116    115   }
   117    116   
   118         -button { @extend %button;
          117  +button { @extend .button;
   119    118   	&:first-of-type {
   120         -		@extend %button;
          119  +		@extend .button;
   121    120   		color: white;
   122    121   		box-shadow: inset 0 1px  otone(-25%),
   123    122   		            inset 0 -1px otone(-50%);
   124    123   		background: linear-gradient(to bottom,
   125    124   			otone(-35%),
   126    125   			otone(-40%) 15%,
   127    126   			otone(-40%) 75%,
................................................................................
   307    306   	}
   308    307   	> .stats {
   309    308   		grid-column: 3 / 4;
   310    309   		grid-row: 1 / 3;
   311    310   		display: flex;
   312    311   		flex-flow: column;
   313    312   		> * { flex-grow: 1; }
   314         -		table { td, th { text-align: center; } }
          313  +		table {
          314  +			width: 100%;
          315  +			td, th { text-align: center; }
          316  +		}
   315    317   	}
   316    318   	> form.actions {
   317    319   		grid-column: 1 / 3; grid-row: 2 / 3;
   318    320   		padding-top: 0.075in;
   319         -		flex-wrap: wrap;
   320    321   		display: flex;
          322  +		flex-flow: column;
   321    323   		justify-content: center;
   322    324   		align-items: center;
   323         -		> a[href] {
   324         -			display: block;
   325         -			margin: 0.025in 0.05in;
   326         -		}
   327         -		> hr {
   328         -			all: unset;
   329         -			display: block;
   330         -			height: 0.3in;
   331         -			width: 1px;
   332         -			border-left: 1px solid rgba(0,0,0,0.6);
          325  +		> div {
          326  +			display: flex;
          327  +			flex-wrap: wrap;
          328  +			flex-flow: row;
          329  +			justify-content: center;
          330  +			align-items: center;
          331  +			margin-bottom: 0.07in;
          332  +			> a[href] {
          333  +				display: block;
          334  +				margin: 0.025in 0.05in;
          335  +			}
   333    336   		}
   334    337   	}
   335    338   }
   336    339   
   337    340   .epithet {
   338    341   	display: inline-block;
   339    342   	background: tone(20%);
................................................................................
   386    389   body.login {
   387    390   	form.auth-select {
   388    391   		@extend %box;
   389    392   		width: 3in;
   390    393   		padding: 0.4in;
   391    394   		p { text-align: center; }
   392    395   		menu {
   393         -			%button {
          396  +			.button {
   394    397   				display: block;
   395    398   				width: 100%;
   396         -				& + %button { border-top: none; }
          399  +				& + button, & + a[href] { border-top: none; }
   397    400   			}
   398    401   		}
   399    402   	}
   400    403   	div.login {
   401    404   		@extend %box;
   402    405   		width: 4in;
   403    406   		padding: 0.4in;
................................................................................
   420    423   			grid-template-columns: 1fr 1fr;
   421    424   			grid-template-rows: 1.2em max-content max-content;
   422    425   			grid-gap: 5px;
   423    426   			> label, input, button { display: block; }
   424    427   			> label { grid-column: 1 / 3; grid-row: 1/2; font-weight: bold }
   425    428   			> input, textarea  { grid-column: 1 / 3; grid-row: 2/3; }
   426    429   			> button { grid-column: 2 / 3; grid-row: 3/4; }
   427         -			> a { @extend %button; grid-column: 1 / 2; grid-row: 3/4; }
          430  +			> a { grid-column: 1 / 2; grid-row: 3/4; }
          431  +			> textarea { @extend %teletype; font-size: 80% !important; height: 1.5in; }
   428    432   		}
   429    433   	}
   430    434   }
   431    435   
   432    436   form.compose {
   433    437   	@extend %box;
   434    438   	display: grid;
................................................................................
   453    457   	text-align: center;
   454    458   	padding: 0.09in 0.2in;
   455    459   	background: tone(-40%);
   456    460   	border: 1px solid black;
   457    461   	font-weight: bold;
   458    462   	text-decoration: none;
   459    463   	cursor: help;
          464  +	max-width: 0.1in;
   460    465   }
   461    466   
   462    467   input.acl {
   463    468   	@extend %teletype;
   464    469   	background: url(/s/padlock.svg) no-repeat;
   465    470   	background-size: 20pt;
   466    471   	background-position: 0.05in 50%;
................................................................................
   485    490   	z-index: 2;
   486    491   	> div {
   487    492   		height: 100%;
   488    493   		overflow-y: scroll;
   489    494   		>p:first-of-type { margin-top: 0; }
   490    495   	}
   491    496   	>a[href="#0"] { // close link
   492         -		@extend %button;
   493    497   		cursor: default;
   494    498   		display: block;
   495    499   		position: absolute;
   496    500   		top: -0.3in;
   497    501   		right: 0.1in;
   498    502   		margin: 0.1in;
   499    503   		padding: 0.1in;
................................................................................
   647    651   %navmenu, body.profile main > menu {
   648    652   	margin-left: -0.25in;
   649    653   	grid-column: 1/2; grid-row: 1/2;
   650    654   	background: linear-gradient(to bottom, tone(-45%),tone(-55%));
   651    655   	border: 1px solid black;
   652    656   	padding: 0.1in;
   653    657   	> a[href] {
   654         -		@extend %button;
   655    658   		display: block;
   656    659   		text-align: left;
   657    660   	}
   658    661   	> a[href] + a[href] {
   659    662   		border-top: none;
   660    663   	}
   661    664   	hr {
................................................................................
   728    731   		}
   729    732   		> input, textarea, .txtbox {
   730    733   			display: block;
   731    734   			width: 100%;
   732    735   		}
   733    736   		> textarea { resize: vertical; min-height: 2in; }
   734    737   	}
   735         -	body.conf & > %button { margin-left: 50%; width: 50%; }
          738  +	body.conf & { > .button { margin-left: 50%; width: 50%; } }
   736    739   	.elem-group {
   737    740   		display: flex;
   738    741   		flex-flow: row;
   739    742   		> .elem {
   740    743   			flex-shrink: 1;
   741    744   			flex-grow: 1;
   742    745   			margin-left: 0.1in;
................................................................................
   758    761   	}
   759    762   	&.vertical-float {
   760    763   		flex-flow: column;
   761    764   		float: right;
   762    765   		width: 40%;
   763    766   		margin-left: 0.1in;
   764    767   	}
   765         -	> %button {
          768  +	> .button, a[href] {
   766    769   		flex-basis: min-content;
   767    770   		flex-grow: 1;
   768    771   		display: block; margin: 2px;
   769    772   	}
   770    773   }
   771    774   
   772    775   .check-panel {
................................................................................
   881    884   		text-align: center;
   882    885   		padding: 0.3em 0;
   883    886   		margin: 0.2em 0.1em;
   884    887   		cursor: default;
   885    888   	}
   886    889   }
   887    890   
   888         -:is(%button, a[href]).neg { --co:  30 }
   889         -:is(%button, a[href]).pos { --co: -30 }
          891  +.button, a[href] {
          892  +	.neg { --co:  30 }
          893  +	.pos { --co: -30 }
          894  +}
   890    895   
   891    896   .pick-list {
   892    897   	display: flex;
   893    898   	flex-flow: row wrap;
   894    899   	padding: 0.1in;
   895    900   	background-color: tone(-50%);
   896    901   	border: 1px solid tone(-53%);

Modified tpl.t from [db48a650e7] to [586a17ee3f].

    50     50   	for i, s in ipairs(segs) do
    51     51   		segs[i] = string.gsub(s, '\\'..tplchar, tplchar_o)
    52     52   		constlen = constlen + string.len(segs[i])
    53     53   	end
    54     54   
    55     55   	for n,d in pairs(docs) do
    56     56   		local html = string.format(
    57         -			'<div id="help-%s" class="modal"> <a href="#0">close</a> <div>%s</div></div>', n, d.text
           57  +			'<div id="help-%s" class="modal"> <a class="button" href="#0">close</a> <div>%s</div></div>', n, d.text
    58     58   		)
    59     59   		segs[#segs] = segs[#segs] .. html
    60     60   		constlen = constlen + #html
    61     61   	end
    62     62   	
    63     63   
    64     64   	local runningtally = symbol(intptr)

Modified view/conf-sec-credmg.tpl from [a2babc26c2] to [4bef3514c2].

     1      1   <hr>
     2      2   <form method="post">
     3      3   	<p>this account can currently be accessed with the credentials listed below. if you fear a credential has been compromised, you can revoke or reset it.</p>
     4         -	<select size="6" name="cred">
            4  +	<select size="6" name="cred" required>
     5      5   		@credlist
     6      6   	</select>
     7      7   	<menu class="horizontal choice">
     8      8   		<button name="act" value="reset">reset</button>
     9      9   		<button name="act" value="revoke">revoke</button>
    10     10   		@?auth
    11     11   	</menu>

Modified view/conf.tpl from [6af7c57c63] to [f4ba0e2cfa].

     1      1   <menu>
     2         -	<a href="/conf/profile">profile</a>
     3         -	<a href="/conf/avi">avatar</a>
     4         -	<a href="/conf/ui">interface</a>
     5         -	<a href="/conf/sec">security</a>
     6         -	<a href="/conf/rel">relationships</a>
     7         -	<a href="/conf/qnt">quarantine</a>
     8         -	<a href="/conf/acl">ACL shortcuts</a>
     9         -	<a href="/conf/rooms">chatrooms</a>
    10         -	<a href="/conf/circles">circles</a>
            2  +	<a class="button" href="/conf/profile">profile</a>
            3  +	<a class="button" href="/conf/avi">avatar</a>
            4  +	<a class="button" href="/conf/ui">interface</a>
            5  +	<a class="button" href="/conf/sec">security</a>
            6  +	<a class="button" href="/conf/rel">relationships</a>
            7  +	<a class="button" href="/conf/qnt">quarantine</a>
            8  +	<a class="button" href="/conf/acl">ACL shortcuts</a>
            9  +	<a class="button" href="/conf/rooms">chatrooms</a>
           10  +	<a class="button" href="/conf/circles">circles</a>
    11     11   	@menu
    12     12   </menu>
    13     13   
    14     14   <div class="panel">
    15     15   	@panel
    16     16   </div>

Modified view/login-challenge.tpl from [cc4592543f] to [be2d94bab1].

     5      5   	</div>
     6      6   	<div class="msg">@challenge</div>
     7      7   	<form action="/login" method="post">
     8      8   		<label for="response">@label</label>
     9      9   		<input type="hidden" name="user" value="@:handle">
    10     10   		@inputfield
    11     11   		<button type="submit" name="authmethod" value="@method">authenticate</button>
    12         -		<a href="/login">cancel</a>
           12  +		<a class="button" href="/login">cancel</a>
    13     13   	</form>
    14     14   </div>

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

     4      4   		<div class="id">@nym</div>
     5      5   		<div class="bio">
     6      6   			@bio
     7      7   		</div>
     8      8   	</div>
     9      9   	<div class="stats">
    10     10   		<table>
    11         -			<tr><th>posts</th> <th>mutuals</th></tr>
    12         -			<tr><td>@nposts</td> <td>@nmutuals</td></tr>
    13         -			<tr><th>following</th> <th>followers</th></tr>
    14         -			<tr><td>@nfollows</td> <td>@nfollowers</td></tr>
           11  +			<tr><th>posts</th>       <th>mutuals</th></tr>
           12  +			<tr><td>@nposts</td>     <td>@nmutuals</td></tr>
           13  +			<tr><th>following</th>   <th>followers</th></tr>
           14  +			<tr><td>@nfollows</td>   <td>@nfollowers</td></tr>
           15  +		</table> <table>
    15     16   			<tr><th>@timephrase</th> <td>@tweetday</td></tr>
    16     17   		</table>
    17     18   		<ul class="remarks">@remarks</ul>
    18     19   	</div>
    19     20   	<form class="actions" method="post">
    20         -		<a class="button" href="/@:xid">posts</a>
    21         -		<a class="button" href="/@:xid/arc">archive</a>
    22         -		<a class="button" href="/@:xid/media">media</a>
    23         -		<a class="button" href="/@:xid/social">associates</a>
    24         -		<hr>
    25         -		@auxbtn
           21  +		<div>
           22  +			<a class="button" href="/@:xid">posts</a>
           23  +			<a class="button" href="/@:xid/arc">archive</a>
           24  +			<a class="button" href="/@:xid/media">media</a>
           25  +			<a class="button" href="/@:xid/social">associates</a>
           26  +		</div>
           27  +		<div>
           28  +			@auxbtn
           29  +		</div>
    26     30   	</form>
    27     31   </div>