Merge pull request #8 from datagrok/master

add tdp-format stats script
master
Nathaniel Smith 2015-11-16 19:03:45 -08:00
commit 50233fc07b
5 changed files with 551 additions and 84 deletions

View File

@ -1,2 +0,0 @@
#!/bin/bash
who | cut -d' ' -f1 | sort -u | wc -l | xargs echo "active_user_count=" | sed 's/ //'

View File

@ -1,13 +1,18 @@
#!/bin/bash
# Feed JSON/tdp output from "stats" into mustache template to generate
# tilde.town homepage. Invoke periodically from crontab.
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
source /var/local/venvs/tildetown/bin/activate
stats=/usr/bin/stats
template=/var/www/tilde.town/template.index.html
mustache=/var/local/tildetown/scripts/mustache.hy
template=/usr/local/tildetown-scripts/tildetown/templates/frontpage.html
mustache=/usr/local/tildetown-scripts/tildetown/mustache.py
input_path=/var/www/tilde.town/tilde.json
output_path=/var/www/tilde.town/index.html
($stats || echo '{}') | hy $mustache $template > $output_path
deactivate
if [ ! -f "$input_path" ]; then
print "homepage generation needs missing $input_path"
exit 1
fi
exec /usr/local/virtualenvs/tildetown/bin/python "$mustache" "$template" < "$input_path" > "$output_path"

View File

@ -1,8 +1,6 @@
#!/bin/bash
cd /var/local
source venvs/tildetown/bin/activate
output=$(python tildetown/tildetown-py/stats.py)
deactivate
echo $output
#!/bin/sh
# run stats.py in the appropriate virtualenv.
#
# invoke periodically from crontab and direct the output to
# /var/www/tilde.town/tilde.json
exec /usr/local/virtualenvs/tildetown/bin/python /usr/local/tildetown-scripts/tildetown/stats.py

219
tildetown/stats.py 100644 → 100755
View File

@ -1,84 +1,169 @@
#!/usr/local/bin/python3
# stats.py - tilde data in tilde data protocol format.
# Copyright 2015 Michael F. Lamb <http://datagrok.org>
# License: GPLv3+
"""
Outputs JSON data conforming to "~dp (Tilde Description Protocol)" as defined
at: http://protocol.club/~datagrok/beta-wiki/tdp.html
It is a JSON structure of the form:
{
'name': (string) the name of the server.
'url': (string) the URL of the server.
'signup_url': (string) the URL of a page describing the process required to request an account on the server.
'want_users': (boolean) whether the server is currently accepting new user requests.
'admin_email': (string) the email address of the primary server administrator.
'description': (string) a free-form description for the server.
'users': [ (array) an array of users on the server, sorted by last activity time
{
'username': (string) the username of the user.
'title': (string) the HTML title of the users index.html page.
'mtime': (number) a timestamp representing the last time the users index.html was modified.
},
...
]
'user_count': (number) the number of users currently registered on the server.
}
We also overload this with some data we were using in the previous version of
stats.py, which is of the form:
{
'users': [ (array) of users on the server.
{
'default': (boolean) Is the user still using their unmodified default index.html?
'favicon': (string) a url to an image representing the user
},
...
]
'live_user_count': (number) count of live users (those who have changed their index.html)
'active_user_count': (number) count of currently logged in users
'generated_at': (string) the time this JSON was generated in '%Y-%m-%d %H:%M:%S' format.
'generated_at_msec': (number) the time this JSON was generated, in milliseconds since the epoch.
'uptime': (string) output of `uptime -p`
}
Usage: stats.py > /var/www/html/tilde.json
"""
import datetime
import json
from functools import partial
from os import listdir
from os.path import getmtime, join
from datetime import datetime
from sh import find, uptime, who, sort, wc, cut
from tildetown.util import slurp, thread, p
import os
import pwd
import re
import subprocess
# this script emits json on standard out that has information about tilde.town
# users. It denotes who has not updated their page from the default. It also
# reports the time this script was run. The user list is sorted by public_html update time.
SYSTEM_USERS = ['wiki', 'root', 'ubuntu', 'nate', 'nobody']
DEFAULT_HTML_FILENAME = "/etc/skel/public_html/index.html"
title_re = re.compile(r'<title[^>]*>(.*)</title>', re.DOTALL)
SYSTEM_USERS = ['wiki', 'root', 'ubuntu', 'nate']
def active_user_count():
"""Return the count of unique usernames logged in."""
return len(set(line.split()[0] for line in
subprocess.check_output(
["who"], universal_newlines=True).splitlines()))
DEFAULT_HTML = slurp("/etc/skel/public_html/index.html")
def get_title(indexhtml):
"""Given an html file, return the content of its <title>"""
with open(indexhtml, 'rt', errors='ignore') as fp:
title = title_re.search(fp.read())
if title:
return title.group(1)
username_to_html_path = lambda u: "/home/{}/public_html".format(u)
def get_users():
"""Generate tuples of the form (username, homedir) for all normal
users on this system.
def default_p(username):
return DEFAULT_HTML == slurp(join(username_to_html_path(username), "index.html"))
"""
return ((p.pw_name, p.pw_dir) for p in pwd.getpwall() if
p.pw_uid >= 1000 and
p.pw_shell != '/bin/false' and
p.pw_name not in SYSTEM_USERS)
def bounded_find(path):
# find might return 1 but still have worked fine.
return find(path, "-maxdepth", "3", _ok_code=[0,1])
def most_recent_within(path):
"""Return the most recent timestamp among all files within path, 3
levels deep.
"""
return max(modified_times(path, maxdepth=3))
def get_active_user_count():
return int(wc(sort(cut(who(), "-d", " ", "-f1"), "-u"), "-l"))
def modified_times(path, maxdepth=None):
"""Walk the directories in path, generating timestamps for all
files.
"""
for root, dirs, files in os.walk(path):
if maxdepth and len(root[len(path):].split(os.sep)) == maxdepth:
dirs.clear()
for f in files:
try:
yield os.path.getmtime(os.path.join(root, f))
except (FileNotFoundError, PermissionError):
pass
def guarded_mtime(path):
try:
return getmtime(path.rstrip())
except Exception as _:
return 0
def tdp_user(username, homedir):
"""Given a unix username, and their home directory, return a TDP format
dict with information about that user.
def modify_time(username):
files_to_mtimes = partial(map, guarded_mtime)
return thread(username,
username_to_html_path,
bounded_find,
files_to_mtimes,
list,
max)
"""
public_html = os.path.join(homedir, 'public_html')
index_html = os.path.join(public_html, 'index.html')
if os.path.exists(index_html):
return {
'username': username,
'title': get_title(index_html),
'mtime': int(most_recent_within(public_html) * 1000),
# tilde.town extensions and backward compatibility
'favicon': 'TODO',
'default': subprocess.call(
['diff', '-q', DEFAULT_HTML_FILENAME, index_html],
stdout=subprocess.DEVNULL) == 0,
}
else:
return {
'username': username,
'default': False
}
def sort_user_list(usernames):
return sorted(usernames, key=modify_time)
def tdp():
now = datetime.datetime.now()
users = sorted(
(tdp_user(u, h) for u, h in get_users()),
key=lambda x:x['mtime'],
reverse=True)
def user_generator():
ignore_system_users = lambda un: un not in SYSTEM_USERS
return filter(ignore_system_users, listdir("/home"))
# TDP format data
data = {
'name': 'tilde.town',
'url': 'http://tilde.town',
'signup_url': 'http://goo.gl/forms/8IvQFTDjlo',
'want_users': True,
'admin_email': 'nks@lambdaphil.es',
'description': " ".join(l.strip() for l in """
an intentional digital community for creating and sharing works of
art, educating peers, and technological anachronism. we are a
completely non-commercial, donation supported, and committed to
rejecting false technological progress in favor of empathy and
sustainable computing.
""".splitlines()),
'user_count': len(users),
'users': users,
}
def get_user_data():
username_to_data = lambda u: {'username': u,
'default': default_p(u),
'favicon':'TODO'}
live_p = lambda user: not user['default']
# tilde.town extensions and backward compatibility
data.update({
'active_user_count': active_user_count(),
'generated_at': now.strftime('%Y-%m-%d %H:%M:%S'),
'generated_at_msec': int(now.timestamp() * 1000),
'uptime': subprocess.check_output(['uptime', '-p'], universal_newlines=True),
'live_user_count': sum(1 for x in data['users'] if not x['default']),
})
all_users = thread(user_generator(),
sort_user_list,
reversed,
partial(map, username_to_data),
list)
live_users = list(filter(live_p, all_users))
active_user_count = get_active_user_count()
return {'all_users': all_users,
'num_users': len(all_users),
'num_live_users': len(live_users),
'active_user_count': active_user_count,
'live_users': live_users,}
def get_data():
user_data = get_user_data()
data = {'generated_at': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
'site_name': 'tilde.town',
'site_url': 'http://tilde.town',
'uptime': str(uptime('-p')).rstrip(),}
data.update(user_data)
return data
def main():
print(json.dumps(tdp(), sort_keys=True, indent=2))
if __name__ == '__main__':
print(json.dumps(get_data()))
raise SystemExit(main())

View File

@ -0,0 +1,381 @@
<html>
<head>
<title>welcome to tilde town!</title>
<meta charset="utf-8">
<link rel="stylesheet" href="style.css" />
<link rel="icon" href="/favicon.ico" />
</head>
<body>
<h1 style="text-align:center">tilde.town</h1>
<h3 style="text-align:center"><em>is a small unix server made for sharing</em></h3>
<p style="text-align:center">
<a href="/~wiki/faq.html">faq</a>
| <a href="/guestbook">sign our guestbook</a>
| <a href="http://goo.gl/forms/8IvQFTDjlo">signup</a>
| <a href="/~wiki/conduct.html">code of conduct</a>
| <a href="/helpdesk">file help ticket</a>
| <a href="https://www.patreon.com/nathanielksmith">donate</a>
| <a href="/~wiki">wiki</a>
</p>
<marquee behavior="alternate"><strong>~*~*~* {{active_user_count}} townies active right now *~*~*~</strong></marquee>
<table width="100%">
<tr>
<td valign="top" width="20%">
<h3>our esteemed users </h3>
<sub>({{live_user_count}} / {{user_count}} shown)</sub><br>
<sub>generated at {{generated_at}}</sub><br>
<sub>sorted by recent changes</sub><br>
<ul>
{{#users}}
{{^default}}
<li>
<a href="/~{{username}}">{{username}}</a>
</li>
{{/default}}
{{/users}}
</ul>
<a href="/users.html">full user list</a>
</td>
<td valign="top" width="40%">
<p>this site is an intentional digital community for creating and
sharing works of art, educating peers, and technological
anachronism. we are a completely
non-commercial, <a href="https://www.patreon.com/nathanielksmith?ty=h">donation supported</a>, and
committed to rejecting false technological progress in favor of
empathy and sustainable computing.</p>
<h3>stuff you can do here</h3>
<ul>
<li>geocities style hosting</li>
<li>internal irc network</li>
<li>private usenet constellation</li>
<li>internal mail</li>
<li>command line / unix tutelage</li>
<li>make ascii art</li>
<li>host twitter bots</li>
<li>participate in our <a href="https://twitter.com/tildetown">communal twitter</a></li>
<li>generate random poetry <em>(under construction)</em></li>
</ul>
<a style="text-decoration:none" href="/cgi/random">
<pre title="go to a random page">
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
| ! /\ | X |
| ! //\\ | / \ |
| @@@ ! |~~~~~~~~~~~~~| ///\\\ |/ \|
| @@@@@ /i\|=============| ////\\\\ |\ /|
| @@@ /(i)\====== == ===| /////\\\\\| \ / |
| /((i))\============| //////\\\\\\ X |
| |% % %|=== ===== ==| I||||||||||I / \ |
| |% % %|====== =====| I||||||||||I/ \|
|::: |% # %|============| I||||||||||I\ /|
|::: |% % %|= ====== ===| I||||||||||I \ / |
|::: |% % #|==== ==+++++++++++++|||||||I X |
|:::HHHHHHHHHHHH |% % %|=======! ! ! ! ! ! !|||||||I / \ |
|:::HHHHHH HHHHH |% # %|= =====! ! ! ! ! ! !|||||||I/ \|
|:::HHHHHHHHHHHH |# % %|=== ===! ! ! ! ! ! !|||||||I\ /|
|:::HHH HHHHHHHH |% % %|=======! ! ! ! ! ! !|||||||I \ / |
|:::HHHHHHTTTTTTTTTTTTTTT % #|== = ==! ! ! ! ! ! !|||||||I X |
|:::HHHHHHI [] [] [] [] I # #|=======! ! ! ! ! ! !|||||||I / \ |
|::: HHHHHI [] [] [] [] I % %|==== =! ! ! ! ! ! !|||||||I/ \|
|:::HHHH HI [] [] [] [] I # %|== ====! ! ! ! ! ! !|||||||I\ /|
|:::HHHHHHI [] [] [] [] I % %|=======! ! ! ! ! ! !|||||||I \ / |
|:::HHHHHHI [] [] [] [] I % #|=== = =! ! ! ! ! ! !|||||||I X |
|:::HH HHHI [] [] [] [] I % #| ======! ! ! ! ! ! !|||||||I / \ |
|:::HHHHHHI [] [] [] [] I # #|= = ===! ! ! ! ! ! !|||||||I/ \|
|:::HHHHH I [] [] [] [] I % %|==== ==! ! ! ! ! ! !|||||||I\ /|
|:::HHHHHHI [] [] [] [] I % #|=======! ! ! ! ! ! !|||||||I \ / |
|:::HHHHHHI [] [] [] [] I # #|= =====! ! ! ! ! ! !|||||||I X |
|:::H HHHHI [] [] [] [] I # #|=== = =! ! ! ! ! ! !|||||||I / \ |
|:::HHHHHHI [] [] [] [] I # #|=======! ! ! ! ! ! !|||||||I/ \|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
o | | |
_|_ | | __| _ _|_ __ _ _
| | |/ / | |/ | / \_| | |_/ |/ |
|_/|_/|__/\_/|_/|__/o|_/\__/ \/ \/ | |_/
</pre>
</a>
<hr>
<pre>
orators, singers, musicians to come!
She will break it to you better than I can.
Saturn expelled his father, and seized his throne
-- I wish our opinions were the same.
Ere departing fade from my eyes your forests of bayonets
Emma soon recollected, and understood him
--'''' My dear papa, he is three-and-twenty.
I hope time has not made you less willing to pardon.
; Nay-be calm, for I am so: Does it burn?
She will break it to you better than I can.
play the part that looks back on the actor or actress!
She continued to look back, but in vain
It is necessary and beside the large sort is puff.
; she is living in dread of the visit.
Year of comets and meteors transient and strange
;'' remember that I am here.-- Mr.
She will break it to you better than I can.
; and Emma was quite in charity with him.
It is a mere nothing after all
The doors of the two rooms were just opposite each other.
She will break it to you better than I can.
I shall just go round by Mrs. Cole 's
Here is realization, Here is a man tallied
Even pleasure, you know, is fatiguing
Keep your raptures for Harriet 's face.
Ere departing fade from my eyes your forests of bayonets
For to one side she leans, Then back she sways
It soon appeared that London was not the place for her.
Perhaps they had the figure of a winged horse on the prow
She will break it to you better than I can.
She will break it to you better than I can.
To conclude, I announce what comes after me.
; nothing delineated or distinguished.
Excelsior Who has gone farthest?
To girlhood, boyhood look, the teacher and the school.
`` How I could so long a time be fancying myself!
`` Yes, sometimes he can.'' Do you mean with regard to this letter?''
Any nonsense will serve. the flesh over and over!
Eleves, I salute you!`` I not aware!'
</pre>
<hr>
<pre>
Have you guess 'd you yourself would not continue?
The wanderer would not heed me
`` He told me at parting, that he should soon write
Mr. Elton looked all happiness at this proposition
what is it to us what the rest do or think?
I doubted it more the next day on Box Hill
Come thou, arise from the ground unto the place yonder
One was the son of Mars, and was killed before Troy
He had done his duty and could return to his son.
I never saw any thing so outree!
; woods, together with mountains, are on fire.
`` He told me at parting, that he should soon write
`` He told me at parting, that he should soon write
; and, abhorring the light, they fly { abroad} by night.
Can not you guess what this parcel holds?''
And these things I see suddenly, what mean they?
And you, paid to defile the People
Very strongly may be sincerely fainting.
she cried with a most open eagerness
`` He told me at parting, that he should soon write
Let me hear from you without delay
By him she was put in mind of what she might do
; but Emma 's countenance was as steady as her words.
Dear Miss Woodhouse, do advise me.''
It was certainly barbara in the eyes of a Greek
One can not creep upon a journey
One was the son of Mars, and was killed before Troy
`` He told me at parting, that he should soon write
[ 77 and struck the guilty{ draught} from his mouth.
; The golden sun of June declines, It has not caught her eye.
Clarke translates miseri senis ore,
: naught there is Save body, having property of touch.
Alas poor boy, he will never be better,
; but if he wished to do it, it might be done.
`` He told me at parting, that he should soon write
One was the son of Mars, and was killed before Troy
I knew who it came from. The virgin shrieks aloud
To feel the presence of a brave commanding officer But she was always right.
I 'd rather you would.'' This was a river of Troy
</pre>
</td>
<td valign="top" width="40%">
<h3>news</h3>
<h4>Systems status</h4>
<p><sub><em>Wed Oct 14 13:49:12 PDT 2015</em></sub></p>
<p>
~vilmibm released a rewrite to the server's infrastructure yesterday. Nothing should be different, but it'll be much easier to work on new features and consume fewer resources.
</p>
<p>
Currently, the <strong>guestbook</strong> is down. Usenet has also been disabled for now since no one was using it and it has a nontrivial impact on the system. If you want to talk about bringing usenet back, bring it up in irc &lt;3.
</p>
<h4>BIRTHDAY! The Town Turns 1</h4>
<p><sub><em>Sun Oct 11 18:54:35 UTC 2015</em></sub></p>
<p>
Exactly a year ago, <a href="/~vilmibm">~vilmibm</a> gave himself
a birthday present in the form of a small unix server meant for
commnunity and sharing. Now, tilde.town is a thriving community of
feels, peer education and beautiful digital art.
</p>
<p>
If you are not yet a towner, check out our <a
href="http://tilde.town/~wiki/conduct.html">code of conduct</a>,
look at some user pages, and <a
href="https://docs.google.com/forms/d/1FSv_-gEU9LDy0b5gL8xm23d5QomMHIIstgr_fL5GFmg/viewform?c=0&w=1">sign
up!</a>. Everyone is welcome here regardless of skill level and if
making SSH keys is a little scary, that's okay. Reach out to <a
href="https://twitter.com/tildetown">for help</a>.
</p>
<p>
<strong>Here's to another year of html and feels.</strong>
</p>
<h4>new stuff!</h4>
<p><sub><em>Sat Aug 1 17:27:15 PDT 2015</em></sub></p>
<p>
today was a day of things happening!
<ul>
<li>the first ever tilde.town volunteer admin meeting happened today. <a href="/~insom">~insom</a>, <a href="/~krowbar">~krowbar</a>, and <a href="/~vilmibm">~vilmibm</a> all met to talk about the future tilde.town and how to ease the burden of things like user signups. Marks the first ever international face-to-face meeting of townies. exciting!
</li>
<li>
<a href="/guestbook">guestbook</a> went live! (<em>lol</em>)
</li>
<li>
you can now click on the pretty ascii tilde.town over to the
left to visit a random page (or just go directly
to <a href="/cgi/random">/cgi/random</a>).
</li>
</ul>
as always, tilde.town is a place for html and feels. feels run
strong and well today. come say hi!
</p>
<p><sub><em>Sun Jul 26 18:01:58 PDT 2015</em></sub></p>
<h4>new homepage design</h4>
<p><sub><em>Sun Jul 26 18:01:58 PDT 2015</em></sub></p>
<p>
<a href="/~vilmibm">~vilmibm</a> made a cleaned up homepage. it's linking to two under construction feature--a new help desk for admin requests and a random page linker. there is also a new <a href="/~wiki/faq.html">FAQ</a>.
</p>
<p>
we've also hit a cool donation milestone of $60. thank you
everyone who has donated! our monthly costs are now covered and if
we hit $65 we can do some more server enhancements.
</p>
<h4>donations! also, new disk</h4>
<p><sub><em>Wed Apr 29 06:04:58 UTC 2015</em></sub></p> <p>An exciting day for
tilde.town. We now have way to donate via <a
href="https://www.patreon.com/nathanielksmith">patreon</a>. Thanks to all the
folx who have already become patrons! y'all make the heart of this sysadmin
warm and fuzz. A big part of the push for donations was a need for more server
space which we have as of tonight's server upgrade/reboot. The main tilde.town
server now has a 40gb disk. Enjoy!</p>
<p>Some updates coming down the pipe:
<ul>
<li>2gb quota for all users</li>
<li>fixed poetry server</li>
<li>better signup process/docs</li>
</ul>
</p>
<h4>welcome haiku</h4>
<p><sub><em> Thu Mar 5 21:19:42 UTC 2015</em></sub></p>
<p>If you signed up in the last two months or so you had a bum welcome present
in your /home. the script has been fixed and now everyone retroactively has a
welcome haiku in their home directory. enjoy.</p>
<h4>server restart</h4>
<p><sub><em>Tue Jan 27 21:13:27 UTC 2015</em></sub></p>
<p>Hi. Today tilde.town had to restart to pick up a patch for <a
href="http://seclists.org/oss-sec/2015/q1/276">CVE 2015-0235</a>.
data.tilde.town (our poetry server) has also been patched and restated. Sorry
for any inconvenience!</p>
<h4>lots of people</h4>
<p><sub><em>Thu Jan 1 07:37:16 UTC 2015</em></sub></p>
<p>we have ~370 users. isn't that wild?</p>
<h4>Scheduled Downtime Tonight</h4>
<p><sub><em>Wed Nov 26 21:19:12 UTC 2014</em></sub></p>
<p>To accommodate our growing user base, there will be a server resize/reboot
tonight (Pacific time). Sadly I cannot give an exact time as I still don't have
internet at my new place and will have to opportunistically find some to
execute this upgrade.</p>
<p>The server should only be down for a few minutes, but this will terminate
any running applications (like tmux/screen/irssi). Any files open in an editor
should be preserved by a swap file but you still may want to save and close
things in the next several hours.</p>
<p>Also, this upgrade means that tilde.town is no longer an essentially free
project, so I may put up something for donations soon.</p>
<h4>100+ users party report</h4>
<p><sub><em>Sun Nov 9 23:07:08 UTC 2014</em></sub></em>
<p>tilde.town now has 102 users. We crossed into three digits last night and
lots of townies hung out in irc to celebrate. Some new features even
launched!</p>
<ul>
<li>the homepage userlist is now sorted by modified time</li>
<li>there is now a shared <pre>tweet</pre> command that all users can use to tweet to the <a href="http://twitter.com/tildetown">@tildetown</a> account (protip: <pre>haiku | tweet</pre>)</li>
<li>run <pre>random_pokemon.sh</pre> to get a random ascii art pokemon (thanks, <a href="http://tilde.town/~sanqui">~sanqui</a>)</li>
<li>a <a href="http://tilde.town/~wiki">git-based wiki</a> that all townies can edit (thanks for the help, <a href="http://tilde.town/~datagrok">~datagrok</a>)</li>
<li>an IRC bot (thanks, <a href="http://tilde.town/~selfsame">~selfsame</a>) that plays numberwang</li>
<li>even moar learnings up on the page of <a href="http://tilde.town/~shanx">~shanx</a></li>
<li>general good feels</li>
</ul>
<h4>80 users!</h4>
<p><sub><em>Wed Oct 29 18:19:45 UTC 2014</em></sub></em>
<p>tilde.town just added its 80th user. Welcome! Some folks have been having
trouble with ssh public keys. Remember, public keys are really confusing if you
aren't too familiar with them, and there is no judgement if you can't
immediately get them to work. Feel free to tweet at <a
href="https://twitter.com/tildetown">@tildetown</a> or send an email to <a
href="mailto:nks@lambdaphil.es">~vilmibm</a> if you'd like some help.</p>
</p>
<h4>60 users</h4>
<p><sub><em>Sat Oct 25 19:37:47 UTC 2014</em></sub></em>
<p>tilde.town is up to 60 users. This is lovely! It is also only a tenth of our
planned total user capacity, so if you are interested in a tilde* account we'd
love to have you. You can even submit a user request with a fancy form now!</p>
<p>
<strong><a href="http://goo.gl/forms/8IvQFTDjlo">submit a user account request!</a></strong>
</p>
</p>
<h4>Change of IP, warnings when you ssh</h4>
<p><sub><em>Sun Oct 19 03:28:59 UTC 2014</em></sub></p>
<p>
In the interest of making sure we don't suddenly disappear from the Internet
as a result of a dynamic IP change on AWS I switched to using an Elastic
IP (amusingly, "elastic" IPs are static).
</p>
<p>
The upside is that we now have a static IP (also it's free) (woo).
</p>
<p>
The downside is that when you try to SSH into tilde.town, now, you'll get an
error about "something nasty" and there will be many @ characters. You'll want
to edit your .ssh/known_hosts file and remove the entry for tilde.town (your
error message should have a cute copy-pasta-able one-liner for doing this for
you).
</p>
<p>
Go ahead and do that, and then log in With Confidence. Hopefully this won't happen again.
</p>
<p>
I'll close by mentioning the imminent arrival of many new tildeverse members. We (the tildeverse operators) are just about ready to accept the signups currently languishing in a waitlist. This means lots of new users, which is lovely, but may mean some growing pains while I adapt our server to the new user load in the most cost-effective way.
</p>
</td>
</tr>
</table>
</body>
</html>