This commit is contained in:
2019-02-06 00:49:12 +03:00
commit 8dbb1bb605
4796 changed files with 506072 additions and 0 deletions

93
livejournal/bin/api2html.pl Executable file
View File

@@ -0,0 +1,93 @@
#!/usr/bin/perl
#
use strict;
unless (-d $ENV{'LJHOME'}) {
die "\$LJHOME not set.\n";
}
chdir $ENV{'LJHOME'} or die "Can't cd to $ENV{'LJOME'}\n";
### apidoc.pl does all the hard work.
my $VAR1;
eval `bin/apidoc.pl`;
my $api = $VAR1;
print "<html>\n";
print "<head><title>LiveJournal API Documentation</title></head>\n";
print "<body>\n";
print "<h1>LiveJournal API Documentation</h1>\n";
## print list
print "<h2>Alphabetic List of Functions</h2>\n";
print "<ul>\n";
foreach my $func (sort keys %$api) {
print "<li><a href=\"#$func\"><tt>$func</tt></a></li>\n";
}
print "</ul>\n";
## print each function
print "<h2>Function Descriptions</h2>\n";
foreach my $func (sort keys %$api) {
my $f = $api->{$func};
my $argstring;
xlinkify(\$f->{'des'});
my $optcount;
foreach my $arg (@{$f->{'args'}}) {
my $comma = $argstring ? ", " : "";
my $lbrack = "";
if ($arg->{'optional'}) {
$optcount++;
$lbrack = "["
}
$argstring .= "$lbrack$comma$arg->{'name'}";
if ($arg->{'list'}) {
$argstring .= "*";
}
}
$argstring .= "]"x$optcount;
print "<a name=\"$func\">\n";
print "<h3><tt>$func</tt></h3>\n";
print "<blockquote><table>\n";
print "<tr valign=\"top\"><td align=\"right\"><i>Description:</i></td>\n";
print "<td>$f->{'des'}</td></tr>\n";
print "<tr valign=\"bottom\"><td align=\"right\"><i>Source:</i></td>\n";
print "<td><tt>$f->{'source'}</tt></td></tr>\n";
if (@{$f->{'args'}}) {
print "<tr valign=\"bottom\"><td align=\"right\"><i>Arguments:</i></td>\n";
print "<td><tt><b>$argstring</b></tt></td></tr>\n";
print "<tr valign=\"bottom\"><td>&nbsp;</td>\n";
print "<td><table cellpadding=\"2\" border=\"1\">\n";
foreach my $arg (@{$f->{'args'}}) {
print "<tr valign=\"top\"><td>$arg->{'name'}</td>";
my $des = $arg->{'des'};
xlinkify(\$des);
print "<td>$des</td></tr>\n";
}
print "</table></td></tr>\n";
}
if ($f->{'returns'}) {
xlinkify(\$f->{'returns'});
print "<tr valign=\"top\"><td align=\"right\"><i>Returns:</i></td>\n";
print "<td>$f->{'returns'}</td></tr>\n";
}
print "</table></blockquote>\n";
print "</a><hr>\n";
}
print "</body>\n";
print "</html>\n";
sub xlinkify {
my $a = shift;
$$a =~ s/\[func\[([^\]]*)]\]/<tt><a href=\"\#$1\">$1<\/a><\/tt>/g;
}

195
livejournal/bin/checkconfig.pl Executable file
View File

@@ -0,0 +1,195 @@
#!/usr/bin/perl
#
my @errors;
my $err = sub {
return unless @_;
die "Problem:\n" . join('', map { " * $_\n" } @_);
};
my %dochecks; # these are the ones we'll actually do
my @checks = ( # put these in the order they should be checked in
"modules",
"env",
"database"
);
foreach my $check (@checks) { $dochecks{$check} = 1; }
my $only = 0;
arg: foreach my $arg (@ARGV) {
($w, $c) = ($arg =~ /^-(no|only)(.*)/) or die "unknown option $arg";
die "only one '-onlyfoo' option may be specified" if $w eq "only" and $only++;
foreach my $check (@checks) {
if ($check eq $c) {
if ($w eq "only") { %dochecks = ( $check => 1 ); }
else { $dochecks{$check} = 0 }
next arg;
}
}
die "unknown check '$c' (known checks: " . join(", ", @checks) . ")\n";
}
my %modules = (
"DBI" => { 'deb' => 'libdbi-perl', },
"DBD::mysql" => { 'deb' => 'libdbd-mysql-perl', },
"Digest::MD5" => { 'deb' => 'libdigest-md5-perl', },
"Digest::SHA1" => { 'deb' => 'libdigest-sha1-perl', },
"Image::Size" => { 'deb' => 'libimage-size-perl', },
"MIME::Lite" => { 'deb' => 'libmime-lite-perl', },
"MIME::Words" => { 'deb' => 'libmime-perl', },
"Compress::Zlib" => { 'deb' => 'libcompress-zlib-perl', },
"Net::SMTP" => {
'deb' => 'libnet-perl',
'opt' => "Alternative to piping into sendmail to send mail.",
},
"Net::DNS" => {
'deb' => 'libnet-dns-perl',
},
"MIME::Base64" => { 'deb' => 'libmime-base64-perl' },
"URI::URL" => { 'deb' => 'liburi-perl' },
"HTML::Tagset" => { 'deb' => 'libhtml-tagset-perl' },
"HTML::Parser" => { 'deb' => 'libhtml-parser-perl', },
"LWP::Simple" => { 'deb' => 'libwww-perl', },
"LWP::UserAgent" => { 'deb' => 'libwww-perl', },
"GD" => { 'deb' => 'libgd-perl' },
"GD::Graph" => {
'deb' => 'libgd-graph-perl',
'opt' => 'Required to make graphs for the statistics page.',
},
"Mail::Address" => { 'deb' => 'libmailtools-perl', },
"Proc::ProcessTable" => {
'deb' => 'libproc-process-perl',
'opt' => "Better reliability for starting daemons necessary for high-traffic installations.",
},
"RPC::XML" => {
'deb' => 'librpc-xml-perl',
'opt' => 'Required for outgoing XMLRPC support',
},
"SOAP::Lite" => {
'deb' => 'libsoap-lite-perl',
'opt' => 'Required for XML-RPC support.',
},
"Unicode::MapUTF8" => { 'deb' => 'libunicode-maputf8-perl', },
"Storable" => {
'deb' => 'libstorable-perl',
},
"XML::RSS" => {
'deb' => 'libxml-rss-perl',
'opt' => 'Required for retrieving RSS off of other sites (syndication).',
},
"XML::Simple" => {
'deb' => 'libxml-simple-perl',
'ver' => 2.12,
},
"String::CRC32" => {
'deb' => 'libstring-crc32-perl',
'opt' => 'Required for palette-altering of PNG files. Only necessary if you plan to make your own S2 styles that use PNGs, not GIFs.',
},
"Time::HiRes" => { 'deb' => 'libtime-hires-perl' },
"IO::WrapTie" => { 'deb' => 'libio-stringy-perl' },
"XML::Atom" => {
'deb' => 'libxml-atom-perl',
'opt' => 'Required for AtomAPI support.',
},
"Math::BigInt::GMP" => {
'opt' => 'Aides Crypt::DH so it isn\'t crazy slow.',
},
"URI::Fetch" => {
'opt' => 'Required for OpenID support.',
},
"Crypt::DH" => {
'opt' => 'Required for OpenID support.',
},
);
sub check_modules {
print "[Checking for Perl Modules....]\n";
my @debs;
foreach my $mod (sort keys %modules) {
my $rv = eval "use $mod;";
if ($@) {
my $dt = $modules{$mod};
if ($dt->{'opt'}) {
print STDERR "Missing optional module $mod: $dt->{'opt'}\n";
} else {
push @errors, "Missing perl module: $mod";
}
push @debs, $dt->{'deb'} if $dt->{'deb'};
next;
}
my $ver_want = $modules{$mod}{ver};
my $ver_got = $mod->VERSION;
if ($ver_want && $ver_got && $ver_got < $ver_want) {
push @errors, "Out of date module: $mod (need $ver_want, $ver_got installed)";
}
}
if (@debs && -e '/etc/debian_version') {
print STDERR "\n# apt-get install ", join(' ', @debs), "\n\n";
}
$err->(@errors);
}
sub check_env {
print "[Checking LJ Environment...]\n";
$err->("\$LJHOME environment variable not set.")
unless $ENV{'LJHOME'};
$err->("\$LJHOME directory doesn't exist ($ENV{'LJHOME'})")
unless -d $ENV{'LJHOME'};
# before ljconfig.pl is called, we want to call the site-local checkconfig,
# otherwise ljconfig.pl might load ljconfig-local.pl, which maybe load
# new modules to implement site-specific hooks.
my $local_config = "$ENV{'LJHOME'}/bin/checkconfig-local.pl";
if (-e $local_config) {
my $good = eval { require $local_config; };
exit 1 unless $good;
}
$err->("No ljconfig.pl file found at $ENV{'LJHOME'}/cgi-bin/ljconfig.pl")
unless -e "$ENV{'LJHOME'}/cgi-bin/ljconfig.pl";
eval { require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl"; };
$err->("Failed to load ljlib.pl: $@") if $@;
# if SMTP_SERVER is set, then Net::SMTP is required, not optional.
if ($LJ::SMTP_SERVER && ! defined $Net::SMTP::VERSION) {
$err->("Net::SMTP isn't available, and you have \$LJ::SMTP_SERVER set.");
}
}
sub check_database {
print "[Checking Database...]\n";
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
my $dbh = LJ::get_dbh("master");
unless ($dbh) {
$err->("Couldn't get master database handle.");
}
foreach my $c (@LJ::CLUSTERS) {
my $dbc = LJ::get_cluster_master($c);
next if $dbc;
$err->("Couldn't get db handle for cluster \#$c");
}
if (%LJ::MOGILEFS_CONFIG && $LJ::MOGILEFS_CONFIG{hosts}) {
print "[Checking MogileFS client.]\n";
my $mog = LJ::mogclient();
die "Couldn't create mogilefs client." unless $mog;
}
}
foreach my $check (@checks) {
next unless $dochecks{$check};
my $cn = "check_".$check;
&$cn;
}
print "All good.\n";
print "NOTE: checkconfig.pl doesn't check everything yet\n";

15
livejournal/bin/cvsreport.pl Executable file
View File

@@ -0,0 +1,15 @@
#!/usr/bin/perl
#
# This is now just a wrapper around the non-LJ-specific multicvs.pl
#
unless (-d $ENV{'LJHOME'}) {
die "\$LJHOME not set.\n";
}
# strip off paths beginning with LJHOME
# (useful if you tab-complete filenames)
$_ =~ s!\Q$ENV{'LJHOME'}\E/?!! foreach (@ARGV);
exit system("$ENV{'LJHOME'}/bin/multicvs.pl",
"--conf=$ENV{'LJHOME'}/cvs/multicvs.conf", @ARGV);

339
livejournal/bin/dbcheck.pl Executable file
View File

@@ -0,0 +1,339 @@
#!/usr/bin/perl
#
use strict;
use DBI;
use Getopt::Long;
my $help = 0;
my $opt_fh = 0;
my $opt_fix = 0;
my $opt_start = 0;
my $opt_stop = 0;
my $opt_err = 0;
my $opt_all = 0;
my $opt_tablestatus;
my $opt_checkreport = 0;
my $opt_rates;
my @opt_run;
exit 1 unless GetOptions('help' => \$help,
'flushhosts' => \$opt_fh,
'start' => \$opt_start,
'stop' => \$opt_stop,
'checkreport' => \$opt_checkreport,
'rates' => \$opt_rates,
'fix' => \$opt_fix,
'run=s' => \@opt_run,
'onlyerrors' => \$opt_err,
'all' => \$opt_all,
'tablestatus' => \$opt_tablestatus,
);
unless (-d $ENV{'LJHOME'}) {
die "\$LJHOME not set.\n";
}
if ($help) {
die ("Usage: dbcheck.pl [opts] [[cmd] args...]\n" .
" --all Check all hosts, even those with no weight assigned.\n" .
" --help Get this help\n" .
" --flushhosts Send 'FLUSH HOSTS' to each db as root.\n".
" --fix Fix (once) common problems.\n".
" --checkreport Show tables that haven't been checked in a while.\n".
" --stop Stop replication.\n".
" --start Start replication.\n".
" --run <sql> Run arbitrary SQL.\n".
" --onlyerrors Will be silent unless there are errors.\n".
" --tablestatus Show warnings about full/sparse tables.\n".
"\n".
"Commands\n".
" (none) Shows replication status.\n".
" queries <host> Shows active queries on host, sorted by running time.\n"
);
}
require "$ENV{'LJHOME'}/cgi-bin/ljdb.pl";
my $dbh = LJ::DB::dbh_by_role("master");
die "Can't get master db handle\n" unless $dbh;
my %dbinfo; # dbid -> hashref
my %name2id; # name -> dbid
my $sth;
my $masterid = 0;
my %subclust; # id -> name of parent (pork-85 -> "pork")
$sth = $dbh->prepare("SELECT dbid, name, masterid, rootfdsn FROM dbinfo");
$sth->execute;
while ($_ = $sth->fetchrow_hashref) {
if ($_->{name} =~ /(.+)\-\d\d$/) {
$subclust{$_->{dbid}} = $1;
next;
}
next unless $_->{'dbid'};
$dbinfo{$_->{'dbid'}} = $_;
$name2id{$_->{'name'}} = $_->{'dbid'};
}
my %role; # rolename -> dbid -> [ norm, curr ]
my %rolebyid; # dbid -> rolename -> [ norm, curr ]
$sth = $dbh->prepare("SELECT dbid, role, norm, curr FROM dbweights");
$sth->execute;
while ($_ = $sth->fetchrow_hashref) {
my $id = $_->{dbid};
if ($subclust{$id}) {
$id = $name2id{$subclust{$id}};
}
next unless defined $dbinfo{$id};
$dbinfo{$id}->{'totalweight'} += $_->{'curr'};
$role{$_->{role}}->{$id} = [ $_->{norm}, $_->{curr} ];
$rolebyid{$id}->{$_->{role}} = [ $_->{norm}, $_->{curr} ];
}
check_report() if $opt_checkreport;
rate_report() if $opt_rates;
my @errors;
my %master_status; # dbid -> [ $file, $pos ]
my $check_master_status = sub {
my $dbid = shift;
my $d = $dbinfo{$dbid};
die "Bogus DB: $dbid" unless $d;
my $db = LJ::DB::root_dbh_by_name($d->{name});
next unless $db;
my ($masterfile, $masterpos) = $db->selectrow_array("SHOW MASTER STATUS");
$master_status{$dbid} = [ $masterfile, $masterpos ];
};
my $check = sub {
my $dbid = shift;
my $d = $dbinfo{$dbid};
die "Bogus DB: $dbid" unless $d;
# calculate roles to show
my $roles;
{
my %drole; # display role -> 1
foreach my $role (grep { $role{$_}{$dbid}[1] } keys %{$rolebyid{$dbid}}) {
my $drole = $role;
$drole =~ s/cluster(\d+)\d/cluster${1}0/;
$drole{$drole} = 1;
}
$roles = join(", ", sort keys %drole);
}
my $db = LJ::DB::root_dbh_by_name($d->{name});
unless ($db) {
printf("%4d %-15s %4s %16s %14s ($roles)\n",
$dbid,
$d->{name},
$d->{masterid} ? $d->{masterid} : "",
) unless $opt_err;
push @errors, "Can't connect to $d->{'name'}";
return 0;
}
my $tzone;
(undef, $tzone) = $db->selectrow_array("show variables like 'timezone'");
$sth = $db->prepare("SHOW PROCESSLIST");
$sth->execute;
my $pcount_total = 0;
my $pcount_busy = 0;
while (my $r = $sth->fetchrow_hashref) {
next if $r->{'State'} =~ /waiting for/i;
next if $r->{'State'} eq "Reading master update";
next if $r->{'State'} =~ /^(Has (sent|read) all)|(Sending binlog)/;
$pcount_total++;
$pcount_busy++ if $r->{'State'};
}
my @master_logs;
my $log_count = 0;
if ($master_status{$dbid} && $master_status{$dbid}->[1]) {
$sth = $db->prepare("SHOW MASTER LOGS");
$sth->execute;
while (my ($log) = $sth->fetchrow_array) {
push @master_logs, $log;
$log_count++;
}
}
my $ss = $db->selectrow_hashref("show slave status");
if ($ss) {
foreach my $k (sort keys %$ss) {
$ss->{lc $k} = $ss->{$k};
}
}
my $diff;
if ($ss) {
if ($ss->{'slave_io_running'} eq "Yes" && $ss->{'slave_sql_running'} eq "Yes") {
if ($ss->{'master_log_file'} eq $ss->{'relay_master_log_file'}) {
$diff = $ss->{'read_master_log_pos'} - $ss->{'exec_master_log_pos'};
} else {
$diff = "XXXXXXX";
push @errors, "Wrong log file: $d->{name}";
}
} else {
$diff = "XXXXXXX";
$ss->{last_error} =~ s/[^\n\r\t\x20-\x7e]//g;
push @errors, "Slave not running: $d->{name}: $ss->{last_error}";
}
my $ms = $master_status{$d->{masterid}} || [];
#print " master: [@$ms], slave at: [$ss->{master_log_file}, $ss->{read_master_log_pos}]\n";
if ($ss->{master_log_file} ne $ms->[0] || $ss->{read_master_log_pos} < $ms->[1] - 20_000) {
push @errors, "$d->{name}: Relay log behind: master=[@$ms], $d->{name}=[$ss->{master_log_file}, $ss->{read_master_log_pos}]";
}
} else {
$diff = "-"; # not applicable
}
#print "$dbid of $d->{masterid}: $d->{name} ($roles)\n";
printf("%4d %-15s %4s repl:%7s %4s conn:%4d/%4d $tzone ($roles)\n",
$dbid,
$d->{name},
$d->{masterid} ? $d->{masterid} : "",
$diff,
$log_count ? sprintf("<%2s>", $log_count) : "",
$pcount_busy, $pcount_total) unless $opt_err;
};
$check_master_status->($_) foreach (sorted_dbids());
$check->($_) foreach (sorted_dbids());
if (@errors) {
if ($opt_err) {
my %ignore;
open(EX, "$ENV{'HOME'}/.dbcheck.ignore");
while (<EX>) {
s/\s+$//;
$ignore{$_} = 1;
}
close EX;
@errors = grep { ! $ignore{$_} } @errors;
}
print STDERR "\nERRORS:\n" if @errors;
foreach (@errors) {
print STDERR " * $_\n";
}
}
my $sorted_cache;
sub sorted_dbids {
return @$sorted_cache if $sorted_cache;
$sorted_cache = [ _sorted_dbids() ];
return @$sorted_cache;
}
sub _sorted_dbids {
my @ids;
my %added; # dbid -> 1
my $add = sub {
my $dbid = shift;
$added{$dbid} = 1;
push @ids, $dbid;
};
my $masterid = (keys %{$role{'master'}})[0];
$add->($masterid);
# then slaves
foreach my $id (sort { $dbinfo{$a}->{name} cmp $dbinfo{$b}->{name} }
grep { ! $added{$_} && $rolebyid{$_}->{slave} } keys %dbinfo) {
$add->($id);
}
# now, figure out which remaining are associated with cluster roles (user clusters)
my %minclust; # dbid -> minimum cluster number associated
my %is_master; # dbid -> bool (is cluster master)
foreach my $dbid (grep { ! $added{$_} } keys %dbinfo) {
foreach my $role (keys %{ $rolebyid{$dbid} || {} }) {
next unless $role =~ /^cluster(\d+)(.*)/;
$minclust{$dbid} = $1 if ! $minclust{$dbid} || $1 < $minclust{$dbid};
$is_master{$dbid} ||= $2 eq "" || $2 eq "a" || $2 eq "b";
}
}
# then misc
foreach my $id (sort { $dbinfo{$a}->{name} cmp $dbinfo{$b}->{name} }
grep { ! $added{$_} && ! $minclust{$_} } keys %dbinfo) {
$add->($id);
}
# then clusters, in order
foreach my $id (sort { $minclust{$a} <=> $minclust{$b} ||
$is_master{$b} <=> $is_master{$a} }
grep { ! $added{$_} && $minclust{$_} } keys %dbinfo) {
$add->($id);
}
return @ids;
}
sub check_report {
foreach my $dbid (sort { $dbinfo{$a}->{name} cmp $dbinfo{$b}->{name} }
keys %dbinfo) {
my $d = $dbinfo{$dbid};
die "Bogus DB: $dbid" unless $d;
my $db = LJ::DB::root_dbh_by_name($d->{name});
unless ($db) {
print "$d->{name}\t?\t?\t?\n";
next;
}
my $dbs = $db->selectcol_arrayref("SHOW DATABASES");
foreach my $dbname (@$dbs) {
$db->do("USE $dbname");
my $ts = $db->selectall_hashref("SHOW TABLE STATUS", "Name");
foreach my $tn (sort keys %$ts) {
my $v = $ts->{$tn};
my $ut = $v->{Check_time} || "0000-00-00 00:00:00";
$ut =~ s/ /,/;
print "$d->{name}\t$dbname\t$tn\t$ut\t$v->{Type}-$v->{Row_format}\t$v->{Rows}\n";
}
}
}
exit 0;
}
use Time::HiRes ();
sub rate_report {
my %prev; # dbid -> [ time, questions ]
while (1) {
print "\n";
my $sum = 0;
foreach my $dbid (sorted_dbids()) {
my $d = $dbinfo{$dbid};
die "Bogus DB: $dbid" unless $d;
my $db = LJ::DB::root_dbh_by_name($d->{name});
next unless $db;
my (undef, $qs) = $db->selectrow_array("SHOW STATUS LIKE 'Questions'");
my $now = Time::HiRes::time();
my $cur = [ $now, $qs ];
if (my $old = $prev{$dbid}) {
my $dt = $now - $old->[0];
my $qnew = $qs - $old->[1];
my $rate = ($qnew / $dt);
$sum += $rate;
printf "%20s: %7.01f q/s\n", $d->{name}, $rate;
}
$prev{$dbid} ||= $cur;
}
printf "%20s: %7.01f q/s\n", "SUM", $sum;
sleep 1;
}
}

392
livejournal/bin/dbselectd.pl Executable file
View File

@@ -0,0 +1,392 @@
#!/usr/bin/perl -w
#
# DB selector daemon. Returns connect information on a preferred DB
# to a requestor.
#
# <LJDEP>
# lib: Getopt::Long, POSIX::, IO::Socket, IO::Select, Socket::, Fcntl::, DBI::
# lib: cgi-bin/ljconfig.pl
# </LJDEP>
use Getopt::Long;
use POSIX;
use IO::Socket;
use IO::Select;
use strict;
use Socket;
use Fcntl;
use DBI;
my $PORT = 5151;
my $PIDFILE = "$ENV{'LJHOME'}/var/dbselectd.pid";
my $SELECT_DELAY = 0.3;
# temporary:
my $DBINFO_FILE = "$ENV{'LJHOME'}/cgi-bin/ljconfig.pl";
my $opt_foreground = 0;
GetOptions("foreground" => \$opt_foreground);
my $pid;
# statistics on known databases
my %db_lastcheck;
my %db_conncount;
my $conf_modtime = 0;
my $conf_stattime = 0;
# Buffers.
my %inbuffer = ();
my %outbuffer = ();
my %cmd = ();
my %clientinfo = ();
sub connect_to
{
my $svr = shift;
my $dbh;
if (ref $LJ::DBCACHE{$svr})
{
$dbh = $LJ::DBCACHE{$svr};
# make sure connection is still good.
my $sth = $dbh->prepare("SELECT CONNECTION_ID()"); # mysql specific
$sth->execute;
my ($id) = $sth->fetchrow_array;
if ($id) { return $dbh; }
undef $dbh;
undef $LJ::DBCACHE{$svr};
}
my $dbname = $LJ::DBINFO{$svr}->{'dbname'} || "livejournal";
$dbh = DBI->connect("DBI:mysql:$dbname:$LJ::DBINFO{$svr}->{'host'}",
$LJ::DBINFO{$svr}->{'user'},
$LJ::DBINFO{$svr}->{'pass'},
{
PrintError => 0,
});
if ($dbh)
{
$LJ::DBCACHE{$svr} = $dbh;
return $dbh;
}
return undef;
}
sub db_can
{
my $svr = shift;
my $cap = shift;
return $LJ::DBINFO{$svr}->{'role'}->{$cap};
}
sub check_server
{
my $svr = shift;
delete $db_conncount{$svr};
delete $db_lastcheck{$svr};
my $dbh = connect_to($svr);
return unless (defined $dbh);
my $sth = $dbh->prepare("SHOW PROCESSLIST");
$sth->execute;
my $ct = 0;
while (my $r = $sth->fetchrow_hashref)
{
# weight busy connections more than idle ones.
if ($r->{'State'}) { $ct += 2; }
else { $ct += 1; }
}
$db_conncount{$svr} = $ct;
$db_lastcheck{$svr} = time();
}
sub connection_load
{
my $svr = shift;
my $time = time();
if (! defined $db_lastcheck{$svr} ||
$time - $db_lastcheck{$svr} > 10)
{
check_server($svr);
}
return $db_conncount{$svr};
}
sub server_power
{
my $svr = shift;
my $cap = shift;
my $weight = $LJ::DBINFO{$svr}->{'role'}->{$cap} || 1;
my $connections = connection_load($svr);
if (defined $connections) {
$connections ||= 1;
} else {
return 0;
}
return ($weight / $connections);
}
sub use_what
{
my $c = shift;
my $cap = shift;
## reload the DB info file if it's been more than 5 seconds since
## its last stat time and if it's changed since what we remember.
my $time = time();
if ($conf_stattime + 5 < $time)
{
my $modtime = (stat($DBINFO_FILE))[9];
if ($modtime > $conf_modtime) {
delete $INC{$DBINFO_FILE};
require $DBINFO_FILE;
$conf_modtime = $modtime;
$conf_stattime = $time;
}
}
my %cand = (); # candidates
# best candidate is one the client is already connected to
foreach my $svr (keys %{$c->{'has'}}) {
if (db_can($svr, $cap)) {
$cand{$svr} = 1;
}
}
# if not connected to anything suitable, then:
unless (%cand)
{
# every db with that capability is a good candidate
foreach my $svr (keys %LJ::DBINFO) {
if (db_can($svr, $cap)) {
$cand{$svr} = 1;
}
}
}
my @cands = keys %cand;
# sort valid candidates by server's connections
my %power;
foreach (@cands) {
$power{$_} = server_power($_, $cap);
}
@cands = sort { $power{$b} <=> $power{$a} } @cands;
# use the one with the highest score:
my $use = $cands[0];
if ($use) {
unless (defined $LJ::DBINFO{$use}->{'dbname'}) {
$LJ::DBINFO{$use}->{'dbname'} = "livejournal";
}
return join(" ", $use, map { $LJ::DBINFO{$use}->{$_} } qw(host user pass dbname));
} else {
return "--";
}
}
sub handle
{
my $select = shift;
my $client = shift;
my $line = shift;
my $c = ($clientinfo{$client} ||= {});
my $out = \$outbuffer{$client};
$line =~ s/^(\S*)\s*//;
my $cmd = $1;
if ($cmd eq "HAVE") {
foreach (split(/,/, $line)) {
next if ($_ eq "master");
$c->{'has'}->{$_} = 1;
}
$$out = "OK\n";
return;
}
if ($cmd eq "NEED") {
my $cap = $line;
my $use = use_what($c, $cap);
$$out = "USE $use\n";
return;
}
if ($cmd eq "STATS") {
my $svr = $line;
$$out = "Stats follow:\n";
foreach my $s (keys %LJ::DBINFO) {
$$out .= "STATS $s = " . connection_load($s) . "\n";
}
$$out .= "End.\n";
return;
}
$$out = "unknown command.\n";
}
# Server crap is below.
$SIG{'TERM'} = sub {
unlink($PIDFILE);
exit 1;
};
if (-e $PIDFILE) {
print "$PIDFILE exists, quitting.\n";
exit 1;
}
sub write_pid
{
my $p = shift;
open(PID, ">$PIDFILE") or die "Couldn't open $PIDFILE for writing: $!\n";
print PID $p;
close(PID);
}
if ($opt_foreground) {
print "Running in foreground...\n";
$pid = $$;
write_pid($pid);
$SIG{'INT'} = sub {
unlink($PIDFILE);
exit 1;
};
} else {
print "Forking off and initializing...\n";
if ($pid = fork) {
# Parent, log pid and exit.
write_pid($pid);
print "Closing ($pid) wrote to $PIDFILE\n";
exit;
}
}
sub killpid_die
{
my $msg = shift;
unlink $PIDFILE;
die $msg;
}
# Connection stuff.
my $server = IO::Socket::INET->new(
"LocalPort" => $PORT,
"Listen" => 10,
"ReuseAddr" => 1,
"Reuse" => 1,
) or killpid_die "Can't make server socket: $@\n";
nonblock($server);
$server->sockopt(SO_REUSEADDR, 1);
my $select = IO::Select->new($server);
print "Looping.\n";
while(1)
{
my $client;
my $rv;
my $data;
# Got connection? Got data?
foreach $client ($select->can_read($SELECT_DELAY)) {
if ($client == $server) {
# New connection, since there's stuff to read from the server sock.
$client = $server->accept();
$select->add($client);
# If the nonblocking mess fails, uh, give up.
unless (nonblock($client)) {
$select->remove($client);
}
} else {
# Read what data we have.
$data = '';
$rv = $client->recv($data, POSIX::BUFSIZ, 0);
unless (defined($rv) && length($data)) {
# If a socket says you can read, but there's nothing there, it's
# actually dead. Clean it up.
cleanup($client);
$select->remove($client);
close($client);
next;
}
$inbuffer{$client} .= $data;
# Check to see if there's a newline at the end. If it is, the
# command is finished. There's only one command line, so I won't
# bother making %cmd a hash with array references to request
# lines. Although this might be needed in the future.
if ($inbuffer{$client} =~ s/^.*\n//) {
$cmd{$client} = $&;
delete $inbuffer{$client};
}
}
}
# Deal with cmd stuff.
foreach $client (keys %cmd) {
my $cmd = $cmd{$client};
$cmd =~ s/[\n\r]+$//;
handle($select, $client, $cmd);
}
%cmd = ();
# Flush buffers
foreach $client ($select->can_write($SELECT_DELAY)) {
# Don't try if there's nothing there.
next unless exists $outbuffer{$client};
$rv = $client->send($outbuffer{$client}, 0);
unless (defined $rv) {
# Something weird happened if we get here, I'll bitch if we ever
# need logging on this thing.
next;
}
if ($rv == length $outbuffer{$client} || $! == POSIX::EWOULDBLOCK) {
substr($outbuffer{$client}, 0, $rv) = '';
delete $outbuffer{$client} unless length $outbuffer{$client};
} else {
# Ahh, something broke. If it was going to block, the above would
# catch it. Close up...
cleanup($client);
$select->remove($client);
close($client);
next;
}
}
}
# Does the messy Socket based nonblock routine...
sub nonblock {
my $socket = shift;
my $flags;
$flags = fcntl($socket, F_GETFL, 0) or return 0;
fcntl($socket, F_SETFL, $flags | O_NONBLOCK) or return 0;
return 1;
}
sub cleanup
{
my $client = shift;
delete $inbuffer{$client};
delete $outbuffer{$client};
delete $cmd{$client};
delete $clientinfo{$client};
}

157
livejournal/bin/deleteusers.pl Executable file
View File

@@ -0,0 +1,157 @@
#!/usr/bin/perl
#
use strict;
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
my $dbh = LJ::get_dbh("master");
$dbh->{'RaiseError'} = 1;
$dbh->{'PrintError'} = 1;
my $sth;
$sth = $dbh->prepare("SELECT userid FROM user WHERE statusvis='D' AND statusvisdate < DATE_SUB(NOW(), INTERVAL 35 DAY) ORDER BY statusvisdate");
$sth->execute;
my @delusers;
while (my $duid = $sth->fetchrow_array) {
push @delusers, $duid;
}
print "Users to delete: ", scalar(@delusers), "\n";
# Get hashref mapping {userid => $u} for all users to be deleted
my $user = LJ::load_userids(@delusers);
LJ::load_props($dbh, "talk");
my $p_delposter = LJ::get_prop("talk", "deleted_poster");
die "No 'deleted_poster' talkprop?" unless $p_delposter;
my $ids;
my $lastbreak = time();
my $pause = sub {
if (time() - $lastbreak > 3) { print "pause.\n"; sleep(1); $lastbreak = time(); }
};
# FIXME: This will soon need to be changed to use methods of the $u
# object rather than global LJ:: functions, but this should work
# for now.
my $runsql = sub {
my $db = $dbh;
if (ref $_[0]) { $db = shift; }
my $user = shift;
my $sql = shift;
print " ($user) $sql\n";
$db->do($sql);
};
my $czero = 0;
foreach my $uid (@delusers)
{
my $du = $user->{$uid};
my $user = $du->{'user'};
print "$du->{'user'} ($du->{'userid'}) @ $du->{'statusvisdate'}";
if ($du->{clusterid} == 0) {
print " (on clusterid 0; skipping)\n";
$czero++;
next;
}
print " (cluster $du->{'clusterid'})...\n";
$pause->();
# get a db handle for the cluster master.
LJ::start_request(); # might've been awhile working with last handle, we don't want to be given an expired one.
my $dbcm = LJ::get_cluster_master($du);
$dbcm->{'RaiseError'} = 1;
$dbcm->{'PrintError'} = 1;
# make all the user's comments posted now be owned by posterid 0 (anonymous)
# but with meta-data saying who used to own it
# ..... hm, with clusters this is a pain. let's not.
# delete memories
print " memories\n";
while (($ids = $dbh->selectcol_arrayref("SELECT memid FROM memorable WHERE userid=$uid LIMIT 100")) && @{$ids})
{
my $in = join(",", @$ids);
print " id: $in\n";
$runsql->($dbh, $user, "DELETE FROM memkeyword WHERE memid IN ($in)");
$runsql->($dbh, $user, "DELETE FROM memorable WHERE memid IN ($in)");
}
# delete todos
print " todos\n";
while (($ids = $dbh->selectcol_arrayref("SELECT todoid FROM todo WHERE journalid=$uid LIMIT 100")) && @{$ids})
{
my $in = join(",", @$ids);
print " id: $in\n";
$runsql->($dbh, $user, "DELETE FROM tododep WHERE todoid IN ($in)");
$runsql->($dbh, $user, "DELETE FROM todokeyword WHERE todoid IN ($in)");
$runsql->($dbh, $user, "DELETE FROM todo WHERE todoid IN ($in)");
}
# delete userpics
{
print " userpics\n";
if ($du->{'dversion'} > 6) {
$ids = $dbcm->selectcol_arrayref("SELECT picid FROM userpic2 WHERE userid=$uid");
} else {
$ids = $dbh->selectcol_arrayref("SELECT picid FROM userpic WHERE userid=$uid");
}
my $in = join(",",@$ids);
if ($in) {
print " userpics: $in\n";
$runsql->($dbcm, $user, "DELETE FROM userpicblob2 WHERE userid=$uid AND picid IN ($in)");
if ($du->{'dversion'} > 6) {
$runsql->($dbcm, $user, "DELETE FROM userpic2 WHERE userid=$uid");
$runsql->($dbcm, $user, "DELETE FROM userpicmap2 WHERE userid=$uid");
$runsql->($dbcm, $user, "DELETE FROM userkeywords WHERE userid=$uid");
} else {
$runsql->($dbh, $user, "DELETE FROM userpic WHERE userid=$uid");
$runsql->($dbh, $user, "DELETE FROM userpicmap WHERE userid=$uid");
}
}
}
# delete posts
print " posts\n";
while (($ids = $dbcm->selectall_arrayref("SELECT jitemid, anum FROM log2 WHERE journalid=$uid LIMIT 100")) && @{$ids})
{
foreach my $idanum (@$ids) {
my ($id, $anum) = ($idanum->[0], $idanum->[1]);
print " deleting $id (a=$anum) ($uid; $du->{'user'})\n";
LJ::delete_entry($du, $id, 0, $anum);
$pause->();
}
}
# misc:
$runsql->($user, "DELETE FROM userusage WHERE userid=$uid");
$runsql->($user, "DELETE FROM friends WHERE userid=$uid");
$runsql->($user, "DELETE FROM friends WHERE friendid=$uid");
$runsql->($user, "DELETE FROM friendgroup WHERE userid=$uid");
$runsql->($dbcm, $user, "DELETE FROM friendgroup2 WHERE userid=$uid");
$runsql->($user, "DELETE FROM memorable WHERE userid=$uid");
$runsql->($dbcm, $user, "DELETE FROM memorable2 WHERE userid=$uid");
$runsql->($dbcm, $user, "DELETE FROM userkeywords WHERE userid=$uid");
$runsql->($dbcm, $user, "DELETE FROM memkeyword2 WHERE userid=$uid");
$runsql->($user, "DELETE FROM userbio WHERE userid=$uid");
$runsql->($dbcm, $user, "DELETE FROM userbio WHERE userid=$uid");
$runsql->($user, "DELETE FROM userinterests WHERE userid=$uid");
$runsql->($user, "DELETE FROM userprop WHERE userid=$uid");
$runsql->($user, "DELETE FROM userproplite WHERE userid=$uid");
$runsql->($user, "DELETE FROM txtmsg WHERE userid=$uid");
$runsql->($user, "DELETE FROM overrides WHERE user='$du->{'user'}'");
$runsql->($user, "DELETE FROM priv_map WHERE userid=$uid");
$runsql->($user, "DELETE FROM infohistory WHERE userid=$uid");
$runsql->($user, "DELETE FROM reluser WHERE userid=$uid");
$runsql->($user, "DELETE FROM reluser WHERE targetid=$uid");
$runsql->($user, "DELETE FROM userlog WHERE userid=$uid");
$runsql->($user, "UPDATE user SET statusvis='X', statusvisdate=NOW(), password='' WHERE userid=$uid");
}
if ($czero) {
print "\nWARNING: There are $czero users on cluster zero pending deletion.\n";
print " These users must be upgraded before they can be expunged with this tool.\n";
}

167
livejournal/bin/dumpsql.pl Executable file
View File

@@ -0,0 +1,167 @@
#!/usr/bin/perl
#
# <LJDEP>
# lib: cgi-bin/ljlib.pl
# </LJDEP>
use strict;
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
require "$ENV{'LJHOME'}/cgi-bin/ljviews.pl";
my $dbh = LJ::get_db_writer();
sub header_text {
return <<"HEADER";
# This file is automatically generated from MySQL by \$LJHOME/bin/dumpsql.pl
# Don't submit a diff against a hand-modified file - dump and diff instead.
HEADER
}
# what tables don't we want to export the auto_increment columns from
# because they already have their own unique string, which is what matters
my %skip_auto = ("userproplist" => "name",
"talkproplist" => "name",
"logproplist" => "name",
"priv_list" => "privcode",
"supportcat" => "catkey",
"ratelist" => "rlid",
);
# get tables to export
my %tables = ();
my $sth = $dbh->prepare("SELECT tablename, redist_mode, redist_where ".
"FROM schematables WHERE redist_mode NOT IN ('off')");
$sth->execute;
while (my ($table, $mode, $where) = $sth->fetchrow_array) {
$tables{$table}->{'mode'} = $mode;
$tables{$table}->{'where'} = $where;
}
my %output; # {general|local} -> [ [ $alphasortkey, $SQL ]+ ]
# dump each table.
foreach my $table (sort keys %tables)
{
my $where;
if ($tables{$table}->{'where'}) {
$where = "WHERE $tables{$table}->{'where'}";
}
my $sth = $dbh->prepare("DESCRIBE $table");
$sth->execute;
my @cols = ();
my $skip_auto = 0;
while (my $c = $sth->fetchrow_hashref) {
if ($c->{'Extra'} =~ /auto_increment/ && $skip_auto{$table}) {
$skip_auto = 1;
} else {
push @cols, $c;
}
}
# DESCRIBE table can be different between developers
@cols = sort { $a->{'Field'} cmp $b->{'Field'} } @cols;
my $cols = join(", ", map { $_->{'Field'} } @cols);
my $sth = $dbh->prepare("SELECT $cols FROM $table $where");
$sth->execute;
my $sql;
while (my @r = $sth->fetchrow_array)
{
my %vals;
my $i = 0;
foreach (map { $_->{'Field'} } @cols) {
$vals{$_} = $r[$i++];
}
my $scope = "general";
$scope = "local" if (defined $vals{'scope'} &&
$vals{'scope'} eq "local");
my $verb = "INSERT IGNORE";
$verb = "REPLACE" if ($tables{$table}->{'mode'} eq "replace" &&
! $skip_auto);
$sql = "$verb INTO $table ";
$sql .= "($cols) ";
$sql .= "VALUES (" . join(", ", map { db_quote($_) } @r) . ");\n";
my $uniqc = $skip_auto{$table};
my $skey = $uniqc ? $vals{$uniqc} : $sql;
push @{$output{$scope}}, [ "$table.$skey.1", $sql ];
if ($skip_auto) {
# for all the *proplist tables, there might be new descriptions
# or columns, but we can't do a REPLACE, because that'd mess
# with their auto_increment ids, so we do insert ignore + update
my $where = "$uniqc=" . db_quote($vals{$uniqc});
delete $vals{$uniqc};
$sql = "UPDATE $table SET ";
$sql .= join(",", map { "$_=" . db_quote($vals{$_}) } sort keys %vals);
$sql .= " WHERE $where;\n";
push @{$output{$scope}}, [ "$table.$skey.2", $sql ];
}
}
}
# don't use $dbh->quote because it's changed between versions
# and developers sending patches can't generate concise patches
# it used to not quote " in a single quoted string, but later it does.
# so we'll implement the new way here.
sub db_quote {
my $s = shift;
return "NULL" unless defined $s;
$s =~ s/\\/\\\\/g;
$s =~ s/\"/\\\"/g;
$s =~ s/\'/\\\'/g;
$s =~ s/\n/\\n/g;
$s =~ s/\r/\\r/g;
return "'$s'";
}
foreach my $k (keys %output) {
my $file = $k eq "general" ? "base-data.sql" : "base-data-local.sql";
print "Dumping $file\n";
my $ffile = "$ENV{'LJHOME'}/bin/upgrading/$file";
open (F, ">$ffile") or die "Can't write to $ffile\n";
print F header_text();
foreach (sort { $a->[0] cmp $b->[0] } @{$output{$k}}) {
print F $_->[1];
}
close F;
}
# and do S1 styles (ugly schema)
print "Dumping s1styles.dat\n";
require "$ENV{'LJHOME'}/bin/upgrading/s1style-rw.pl";
my $ss = {};
my $pubstyles = LJ::S1::get_public_styles({ 'formatdata' => 1});
foreach my $s (values %$pubstyles) {
my $uniq = "$s->{'type'}/$s->{'styledes'}";
$ss->{$uniq}->{$_} = $s->{$_} foreach keys %$s;
}
s1styles_write($ss);
# and dump mood info
print "Dumping moods.dat\n";
open (F, ">$ENV{'LJHOME'}/bin/upgrading/moods.dat") or die;
$sth = $dbh->prepare("SELECT moodid, mood, parentmood FROM moods ORDER BY moodid");
$sth->execute;
while (@_ = $sth->fetchrow_array) {
print F "MOOD @_\n";
}
$sth = $dbh->prepare("SELECT moodthemeid, name, des FROM moodthemes WHERE is_public='Y' ORDER BY name");
$sth->execute;
while (my ($id, $name, $des) = $sth->fetchrow_array) {
$name =~ s/://;
print F "MOODTHEME $name : $des\n";
my $std = $dbh->prepare("SELECT moodid, picurl, width, height FROM moodthemedata ".
"WHERE moodthemeid=$id ORDER BY moodid");
$std->execute;
while (@_ = $std->fetchrow_array) {
print F "@_\n";
}
}
close F;
print "Done.\n";

144
livejournal/bin/fingerd.pl Executable file
View File

@@ -0,0 +1,144 @@
#!/usr/bin/perl
#
# finger server.
#
# accepts two optional arguments, host and port.
# doesn't daemonize.
#
#
# <LJDEP>
# lib: Socket::, Text::Wrap, cgi-bin/ljlib.pl
# </LJDEP>
my $bindhost = shift @ARGV;
my $port = shift @ARGV;
unless ($bindhost) {
$bindhost = "0.0.0.0";
}
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
use Socket;
use Text::Wrap;
$SIG{'INT'} = sub {
print "Interrupt caught!\n";
close FH;
close CL;
exit;
};
my $proto = getprotobyname('tcp');
socket(FH, PF_INET, SOCK_STREAM, $proto) || die $!;
$port ||= 79;
my $localaddr = inet_aton($bindhost);
my $sin = sockaddr_in($port, $localaddr);
setsockopt (FH,SOL_SOCKET,SO_REUSEADDR,1) or
die "setsockopt() failed: $!\n";
bind (FH, $sin) || die $!;
listen(FH, 10);
while (LJ::start_request())
{
accept(CL, FH) || die $!;
my $line = <CL>;
chomp $line;
$line =~ s/\0//g;
$line =~ s/\s//g;
if ($line eq "") {
print CL "Welcome to the $LJ::SITENAME finger server!
You can make queries in the following form:
\@$LJ::DOMAIN - this help message
user\@$LJ::DOMAIN - their userinfo
";
close CL;
next;
}
my $dbr = LJ::get_dbh("slave", "master");
if ($line =~ /^(\w{1,15})$/) {
# userinfo!
my $user = $1;
my $quser = $dbr->quote($user);
my $sth = $dbr->prepare("SELECT user, has_bio, caps, userid, name, email, bdate, allow_infoshow FROM user WHERE user=$quser");
$sth->execute;
my $u = $sth->fetchrow_hashref;
unless ($u) {
print CL "\nUnknown user ($user)\n";
close CL;
next;
}
my $bio;
if ($u->{'has_bio'} eq "Y") {
$sth = $dbr->prepare("SELECT bio FROM userbio WHERE userid=$u->{'userid'}");
$sth->execute;
($bio) = $sth->fetchrow_array;
}
delete $u->{'has_bio'};
$u->{'accttype'} = LJ::name_caps($u->{'caps'});
if ($u->{'allow_infoshow'} eq "Y") {
LJ::load_user_props($dbr, $u, "opt_whatemailshow",
"country", "state", "city", "zip",
"aolim", "icq", "url", "urlname",
"yahoo", "msn");
} else {
$u->{'opt_whatemailshow'} = "N";
}
delete $u->{'allow_infoshow'};
if ($u->{'opt_whatemailshow'} eq "L") {
delete $u->{'email'};
}
if ($LJ::USER_EMAIL && LJ::get_cap($u, "useremail")) {
if ($u->{'email'}) { $u->{'email'} .= ", "; }
$u->{'email'} .= "$user\@$LJ::USER_DOMAIN";
}
if ($u->{'opt_whatemailshow'} eq "N") {
delete $u->{'email'};
}
delete $u->{'opt_whatemailshow'};
my $max = 1;
foreach (keys %$u) {
if (length($_) > $max) { $max = length($_); }
}
$max++;
delete $u->{'caps'};
print CL "\nUserinfo for $user...\n\n";
foreach my $k (sort keys %$u) {
printf CL "%${max}s : %s\n", $k, $u->{$k};
}
if ($bio) {
$bio =~ s/^\s+//;
$bio =~ s/\s+$//;
print CL "\nBio:\n\n";
$Text::Wrap::columns = 77;
print CL Text::Wrap::wrap(" ", " ", $bio);
}
print CL "\n\n";
close CL;
next;
}
print CL "Unsupported/unimplemented query type: $line\n";
print CL "length: ", length($line), "\n";
close CL;
next;
}

128
livejournal/bin/interdoc.pl Executable file
View File

@@ -0,0 +1,128 @@
#!/usr/bin/perl
# This script parses LJ dependency info from all the other files on
# that make up the site. Usually that dependency data is at the end
# of the files, but in this file it's here at the top for two reasons:
# as an example, and because otherwise this script would parse itself
# and start at the wrong place. So, here's this file's dependency
# data:
#
# <LJDEP>
# lib: Getopt::Long
# </LJDEP>
#
# This file parses files for lines containing <LJDEP> then starts
# looking for dependency declarations on subsequent lines until
# </LJDEP> is found. Note that leading junk is ignored. The
# dependencies are of the form:
#
# type: item, item, item
#
# Where type is one of:
#
# file -- data file
# form -- form with method=GET
# lib -- perl module or library (append :: if ! /::/)
# link -- web link
# mailto -- mailto link
# post -- form with method=POST
# prog -- program that's run
# hook -- LJ hook name
#
use strict;
use Getopt::Long;
my $opt_warn = 0;
my $opt_types = 0;
GetOptions('warn' => \$opt_warn,
'types' => \$opt_types);
unless (-d $ENV{'LJHOME'}) {
die "\$LJHOME not set.\n";
}
chdir $ENV{'LJHOME'} or die "Can't cd to $ENV{'LJOME'}\n";
find(qw(bin cgi-bin htdocs));
exit;
sub find
{
my @dirs = @_;
while (@dirs)
{
my $dir = shift @dirs;
next if ($dir eq "htdocs/img");
next if ($dir eq "htdocs/doc");
opendir (D, $dir);
my @files = sort { $a cmp $b } readdir(D);
close D;
foreach my $f (@files) {
next if ($f eq "." || $f eq "..");
my $full = "$dir/$f";
if (-d $full) { find($full); }
elsif (-f $full) { check_file($full); }
}
}
}
sub check_file
{
$_ = shift;
next unless (-f);
next if (/\.(gif|jpg|png|class|jar|zip|exe|gz|deb|rpm|ico)$/);
next if (/~$/);
my $file = $_;
my $indep = 0;
my %deps;
open (F, $file);
while (my $l = <F>)
{
if (! $indep) {
if ($l =~ /<LJDEP>/) {
$indep = 1;
$deps{'_found'} = 1;
}
next;
}
if ($l =~ /<\/LJDEP>/) {
last;
}
if ($l =~ /(\w+):(.+)/) {
my $k = $1;
my $v = $2;
$v =~ s/^\s+//;
$v =~ s/\s+$//;
my @vs = split(/\s*\,\s*/, $v);
foreach (@vs) {
push @{$deps{$k}}, $_;
}
}
}
close (F);
if (delete $deps{'_found'}) {
foreach my $t (keys %deps) {
foreach my $v (@{$deps{$t}}) {
if ($opt_types) {
print "$t\n";
} else {
print join("\t", $file, $t, $v), "\n";
}
}
}
} else {
if ($opt_warn) {
print STDERR "No dep info: $file\n";
}
}
}

3
livejournal/bin/jmk Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/sh
java -jar $LJHOME/bin/jmk.jar $@

43
livejournal/bin/lj-inline.pl Executable file
View File

@@ -0,0 +1,43 @@
#!/usr/bin/perl
#
use strict;
use lib "$ENV{LJHOME}/cgi-bin";
BEGIN {
$LJ::HAVE_INLINE = eval 'use Inline Config => DIRECTORY => ($ENV{LJ_INLINE_DIR} || "$ENV{LJHOME}/Inline"); use Inline "C"; 1;';
# to shutup Apache::SendStat's warning:
$LJ::JUST_COMPILING = 1;
}
print "This script will recompile ljcom's Inline.pm C code, if necessary. You need a C compiler installed.\n";
unless ($LJ::HAVE_INLINE) {
print "\nBut you don't have Inline.pm installed, so quitting now.\n";
exit 1;
}
print "Testing your Inline install...\n";
unless (inline_test()) {
print "Error. Sure you have a C compiler installed?\n";
exit 1;
}
print "ljlib/ljlib-local.pl (if anything)...\n";
require "ljlib.pl";
print "Apache::SendStats...\n";
# wrapped in eval because ap_scoreboard_image isn't around
# when not running inside apache
eval "use Apache::SendStats;";
print "Done.\n";
__DATA__
__C__
int inline_test () {
printf("Your Inline install is good. Proceeding...\n");
return 1;
}

631
livejournal/bin/ljblockwatcher.pl Executable file
View File

@@ -0,0 +1,631 @@
#!/usr/bin/perl
##############################################################################
=head1 NAME
dbreportd - Report database latencies at regular intervals.
=head1 SYNOPSIS
$ dbreportd OPTIONS
=head1 OPTIONS
=over 4
=item -c, --clearscreen
Clear the screen and home the cursor before printing each report, like top. May
not work on all terminals.
=item -d, --debug
Turn on debugging information. May be specified more than once for (potentially)
increased levels of debugging.
=item -h, --help
Output a help message and exit.
=item -i, --interval=SECONDS
Set the number of seconds between reports to SECONDS. Defaults to 3 second
intervals.
=item -p, --port=PORT
Set the port to listen on for reports. This is set in ljconfig.pl, but can be
overridden here.
=item -V, --version
Output version information and exit.
=back
=head1 REQUIRES
I<Token requires line>
=head1 DESCRIPTION
None yet.
=head1 AUTHOR
Michael Granger <ged@FaerieMUD.org>
Copyright (c) 2004 Danga Interactive. All rights reserved.
This program is Open Source software. You may use, modify, and/or redistribute
this software under the terms of the Perl Artistic License. (See
http://language.perl.com/misc/Artistic.html)
THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
FITNESS FOR A PARTICULAR PURPOSE.
=cut
# :TODO: Change param order in received msgs
##############################################################################
package dbreportd;
use strict;
use warnings qw{all};
###############################################################################
### I N I T I A L I Z A T I O N
###############################################################################
BEGIN {
# Turn STDOUT buffering off
$| = 1;
# Versioning stuff and custom includes
use vars qw{$VERSION $RCSID};
$VERSION = do { my @r = (q$Revision: 1.3 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r };
$RCSID = q$Id: ljblockwatcher.pl,v 1.3 2004/03/09 22:25:05 deveiant Exp $;
# Define some constants
use constant TRUE => 1;
use constant FALSE => 0;
# How many time samples to keep around to determine average latency
use constant SAMPLE_DEPTH => 10;
# How many samples to show in the "top <n> slow queries"
use constant TOP_QUERY_SIZE => 5;
# ANSI vt100 escape codes for various things
use constant VT100_CLEARSCREEN => "\e[2J";
use constant VT100_HOME => "\e[0;0H";
# Modules
use Getopt::Long qw{GetOptions};
use Pod::Usage qw{pod2usage};
use IO::Socket::INET qw{};
use IO::Select qw{};
use Time::HiRes qw{usleep};
use Data::Dumper qw{};
# Turn on option bundling (-vid)
Getopt::Long::Configure( "bundling" );
}
our $Debug = FALSE;
### Main body
MAIN: {
my (
$helpFlag, # User requested help?
$versionFlag, # User requested version info?
$interval, # Interval between generated reports
$port, # Port number to listen on
$msg, # The message buffer for reports
$sock, # UDP socket
$selector, # IO::Select object
$lastReport, # time() of last report output
$host, # Message host
$time, # Message time
$notes, # Message notes
$type, # Operation type (currently unused)
%buffers, # SampleBuffers keyed by host
$clearscreenFlag, # Clear the screen before every report?
);
# Print the program header and read in command line options
GetOptions(
'd|debug+' => \$Debug,
'h|help' => \$helpFlag,
'i|interval=i' => \$interval,
'V|version' => \$versionFlag,
'p|port=i' => \$port,
'c|clearscreen' => \$clearscreenFlag,
) or abortWithUsage();
# If the -h flag or -V flag was given, just show the help or version,
# respectively, and exit.
helpMode() and exit if $helpFlag;
versionMode() and exit if $versionFlag;
# Either get the port from the command line or a default
$port ||= 4774;
# Set the interval to a default if it wasn't specified
$interval = 3 if !defined $interval;
# Open a receiving UDP socket
print VT100_CLEARSCREEN, VT100_HOME if $clearscreenFlag;
print "Setting up listener on port $port\n";
$sock = new IO::Socket::INET (
Proto => 'udp',
LocalPort => $port
) or die "Failed to open receiving socket: $!";
$selector = new IO::Select;
$selector->add( $sock );
$lastReport = time();
%buffers = ();
# Print reports every couple of seconds
while ( 1 ) {
if ( $selector->can_read($interval) ) {
# Get the message and split it back into four parts
my $addr = $sock->recv( $msg, 1024, 0 );
print ">>> Message: $msg\n" if $Debug;
( $host, $type, $time, $notes ) = split( /\x3/, $msg, 4 );
# Add the time and notes to the table of hosts
$buffers{ $host } ||= new SampleBuffer ( $host, depth => SAMPLE_DEPTH );
$buffers{ $host }->add( $type, $time, $notes );
} else {
sleep 0.5;
}
} continue {
if ( (time() - $lastReport) > $interval ) {
print VT100_CLEARSCREEN, VT100_HOME if $clearscreenFlag;
print_report( values %buffers );
$lastReport = time();
}
};
}
### FUNCTION: print_report( @buffers )
### Given a list of SampleBuffer objects, print a table with the ones with the
### highest average times.
sub print_report {
my @buffers = @_;
my (
$row, # Row count for display
@top, # Top 5 slowest average buffers
%top, # ^-- Hash of same
@sbuffers, # Buffer objects sorted by hostname
@wbuffers, # Buffer objects sorted by worst op
$fmt, # printf format for report rows
$prefix, # Line prefixes
);
if ( @buffers ) {
# Pick the 5 slowest operations
@top =
map { $_->[0] }
sort { $b->[1] <=> $a->[1] }
map { [$_->host, $_->average_time] }
@buffers;
$row = 0;
%top = ();
foreach my $host ( @top[0 ... TOP_QUERY_SIZE] ) {
last unless defined $host;
$top{$host} = ++$row unless exists $top{$host};
}
#print Data::Dumper->Dumpxs( [\%top], ['top'] ), "\n";
# Make an array of sorted buffer objects by worst average time
@sbuffers =
map { $_->[0] }
sort { $b->[1] <=> $a->[1] }
map { [$_, $_->average_time] }
@buffers;
# Make an array of sorted buffer objects by worst time
@wbuffers =
map { $_->[0] }
sort { $b->[1] <=> $a->[1] }
map { [$_, $_->worst_time] }
@buffers;
# Output all hosts with the average worst operation times
$fmt = "%-2s%25s %0.5fs";
$row = 0;
header( "Average longest blocking operations, by host" );
foreach my $buf (@sbuffers) {
$row++;
if ( exists $top{$buf->host} && $top{$buf->host} <= 3 ) {
$prefix = '+';
} else {
$prefix = ' ';
}
printf "$fmt\n", $prefix, $buf->host, $buf->average_time;
}
print "\n";
# Output the worst operations with their notes
$row = 0;
$fmt = "%0.5fs: '%s' [%s/%s]\n";
header( "%d worst blockers", TOP_QUERY_SIZE );
foreach my $buf (@wbuffers[0 ... TOP_QUERY_SIZE]) {
last unless defined $buf;
$row++;
my $sample = $buf->worst_sample;
printf( $fmt,
$sample->time,
$sample->notes || "(none)",
$sample->type,
$buf->host );
}
print "\n";
# Print the raw buffer objects if debugging
if ( $Debug ) {
header( "Raw buffers" );
foreach my $buf ( @buffers ) {
local $Data::Dumper::Indent = 0;
local $Data::Dumper::Terse = TRUE;
print Data::Dumper->Dumpxs( [$buf], ['buf'] ), "\n";
}
}
print "\n";
}
else {
print "No hosts reporting.\n";
}
}
### FUNCTION: header( $fmt, @args )
### Printf the given message as a header.
sub header {
my ( $fmt, @args ) = @_;
my $msg = sprintf( $fmt, @args );
chomp( $msg );
print "$msg\n", '-' x 75, "\n";
}
### FUNCTION: helpMode()
### Exit normally after printing the usage message
sub helpMode {
pod2usage( -verbose => 1, -exitval => 0 );
}
### FUNCTION: versionMode()
### Exit normally after printing version information
sub versionMode {
print STDERR "dbreportd $VERSION\n";
exit;
}
### FUNCTION: abortWithUsage()
### Abort the program showing usage message.
sub abortWithUsage {
if ( @_ ) {
pod2usage( -verbose => 1, -exitval => 1, -msg => join('', @_) );
} else {
pod2usage( -verbose => 1, -exitval => 1 );
}
}
### FUNCTION: abort( @messages )
### Print the specified messages to the terminal and exit with a non-zero status.
sub abort {
my $msg = @_ ? join '', @_ : "unknown error";
print STDERR $msg, "\n";
exit 1;
}
#####################################################################
### T I M E S A M P L E C L A S S
#####################################################################
package Sample;
use strict;
BEGIN {
use vars qw{$AUTOLOAD};
use Carp qw{croak confess};
use Data::Dumper ();
$Data::Dumper::Terse = 1;
$Data::Dumper::Indent = 1;
}
### METHOD: new( $host )
### Create a new sample buffer for the given host
sub new {
my $proto = shift;
my $class = ref $proto || $proto;
my $self = bless {
type => 'db',
time => 0.0,
notes => '',
}, $class;
if ( @_ && (@_ % 2 == 0) ) {
my %args = @_;
foreach my $meth ( keys %args ) {
$self->$meth( $args{$meth} );
}
}
return $self;
}
### FUNCTION: blessed( $var )
### Returns a true value if the given value is a blessed reference.
sub blessed {
my $arg = shift;
return ref $arg && UNIVERSAL::isa( $arg, 'UNIVERSAL' );
}
### (PROXY) METHOD: AUTOLOAD( @args )
### Proxy method to build (non-translucent) object accessors.
sub AUTOLOAD {
my $self = shift;
confess "Cannot be called as a function" unless $self && blessed $self;
( my $name = $AUTOLOAD ) =~ s{.*::}{};
### Build an accessor for extant attributes
if ( exists $self->{$name} ) {
### Define an accessor for this attribute
my $method = sub {
my $closureSelf = shift or confess "Cannot be called as a function";
$closureSelf->{$name} = shift if @_;
return $closureSelf->{$name};
};
### Install the new method in the symbol table
NO_STRICT_REFS: {
no strict 'refs';
*{$AUTOLOAD} = $method;
}
### Now jump to the new method after sticking the self-ref back onto the
### stack
unshift @_, $self;
goto &$AUTOLOAD;
}
### Try to delegate to our parent's version of the method
my $parentMethod = "SUPER::$name";
return $self->$parentMethod( @_ );
}
sub DESTROY {}
sub END {}
#####################################################################
### S A M P L E B U F F E R C L A S S
#####################################################################
### Class for tracking latencies for a given host
package SampleBuffer;
use strict;
BEGIN {
use Carp qw{croak confess};
use vars qw{$AUTOLOAD};
}
### METHOD: new( $host )
### Create a new sample buffer for the given host
sub new {
my $proto = shift;
my $class = ref $proto || $proto;
my $host = shift or die "No hostname given";
my $self = bless {
host => $host,
samples => {},
depth => 10,
}, $class;
if ( @_ && (@_ % 2 == 0) ) {
my %args = @_;
foreach my $meth ( keys %args ) {
$self->$meth( $args{$meth} );
}
}
return $self;
}
### METHOD: add( $type, $time, $notes )
### Add the specified I<time> to the sample buffer for the given I<type> with
### the given I<notes>.
sub add {
my $self = shift or confess "Cannot be called as a function";
my ( $type, $time, $notes ) = @_;
$self->{samples}{ $type } ||= [];
my $slist = $self->{samples}{ $type };
my $sample = new Sample ( type => $type, time => $time, notes => $notes );
unshift @$slist, $sample;
pop @$slist if @$slist > $self->{depth};
return scalar @$slist;
}
### METHOD: samples( [$type] )
### Fetch a list of the samples of the given I<type> in the buffer, or a list of
### all samples if I<type> is not specified.
sub samples {
my $self = shift or confess "Cannot be used as a function";
my $type = shift;
my @samples = ();
# Gather the samples that are going to be used to make the average, either
# the specific kind requested, or all of 'em.
if ( $type ) {
# Regexp filter
if ( ref $type eq 'Regexp' ) {
foreach my $key ( keys %{$self->{samples}} ) {
push @samples, @{$self->{samples}{ $key }}
if $type =~ $key;
}
}
# Any other filter just gets string-equalled.
else {
@samples = @{$self->{samples}{ $type }};
}
} else {
foreach my $type ( keys %{$self->{samples}} ) {
push @samples, @{$self->{samples}{ $type }};
}
}
return @samples;
}
### METHOD: average_time( [$type] )
### Return the average of all the times currently in the buffer for the given
### I<type>. If I<type> isn't given, returns the overall average.
sub average_time {
my $self = shift or confess "Cannot be used as a function";
my $type = shift;
my ( $time, $count ) = ( 0, 0 );
# Now add and count all the time from each target sample
foreach my $sample ( $self->samples($type) ) {
$time += $sample->time;
$count++;
}
return $time / $count;
}
### METHOD: worst_sample( [$type] )
### Return the worst sample in the buffer for the given I<type>. If no type is
### given, return the worst overall sample.
sub worst_sample {
my $self = shift or confess "Cannot be used as a function";
my $type = shift;
return () unless %{$self->{samples}};
my @samples =
map { $_->[0] }
sort { $a->[1] <=> $b->[1] }
map { [$_, $_->time] } $self->samples( $type );
return $samples[-1];
}
### METHOD: worst_time( [$type] )
### Return the worst time in the buffer for the given I<type>. If no I<type> is
### given, returns the worst overall time.
sub worst_time {
my $self = shift or confess "Cannot be used as a function";
my $type = shift;
my $samp = $self->worst_sample( $type ) or return ();
return $samp->time;
}
### METHOD: worst_notes( [$type] )
### Return the notes from the worst sample in the buffer for the given
### I<type>. If I<type> is not specified, returns the notes for the worst
### overall sample.
sub worst_notes {
my $self = shift or confess "Cannot be used as a function";
my $type = shift;
my $samp = $self->worst_sample( $type ) or return ();
return $samp->notes;
}
### FUNCTION: blessed( $var )
### Returns a true value if the given value is a blessed reference.
sub blessed {
my $arg = shift;
return ref $arg && UNIVERSAL::isa( $arg, 'UNIVERSAL' );
}
### (PROXY) METHOD: AUTOLOAD( @args )
### Proxy method to build (non-translucent) object accessors.
sub AUTOLOAD {
my $self = shift;
confess "Cannot be called as a function" unless $self && blessed $self;
( my $name = $AUTOLOAD ) =~ s{.*::}{};
### Build an accessor for extant attributes
if ( exists $self->{$name} ) {
### Define an accessor for this attribute
my $method = sub {
my $closureSelf = shift or confess "Cannot be called as a function";
$closureSelf->{$name} = shift if @_;
return $closureSelf->{$name};
};
### Install the new method in the symbol table
NO_STRICT_REFS: {
no strict 'refs';
*{$AUTOLOAD} = $method;
}
### Now jump to the new method after sticking the self-ref back onto the
### stack
unshift @_, $self;
goto &$AUTOLOAD;
}
### Try to delegate to our parent's version of the method
my $parentMethod = "SUPER::$name";
return $self->$parentMethod( @_ );
}
sub DESTROY {}
sub END {}

139
livejournal/bin/ljmaint.pl Executable file
View File

@@ -0,0 +1,139 @@
#!/usr/bin/perl
#
# <LJDEP>
# lib: Fcntl::, cgi-bin/ljlib.pl
# file: bin/maint/taskinfo.txt, bin/maint/taskinfo-local.txt
# </LJDEP>
use strict;
use vars qw(%maint %maintinfo $VERBOSE);
unless (-d $ENV{'LJHOME'}) {
die "\$LJHOME not set.\n";
}
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
my $MAINT = "$LJ::HOME/bin/maint";
load_tasks();
$VERBOSE = 1; # 0=quiet, 1=normal, 2=verbose
if (@ARGV)
{
## check the correctness of the taskinfo files
if ($ARGV[0] eq "--check") {
foreach my $task (keys %maintinfo)
{
my %loaded;
my $source = $maintinfo{$task}->{'source'};
unless (-e "$MAINT/$source") {
print "$task references missing file $source\n";
next;
}
unless ($loaded{$source}++) {
require "$MAINT/$source";
}
unless (ref $maint{$task} eq "CODE") {
print "$task is missing code in $source\n";
}
}
exit 0;
}
if ($ARGV[0] =~ /^-v(.?)/) {
if ($1 eq "") { $VERBOSE = 2; }
else { $VERBOSE = $1; }
shift @ARGV;
}
my @targv;
my $hit_colon = 0;
foreach my $arg (@ARGV)
{
if ($arg eq ';') {
$hit_colon = 1;
run_task(@targv);
@targv = ();
next;
}
push @targv, $arg;
}
if ($hit_colon) {
# new behavior: task1 arg1 arg2 ; task2 arg arg2
run_task(@targv);
} else {
# old behavior: task1 task2 task3 (no args, ever)
foreach my $task (@targv) {
run_task($task);
}
}
}
else
{
print "Available tasks: \n";
foreach (sort keys %maintinfo) {
print " $_ - $maintinfo{$_}->{'des'}\n";
}
}
sub run_task
{
my $task = shift;
return unless ($task);
my @args = @_;
print "Running task '$task':\n\n" if ($VERBOSE >= 1);
unless ($maintinfo{$task}) {
print "Unknown task '$task'\n";
return;
}
$LJ::LJMAINT_VERBOSE = $VERBOSE;
require "$MAINT/$maintinfo{$task}->{'source'}";
my $opts = $maintinfo{$task}{opts} || {};
my $lock = undef;
my $lockname = "mainttask-$task";
if ($opts->{'locking'} eq "per_host") {
$lockname .= "-$LJ::SERVER_NAME";
}
unless ($opts->{no_locking} ||
($lock = LJ::locker()->trylock($lockname))
) {
print "Task '$task' already running ($DDLockClient::Error). Quitting.\n" if $VERBOSE >= 1;
exit 0;
}
eval {
$maint{$task}->(@args);
};
if ( $@ ) {
print STDERR "ERROR> task $task died: $@\n\n";
}
}
sub load_tasks
{
foreach my $filename (qw(taskinfo.txt taskinfo-local.txt))
{
my $file = "$MAINT/$filename";
open (F, $file) or next;
my $source;
while (my $l = <F>) {
next if ($l =~ /^\#/);
if ($l =~ /^(\S+):\s*/) {
$source = $1;
next;
}
if ($l =~ /^\s*(\w+)\s*-\s*(.+?)\s*$/) {
$maintinfo{$1}->{'des'} = $2;
$maintinfo{$1}->{'source'} = $source;
}
}
close (F);
}
}

202
livejournal/bin/ljsysban.pl Executable file
View File

@@ -0,0 +1,202 @@
#!/usr/bin/perl
#
use strict;
use Getopt::Long;
# parse input options
my ($list, $add, $modify, $banid, $status, $bandate, $banuntil, $what, $value, $note);
exit 1 unless GetOptions('list' => \$list,
'add' => \$add,
'modify' => \$modify,
'banid=s' => \$banid,
'status=s' => \$status,
'bandate=s' => \$bandate,
'banuntil=s' => \$banuntil,
'what=s' => \$what,
'value=s' => \$value,
'note=s' => \$note,
);
# did they give valid input?
my $an_opt = ($what || $value || $status || $bandate || $banuntil || $note);
unless (($list && (($banid && ! $an_opt) || (! $banid && $an_opt)) ||
($add && $what && $value) ||
($modify && $banid && $an_opt))) {
die "Usage: ljsysban.pl [opts]\n\n" .
" --list { <--banid=?> | or one of:\n" .
" [--what=? --status=? --bandate=datetime --banuntil=datetime\n" .
" --value=? --note=?]\n" .
" }\n\n" .
" --add <--what=? --value=?\n" .
" [--status=? --bandate=datetime --banuntil=datetime --note=?]>\n\n" .
" --modify <--banid=?>\n" .
" [--status=? --bandate=datetime --banuntil=datetime --value=? --note=?]\n\n";
}
# now load in the beast
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
my $dbh = LJ::get_db_writer();
# list bands
if ($list) {
my $where;
if ($banid) {
$where = "banid=" . $dbh->quote($banid);
} else {
my @where = ();
push @where, ("what=" . $dbh->quote($what)) if $what;
push @where, ("value=" . $dbh->quote($value)) if $value;
push @where, ("status=" . $dbh->quote($status)) if $status;
push @where, ("bandate=" . $dbh->quote($bandate)) if $bandate;
push @where, ("banuntil=" . $dbh->quote($banuntil)) if $banuntil;
push @where, ("note=" . $dbh->quote($note)) if $note;
$where = join(" AND ", @where);
}
my $sth = $dbh->prepare("SELECT * FROM sysban WHERE $where ORDER BY bandate ASC");
$sth->execute;
my $ct;
while (my $ban = $sth->fetchrow_hashref) {
print "> banid: $ban->{'banid'}, status: $ban->{'status'}, ";
print "bandate: " . ($ban->{'bandate'} ? $ban->{'bandate'} : "BOT") . ", ";
print "banuntil: " . ($ban->{'banuntil'} ? $ban->{'banuntil'} : "EOT") . "\n";
print "> what: $ban->{'what'}, value: $ban->{'value'}\n";
print "> note: $ban->{'note'}\n" if $ban->{'note'};
print "\n";
$ct++;
}
print "\n\tNO MATCHES\n\n" unless $ct;
exit;
}
# add new ban
if ($add) {
$status = ($status eq 'expired' ? 'expired' : 'active');
$dbh->do("INSERT INTO sysban (status, what, value, note, bandate, banuntil)" .
"VALUES (?, ?, ?, ?, " .
($bandate ? $dbh->quote($bandate) : 'NOW()') . ", " .
($banuntil ? $dbh->quote($banuntil) : 'NULL') . ")",
undef, $status, $what, $value, $note);
die $dbh->errstr if $dbh->err;
my $insertid = $dbh->{'mysql_insertid'};
if ($what eq 'ip') {
LJ::procnotify_add("ban_ip", { 'ip' => $value,
'exptime' => LJ::mysqldate_to_time($banuntil) });
LJ::MemCache::delete("sysban:ip");
}
if ($what eq 'uniq') {
LJ::procnotify_add("ban_uniq", { 'uniq' => $value,
'exptime' => LJ::mysqldate_to_time($banuntil) });
LJ::MemCache::delete("sysban:uniq");
}
# log in statushistory
LJ::statushistory_add(0, 0, 'sysban_add',
"banid=$insertid; status=$status; " .
"bandate=" . ($bandate || LJ::mysql_time()) . "; " .
"banuntil=" . ($banuntil || 'NULL') . "; " .
"what=$what; value=$value; " .
"note=$note;");
print "CREATED: banid=$insertid\n";
exit;
}
# modify existing ban
if ($modify) {
# load selected ban
my $ban = $dbh->selectrow_hashref("SELECT * FROM sysban WHERE banid=?", undef, $banid);
die $dbh->errstr if $dbh->err;
my @set = ();
# ip/uniq ban and we're going to change the value
if (($value && $value ne $ban->{'value'}) ||
$banuntil && $banuntil ne $ban->{'banuntil'} ||
($status && $status ne $ban->{'status'} && $status eq 'expired')) {
if ($ban->{'what'} eq 'ip') {
LJ::procnotify_add("unban_ip", { 'ip' => $value || $ban->{'value'}});
LJ::MemCache::delete("sysban:ip");
}
if ($ban->{'what'} eq 'uniq') {
LJ::procnotify_add("unban_uniq", { 'uniq' => $value || $ban->{'value'} });
LJ::MemCache::delete("sysban:uniq");
}
}
# what - must have a value
if ($what && $what ne $ban->{'what'}) {
$ban->{'what'} = $what;
push @set, "what=" . $dbh->quote($ban->{'what'});
}
# ip/uniq ban and we are going to change the value
if (($value && $value ne $ban->{'value'}) ||
$banuntil && $banuntil ne $ban->{'banuntil'} ||
($status && $status ne $ban->{'status'} && $status eq 'active')) {
my $new_banuntil = $banuntil || $ban->{'banuntil'};
if ($ban->{'what'} eq 'ip') {
LJ::procnotify_add("ban_ip", { 'ip' => $value || $ban->{'value'},
'exptime' => LJ::mysqldate_to_time($new_banuntil) });
LJ::MemCache::delete("sysban:ip");
}
if ($ban->{'what'} eq 'uniq') {
LJ::procnotify_add("ban_uniq", { 'uniq' => $value || $ban->{'value'},
'exptime' => LJ::mysqldate_to_time($new_banuntil) });
LJ::MemCache::delete("sysban:uniq");
}
}
# value - must have a value
if ($value && $value ne $ban->{'value'}) {
$ban->{'value'} = $value;
push @set, "value=" . $dbh->quote($ban->{'value'});
}
# status - must have a value
if ($status && $status ne $ban->{'status'}) {
$ban->{'status'} = ($status eq 'expired' ? 'expired' : 'active');
push @set, "status=" . $dbh->quote($ban->{'status'});
}
# banuntil
if ($banuntil && $banuntil ne $ban->{'banuntil'}) {
$ban->{'banuntil'} = ($banuntil && $banuntil ne 'NULL') ? $banuntil : 0;
push @set, "banuntil=" . ($ban->{'banuntil'} ? $dbh->quote($ban->{'banuntil'}) : 'NULL');
}
# bandate - must have a value
if ($bandate && $bandate ne $ban->{'bandate'}) {
$ban->{'bandate'} = $bandate;
push @set, "bandate=" . $dbh->quote($ban->{'bandate'});
}
# note - can be changed to blank
if (defined $note && $note ne $ban->{'note'}) {
$ban->{'note'} = $note;
push @set, "note=" . $dbh->quote($ban->{'note'});
}
# do update
$dbh->do("UPDATE sysban SET " . join(", ", @set) . " WHERE banid=?", undef, $ban->{'banid'});
# log in statushistory
my $msg; map { $msg .= " " if $msg;
$msg .= "$_=$ban->{$_};" } qw(banid status bandate banuntil what value note);
LJ::statushistory_add(0, 0, 'sysban_mod', $msg);
print "MODIFIED: banid=$banid\n";
exit;
}

1149
livejournal/bin/ljubackup.pl Executable file

File diff suppressed because it is too large Load Diff

1336
livejournal/bin/ljumover.pl Executable file

File diff suppressed because it is too large Load Diff

110
livejournal/bin/logsummarize.pl Executable file
View File

@@ -0,0 +1,110 @@
#!/usr/bin/perl
#
use strict;
unless (-d $ENV{'LJHOME'}) {
die "\$LJHOME not set.\n";
}
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
my $db = LJ::get_dbh("logs");
unless ($db) {
die "No 'logs' db handle found.\n";
}
$db->{'InactiveDestroy'} = 1;
my $sth;
my %table;
$sth = $db->prepare("SHOW TABLES LIKE 'access%'");
$sth->execute;
while (my $t = $sth->fetchrow_array) {
$table{$t} = 1;
}
my @need_summary = sort grep { /^access\d{8,8}$/ } keys %table;
pop @need_summary; # don't summarize the current day yet.
my $nsum_total = @need_summary;
my $nsum_ct = 0;
use constant F_SERVER => 0;
use constant F_LANG => 1;
use constant F_METHOD => 2;
use constant F_VHOST => 3;
use constant F_URI => 4;
use constant F_STATUS => 5;
use constant F_CTYPE => 6;
use constant F_BYTES => 7;
use constant F_BROWSER => 8;
use constant F_REF => 9;
foreach my $table (@need_summary)
{
$nsum_ct++;
print "Summarizing $table ($nsum_ct/$nsum_total)\n";
my $row_total = $db->selectrow_array("SELECT COUNT(*) FROM $table");
print " rows = $row_total\n";
my $sth = $db->prepare("SELECT server, langpref, method, vhost, uri, ".
" status, ctype, bytes, browser, ref ".
"FROM $table");
$sth->{'mysql_use_result'} = 1;
$sth->execute;
my ($r, $row_ct);
my %st;
while ($r = $sth->fetchrow_arrayref) {
$row_ct++;
if ($row_ct % 10000 == 0) {
printf " $row_ct/$row_total (%%%.02f)\n", 100*$row_ct/$row_total;
}
next if ($r->[F_URI] =~ m!^/userpic!);
$st{'count'}->{'total'}++;
$st{'count'}->{'bytes'} += $r->[F_BYTES];
$st{'http_meth'}->{$r->[F_METHOD]}++;
$st{'http_status'}->{$r->[F_STATUS]}++;
$st{'browser'}->{$r->[F_BROWSER]}++;
$st{'host'}->{$r->[F_VHOST]}++;
if ($r->[F_URI] =~ s!^/(users/|~)\w+/?!/users/*/!) {
$r->[F_URI] =~ s!day/\d\d\d\d/\d\d/\d\d!day!;
$r->[F_URI] =~ s!calendar/\d\d\d\d!calendar!;
}
if ($r->[F_VHOST] =~ /^(www\.)livejournal\.com$/) {
$st{'uri'}->{$r->[F_URI]}++;
} else {
$r->[F_URI] =~ s!day/\d\d\d\d/\d\d/\d\d!day!;
$r->[F_URI] =~ s!calendar/\d\d\d\d!calendar!;
$st{'uri'}->{"user:" . $r->[F_URI]}++;
}
my $ref = $r->[F_REF];
if ($ref =~ m!^http://([^/]+)!) {
$ref = $1;
$st{'referer'}->{$ref}++ unless ($ref =~ /livejournal\.com$/);
}
}
my $tabledate = $table;
$tabledate =~ s/^access//;
print " Writing stats file.\n";
open (S, "| gzip -c > $ENV{'LJHOME'}/var/stats-$tabledate.gz") or die "Can't open stats file";
foreach my $cat (sort keys %st) {
print "Writing cat: $cat\n";
foreach my $k (sort { $st{$cat}->{$b} <=> $st{$cat}->{$a} } keys %{$st{$cat}}) {
print S "$cat\t$k\t$st{$cat}->{$k}\n"
or die "Failed writing to stats-$tabledate.gz. Device full?\n";
}
}
close S;
$db->do("DROP TABLE $table");
}

536
livejournal/bin/mailgated.pl Executable file
View File

@@ -0,0 +1,536 @@
#!/usr/bin/perl
#
# <LJDEP>
# lib: MIME::Parser, Mail::Address, cgi-bin/ljlib.pl, cgi-bin/supportlib.pl
# </LJDEP>
use strict;
use lib "$ENV{LJHOME}/cgi-bin";
use Getopt::Long;
use Sys::Hostname;
use MIME::Parser;
use Mail::Address;
use Proc::ProcessTable;
use Unicode::MapUTF8 ();
use File::Temp ();
use File::Path ();
use Danga::Daemon;
require "$ENV{LJHOME}/cgi-bin/ljconfig.pl";
# worker globals
use vars qw/ $mailspool $mailspool_new $workdir $maxloop
$hostname $locktype $opt /;
$opt = {};
Getopt::Long::GetOptions $opt, qw/ workdir=s lock=s maxloop=s /;
# mailspool should match the MTA delivery location.
$mailspool = $LJ::MAILSPOOL || "$ENV{'LJHOME'}/mail";
$mailspool_new = "$mailspool/new";
# setup defaults
$hostname = $1 if Sys::Hostname::hostname() =~ /^([\w-]+)/;
$locktype = $opt->{'lock'} || $LJ::MAILLOCK;
die "Invalid lock mechanism specified. Set \$LJ::MAILLOCK or use --lock.\n"
unless $locktype =~ /hostname|none|ddlockd/i;
$workdir = $opt->{'workdir'} || "$mailspool/tmp";
$maxloop = $opt->{'maxloop'} || 100;
# sanity checks
die "Invalid mailspool: $mailspool\n" unless -d $mailspool_new;
die "Unable to read mailspool: $mailspool\n" unless -r $mailspool;
Danga::Daemon::daemonize(
\&worker,
{
interval => 10,
shedprivs => 'lj',
listenport => 15000,
listencode => \&cmd_interface,
}
);
# main event loop for mailgated.
# examine mailspool, populate queues, and call
# process() as needed.
sub worker
{
require "$ENV{'LJHOME'}/cgi-bin/ljemailgateway.pl";
require "$ENV{'LJHOME'}/cgi-bin/supportlib.pl";
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
require "$ENV{'LJHOME'}/cgi-bin/sysban.pl";
$| = 1;
debug("Starting loop:");
cleanup();
LJ::start_request();
# Get list of files to process.
# If a file simply exists in the mailspool, it needs attention.
debug("\tprocess");
opendir( MDIR, $mailspool_new )
|| die "Unable to open mailspool $mailspool_new: $!\n";
my @all_files = readdir(MDIR);
closedir MDIR;
# Separate new messages from retries.
# Hostname as part of the filename is Maildir specification -
# use 'hostname' locking to be safe across NFS.
my ( @new_messages, @retry_messages );
foreach (@all_files) {
next if /^\./;
next if $locktype eq 'hostname' && !/\.$hostname\b/;
if ( get_pcount($_) == 0 ) { # new message
push @new_messages, $_;
}
else { # message retry
push @retry_messages, $_;
}
}
# Make sure at least half of our processesing
# queue is made up of new messages.
# Randomize, so if we're running multiple mailgated
# processess, they'll be more likely to be working on
# different messages.
rand_array( \@retry_messages, int( $maxloop / 2 ) ); # half queue max
# fill the rest of the queue with new messages.
rand_array( \@new_messages, $maxloop - ( scalar @retry_messages ) );
# do the work
foreach my $file ( @new_messages, @retry_messages ) {
my $lock;
if ( get_pcount($file) % 20 == 0 ) { # only retry every 20th iteration
if ( lc($locktype) eq 'ddlockd' ) {
$lock = LJ::locker()->trylock("mailgated-$file");
next unless $lock;
}
eval { process($file); };
if ($@) {
debug("\t\t$@");
set_pcount($file);
}
}
else {
set_pcount($file);
}
}
debug("\tdone\n");
LJ::end_request();
}
# additional command line options
sub cmd_interface
{
my ( $line, $s, $c, $codeloop, $codeopts ) = @_;
if ($line =~ /help/i) {
foreach (sort qw/ ping pids reload stop queuesize status /) {
print $c "\t$_\n";
}
print $c ".\nOK\n";
return 1;
}
if ($line =~ /queuesize/) {
if (! opendir(MDIR, $mailspool_new)) {
print $c "Unable to open mailspool $mailspool_new: $!\n";
} else {
my $count = 0;
foreach (readdir(MDIR)) {
next if /^\./;
$count++;
}
closedir MDIR;
print $c "$count\n";
}
return 1;
}
if ($line =~ /status/) {
my $pid = $Danga::Daemon::pid;
my $t = new Proc::ProcessTable;
my $state;
foreach my $p ( @{$t->table} ){
$state = $p->state if $p->pid == $pid;
}
print $c "mailgate ";
print $c ($state ne 'defunct' && kill 0, $pid) ? "running" : "down";
print $c "\n";
return 1;
}
return;
}
# Remove prior run workdirs.
# File::Temp's CLEANUP only works upon program exit.
sub cleanup
{
debug("\tcleanup");
my $now = time();
unless ( opendir( TMP, $workdir ) ) {
debug("\t\tCan't open workdir $workdir: $!");
return;
}
my $limit = 0;
foreach ( readdir(TMP) ) {
next unless /^ljmailgate_/;
last if $limit >= 50;
$limit++;
my $modtime = ( stat("$workdir/$_") )[9];
if ( $now - $modtime > 300 ) {
File::Path::rmtree("$workdir/$_");
debug("\t\t$workdir/$_");
}
}
closedir TMP;
return 0;
}
# takes an array ref - truncates to max size and shuffles it.
sub rand_array
{
my ( $array, $max ) = @_;
my ( @tmp, $c );
while (@$array) {
push( @tmp, splice( @$array, rand(@$array), 1 ) );
last if ++$c == $max;
}
@$array = @tmp;
return;
}
sub set_pcount
{
my ( $file, $resetattempt ) = @_;
my $attempt = get_pcount($file);
$attempt++;
$attempt = 0 if $resetattempt;
my $name = $file;
$name =~ s/:\d+$//;
$name = $name . ":" . $attempt;
rename "$mailspool_new/$file", "$mailspool_new/$name";
return 0;
}
# return the number of times we've seen this
# message in the queue
sub get_pcount
{
return 0 unless shift() =~ /:(\d+)$/;
return $1;
}
# Either an unrecoverable error, or a total success. ;)
# Regardless, we're done with this message.
# Remove it so it isn't processed again.
our $last_file;
our $last_tempdir;
sub dequeue
{
my $msg = shift;
debug("\t\t dequeued: $msg") if $msg;
unlink("$mailspool_new/$last_file")
|| debug("\t\t Can't unlink $last_file!");
File::Path::rmtree($last_tempdir);
return 0;
}
# cleanup mime tempdirs, update attempt number,
# but don't delete the message.
sub retry
{
my $msg = shift;
debug("\t\t retrying: $msg") if $msg;
set_pcount($last_file);
File::Path::rmtree($last_tempdir);
return 0;
}
# examine message contents and decide what to do
# with it.
sub process
{
my $file = shift;
debug("\t\t$file");
my $tmpdir =
File::Temp::tempdir( "ljmailgate_" . 'X' x 20, DIR => $workdir );
my $parser = new MIME::Parser;
# for dequeue sub:
$last_file = $file;
$last_tempdir = $tmpdir;
$parser->output_dir($tmpdir);
# Close the message as quickly as possible, in case
# we need to change status mid process.
open( MESSAGE, "$mailspool_new/$file" )
|| debug("\t\t Can't open file: $!") && return;
my $entity;
eval { $entity = $parser->parse( \*MESSAGE ) };
close MESSAGE;
return dequeue("Can't parse MIME") if $@;
my $head = $entity->head;
$head->unfold;
my $subject = $head->get('Subject');
chomp $subject;
# ignore spam/vacation/auto-reply messages
if ( $subject =~ /auto.?(response|reply)/i
|| $subject =~
/^(Undelive|Mail System Error - |ScanMail Message: |\+\s*SPAM|Norton AntiVirus)/i
|| $subject =~ /^(Mail Delivery Problem|Mail delivery failed)/i
|| $subject =~ /^failure notice$/i
|| $subject =~ /\[BOUNCED SPAM\]/i
|| $subject =~ /^Symantec AVF /i
|| $subject =~ /Attachment block message/i
|| $subject =~ /Use this patch immediately/i
|| $subject =~ /^YOUR PAYPAL\.COM ACCOUNT EXPIRES/i
|| $subject =~ /^don\'t be late! ([\w\-]{1,15})$/i
|| $subject =~ /^your account ([\w\-]{1,15})$/i )
{
return dequeue("Spam");
}
# quick and dirty (and effective) scan for viruses
return dequeue("Virus found") if virus_check($entity);
# see if it's a post-by-email
my @to = Mail::Address->parse( $head->get('To') );
if ( scalar @to > 0 ) {
foreach my $dest ( @to ) {
next unless $dest->address =~ /^(\S+?)\@\Q$LJ::EMAIL_POST_DOMAIN\E$/i;
my $user = $1;
# FIXME: verify auth (extra from $user/$subject/$body), require ljprotocol.pl, do post.
# unresolved: where to temporarily store messages before they're approved?
# perhaps the modblob table? perhaps a column it can be used to determine
# whether it's a moderated community post vs. an un-acked phone post.
my $post_rv;
my $post_msg = LJ::Emailpost::process( $entity, $user, \$post_rv );
return $post_rv ? dequeue($post_msg) : retry($post_msg);
}
}
# stop more spam, based on body text checks
my $tent = LJ::Emailpost::get_entity($entity);
$tent = LJ::Emailpost::get_entity( $entity, 'html' ) unless $tent;
return dequeue("Can't find text or html entity") unless $tent;
my $body = $tent->bodyhandle->as_string;
$body = LJ::trim($body);
### spam
if ( $body =~ /I send you this file in order to have your advice/i
|| $body =~ /^Content-Type: application\/octet-stream/i
|| $body =~ /^(Please see|See) the attached file for details\.?$/i )
{
return dequeue("Spam");
}
# From this point on we know it's a support request of some type,
my $email2cat = LJ::Support::load_email_to_cat_map();
my $to;
my $toarg;
my $ignore = 0;
foreach my $a ( @to, Mail::Address->parse( $head->get('Cc') ) ) {
my $address = $a->address;
my $arg;
if ( $address =~ /^(.+)\+(.*)\@(.+)$/ ) {
( $address, $arg ) = ( "$1\@$3", $2 );
}
if ( defined $LJ::ALIAS_TO_SUPPORTCAT{$address} ) {
$address = $LJ::ALIAS_TO_SUPPORTCAT{$address};
}
if ( defined $email2cat->{$address} ) {
$to = $address;
$toarg = $arg;
}
$ignore = 1 if $address eq $LJ::IGNORE_EMAIL;
$ignore = 1 if $address eq $LJ::BOGUS_EMAIL;
}
return dequeue("Not deliverable to support system (no match To:)")
unless $to;
my $adf = ( Mail::Address->parse( $head->get('From') ) )[0];
return dequeue("Bogus From: header") unless $adf;
my $name = $adf->name;
my $from = $adf->address;
$subject ||= "(No Subject)";
# is this a reply to another post?
if ( $toarg =~ /^(\d+)z(.+)$/ ) {
my $spid = $1;
my $miniauth = $2;
my $sp = LJ::Support::load_request($spid);
LJ::Support::mini_auth($sp) eq $miniauth
or die "Invalid authentication?";
if ( LJ::sysban_check( 'support_email', $from ) ) {
my $msg = "Support request blocked based on email.";
LJ::sysban_block( 0, $msg, { 'email' => $from } );
return dequeue($msg);
}
# make sure it's not locked
return dequeue("Request is locked, can't append comment.")
if LJ::Support::is_locked($sp);
# valid. need to strip out stuff now with authcodes:
$body =~ s!http://.+/support/act\.bml\S+![snipped]!g;
$body =~ s!\+(\d)+z\w{1,10}\@!\@!g;
$body =~ s!&auth=\S+!!g;
## try to get rid of reply stuff.
# Outlook Express:
$body =~ s!(\S+.*?)-{4,10} Original Message -{4,10}.+!$1!s;
# Pine/Netscape
$body =~ s!(\S+.*?)\bOn [^\n]+ wrote:\n.+!$1!s;
# append the comment, re-open the request if necessary
my $splid = LJ::Support::append_request(
$sp,
{
'type' => 'comment',
'body' => $body,
}
)
or return dequeue("Error appending request?");
LJ::Support::touch_request($spid);
return dequeue("Support reply success");
}
# Now see if we want to ignore this particular email and bounce it back with
# the contents from a file. Check $LJ::DENY_REQUEST_FROM_EMAIL first. Note
# that this will only bounce initial emails; if a user replies to an email
# from a request that's open, it'll be accepted above.
my ( $content_file, $content );
if ( %LJ::DENY_REQUEST_FROM_EMAIL && $LJ::DENY_REQUEST_FROM_EMAIL{$to} ) {
$content_file = $LJ::DENY_REQUEST_FROM_EMAIL{$to};
$content = LJ::load_include($content_file);
}
if ( $content_file && $content ) {
# construct mail to send to user
my $email = <<EMAIL_END;
$content
Your original message:
$body
EMAIL_END
# send the message
LJ::send_mail(
{
'to' => $from,
'from' => $LJ::BOGUS_EMAIL,
'subject' => "Your Email to $to",
'body' => $email,
'wrap' => 1,
}
);
# all done
return dequeue("Support request bounced to origin");
}
# make a new post.
my @errors;
# convert email body to utf-8
my $content_type = $head->get('Content-type:');
my $charset = $1
if $content_type =~ /\bcharset=[\'\"]?(\S+?)[\'\"]?[\s\;]/i;
if ( defined($charset)
&& $charset !~ /^UTF-?8$/i
&& Unicode::MapUTF8::utf8_supported_charset($charset) )
{
$body =
Unicode::MapUTF8::to_utf8(
{ -string => $body, -charset => $charset } );
}
my $spid = LJ::Support::file_request(
\@errors,
{
'spcatid' => $email2cat->{$to}->{'spcatid'},
'subject' => $subject,
'reqtype' => 'email',
'reqname' => $name,
'reqemail' => $from,
'body' => $body,
}
);
if (@errors) {
# FIXME: detect trasient vs. permanent errors (changes to
# file_request above, probably) and either dequeue or try
# later
return dequeue("Support errors: @errors");
}
else {
return dequeue("Support request success");
}
}
# returns true on found virus
sub virus_check
{
my $entity = shift;
return unless $entity;
my @exe = LJ::Emailpost::get_entity( $entity, 'all' );
return unless scalar @exe;
# If an attachment's encoding begins with one of these strings,
# we want to completely drop the message.
# (Other 'clean' attachments are silently ignored, and the
# message is allowed.)
my @virus_sigs =
qw(
TVqQAAMAA TVpQAAIAA TVpAALQAc TVpyAXkAX TVrmAU4AA
TVrhARwAk TVoFAQUAA TVoAAAQAA TVoIARMAA TVouARsAA
TVrQAT8AA UEsDBBQAA UEsDBAoAAA
R0lGODlhaAA7APcAAP///+rp6puSp6GZrDUjUUc6Zn53mFJMdbGvvVtXh2xre8bF1x8cU4yLprOy
);
# get the length of the longest virus signature
my $maxlength =
length( ( sort { length $b <=> length $a } @virus_sigs )[0] );
$maxlength = 1024 if $maxlength >= 1024; # capped at 1k
foreach my $part (@exe) {
my $contents = $part->stringify_body;
$contents = substr $contents, 0, $maxlength;
foreach (@virus_sigs) {
return 1 if index( $contents, $_ ) == 0;
}
}
return;
}

86
livejournal/bin/maint/bday.pl Executable file
View File

@@ -0,0 +1,86 @@
#!/usr/bin/perl
#
use strict;
use vars qw(%maint);
$maint{'bdaymail'} = sub
{
my $dbr = LJ::get_db_reader();
my $sth;
# get everybody whose birthday is today.
$sth = $dbr->prepare("SELECT u.userid, u.user, u.name, u.email ".
"FROM user u, userusage uu WHERE u.userid=uu.userid AND ".
"u.bdate IS NOT NULL AND u.status='A' AND ".
"u.statusvis='V' AND u.bdate <> '0000-00-00' AND ".
"MONTH(NOW())=MONTH(u.bdate) AND DAYOFMONTH(NOW())=DAYOFMONTH(u.bdate) ".
"AND uu.timeupdate > DATE_SUB(NOW(), INTERVAL 1 MONTH) AND ".
"u.journaltype='P'");
$sth->execute;
my @bdays; push @bdays, $_ while ($_ = $sth->fetchrow_hashref);
$sth->finish;
# go through each birthday person and tell them happy birthday.
foreach my $bu (@bdays)
{
my ($user, $userid, $name, $email) = map { $bu->{$_} } qw(user userid name email);
print "$user ($userid) .. $name .. $email\n";
LJ::send_mail({
'to' => $email,
'toname' => $name,
'subject' => "Happy Birthday!",
'from' => $LJ::ADMIN_EMAIL,
'fromname' => $LJ::SITENAME,
'body' => ("Happy Birthday $name!!\n\n".
"According to our records, today is your birthday... everybody here ".
"at $LJ::SITENAME would like to wish you a happy birthday!\n\n".
"If you have any interesting birthday stories to share, do let us know! ".
"Or better, email them to us and also update your LiveJournal with them. ".
":) And if you have any questions/comments about the service in general, ".
"let us know too... we're real people, not a huge corporation, so we read ".
"and try to reply to all email.\n\n".
"Anyway... the point of this email was originally just HAPPY BIRTHDAY!\n\n".
"--\n$LJ::SITENAME\n$LJ::SITEROOT/\n"),
});
# and now, tell people that list them as friends.
$sth = $dbr->prepare("SELECT u.user, u.name, u.email ".
"FROM user u, friends f, userprop up, userproplist upl, userusage uu ".
"WHERE f.friendid=$userid AND f.userid=u.userid AND ".
"up.userid=u.userid AND upl.upropid=up.upropid AND uu.userid=u.userid AND ".
"upl.name='opt_bdaymail' AND up.value='1' AND ".
"u.journaltype='P' AND u.status='A' AND u.statusvis='V' AND ".
"uu.timeupdate>DATE_SUB(NOW(), INTERVAL 1 MONTH) AND ".
"u.userid <> $userid");
$sth->execute;
if ($dbr->err) { die $dbr->errstr; }
my @friendof; push @friendof, $_ while ($_ = $sth->fetchrow_hashref);
# possesive es
my $s = ($name =~ /s$/i) ? "'" : "'s";
foreach my $fu (@friendof)
{
my ($fuser, $fname, $femail) = map { $fu->{$_} } qw(user name email);
print " mail $fuser about $user...\n";
LJ::send_mail({
'to' => $femail,
'toname' => $fname,
'subject' => "Birthday Reminder!",
'from' => $LJ::ADMIN_EMAIL,
'fromname' => $LJ::SITENAME,
'body' => ("This is a reminder that today is $name$s birthday ".
"(LiveJournal user: $user). You have $name listed as ".
"a friend in your LiveJournal, so we thought this ".
"reminder would be useful.".
"\n\n--\n$LJ::SITENAME\n$LJ::SITEROOT/\n"),
});
}
}
};
1;

361
livejournal/bin/maint/captcha.pl Executable file
View File

@@ -0,0 +1,361 @@
#!/usr/bin/perl
use strict;
use vars qw(%maint %maintinfo);
use LJ::Captcha qw{};
use LJ::Blob qw{};
use File::Temp qw{tempdir};
use File::Path qw{rmtree};
use File::Spec qw{};
our ( $FakeUserId, $ClusterId, $Digits, $DigitCount,
$ExpireThresUser, $ExpireThresNoUser );
# Data for code-generation
$Digits = "abcdefghkmnpqrstuvwzyz23456789";
$DigitCount = length( $Digits );
# Maximum age of answered captchas. this is just
# for double-click protection.
$ExpireThresUser = 2 * 60; # two minutes
# 24 hours for captchas which were given out but not answered.
# (they might leave their browser window open or something)
$ExpireThresNoUser = 24 * 3600; # 1 day
#####################################################################
### F U N C T I O N S
#####################################################################
### Read a file in as a scalar and return it
sub readfile ($) {
my ( $filename ) = @_;
open my $fh, "<$filename" or die "open: $filename: $!";
local $/ = undef;
my $data = <$fh>;
return $data;
}
### Generate an n-character challenge code
sub gencode ($) {
my ( $digits ) = @_;
my $code = '';
for ( 1..$digits ) {
$code .= substr( $Digits, int(rand($DigitCount)), 1 );
}
return $code;
}
#####################################################################
### M A I N T E N A N C E T A S K S
#####################################################################
$maintinfo{gen_audio_captchas}{opts}{locking} = "per_host";
$maint{gen_audio_captchas} = sub {
my (
$u, # Fake user record for Blob::put
$dbh, # Database handle (writer)
$count, # Count of currently-extant audio challenges
$need, # How many we need to still create
$make, # how many we're actually going to create this round
$tmpdir, # Temporary working directory
$code, # The generated challenge code
$wav, # Wav file
$data, # Wav file data
$err, # Error-message ref for Blob::put calls
$capid, # Captcha row id
$anum, # Deseries-ifier value
);
print "-I- Generating new audio captchas...\n";
$dbh = LJ::get_dbh({raw=>1}, "master") or die "Failed to get_db_writer()";
$dbh->do("SET wait_timeout=28800");
# Count how many challenges there are currently
$count = $dbh->selectrow_array(q{
SELECT COUNT(*)
FROM captchas
WHERE
type = 'audio'
AND issuetime = 0
});
my $MaxItems = $LJ::CAPTCHA_AUDIO_PREGEN || 500;
# If there are enough, don't generate any more
print "Current count is $count of $MaxItems...";
if ( $count >= $MaxItems ) {
print "already have enough.\n";
return;
} else {
$make = $need = $MaxItems - $count;
$make = $LJ::CAPTCHA_AUDIO_MAKE
if defined $LJ::CAPTCHA_AUDIO_MAKE && $make > $LJ::CAPTCHA_AUDIO_MAKE;
print "generating $make new audio challenges.\n";
}
# Clean up any old audio directories lying about from failed generations
# before. In theory, File::Temp::tempdir() is supposed to clean them up
# itself, but it doesn't appear to be doing so.
foreach my $olddir ( glob "audio_captchas_*" ) {
# If it's been more than an hour since it's been changed from the
# starting time of the script, kill it
if ( (-M $olddir) * 24 > 1 ) {
print "cleaning up old working temp directory ($olddir).\n";
rmtree( $olddir ) or die "rmtree: $olddir: $!";
}
}
# Load the system user for Blob::put() and create an auto-cleaning temp
# directory for audio generation
$u = LJ::load_user( "system" )
or die "Couldn't load the system user.";
$tmpdir = tempdir( "audio_captchas_XXXXXX", CLEANUP => 0 );
# target location
my $location = $LJ::CAPTCHA_MOGILEFS ? 'mogile' : 'blob';
# Generate the challenges
for ( my $i = 0; $i < $make; $i++ ) {
print "Generating audio $i...";
( $wav, $code ) = LJ::Captcha::generate_audio( $tmpdir );
$data = readfile( $wav );
unlink $wav or die "unlink: $wav: $!";
# Generate the capid + anum
print "generating new capid/anum...";
$capid = LJ::alloc_global_counter( 'C' );
die "Couldn't allocate capid" unless $capid;
$anum = int( rand 65_535 );
# Insert the blob
print "uploading (capid = $capid, anum = $anum)...";
if ($location eq 'mogile') {
my $mogfs = LJ::mogclient(); # force load
die "Requested to store captchas on MogileFS, but it's not loaded.\n"
unless $mogfs;
my $fh = $mogfs->new_file("captcha:$capid", 'captcha')
or die "Unable to contact MogileFS server for storage.\n";
$fh->print($data);
$fh->close
or die "Unable to save captcha to MogileFS server: $@\n";
} else {
LJ::Blob::put( $u, 'captcha_audio', 'wav', $capid, $data, \$err )
or die "Error uploading to media server: $err";
}
# Insert the captcha into the DB. If it fails for some reason, delete
# the just-uploaded file from the media storage system too.
print "inserting (code = $code)...";
my $rval = eval {
$dbh->do(q{
INSERT INTO captchas( capid, type, location, answer, anum )
VALUES ( ?, 'audio', ?, ?, ? )
}, undef, $capid, $location, $code, $anum);
};
if ( !$rval || $@ ) {
my $err = $@ || $dbh->errstr;
if ( $location eq 'mogile' ) {
LJ::mogclient()->delete( "captcha:$capid" );
} else {
LJ::Blob::delete( $u, 'captcha_audio', 'wav', $capid );
}
die "audio captcha insert error on ($capid, $location, $code, $anum): $err";
}
print "done.\n";
}
print "cleaning up working temporary directory ($tmpdir).\n";
rmtree( $tmpdir ) or die "Failed directory cleanup: $!";
print "done. Created $make new audio captchas.\n";
return 1;
};
$maintinfo{gen_image_captchas}{opts}{locking} = "per_host";
$maint{gen_image_captchas} = sub {
my (
$u, # Fake user record for Blob::put
$dbh, # Database handle (writer)
$count, # Count of currently-extant audio challenges
$need, # How many we need to still create
$code, # The generated challenge code
$png, # PNG data
$err, # Error-message ref for Blob::put calls
$capid, # Captcha row id
$anum, # Deseries-ifier value
);
print "-I- Generating new image captchas...\n";
$dbh = LJ::get_dbh({raw=>1}, "master") or die "Failed to get_db_writer()";
$dbh->do("SET wait_timeout=28800");
# Count how many challenges there are currently
$count = $dbh->selectrow_array(q{
SELECT COUNT(*)
FROM captchas
WHERE
type = 'image'
AND issuetime = 0
});
my $MaxItems = $LJ::CAPTCHA_IMAGE_PREGEN || 1000;
# If there are enough, don't generate any more
print "Current count is $count of $MaxItems...";
if ( $count >= $MaxItems ) {
print "already have enough.\n";
return;
} else {
$need = $MaxItems - $count;
print "generating $need new image challenges.\n";
}
# Load system user for Blob::put()
$u = LJ::load_user( "system" )
or die "Couldn't load the system user.";
$dbh = LJ::get_db_writer() or die "Failed to get_db_writer()";
# target location
my $location = $LJ::CAPTCHA_MOGILEFS ? 'mogile' : 'blob';
# Generate the challenges
for ( my $i = 0; $i < $need; $i++ ) {
print "Generating image $i...";
$code = gencode( 7 );
( $png ) = LJ::Captcha::generate_visual( $code );
# Generate the capid + anum
print "generating new capid/anum...";
$capid = LJ::alloc_global_counter( 'C' );
die "Couldn't allocate capid" unless $capid;
$anum = int( rand 65_535 );
# Insert the blob
print "uploading (capid = $capid, anum = $anum)...";
if ($location eq 'mogile') {
my $mogfs = LJ::mogclient(); # force load
die "Requested to store captchas on MogileFS, but it's not loaded.\n"
unless $mogfs;
my $fh = $mogfs->new_file("captcha:$capid", 'captcha')
or die "Unable to contact MogileFS server for storage.\n";
$fh->print($png);
$fh->close
or die "Unable to save captcha to MogileFS server: $@\n";
} else {
LJ::Blob::put( $u, 'captcha_image', 'png', $capid, $png, \$err )
or die "Error uploading to media server: $err";
}
# Insert the captcha into the DB. If it fails for some reason, delete
# the just-uploaded file from the media storage system too.
print "inserting (code = $code)...";
my $rval = eval {
$dbh->do(q{
INSERT INTO captchas( capid, type, location, answer, anum )
VALUES ( ?, 'image', ?, ?, ? )
}, undef, $capid, $location, $code, $anum);
};
if ( !$rval || $@ ) {
my $err = $@ || $dbh->errstr;
if ( $location eq 'mogile' ) {
LJ::mogclient()->delete( "captcha:$capid" );
} else {
LJ::Blob::delete( $u, 'captcha_image', 'png', $capid );
}
die "image captcha insert error on ($capid, $location, $code, $anum): $err";
}
print "done.\n";
}
print "done. Created $need new image captchas.\n";
return 1;
};
$maint{clean_captchas} = sub {
my (
$u, # System user
$expired, # arrayref of arrayrefs of expired captchas
$dbh, # Database handle (writer)
$sql, # SQL statement
$sth, # Statement handle
$count, # Deletion count
$err, # Error message reference for Blob::delete calls
);
print "-I- Cleaning captchas.\n";
# Find captchas to delete
$sql = q{
SELECT
capid, type, location
FROM captchas
WHERE
( issuetime <> 0 AND issuetime < ? )
OR
( userid > 0
AND ( issuetime <> 0 AND issuetime < ? )
)
LIMIT 2500
};
$dbh = LJ::get_db_writer()
or die "No master DB handle";
$expired = $dbh->selectall_arrayref( $sql, undef,
time() - $ExpireThresNoUser,
time() - $ExpireThresUser );
die "selectall_arrayref: $sql: ", $dbh->errstr if $dbh->err;
if ( @$expired ) {
print "found ", scalar @$expired, " captchas to delete...\n";
} else {
print "Done: No captchas to delete.\n";
return;
}
# Prepare deletion statement
$sql = q{ DELETE FROM captchas WHERE capid = ? };
$sth = $dbh->prepare( $sql );
# Fetch system user
$u = LJ::load_user( "system" )
or die "Couldn't load the system user.";
# Now delete each one from the DB and the media server
foreach my $captcha ( @$expired ) {
my ( $capid, $type, $location ) = @$captcha;
$location ||= 'blob';
print "Deleting captcha $capid ($type, $location)\n";
my $ext = $type eq 'audio' ? 'wav' : 'png';
if ($location eq 'mogile') {
my $mogfs = LJ::mogclient(); # force load
die "Requested to delete captchas from MogileFS, but it's not loaded.\n"
unless $mogfs;
$mogfs->delete("captcha:$capid")
or die "Unable to delete captcha from MogileFS server for capid = $capid.\n";
} else {
LJ::Blob::delete( $u, "captcha_$type", $ext, $capid, \$err )
or die "Failed to delete $type file from media server for ".
"capid = $capid: $err";
}
$sth->execute( $capid )
or die "execute: $sql ($capid): ", $sth->errstr;
$count++;
}
print "Done: deleted $count expired captchas.\n";
return 1;
};

View File

@@ -0,0 +1,207 @@
#!/usr/bin/perl
#
$maint{'clean_caches'} = sub
{
my $dbh = LJ::get_db_writer();
my $sth;
my $verbose = $LJ::LJMAINT_VERBOSE;
print "-I- Cleaning authactions.\n";
$dbh->do("DELETE FROM authactions WHERE datecreate < DATE_SUB(NOW(), INTERVAL 30 DAY)");
print "-I- Cleaning faquses.\n";
$dbh->do("DELETE FROM faquses WHERE dateview < DATE_SUB(NOW(), INTERVAL 7 DAY)");
print "-I- Cleaning duplock.\n";
$dbh->do("DELETE FROM duplock WHERE instime < DATE_SUB(NOW(), INTERVAL 1 HOUR)");
print "-I- Cleaning commenturl.\n";
$dbh->do("DELETE FROM commenturls WHERE timecreate < UNIX_TIMESTAMP() - 86400*30 LIMIT 50000");
print "-I- Cleaning captcha sessions.\n";
foreach my $c (@LJ::CLUSTERS) {
my $dbcm = LJ::get_cluster_master($c);
next unless $dbcm;
$dbcm->do("DELETE FROM captcha_session WHERE sesstime < UNIX_TIMESTAMP()-86400");
}
print "-I- Cleaning old anonymous comment IP logs.\n";
my $count;
foreach my $c (@LJ::CLUSTERS) {
my $dbcm = LJ::get_cluster_master($c);
next unless $dbcm;
# 432,000 seconds is 5 days
$count += $dbcm->do('DELETE FROM tempanonips WHERE reporttime < (UNIX_TIMESTAMP() - 432000)');
}
print " deleted $count\n";
print "-I- Cleaning diresearchres.\n";
# need insert before delete so master logs delete and slaves actually do it
$dbh->do("INSERT INTO dirsearchres2 VALUES (MD5(NOW()), DATE_SUB(NOW(), INTERVAL 31 MINUTE), '')");
$dbh->do("DELETE FROM dirsearchres2 WHERE dateins < DATE_SUB(NOW(), INTERVAL 30 MINUTE)");
print "-I- Cleaning meme.\n";
do {
$sth = $dbh->prepare("DELETE FROM meme WHERE ts < DATE_SUB(NOW(), INTERVAL 7 DAY) LIMIT 250");
$sth->execute;
if ($dbh->err) { print $dbh->errstr; }
print " deleted ", $sth->rows, "\n";
} while ($sth->rows && ! $sth->err);
print "-I- Cleaning old pending comments.\n";
$count = 0;
foreach my $c (@LJ::CLUSTERS) {
my $dbcm = LJ::get_cluster_master($c);
next unless $dbcm;
# 3600 seconds is one hour
my $time = time() - 3600;
$count += $dbcm->do('DELETE FROM pendcomments WHERE datesubmit < ? LIMIT 2000', undef, $time);
}
print " deleted $count\n";
# move rows from talkleft_xfp to talkleft
print "-I- Moving talkleft_xfp.\n";
my $xfp_count = $dbh->selectrow_array("SELECT COUNT(*) FROM talkleft_xfp");
print " rows found: $xfp_count\n";
if ($xfp_count) {
my @xfp_cols = qw(userid posttime journalid nodetype nodeid jtalkid publicitem);
my $xfp_cols = join(",", @xfp_cols);
my $xfp_cols_join = join(",", map { "t.$_" } @xfp_cols);
my %insert_vals;
my %delete_vals;
# select out 1000 rows from random clusters
$sth = $dbh->prepare("SELECT u.clusterid,u.user,$xfp_cols_join " .
"FROM talkleft_xfp t, user u " .
"WHERE t.userid=u.userid LIMIT 1000");
$sth->execute();
my $row_ct = 0;
while (my $row = $sth->fetchrow_hashref) {
my %qrow = map { $_, $dbh->quote($row->{$_}) } @xfp_cols;
push @{$insert_vals{$row->{'clusterid'}}},
("(" . join(",", map { $qrow{$_} } @xfp_cols) . ")");
push @{$delete_vals{$row->{'clusterid'}}},
("(userid=$qrow{'userid'} AND " .
"journalid=$qrow{'journalid'} AND " .
"nodetype=$qrow{'nodetype'} AND " .
"nodeid=$qrow{'nodeid'} AND " .
"posttime=$qrow{'posttime'} AND " .
"jtalkid=$qrow{'jtalkid'})");
$row_ct++;
}
foreach my $clusterid (sort keys %insert_vals) {
my $dbcm = LJ::get_cluster_master($clusterid);
unless ($dbcm) {
print " cluster down: $clusterid\n";
next;
}
print " cluster $clusterid: " . scalar(@{$insert_vals{$clusterid}}) .
" rows\n" if $verbose;
$dbcm->do("INSERT INTO talkleft ($xfp_cols) VALUES " .
join(",", @{$insert_vals{$clusterid}})) . "\n";
if ($dbcm->err) {
print " db error (insert): " . $dbcm->errstr . "\n";
next;
}
# no error, delete from _xfp
$dbh->do("DELETE FROM talkleft_xfp WHERE " .
join(" OR ", @{$delete_vals{$clusterid}})) . "\n";
if ($dbh->err) {
print " db error (delete): " . $dbh->errstr . "\n";
next;
}
}
print " rows remaining: " . ($xfp_count - $row_ct) . "\n";
}
# move clustered recentaction summaries from their respective clusters
# to the global actionhistory table
print "-I- Migrating recentactions.\n";
foreach my $cid (@LJ::CLUSTERS) {
next unless $cid;
my $dbcm = LJ::get_cluster_master($cid);
unless ($dbcm) {
print " cluster down: $clusterid\n";
next;
}
unless ($dbcm->do("LOCK TABLES recentactions WRITE")) {
print " db error (lock): " . $dbcm->errstr . "\n";
next;
}
my $sth = $dbcm->prepare
("SELECT what, COUNT(*) FROM recentactions GROUP BY 1");
$sth->execute;
if ($dbcm->err) {
print " db error (select): " . $dbcm->errstr . "\n";
next;
}
my %counts = ();
my $total_ct = 0;
while (my ($what, $ct) = $sth->fetchrow_array) {
$counts{$what} += $ct;
$total_ct += $ct;
}
print " cluster $cid: $total_ct rows\n" if $verbose;
# Note: We can experience failures on both sides of this
# transaction. Either our delete can succeed then
# insert fail or vice versa. Luckily this data is
# for statistical purposes so we can just live with
# the possibility of a small skew.
unless ($dbcm->do("DELETE FROM recentactions")) {
print " db error (delete): " . $dbcm->errstr . "\n";
next;
}
# at this point if there is an error we will ignore it and try
# to insert the count data above anyway
$dbcm->do("UNLOCK TABLES")
or print " db error (unlock): " . $dbcm->errstr . "\n";
# nothing to insert, why bother?
next unless %counts;
# insert summary into global actionhistory table
my @bind = ();
my @vals = ();
while (my ($what, $ct) = each %counts) {
push @bind, "(UNIX_TIMESTAMP(),?,?,?)";
push @vals, $cid, $what, $ct;
}
my $bind = join(",", @bind);
$dbh->do("INSERT INTO actionhistory (time, clusterid, what, count) " .
"VALUES $bind", undef, @vals);
if ($dbh->err) {
print " db error (insert): " . $dbh->errstr . "\n";
# something's badly b0rked, don't try any other clusters for now
last;
}
# next cluster
}
};
1;

View File

@@ -0,0 +1,76 @@
#!/usr/bin/perl
#
$maint{joinmail} = sub {
# this needs to be resumeable, so that it can run once every 10 or 15 minutes to digest things
# that are a day old but haven't been sent. also, the first query down there needs to include
# the right authaction type in the WHERE clause, and NOT do a GROUP BY.
print "Returning without running... I'm disabled right now.\n";
return 1;
my $dbr = LJ::get_db_reader();
# get all information
my $pending = $dbr->selectall_arrayref("SELECT userid, COUNT(arg1) FROM authactions " .
"WHERE used = 'N' AND datecreate > DATE_SUB(NOW(), INTERVAL 1 DAY)" .
"GROUP BY userid") || [];
# get userids of communities
my @commids;
push @commids, $_->[0]+0 foreach @$pending;
my $cus = LJ::load_userids(@commids);
# now let's get the maintainers of these
my $in = join ',', @commids;
my $maintrows = $dbr->selectall_arrayref("SELECT userid, targetid FROM reluser WHERE userid IN ($in) AND type = 'A'") || [];
my @maintids;
my %maints;
foreach (@$maintrows) {
push @{$maints{$_->[0]}}, $_->[1];
push @maintids, $_->[1];
}
my $mus = LJ::load_userids(@maintids);
# tell the maintainers that they got new people.
foreach my $row (@$pending) {
my $cuser = $cus->{$row->[0]}{user};
print "$cuser: $row->[1] invites: ";
my %email; # see who we emailed on this comm
foreach my $mid (@{$maints{$row->[0]}}) {
print "$mid ";
next if $email{$mus->{$mid}{email}}++;
LJ::load_user_props($mus->{$mid}, 'opt_communityjoinemail');
next unless $mus->{$mid}{opt_communityjoinemail} eq 'D'; # Daily or Digest
my $body = "Dear $mus->{$mid}{user},\n\n" .
"Over the past day or so, $row->[1] request(s) to join the \"$cuser\" community have " .
"been received. To look at the currently pending membership requests, please visit the pending " .
"membership page:\n\n" .
"\t$LJ::SITEROOT/community/pending.bml?comm=$cuser\n\n" .
"You may also ignore this email. Outstanding requests to join will expire after a period of 30 days.\n\n" .
"If you wish to no longer receive these emails, visit the community management page and " .
"set the relevant options:\n\n\t$LJ::SITEROOT/community/manage.bml\n\n" .
"Regards,\n$LJ::SITENAME Team\n";
LJ::send_mail({
to => $mus->{$mid}{email},
from => $LJ::COMMUNITY_EMAIL,
fromname => $LJ::SITENAME,
charset => 'utf-8',
subject => "$cuser Membership Requests",
body => $body,
wrap => 76,
});
}
print "\n";
}
};
$maint{clean_spamreports} = sub {
my $dbh = LJ::get_db_writer();
my $len = 86400 * 90; # 90 days
my $ct = $dbh->do("DELETE FROM spamreports WHERE reporttime < UNIX_TIMESTAMP() - $len")+0;
print "Deleted $ct reports.\n";
};
1;

530
livejournal/bin/maint/stats.pl Executable file
View File

@@ -0,0 +1,530 @@
#!/usr/bin/perl
#
use strict;
use vars qw(%maint);
require "$ENV{'LJHOME'}/cgi-bin/statslib.pl";
# filled in by ljmaint.pl, 0=quiet, 1=normal, 2=verbose
$LJ::Stats::VERBOSE = $LJ::LJMAINT_VERBOSE >= 2 ? 1 : 0;
$maint{'genstats'} = sub
{
my @which = @_ || qw(users countries
states gender clients
pop_interests meme pop_faq);
# popular faq items
LJ::Stats::register_stat
({ 'type' => "global",
'jobname' => "popfaq",
'statname' => "pop_faq",
'handler' =>
sub {
my $db_getter = shift;
return undef unless ref $db_getter eq 'CODE';
my $db = $db_getter->();
return undef unless $db;
my $sth = $db->prepare("SELECT faqid, COUNT(*) FROM faquses WHERE " .
"faqid<>0 GROUP BY 1 ORDER BY 2 DESC LIMIT 50");
$sth->execute;
die $db->errstr if $db->err;
my %ret;
while (my ($id, $count) = $sth->fetchrow_array) {
$ret{$id} = $count;
}
return \%ret;
},
});
# popular interests
LJ::Stats::register_stat
({ 'type' => "global",
'jobname' => "pop_interests",
'statname' => "pop_interests",
'handler' =>
sub {
my $db_getter = shift;
return undef unless ref $db_getter eq 'CODE';
my $db = $db_getter->();
return undef unless $db;
return {} if $LJ::DISABLED{'interests-popular'};
# see what the previous min was, then subtract 20% of max from it
my ($prev_min, $prev_max) = $db->selectrow_array("SELECT MIN(statval), MAX(statval) " .
"FROM stats WHERE statcat='pop_interests'");
my $stat_min = int($prev_min - (0.2*$prev_max));
$stat_min = 1 if $stat_min < 1;
my $sth = $db->prepare("SELECT interest, intcount FROM interests WHERE intcount>? " .
"ORDER BY intcount DESC, interest ASC LIMIT 400");
$sth->execute($stat_min);
die $db->errstr if $db->err;
my %ret;
while (my ($int, $count) = $sth->fetchrow_array) {
$ret{$int} = $count;
}
return \%ret;
},
});
# popular memes
LJ::Stats::register_stat
({ 'type' => "global",
'jobname' => "meme",
'statname' => "popmeme",
'handler' =>
sub {
my $db_getter = shift;
return undef unless ref $db_getter eq 'CODE';
my $db = $db_getter->();
return undef unless $db;
return {} if $LJ::DISABLED{'meme'};
my $sth = $db->prepare("SELECT url, count(*) FROM meme " .
"GROUP BY 1 ORDER BY 2 DESC LIMIT 100");
$sth->execute;
die $db->errstr if $db->err;
my %ret;
while (my ($url, $count) = $sth->fetchrow_array) {
$ret{$url} = $count;
}
return \%ret;
},
});
# clients
LJ::Stats::register_stat
({ 'type' => "global",
'jobname' => "clients",
'statname' => "client",
'handler' =>
sub {
my $db_getter = shift;
return undef unless ref $db_getter eq 'CODE';
my $db = $db_getter->();
return undef unless $db;
return {} if $LJ::DISABLED{'clientversionlog'};
my $usertotal = $db->selectrow_array("SELECT MAX(userid) FROM user");
my $blocks = LJ::Stats::num_blocks($usertotal);
my %ret;
foreach my $block (1..$blocks) {
my ($low, $high) = LJ::Stats::get_block_bounds($block);
$db = $db_getter->(); # revalidate connection
my $sth = $db->prepare("SELECT c.client, COUNT(*) AS 'count' FROM clients c, clientusage cu " .
"WHERE c.clientid=cu.clientid AND cu.userid BETWEEN $low AND $high " .
"AND cu.lastlogin > DATE_SUB(NOW(), INTERVAL 30 DAY) GROUP BY 1 ORDER BY 2");
$sth->execute;
die $db->errstr if $db->err;
while ($_ = $sth->fetchrow_hashref) {
$ret{$_->{'client'}} += $_->{'count'};
}
print LJ::Stats::block_status_line($block, $blocks);
}
return \%ret;
},
});
# user table analysis
LJ::Stats::register_stat
({ 'type' => "global",
'jobname' => "users",
'statname' => ["account", "newbyday", "age", "userinfo"],
'handler' =>
sub {
my $db_getter = shift;
return undef unless ref $db_getter eq 'CODE';
my $db = $db_getter->();
return undef unless $db;
my $usertotal = $db->selectrow_array("SELECT MAX(userid) FROM user");
my $blocks = LJ::Stats::num_blocks($usertotal);
my %ret; # return hash, (statname => { arg => val } since 'statname' is arrayref above
# iterate over user table in batches
foreach my $block (1..$blocks) {
my ($low, $high) = LJ::Stats::get_block_bounds($block);
# user query: gets user,caps,age,status,allow_getljnews
$db = $db_getter->(); # revalidate connection
my $sth = $db->prepare
("SELECT user, caps, " .
"FLOOR((TO_DAYS(NOW())-TO_DAYS(bdate))/365.25) AS 'age', " .
"status, allow_getljnews " .
"FROM user WHERE userid BETWEEN $low AND $high");
$sth->execute;
die $db->errstr if $db->err;
while (my $rec = $sth->fetchrow_hashref) {
# account types
my $capnameshort = LJ::name_caps_short($rec->{'caps'});
$ret{'account'}->{$capnameshort}++;
# ages
$ret{'age'}->{$rec->{'age'}}++
if $rec->{'age'} > 4 && $rec->{'age'} < 110;
# users receiving news emails
$ret{'userinfo'}->{'allow_getljnews'}++
if $rec->{'status'} eq "A" && $rec->{'allow_getljnews'} eq "Y";
}
# userusage query: gets timeupdate,datereg,nowdate
my $sth = $db->prepare
("SELECT DATE_FORMAT(timecreate, '%Y-%m-%d') AS 'datereg', " .
"DATE_FORMAT(NOW(), '%Y-%m-%d') AS 'nowdate', " .
"UNIX_TIMESTAMP(timeupdate) AS 'timeupdate' " .
"FROM userusage WHERE userid BETWEEN $low AND $high");
$sth->execute;
die $db->errstr if $db->err;
while (my $rec = $sth->fetchrow_hashref) {
# date registered
$ret{'newbyday'}->{$rec->{'datereg'}}++
unless $rec->{'datereg'} eq $rec->{'nowdate'};
# total user/activity counts
$ret{'userinfo'}->{'total'}++;
if (my $time = $rec->{'timeupdate'}) {
my $now = time();
$ret{'userinfo'}->{'updated'}++;
$ret{'userinfo'}->{'updated_last30'}++ if $time > $now-60*60*24*30;
$ret{'userinfo'}->{'updated_last7'}++ if $time > $now-60*60*24*7;
$ret{'userinfo'}->{'updated_last1'}++ if $time > $now-60*60*24*1;
}
}
print LJ::Stats::block_status_line($block, $blocks);
}
return \%ret;
},
});
LJ::Stats::register_stat
({ 'type' => "clustered",
'jobname' => "countries",
'statname' => "country",
'handler' =>
sub {
my $db_getter = shift;
return undef unless ref $db_getter eq 'CODE';
my $db = $db_getter->();
my $cid = shift;
return undef unless $db && $cid;
my $upc = LJ::get_prop("user", "country");
die "Can't find country userprop. Database populated?\n" unless $upc;
my $usertotal = $db->selectrow_array("SELECT MAX(userid) FROM userproplite2");
my $blocks = LJ::Stats::num_blocks($usertotal);
my %ret;
foreach my $block (1..$blocks) {
my ($low, $high) = LJ::Stats::get_block_bounds($block);
$db = $db_getter->(); # revalidate connection
my $sth = $db->prepare("SELECT u.value, COUNT(*) AS 'count' FROM userproplite2 u " .
"LEFT JOIN clustertrack2 c ON u.userid=c.userid " .
"WHERE u.upropid=? AND u.value<>'' AND u.userid=c.userid " .
"AND u.userid BETWEEN $low AND $high " .
"AND (c.clusterid IS NULL OR c.clusterid=?)" .
"GROUP BY 1 ORDER BY 2");
$sth->execute($upc->{'id'}, $cid);
die "clusterid: $cid, " . $db->errstr if $db->err;
while ($_ = $sth->fetchrow_hashref) {
$ret{$_->{'value'}} += $_->{'count'};
}
print LJ::Stats::block_status_line($block, $blocks);
}
return \%ret;
},
});
LJ::Stats::register_stat
({ 'type' => "clustered",
'jobname' => "states",
'statname' => "stateus",
'handler' =>
sub {
my $db_getter = shift;
return undef unless ref $db_getter eq 'CODE';
my $db = $db_getter->();
my $cid = shift;
return undef unless $db && $cid;
my $upc = LJ::get_prop("user", "country");
die "Can't find country userprop. Database populated?\n" unless $upc;
my $ups = LJ::get_prop("user", "state");
die "Can't find state userprop. Database populated?\n" unless $ups;
my $usertotal = $db->selectrow_array("SELECT MAX(userid) FROM userproplite2");
my $blocks = LJ::Stats::num_blocks($usertotal);
my %ret;
foreach my $block (1..$blocks) {
my ($low, $high) = LJ::Stats::get_block_bounds($block);
$db = $db_getter->(); # revalidate connection
my $sth = $db->prepare("SELECT ua.value, COUNT(*) AS 'count' " .
"FROM userproplite2 ua, userproplite2 ub " .
"WHERE ua.userid=ub.userid AND ua.upropid=? AND " .
"ub.upropid=? and ub.value='US' AND ub.value<>'' " .
"AND ua.userid BETWEEN $low AND $high " .
"GROUP BY 1 ORDER BY 2");
$sth->execute($ups->{'id'}, $upc->{'id'});
die $db->errstr if $db->err;
while ($_ = $sth->fetchrow_hashref) {
$ret{$_->{'value'}} += $_->{'count'};
}
print LJ::Stats::block_status_line($block, $blocks);
}
return \%ret;
},
});
LJ::Stats::register_stat
({ 'type' => "clustered",
'jobname' => "gender",
'statname' => "gender",
'handler' =>
sub {
my $db_getter = shift;
return undef unless ref $db_getter eq 'CODE';
my $db = $db_getter->();
my $cid = shift;
return undef unless $db && $cid;
my $upg = LJ::get_prop("user", "gender");
die "Can't find gender userprop. Database populated?\n" unless $upg;
my $usertotal = $db->selectrow_array("SELECT MAX(userid) FROM userproplite2");
my $blocks = LJ::Stats::num_blocks($usertotal);
my %ret;
foreach my $block (1..$blocks) {
my ($low, $high) = LJ::Stats::get_block_bounds($block);
$db = $db_getter->(); # revalidate connection
my $sth = $db->prepare("SELECT value, COUNT(*) AS 'count' FROM userproplite2 up " .
"LEFT JOIN clustertrack2 c ON up.userid=c.userid " .
"WHERE up.upropid=? AND up.userid BETWEEN $low AND $high " .
"AND (c.clusterid IS NULL OR c.clusterid=?) GROUP BY 1");
$sth->execute($upg->{'id'}, $cid);
die "clusterid: $cid, " . $db->errstr if $db->err;
while ($_ = $sth->fetchrow_hashref) {
$ret{$_->{'value'}} += $_->{'count'};
}
print LJ::Stats::block_status_line($block, $blocks);
}
return \%ret;
},
});
# run stats
LJ::Stats::run_stats(@which);
#### dump to text file
print "-I- Dumping to a text file.\n";
{
my $dbh = LJ::Stats::get_db("dbh");
my $sth = $dbh->prepare("SELECT statcat, statkey, statval FROM stats ORDER BY 1, 2");
$sth->execute;
die $dbh->errstr if $dbh->err;
open (OUT, ">$LJ::HTDOCS/stats/stats.txt");
while (my @row = $sth->fetchrow_array) {
next if grep { $row[0] eq $_ } @LJ::PRIVATE_STATS;
print OUT join("\t", @row), "\n";
}
close OUT;
}
print "-I- Done.\n";
};
$maint{'genstats_size'} = sub {
LJ::Stats::register_stat
({ 'type' => "global",
'jobname' => "size-accounts",
'statname' => "size",
'handler' =>
sub {
my $db_getter = shift;
return undef unless ref $db_getter eq 'CODE';
my $db = $db_getter->();
return undef unless $db;
# not that this isn't a total of current accounts (some rows may have
# been deleted), but rather a total of accounts ever created
my $size = $db->selectrow_array("SELECT MAX(userid) FROM user");
return { 'accounts' => $size };
},
});
LJ::Stats::register_stat
({ 'type' => "clustered",
'jobname' => "size-accounts_active",
'statname' => "size",
'handler' =>
sub {
my $db_getter = shift;
return undef unless ref $db_getter eq 'CODE';
my $db = $db_getter->();
return undef unless $db;
my $period = 30; # one month is considered active
my $active = $db->selectrow_array
("SELECT COUNT(*) FROM clustertrack2 WHERE ".
"timeactive > UNIX_TIMESTAMP()-86400*$period");
return { 'accounts_active' => $active };
},
});
print "-I- Generating account size stats.\n";
LJ::Stats::run_stats("size-accounts", "size-accounts_active");
print "-I- Done.\n";
};
$maint{'genstats_weekly'} = sub
{
LJ::Stats::register_stat
({ 'type' => "global",
'jobname' => "supportrank",
'statname' => "supportrank",
'handler' =>
sub {
my $db_getter = shift;
return undef unless ref $db_getter eq 'CODE';
my $db = $db_getter->();
return undef unless $db;
my %supportrank;
my $rank = 0;
my $lastpoints = 0;
my $buildup = 0;
my $sth = $db->prepare
("SELECT u.userid, SUM(sp.points) AS 'points' " .
"FROM user u, supportpoints sp " .
"WHERE u.userid=sp.userid GROUP BY 1 ORDER BY 2 DESC");
$sth->execute;
die $db->errstr if $db->err;
while ($_ = $sth->fetchrow_hashref) {
if ($lastpoints != $_->{'points'}) {
$lastpoints = $_->{'points'};
$rank += (1 + $buildup);
$buildup = 0;
} else {
$buildup++;
}
$supportrank{$_->{'userid'}} = $rank;
}
# move old 'supportrank' stat to supportrank_prev
# no API for this :-/
{
my $dbh = LJ::Stats::get_db("dbh");
$dbh->do("DELETE FROM stats WHERE statcat='supportrank_prev'");
$dbh->do("UPDATE stats SET statcat='supportrank_prev' WHERE statcat='supportrank'");
}
return \%supportrank;
}
});
print "-I- Generating weekly stats.\n";
LJ::Stats::run_stats('supportrank');
print "-I- Done.\n";
};
$maint{'build_randomuserset'} = sub
{
## this sets up the randomuserset table daily (or whenever) that htdocs/random.bml uses to
## find a random user that is both 1) publicly listed in the directory, and 2) updated
## within the past 24 hours.
## note that if a user changes their privacy setting to not be in the database, it'll take
## up to 24 hours for them to be removed from the random.bml listing, but that's acceptable.
my $dbh = LJ::get_db_writer();
print "-I- Building randomuserset.\n";
$dbh->do("TRUNCATE TABLE randomuserset");
$dbh->do("REPLACE INTO randomuserset (userid) " .
"SELECT uu.userid FROM userusage uu, user u " .
"WHERE u.userid=uu.userid AND u.allow_infoshow='Y' " .
"AND uu.timeupdate > DATE_SUB(NOW(), INTERVAL 1 DAY) ORDER BY RAND() LIMIT 5000");
my $num = $dbh->selectrow_array("SELECT MAX(rid) FROM randomuserset");
$dbh->do("REPLACE INTO stats (statcat, statkey, statval) " .
"VALUES ('userinfo', 'randomcount', $num)");
print "-I- Done.\n";
};
$maint{'memeclean'} = sub
{
my $dbh = LJ::get_db_writer();
print "-I- Cleaning memes.\n";
my $sth = $dbh->prepare("SELECT statkey FROM stats WHERE statcat='popmeme'");
$sth->execute;
die $dbh->errstr if $dbh->err;
while (my $url = $sth->fetchrow_array) {
my $copy = $url;
LJ::run_hooks("canonicalize_url", \$copy);
unless ($copy) {
my $d = $dbh->quote($url);
$dbh->do("DELETE FROM stats WHERE statcat='popmeme' AND statkey=$d");
print " deleting: $url\n";
}
}
print "-I- Done.\n";
};
1;

View File

@@ -0,0 +1,122 @@
#!/usr/bin/perl
#
use GD::Graph::bars;
$maint{'genstatspics'} = sub
{
my $dbh = LJ::get_db_writer();
my $sth;
### get posts by day data from summary table
print "-I- new accounts by day.\n";
$sth = $dbh->prepare("SELECT DATE_FORMAT(statkey, '%m-%d') AS 'day', statval AS 'new' FROM stats WHERE statcat='newbyday' ORDER BY statkey DESC LIMIT 60");
$sth->execute;
if ($dbh->err) { die $dbh->errstr; }
my @data;
my $i;
my $max;
while ($_ = $sth->fetchrow_hashref)
{
my $val = $_->{'new'};
unshift @{$data[0]}, ($i++ % 5 == 0 ? $_->{'day'} : "");
unshift @{$data[1]}, $val;
if ($val > $max) { $max = $val; }
}
# posts by day graph
my $g = GD::Graph::bars->new(520, 350);
$g->set(
x_label => 'Day',
y_label => 'Accounts',
title => 'New accounts per day',
tranparent => 0,
y_max_value => $max,
);
my $gd = $g->plot(\@data);
open(IMG, ">$LJ::HTDOCS/stats/newbyday.png") or die $!;
binmode IMG;
print IMG $gd->png;
close IMG;
unless ($LJ::DISABLED{'stats-postsbyday'}) {
print "-I- posts in last 60 days.\n";
### suck the data in
$sth = $dbh->prepare("SELECT DATE_FORMAT(statkey, '%m-%d') AS 'day', statval AS 'posts' FROM stats WHERE statcat='postsbyday' ORDER BY statkey DESC LIMIT 60");
$sth->execute;
if ($dbh->err) { die $dbh->errstr; }
### analyze the last 60 days data
my @data;
my $i;
my $max;
while ($_ = $sth->fetchrow_hashref)
{
my $val = $_->{'posts'};
unshift @{$data[0]}, ($i++ % 5 == 0 ? $_->{'day'} : "");
unshift @{$data[1]}, $val;
if ($val > $max) { $max = $val; }
}
# posts by day graph
my $g = GD::Graph::bars->new(520, 350);
$g->set(
x_label => 'Day',
y_label => 'Posts',
title => 'Posts per day',
tranparent => 0,
y_max_value => $max,
);
my $gd = $g->plot(\@data);
open(IMG, ">$LJ::HTDOCS/stats/postsbyday.png") or die $!;
binmode IMG;
print IMG $gd->png;
close IMG;
print "-I- posts by week.\n";
### suck the data in
$sth = $dbh->prepare("SELECT DATE_FORMAT(statkey, '%X-%V') AS 'week', SUM(statval) AS 'posts' FROM stats WHERE statcat='postsbyday' AND DATE_FORMAT(statkey, '%X-%V') <> DATE_FORMAT(NOW(), '%X-%V') AND statkey>'1999-06-01' GROUP BY 1 ORDER BY statkey DESC");
$sth->execute;
if ($dbh->err) { die $dbh->errstr; }
### analyze the last 60 days data
my @data;
my $i;
my $max;
while ($_ = $sth->fetchrow_hashref)
{
my $val = $_->{'posts'};
unshift @{$data[0]}, ($i++ % 10 == 0 ? $_->{'week'} : "");
unshift @{$data[1]}, $val;
if ($val > $max) { $max = $val; }
}
# posts by week graph
my $g = GD::Graph::bars->new(520, 350);
$g->set(
x_label => 'Week',
y_label => 'Posts',
title => 'Posts per week',
tranparent => 0,
y_max_value => $max,
);
my $gd = $g->plot(\@data);
open(IMG, ">$LJ::HTDOCS/stats/postsbyweek.png") or die $!;
binmode IMG;
print IMG $gd->png;
close IMG;
}
print "-I- done.\n";
};
1;

513
livejournal/bin/maint/synsuck.pl Executable file
View File

@@ -0,0 +1,513 @@
#!/usr/bin/perl
#
use strict;
use vars qw(%maint %maintinfo);
use lib "$ENV{'LJHOME'}/cgi-bin"; # extra XML::Encoding files in cgi-bin/XML/*
use LWP::UserAgent;
use XML::RSS;
use HTTP::Status;
require "ljprotocol.pl";
require "parsefeed.pl";
require "cleanhtml.pl";
$maintinfo{'synsuck'}{opts}{locking} = "per_host";
$maint{'synsuck'} = sub
{
my $maxcount = shift || 0;
my $verbose = $LJ::LJMAINT_VERBOSE;
my %child_jobs; # child pid => [ userid, lock ]
my $process_user = sub {
my $urow = shift;
return unless $urow;
my ($user, $userid, $synurl, $lastmod, $etag, $readers) =
map { $urow->{$_} } qw(user userid synurl lastmod etag numreaders);
# we're a child process now, need to invalidate caches and
# get a new database handle
LJ::start_request();
my $dbh = LJ::get_db_writer();
# see if things have changed since we last looked and acquired the lock.
# otherwise we could 1) check work, 2) get lock, and between 1 and 2 another
# process could do both steps. we don't want to duplicate work already done.
my $now_checknext = $dbh->selectrow_array("SELECT checknext FROM syndicated ".
"WHERE userid=?", undef, $userid);
return if $now_checknext ne $urow->{checknext};
my $ua = LWP::UserAgent->new("timeout" => 10);
my $reader_info = $readers ? "; $readers readers" : "";
$ua->agent("$LJ::SITENAME ($LJ::ADMIN_EMAIL; for $LJ::SITEROOT/users/$user/" . $reader_info . ")");
my $delay = sub {
my $minutes = shift;
my $status = shift;
# add some random backoff to avoid waves building up
$minutes += int(rand(5));
$dbh->do("UPDATE syndicated SET lastcheck=NOW(), checknext=DATE_ADD(NOW(), ".
"INTERVAL ? MINUTE), laststatus=? WHERE userid=?",
undef, $minutes, $status, $userid);
};
print "[$$] Synsuck: $user ($synurl)\n" if $verbose;
my $req = HTTP::Request->new("GET", $synurl);
$req->header('If-Modified-Since', LJ::time_to_http($lastmod))
if $lastmod;
$req->header('If-None-Match', $etag)
if $etag;
my ($content, $too_big);
my $res = $ua->request($req, sub {
if (length($content) > 1024*150) { $too_big = 1; return; }
$content .= $_[0];
}, 4096);
if ($too_big) { $delay->(60, "toobig"); return; }
if ($res->is_error()) {
# http error
print "HTTP error!\n" if $verbose;
# overload parseerror here because it's already there -- we'll
# never have both an http error and a parse error on the
# same request
$delay->(3*60, "parseerror");
LJ::set_userprop($userid, "rssparseerror", $res->status_line());
return;
}
# check if not modified
if ($res->code() == RC_NOT_MODIFIED) {
print " not modified.\n" if $verbose;
$delay->($readers ? 60 : 24*60, "notmodified");
return;
}
# WARNING: blatant XML spec violation ahead...
#
# Blogger doesn't produce valid XML, since they don't handle encodings
# correctly. So if we see they have no encoding (which is UTF-8 implictly)
# but it's not valid UTF-8, say it's Windows-1252, which won't
# cause XML::Parser to barf... but there will probably be some bogus characters.
# better than nothing I guess. (personally, I'd prefer to leave it broken
# and have people bitch at Blogger, but jwz wouldn't stop bugging me)
# XML::Parser doesn't include Windows-1252, but we put it in cgi-bin/XML/* for it
# to find.
my $encoding;
if ($content =~ /<\?xml.+?>/ && $& =~ /encoding=([\"\'])(.+?)\1/) {
$encoding = lc($2);
}
if (! $encoding && ! LJ::is_utf8($content)) {
$content =~ s/\?>/ encoding='windows-1252' \?>/;
}
# WARNING: another hack...
# People produce what they think is iso-8859-1, but they include
# Windows-style smart quotes. Check for invalid iso-8859-1 and correct.
if ($encoding =~ /^iso-8859-1$/i && $content =~ /[\x80-\x9F]/) {
# They claimed they were iso-8859-1, but they are lying.
# Assume it was Windows-1252.
print "Invalid ISO-8859-1; assuming Windows-1252...\n" if $verbose;
$content =~ s/encoding=([\"\'])(.+?)\1/encoding='windows-1252'/;
}
# parsing time...
my ($feed, $error) = LJ::ParseFeed::parse_feed($content);
if ($error) {
# parse error!
print "Parse error! $error\n" if $verbose;
$delay->(3*60, "parseerror");
$error =~ s! at /.*!!;
$error =~ s/^\n//; # cleanup of newline at the beggining of the line
LJ::set_userprop($userid, "rssparseerror", $error);
return;
}
# another sanity check
unless (ref $feed->{'items'} eq "ARRAY") {
$delay->(3*60, "noitems");
return;
}
my @items = reverse @{$feed->{'items'}};
# take most recent 20
splice(@items, 0, @items-20) if @items > 20;
# delete existing items older than the age which can show on a
# friends view.
my $su = LJ::load_userid($userid);
my $udbh = LJ::get_cluster_master($su);
unless ($udbh) {
$delay->(15, "nodb");
return;
}
# TAG:LOG2:synsuck_delete_olderitems
my $secs = ($LJ::MAX_FRIENDS_VIEW_AGE || 3600*24*14)+0; # 2 week default.
my $sth = $udbh->prepare("SELECT jitemid, anum FROM log2 WHERE journalid=? AND ".
"logtime < DATE_SUB(NOW(), INTERVAL $secs SECOND)");
$sth->execute($userid);
die $udbh->errstr if $udbh->err;
while (my ($jitemid, $anum) = $sth->fetchrow_array) {
print "DELETE itemid: $jitemid, anum: $anum... \n" if $verbose;
if (LJ::delete_entry($su, $jitemid, 0, $anum)) {
print "success.\n" if $verbose;
} else {
print "fail.\n" if $verbose;
}
}
# determine if link tags are good or not, where good means
# "likely to be a unique per item". some feeds have the same
# <link> element for each item, which isn't good.
# if we have unique ids, we don't compare link tags
my ($compare_links, $have_ids) = 0;
{
my %link_seen;
foreach my $it (@items) {
$have_ids = 1 if $it->{'id'};
next unless $it->{'link'};
$link_seen{$it->{'link'}} = 1;
}
$compare_links = 1 if !$have_ids and $feed->{'type'} eq 'rss' and
scalar(keys %link_seen) == scalar(@items);
}
# if we have unique links/ids, load them for syndicated
# items we already have on the server. then, if we have one
# already later and see it's changed, we'll do an editevent
# instead of a new post.
my %existing_item = ();
if ($have_ids || $compare_links) {
my $p = $have_ids ? LJ::get_prop("log", "syn_id") :
LJ::get_prop("log", "syn_link");
my $sth = $udbh->prepare("SELECT jitemid, value FROM logprop2 WHERE ".
"journalid=? AND propid=? LIMIT 1000");
$sth->execute($su->{'userid'}, $p->{'id'});
while (my ($itemid, $id) = $sth->fetchrow_array) {
$existing_item{$id} = $itemid;
}
}
# post these items
my $newcount = 0;
my $errorflag = 0;
my $mindate; # "yyyy-mm-dd hh:mm:ss";
my $notedate = sub {
my $date = shift;
$mindate = $date if ! $mindate || $date lt $mindate;
};
foreach my $it (@items) {
# remove the SvUTF8 flag. it's still UTF-8, but
# we don't want perl knowing that and fucking stuff up
# for us behind our back in random places all over
# http://zilla.livejournal.org/show_bug.cgi?id=1037
foreach my $attr (qw(subject text link)) {
$it->{$attr} = pack('C*', unpack('C*', $it->{$attr}));
}
my $dig = LJ::md5_struct($it)->b64digest;
my $prevadd = $dbh->selectrow_array("SELECT MAX(dateadd) FROM synitem WHERE ".
"userid=? AND item=?", undef,
$userid, $dig);
if ($prevadd) {
$notedate->($prevadd);
next;
}
my $now_dateadd = $dbh->selectrow_array("SELECT NOW()");
die "unexpected format" unless $now_dateadd =~ /^\d\d\d\d\-\d\d\-\d\d \d\d:\d\d:\d\d$/;
$dbh->do("INSERT INTO synitem (userid, item, dateadd) VALUES (?,?,?)",
undef, $userid, $dig, $now_dateadd);
$notedate->($now_dateadd);
$newcount++;
print "[$$] $dig - $it->{'subject'}\n" if $verbose;
$it->{'text'} =~ s/^\s+//;
$it->{'text'} =~ s/\s+$//;
my $htmllink;
if (defined $it->{'link'}) {
$htmllink = "<p class='ljsyndicationlink'>" .
"<a href='$it->{'link'}'>$it->{'link'}</a></p>";
}
# Show the <guid> link if it's present and different than the
# <link>.
# [zilla: 267] Patch: Chaz Meyers <lj-zilla@thechaz.net>
if ( defined $it->{'id'} && $it->{'id'} ne $it->{'link'}
&& $it->{'id'} =~ m!^http://! )
{
$htmllink .= "<p class='ljsyndicationlink'>" .
"<a href='$it->{'id'}'>$it->{'id'}</a></p>";
}
# rewrite relative URLs to absolute URLs, but only invoke the HTML parser
# if we see there's some image or link tag, to save us some work if it's
# unnecessary (the common case)
if ($it->{'text'} =~ /<(?:img|a)\b/i) {
# TODO: support XML Base? http://www.w3.org/TR/xmlbase/
my $base_href = $it->{'link'} || $synurl;
LJ::CleanHTML::resolve_relative_urls(\$it->{'text'}, $base_href);
}
# $own_time==1 means we took the time from the feed rather than localtime
my ($own_time, $year, $mon, $day, $hour, $min);
if ($it->{'time'} &&
$it->{'time'} =~ m!^(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d)!) {
$own_time = 1;
($year, $mon, $day, $hour, $min) = ($1,$2,$3,$4,$5);
} else {
$own_time = 0;
my @now = localtime();
($year, $mon, $day, $hour, $min) =
($now[5]+1900, $now[4]+1, $now[3], $now[2], $now[1]);
}
my $command = "postevent";
my $req = {
'username' => $user,
'ver' => 1,
'subject' => $it->{'subject'},
'event' => "$htmllink$it->{'text'}",
'year' => $year,
'mon' => $mon,
'day' => $day,
'hour' => $hour,
'min' => $min,
'props' => {
'syn_link' => $it->{'link'},
},
};
$req->{'props'}->{'syn_id'} = $it->{'id'}
if $it->{'id'};
my $flags = {
'nopassword' => 1,
};
# if the post contains html linebreaks, assume it's preformatted.
if ($it->{'text'} =~ /<(?:p|br)\b/i) {
$req->{'props'}->{'opt_preformatted'} = 1;
}
# do an editevent if we've seen this item before
my $id = $have_ids ? $it->{'id'} : $it->{'link'};
my $old_itemid = $existing_item{$id};
if ($id && $old_itemid) {
$newcount--; # cancel increment above
$command = "editevent";
$req->{'itemid'} = $old_itemid;
# the editevent requires us to resend the date info, which
# we have to go fetch first, in case the feed doesn't have it
# TAG:LOG2:synsuck_fetch_itemdates
unless($own_time) {
my $origtime =
$udbh->selectrow_array("SELECT eventtime FROM log2 WHERE ".
"journalid=? AND jitemid=?", undef,
$su->{'userid'}, $old_itemid);
$origtime =~ /(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d)/;
$req->{'year'} = $1;
$req->{'mon'} = $2;
$req->{'day'} = $3;
$req->{'hour'} = $4;
$req->{'min'} = $5;
}
}
my $err;
my $res = LJ::Protocol::do_request($command, $req, \$err, $flags);
unless ($res && ! $err) {
print " Error: $err\n" if $verbose;
$errorflag = 1;
}
}
# delete some unneeded synitems. the limit 1000 is because
# historically we never deleted and there are accounts with
# 222,000 items on a myisam table, and that'd be quite the
# delete hit.
# the 14 day interval is because if a remote site deleted an
# entry, it's possible for the oldest item that was previously
# gone to reappear, and we want to protect against that a
# little.
if ($LJ::SYNITEM_CLEAN) {
$dbh->do("DELETE FROM synitem WHERE userid=? AND ".
"dateadd < ? - INTERVAL 14 DAY LIMIT 1000",
undef, $userid, $mindate);
}
$dbh->do("UPDATE syndicated SET oldest_ourdate=? WHERE userid=?",
undef, $mindate, $userid);
# bail out if errors, and try again shortly
if ($errorflag) {
$delay->(30, "posterror");
return;
}
# update syndicated account's userinfo if necessary
LJ::load_user_props($su, "url", "urlname");
{
my $title = $feed->{'title'};
$title = $su->{'user'} unless LJ::is_utf8($title);
$title =~ s/[\n\r]//g;
if ($title && $title ne $su->{'name'}) {
LJ::update_user($su, { name => $title });
LJ::set_userprop($su, "urlname", $title);
}
my $link = $feed->{'link'};
if ($link && $link ne $su->{'url'}) {
LJ::set_userprop($su, "url", $link);
}
my $des = $feed->{'description'};
if ($des) {
my $bio;
if ($su->{'has_bio'} eq "Y") {
$bio = $udbh->selectrow_array("SELECT bio FROM userbio WHERE userid=?", undef,
$su->{'userid'});
}
if ($bio ne $des && $bio !~ /\[LJ:KEEP\]/) {
if ($des) {
$su->do("REPLACE INTO userbio (userid, bio) VALUES (?,?)", undef,
$su->{'userid'}, $des);
} else {
$su->do("DELETE FROM userbio WHERE userid=?", undef, $su->{'userid'});
}
LJ::update_user($su, { has_bio => ($des ? "Y" : "N") });
LJ::MemCache::delete([$su->{'userid'}, "bio:$su->{'userid'}"]);
}
}
}
my $r_lastmod = LJ::http_to_time($res->header('Last-Modified'));
my $r_etag = $res->header('ETag');
# decide when to poll next (in minutes).
# FIXME: this is super lame. (use hints in RSS file!)
my $int = $newcount ? 30 : 60;
my $status = $newcount ? "ok" : "nonew";
my $updatenew = $newcount ? ", lastnew=NOW()" : "";
# update reader count while we're changing things, but not
# if feed is stale (minimize DB work for inactive things)
if ($newcount || ! defined $readers) {
$readers = $dbh->selectrow_array("SELECT COUNT(*) FROM friends WHERE ".
"friendid=?", undef, $userid);
}
# if readers are gone, don't check for a whole day
$int = 60*24 unless $readers;
$dbh->do("UPDATE syndicated SET checknext=DATE_ADD(NOW(), INTERVAL $int MINUTE), ".
"lastcheck=NOW(), lastmod=?, etag=?, laststatus=?, numreaders=? $updatenew ".
"WHERE userid=$userid", undef, $r_lastmod, $r_etag, $status, $readers);
};
###
### child process management
###
# get the next user to be processed
my @all_users;
my $get_next_user = sub {
return shift @all_users if @all_users;
# need to get some more rows
my $dbh = LJ::get_db_writer();
my $current_jobs = join(",", map { $dbh->quote($_->[0]) } values %child_jobs);
my $in_sql = " AND u.userid NOT IN ($current_jobs)" if $current_jobs;
my $sth = $dbh->prepare("SELECT u.user, s.userid, s.synurl, s.lastmod, " .
" s.etag, s.numreaders, s.checknext " .
"FROM user u, syndicated s " .
"WHERE u.userid=s.userid AND u.statusvis='V' " .
"AND s.checknext < NOW()$in_sql " .
"ORDER BY RAND() LIMIT 500");
$sth->execute;
while (my $urow = $sth->fetchrow_hashref) {
push @all_users, $urow;
}
return undef unless @all_users;
return shift @all_users;
};
# fork and manage child processes
my $max_threads = $LJ::SYNSUCK_MAX_THREADS || 1;
print "[$$] PARENT -- using $max_threads workers\n" if $verbose;
my $threads = 0;
my $userct = 0;
my $keep_forking = 1;
while ( $maxcount == 0 || $userct < $maxcount ) {
if ($threads < $max_threads && $keep_forking) {
my $urow = $get_next_user->();
unless ($urow) {
$keep_forking = 0;
next;
}
my $lockname = "synsuck-user-" . $urow->{user};
my $lock = LJ::locker()->trylock($lockname);
next unless $lock;
print "Got lock on '$lockname'. Running\n" if $verbose;
# spawn a new process
if (my $pid = fork) {
# we are a parent, nothing to do?
$child_jobs{$pid} = [$urow->{'userid'}, $lock];
$threads++;
$userct++;
} else {
# handles won't survive the fork
LJ::disconnect_dbs();
$process_user->($urow);
exit 0;
}
# wait for child(ren) to die
} else {
my $child = wait();
last if $child == -1;
delete $child_jobs{$child};
$threads--;
}
}
# Now wait on any remaining children so we don't leave zombies behind.
while ( %child_jobs ) {
my $child = wait();
last if $child == -1;
delete $child_jobs{ $child };
$threads--;
}
print "[$$] $userct users processed\n" if $verbose;
return;
};
1;
# Local Variables:
# mode: perl
# c-basic-indent: 4
# indent-tabs-mode: nil
# End:

View File

@@ -0,0 +1,27 @@
bday.pl:
bdaymail - Sends people birthday wishes & notifications
stats.pl:
build_randomuserset - builds/cleans table of users applicable for inclusion in random listings
genstats - Generates the nightly statistics
genstats_size - Generates the site size stats
genstats_weekly - Generates the weekly statistics
memeclean - Removes things from meme summary that are excluded by new URL cleaner rules
statspics.pl:
genstatspics - Makes a bunch of graphs to show on the statistics page.
clean_caches.pl:
clean_caches - removes old cache files
synsuck.pl:
synsuck - Polls needed remote, syndicated RSS/etc and updates journals.
captcha.pl:
gen_audio_captchas - Generate any needed new audio challenges.
gen_image_captchas - Generate any needed new graphical challenges.
clean_captchas - Purge old challenges from the database.
generic.pl:
joinmail - Generates daily email digests for community join requests
clean_spamreports - Clean out data from the spamreports table older than 90 days.

1000
livejournal/bin/moveucluster.pl Executable file

File diff suppressed because it is too large Load Diff

2750
livejournal/bin/moveuclusterd.pl Executable file

File diff suppressed because it is too large Load Diff

253
livejournal/bin/qbufferd.pl Executable file
View File

@@ -0,0 +1,253 @@
#!/usr/bin/perl
#
# <LJDEP>
# lib: Proc::ProcessTable, cgi-bin/ljlib.pl
# </LJDEP>
use strict;
use Getopt::Long
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
require "$ENV{'LJHOME'}/cgi-bin/supportlib.pl";
require "$ENV{'LJHOME'}/cgi-bin/ljcmdbuffer.pl";
my $opt_foreground;
my $opt_debug;
my $opt_stop;
exit 1 unless GetOptions('foreground' => \$opt_foreground,
'debug' => \$opt_debug,
'stop' => \$opt_stop,
);
BEGIN {
$LJ::OPTMOD_PROCTABLE = eval "use Proc::ProcessTable; 1;";
}
my $DELAY = $LJ::QBUFFERD_DELAY || 15;
my $pidfile = $LJ::QBUFFERD_PIDFILE || "$ENV{'LJHOME'}/var/qbufferd.pid";
my $pid;
if (-e $pidfile) {
open (PID, $pidfile);
chomp ($pid = <PID>);
close PID;
if ($opt_stop) {
if (kill 15, $pid) {
print "Shutting down qbufferd.\n";
} else {
print "qbufferd not running?\n";
}
exit;
}
if ($LJ::OPTMOD_PROCTABLE) {
my $processes = Proc::ProcessTable->new()->table;
if (grep { $_->cmndline =~ /perl.+qbufferd/ && $_->pid != $$ } @$processes) {
exit;
}
} else {
if (kill 0, $pid) {
# seems to still be running (at least something is with that pid)
exit;
}
}
}
if ($opt_stop) {
print "qbufferd not running?\n";
exit;
}
$SIG{'INT'} = \&stop_qbufferd;
$SIG{'TERM'} = \&stop_qbufferd;
$SIG{'HUP'} = sub {
# nothing. maybe later make a HUP force a flush?
};
if (!$opt_foreground && ($pid = fork))
{
unless (open (PID, ">$pidfile")) {
kill 15, $pid;
die "Couldn't write PID file. Exiting.\n";
}
print PID $pid, "\n";
close PID;
print "qbufferd started with pid $pid\n";
if (-s $pidfile) { print "pid file written ($pidfile)\n"; }
exit;
}
# Close filehandles unless running in --debug or --foreground mode.
unless ( $opt_debug || $opt_foreground ) {
close STDIN && open STDIN, "</dev/null";
close STDOUT && open STDOUT, "+>&STDIN";
close STDERR && open STDERR, "+>&STDIN";
}
# fork off a separate qbufferd process for all specified
# job types in @LJ::QBUFFERD_ISOLATE, and then
# another process for all other job types. The current process
# will keep tabs on all of those
my %isolated;
my %pids; # job -> pid
my %jobs; # pid -> job
my $working = 0; # 1 for processes that do actual work
my $my_job;
foreach my $job (@LJ::QBUFFERD_ISOLATE) {
$isolated{$job} = 1;
}
foreach my $job (@LJ::QBUFFERD_ISOLATE, "_others_") {
if (my $child = fork) {
# parent.
$pids{$job} = $child;
$jobs{$child} = $job;
next;
} else {
# child.
$0 .= " [$job]";
$my_job = $job;
$working = 1;
last;
}
}
# at this point, $my_job is either the specialized 'cmd' to run, or
# '_others_' to mean everything besides stuff with their own processes.
# $working is 1 for nonempty values of $my_job .
sub stop_qbufferd
{
# stop children
unless ($working) {
foreach my $job (keys %pids) {
my $child = $pids{$job};
print "Killing child pid $child job: $job\n" if $opt_debug;
kill 15, $child;
}
unlink $pidfile;
}
print "Quitting: " . ($working ? "job $my_job" : "parent") . "\n" if $opt_debug;
exit;
}
while(not $working) {
# controlling process's cycle
my $pid;
$pid = wait();
print "Child exited, pid $pid, job $jobs{$pid}\n" if $opt_debug;
if ($jobs{$pid}) {
my $job = $jobs{$pid};
print "Restarting job $job\n" if $opt_debug;
delete $pids{$job};
delete $jobs{$pid};
if (my $child = fork) {
# parent.
$pids{$job} = $child;
$jobs{$child} = $job;
} else {
# child.
$0 .= " [$job]";
$my_job = $job;
$working = 1; # go work
}
}
}
# the actual work begins here
my @all_jobs = qw(delitem weblogscom send_mail support_notify dirty);
foreach my $hook (keys %LJ::HOOKS) {
next unless $hook =~ /^cmdbuf:(\w+):run$/;
push @all_jobs, $1;
}
while (LJ::start_request())
{
my $cycle_start = time();
print "Starting cycle. Job $my_job\n" if $opt_debug;
# syndication (checks RSS that need to be checked)
if ($my_job eq "synsuck") {
system("$ENV{'LJHOME'}/bin/ljmaint.pl", "-v0", "synsuck");
print "Sleeping. Job $my_job\n" if $opt_debug;
my $elapsed = time() - $cycle_start;
sleep ($DELAY-$elapsed) if $elapsed < $DELAY;
next;
}
# do main cluster updates
my $dbh = LJ::get_dbh("master");
unless ($dbh) {
sleep 10;
next;
}
# keep track of what commands we've run the start hook for
my %started;
# handle clusters
foreach my $c (@LJ::CLUSTERS) {
print "Cluster: $c Job: $my_job\n" if $opt_debug;
my $db = LJ::get_cluster_master($c);
next unless $db;
my @check_jobs = ($my_job);
if ($my_job eq "_others_") { @check_jobs = grep { ! $isolated{$_} } @all_jobs; }
foreach my $cmd (@check_jobs) {
my $have_jobs = $db->selectrow_array("SELECT cbid FROM cmdbuffer WHERE cmd=? LIMIT 1",
undef, $cmd);
next unless $have_jobs;
print " Starting $cmd...\n" if $opt_debug;
unless ($started{$cmd}++) {
LJ::Cmdbuffer::flush($dbh, undef, "$cmd:start");
}
LJ::Cmdbuffer::flush($dbh, $db, $cmd);
print " Finished $cmd.\n" if $opt_debug;
# monitor process size and job counts to suicide if necessary
my $size = 0;
if (open(S, "/proc/$$/status")) {
my $file;
{ local $/ = undef; $file = <S>; }
$size = $1 if $file =~ /VmSize:.+?(\d+)/;
close S;
}
# is it our time to go?
my $kill_job_ct = LJ::Cmdbuffer::get_property($cmd, 'kill_job_ct') || 0;
my $kill_mem_size = LJ::Cmdbuffer::get_property($cmd, 'kill_mem_size') || 0;
if ($kill_job_ct && $started{$cmd} >= $kill_job_ct ||
$kill_mem_size && $size >= $kill_mem_size)
{
# trigger reload of current child process
print "Job suicide: $cmd. (size=$size, rpcs=" . ($started{dirty}+0) . ")\n"
if $opt_debug;
# run end hooks before dying
foreach my $cmd (keys %started) {
LJ::Cmdbuffer::flush($dbh, undef, "$cmd:finish");
}
exit 0;
}
}
}
# run the end hook for all commands we've run
foreach my $cmd (keys %started) {
LJ::Cmdbuffer::flush($dbh, undef, "$cmd:finish");
}
print "Sleeping. Job $my_job\n" if $opt_debug;
my $elapsed = time() - $cycle_start;
sleep ($DELAY-$elapsed) if $elapsed < $DELAY;
};

207
livejournal/bin/statserv.pl Executable file
View File

@@ -0,0 +1,207 @@
#!/usr/bin/perl -w
# LiveJournal statistics server. Sits on a UDP port and journals
# information on the incoming hit rate, manages site bans, etc.
# Loosely based on the ljrpcd code to save typing ;)
# <LJDEP>
# lib: IO::Socket Proc::ProcessTable IO::Handle DBI
#
# </LJDEP>
use strict;
use IO::Socket;
use IO::Handle;
use Proc::ProcessTable;
use DBI;
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
# Max message length and port to bind.
my $MAXLEN = 512;
my $PORTNO = 6200;
my $PIDFILE = '/home/lj/var/statserv.pid';
my $LOGDIR = '/home/lj/logs/';
# Maximum amount of hits they can use in five minutes.
my %maxes = ( 'ip' => 15, 'guest' => 20, 'user' => 25 );
# Pid and pidfile.
my $pid;
my $is_parent = 1;
# Socket. Needs to be here for the HUP stuff.
my $sock;
# Cache hash.
my %caches = ();
# Cache array.
my @events = ();
# Exceptions hash (IP range or username as keys)
# If you want some host (such as a big stupid random proxy) to
# be more lenient with the number of hits it can make in five minutes,
# put the value in here. If value is -1, then there is no limit.
my %except = ();
# In case we're shot, unlink the pidfile.
$SIG{TERM} = sub {
unlink($PIDFILE);
exit 1;
};
# Local network bind to.
my $MYNET = '10.0';
if (-e $PIDFILE) {
open (PID, $PIDFILE);
my $tpid;
chomp ($tpid = <PID>);
close PID;
my $processes = Proc::ProcessTable->new()->table;
if (grep { $_->cmndline =~ /statserv/ } @$processes) {
print "Process exists already, quitting.\n";
exit 1;
}
}
print "LiveJournal Statistics Daemon starting up into the background...\n";
if ($pid = fork) {
# Parent, log pid and exit.
open(PID, ">$PIDFILE") or die "Couldn't open $PIDFILE for writing: $!\n";
print PID $pid;
close(PID);
print "Closing ($pid) wrote to $PIDFILE\n";
$is_parent = 1;
exit;
} else {
# This is the child.
my($cmdmsg, $remaddr, $remhost);
# HUP signal handler.
$SIG{HUP} = \&restart_request;
# SIGUSR handler.
$SIG{USR1} = sub { open_logfile(); };
open_logfile();
$sock = IO::Socket::INET->new(LocalPort => "$PORTNO", Proto => 'udp') or die "socket: $@";
# Main loop.
while ($sock->recv($cmdmsg, $MAXLEN)) {
my ($port, $ipaddr) = sockaddr_in($sock->peername);
my $ip_addr = inet_ntoa($ipaddr);
# Make sure it's from around here.
if ($ip_addr !~ m/^$MYNET/) {
print "Got message from an invalid host.\n";
next;
}
# Quick command parsing, since there isn't much to it.
if ($cmdmsg =~ s/^cmd:\s//) {
handle_request($cmdmsg);
next;
}
}
die "recv: $!\n";
}
# Sub to restart the daemon.
sub restart_request {
$sock->close;
unlink($PIDFILE);
exec($0);
}
# Handle the request. This updates the appropriate caches,
# and may set a ban.
# Requests look like:
# cmd: cachename : ip_addr : type : url
# type can be: ip, guest, or user
# If type is "ip" then cachename can be anything. I suggest
# it be set to "ip" as well. If just to save space.
sub handle_request {
my $cmd = shift;
my $now = time();
# Clear expired events.
clean_events($now);
# As of now, we don't care about the URL, really.
if ($cmd =~ m/^(\w+)\s:\s([\d\.]+)\s:\s(\w+)/) {
my $user = $1;
my $ip_addr = $2;
my $type = $3;
# If there was no cookie of any kind, the type
# name is set to "ip" - in this case we up the
# cache number for the IP range.
if ($type eq "ip") {
# This regex is dumb, but the data we have is trustable.
$user = $ip_addr;
$user =~ s/(\d+)\.(\d+)\.(\d+)\.(\d+)/$1\.$2\.$3\./;
}
unless (exists $caches{$user}) {
$caches{$user} = { 'numhit' => 0, 'type' => $type };
}
push @events, [ $user, $now ];
$caches{$user}->{'numhit'}++;
# Now we check to see if they have hit too fast, and ban if so.
if (should_ban($user)) {
# FIXME: For final operation, this should be replaced with
# a call to set_ban(). This is also going to spam a ton,
# but with the "spiffy" algorithm I can't easily nuke a user.
print "Would have banned user $user. Hits: " . $caches{$user}->{'numhit'} . "\n";
}
# After this, "add_stat($user, $type, $url)" should run.
} else {
print "Got a mal-formed request: $cmd\n";
}
}
# Returns 1 if the passed "user" should be banned, 0 if not.
sub should_ban {
my $user = shift;
my $max = $except{$user} || $maxes{$caches{$user}->{'type'}} || 0;
# If it doesn't have a defined class, do we really want it around?
return 1 unless ($max);
return 1 if ($caches{$user}->{'numhit'} > $max);
return 0;
}
# Removes old events, and decrements caches.
sub clean_events {
my $now = shift;
while (@events && $events[0]->[1] < $now - 360) {
my $deadevt = shift @events;
if (--$caches{$deadevt->[0]}->{'numhits'} < 1) {
delete $caches{$deadevt->[0]};
}
}
}
# Placeholder. Sets a ban in the database.
sub set_ban {
}
# Placeholder. Runs various stats collections.
sub add_stat {
}
# Opens a new tagged logfile. Also sets it to the default
# filehandle, sets autoflush, and returns the new handle.
sub open_logfile {
my $now = time();
my $logname = $LOGDIR . "statserv-" . $now . "\.log\n";
my $logfh = new IO::Handle;
open($logfh, ">> $logname") or die "Couldn't open $logname: $!\n";
my $oldfh = select($logfh);
# Make sure the old one is closed.
close($oldfh);
# Set autoflush and return.
$| = 1;
return $logfh;
}

View File

@@ -0,0 +1,33 @@
#!/usr/bin/perl
#
use strict;
require "$ENV{LJHOME}/cgi-bin/ljlib.pl";
my $cid = shift;
die "Usage: truncate-cluster.pl <clusterid>\n" unless $cid =~ /^\d+$/;
my $dbh = LJ::get_db_writer();
my $ct = $dbh->selectrow_array("SELECT COUNT(*) FROM user WHERE clusterid=?", undef, $cid);
die $dbh->errstr if $dbh->err;
if ($ct > 0) {
die "Can't truncate a cluster with users. Cluster \#$cid has $ct users.\n";
}
my $cm = LJ::get_cluster_master({raw=>1}, $cid);
die "Can't get handle to cluster \#$cid\n" unless $cm;
my $size;
foreach my $table (sort (@LJ::USER_TABLES, @LJ::USER_TABLES_LOCAL)) {
my $ts = $cm->selectrow_hashref("SHOW TABLE STATUS like '$table'");
die "Can't get table status for $table\n" unless $ts;
print "Size of $table = $ts->{'Data_length'}\n";
next unless $ts->{'Data_length'};
$cm->do("TRUNCATE TABLE $table");
die $cm->errstr if $cm->err;
$size += $ts->{'Data_length'};
}
print "Total size truncated (excluding indexes): $size\n";

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,72 @@
#!/usr/bin/perl
use strict;
use Getopt::Long;
# load libraries now
use lib "$ENV{'LJHOME'}/cgi-bin";
use LJ::Blob;
use Image::Size ();
require "ljlib.pl";
my $opt_fast;
exit 1 unless
GetOptions("fast" => \$opt_fast,
);
my $clusterid = shift;
die "Usage: blobify_userpics.pl <clusterid>\n"
unless $clusterid;
my $db = LJ::get_cluster_master($clusterid);
die "Invalid/down cluster: $clusterid\n" unless $db;
print "Getting count.\n";
my $total = $db->selectrow_array("SELECT COUNT(*) FROM userpicblob2");
my $done = 0;
my $loop = 1;
while ($loop) {
$loop = 0;
LJ::start_request(); # shrink caches
print "Getting 200.\n";
my $sth = $db->prepare("SELECT userid, picid, imagedata FROM userpicblob2 LIMIT 200");
$sth->execute;
while (my ($uid, $picid, $image) = $sth->fetchrow_array) {
$loop = 1;
my $u = LJ::load_userid($uid);
die "Can't find userid: $uid" unless $u;
# sometimes expunges don't expunge all the way.
if ($u->{'statusvis'} eq "X") {
$db->do("DELETE FROM userpicblob2 WHERE userid=$uid AND picid=$picid");
next;
}
my ($sx, $sy, $fmt) = Image::Size::imgsize(\$image);
die "Unknown format" unless $fmt eq "GIF" || $fmt eq "JPG" || $fmt eq "PNG";
$fmt = lc($fmt);
my $err;
my $rv = LJ::Blob::put($u, "userpic", $fmt, $picid, $image, \$err);
die "Error putting file: $u->{'user'}/$picid\n" unless $rv;
unless ($opt_fast) {
# extra paranoid!
my $get = LJ::Blob::get($u, "userpic", $fmt, $picid);
die "Re-fetch didn't match" unless $get eq $image;
}
$db->do("DELETE FROM userpicblob2 WHERE userid=$uid AND picid=$picid");
$done++;
printf " Moved $uid/$picid.$fmt ($done/$total = %.2f%%)\n", ($done / $total * 100);
}
}
my $end_ct = $db->selectrow_array("SELECT COUNT(*) FROM userpicblob2");
if ($end_ct == 0) {
$db->do("TRUNCATE TABLE userpicblob2");
}
print "Done.\n";

View File

@@ -0,0 +1,77 @@
#!/usr/bin/perl
use strict;
my $clusterid = shift;
die "Usage: compress_cluster <clusterid>\n"
unless $clusterid;
# load libraries now
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
# force this option on, since that's the point of the tool
$LJ::COMPRESS_TEXT = 1;
my $db = LJ::get_cluster_master($clusterid);
die "Invalid/down cluster: $clusterid\n" unless $db;
# table, column, [ prikey1, prikey2 ]
foreach my $t (['logtext2', 'event', ['journalid', 'jitemid']],
['talktext2', 'body', ['journalid', 'jtalkid']]) {
my ($table, $col, $key) = @$t;
my ($pk1, $pk2) = @$key; # 2 sections of primary key
my $total = $db->selectrow_array("SELECT COUNT(*) FROM $table");
print "Processing table: $table [$total total rows]\n";
$db->do("HANDLER $table OPEN");
my $ct = 0;
my $modct = 0;
my $bytes_pre;
my $bytes_post;
my $stats = sub {
printf("%6.2f%% done (mod=%.2f%%, size=%.2f%%),\n",
($ct / $total) * 100,
($modct / $ct) * 100,
($bytes_post / $bytes_pre) * 100);
};
my $loop = 1;
while ($loop) {
my $sth = $db->prepare("HANDLER $table READ `PRIMARY` NEXT LIMIT 100");
$sth->execute;
$loop = 0;
while (my $row = $sth->fetchrow_hashref) {
$loop = 1;
# print status
$stats->() if (++$ct % 1000 == 0);
# try to compress the text
my $orig_len = length($row->{$col});
$bytes_pre += $orig_len;
my $new_text = LJ::text_compress($row->{$col});
my $new_len = length($new_text);
$bytes_post += $new_len;
# do nothing if the "compressed" and uncompressed sizes are the same
next if $new_text eq $row->{$col};
# update this row since it compressed
$db->do("UPDATE $table SET $col=? WHERE $pk1=? AND $pk2=? AND $col=?",
undef, $new_text, $row->{$pk1}, $row->{$pk2}, $row->{$col});
$modct++;
}
}
$stats->();
$db->do("HANDLER $table CLOSE");
print "$ct rows processed, $modct modified\n\n";
}

View File

@@ -0,0 +1,41 @@
#!/usr/bin/perl
#
use strict;
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
my $dbh = LJ::get_dbh("master");
my $user = shift @ARGV;
my $where = "dversion=1 LIMIT 1";
if ($user) {
$where = "user=" . $dbh->quote($user);
}
my $u = $dbh->selectrow_hashref("SELECT * FROM user WHERE $where");
unless ($u) {
die "No users with dversion==1 to convert. Done.\n" unless $user;
die "User not found.\n";
}
die "User not dversion 1\n" unless $u->{'dversion'} == 1;
my $dbch = LJ::get_cluster_master($u);
die "Can't connect to cluster master.\n" unless $dbch;
print "$u->{'user'}:\n";
my @pics = @{$dbh->selectcol_arrayref("SELECT picid FROM userpic WHERE ".
"userid=$u->{'userid'}")};
foreach my $picid (@pics) {
print " $picid...\n";
my $imagedata = $dbh->selectrow_array("SELECT imagedata FROM userpicblob ".
"WHERE picid=$picid");
$imagedata = $dbh->quote($imagedata);
$dbch->do("REPLACE INTO userpicblob2 (userid, picid, imagedata) VALUES ".
"($u->{'userid'}, $picid, $imagedata)");
}
$dbh->do("UPDATE user SET dversion=2 WHERE userid=$u->{'userid'}");
print "Done.\n";

View File

@@ -0,0 +1,320 @@
#!/usr/bin/perl
#
use strict;
$| = 1;
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
my $BLOCK_MOVE = 5000; # user rows to get at a time before moving
my $BLOCK_INSERT = 25; # rows to insert at a time when moving users
my $BLOCK_UPDATE = 1000; # users to update at a time if they had no data to move
# used for keeping stats notes
my %stats = (); # { 'action' => { 'pass' => { 'stat' => 'value' } } }
# rows come order by user, keep last username so we can avoid dups
my $lastuser;
# what pass are we on?
my $pass;
my $get_db_writer = sub {
return LJ::get_dbh({raw=>1}, "master");
};
my $get_db_slow = sub {
return LJ::get_dbh({raw=>1}, "slow", "master");
};
my $get_cluster_master = sub {
my $cid = shift;
return LJ::get_dbh({raw=>1}, "cluster$cid");
};
# percentage complete
my $status = sub {
my ($ct, $tot, $units, $pass, $user) = @_;
my $len = length($tot);
my $passtxt = $pass ? "[Pass: $pass] " : '';
my $usertxt = $user ? " Moving user: $user" : '';
return sprintf(" $passtxt\[%6.2f%%: %${len}d/%${len}d $units]$usertxt\n",
($ct / $tot) * 100, $ct, $tot);
};
my $header = sub {
my $size = 50;
return "\n" .
("#" x $size) . "\n" .
"# $_[0] " . (" " x ($size - length($_[0]) - 4)) . "#\n" .
("#" x $size) . "\n\n";
};
# mover function
my $move_user = sub {
my $user = shift;
# if the current user is the same as the last,
# we have a duplicate so skip it
return 0 if $user eq $lastuser;
$lastuser = $user;
my $u = LJ::load_user($user);
return 0 unless $u->{'dversion'} == 4;
# update user count for this pass
$stats{'move'}->{$pass}->{'user_ct'}++;
# print status
print $status->($stats{'move'}->{$pass}->{'ct'},
$stats{'move'}->{$pass}->{'total'}, "rows", $pass, $user);
# ignore expunged users
if ($u->{'statusvis'} eq "X") {
LJ::update_user($u, { 'dversion' => 5 })
or die "error updating dversion";
$u->{'dversion'} = 5; # update local copy in memory
return 1;
}
# get a handle for every user to revalidate our connection?
my $dbh = $get_db_writer->()
or die "Can't connect to global master";
my $dbslo = $get_db_slow->()
or die "Can't connect to global slow master";
my $dbcm = $get_cluster_master->($u->{'clusterid'})
or die "Can't connect to cluster master ($u->{'clusterid'})";
# be careful, we're moving data
foreach my $db ($dbh, $dbslo, $dbcm) {
$db->do("SET wait_timeout=28800");
$db->{'RaiseError'} = 1;
}
my @map = (['style' => 's1style',
qw(styleid userid styledes type formatdata is_public
is_embedded is_colorfree opt_cache has_ads lastupdate) ],
['overrides' => 's1overrides',
qw(userid override) ]
);
# in moving, s1stylecache gets special cased because its
# name hasn't changed, only location. so if there is only
# one cluster, then there's no point in physically moving it
if (@LJ::CLUSTERS > 1) {
push @map, ['s1stylecache' => 's1stylecache',
qw(styleid cleandate type opt_cache vars_stor vars_cleanver) ];
}
# user 'system' is a special case. if we encounter this user we'll swap $dbcm
# to secretly be a $dbh. because the 'system' user uses the clustered tables
# on the global dbs, the queries will still work, we just need to misdirect them
$dbcm = $dbh if $u->{'user'} eq 'system';
# styleids to delete since s1stylemap isn't keyed on user
my @delete_styleids = ();
# update tables
foreach my $tableinf (@map) {
# find src and dest table names
my $src_table = shift @$tableinf;
my $dest_table = shift @$tableinf;
# if this is the style table, replace into stylemap here,
# so that if this process is killed, style and stylemap
# won't get too out of sync
my $do_stylemap = $src_table eq 'style' && $dest_table eq 's1style';
# find what columns this table has
my @cols = @$tableinf;
my $cols = join(",", @cols);
my $bind_row = "(" . join(",", map { "?" } @cols) . ")";
my (@bind, @vals);
my (@map_bind, @map_vals);
# flush rows to destination table
my $flush = sub {
return unless @bind;
# insert data
my $bind = join(",", @bind);
$dbcm->do("REPLACE INTO $dest_table ($cols) VALUES $bind", undef, @vals);
# insert new styles into s1stylemap
if ($do_stylemap) {
my $map_bind = join(",", @map_bind);
$dbh->do("REPLACE INTO s1stylemap (styleid, userid) VALUES $map_bind",
undef, @map_vals);
}
# reset values
@bind = ();
@vals = ();
};
# s1stylecache is the only table keyed on styleid, not user
my $where = "user=" . $dbh->quote($u->{'user'});
if ($src_table eq "s1stylecache") {
my $ids = $dbh->selectcol_arrayref("SELECT styleid FROM style WHERE user=?",
undef, $u->{'user'});
my $ids_in = join(",", map { $dbh->quote($_) } @$ids) || "0";
$where = "styleid IN ($ids_in)";
}
# select from source table and build data for insert
my $sth = $dbh->prepare("SELECT * FROM $src_table WHERE $where");
$sth->execute();
while (my $row = $sth->fetchrow_hashref) {
# so that when we look for userid later, it'll be there
$row->{'userid'} = $u->{'userid'};
# build data for insert
push @bind, $bind_row;
push @vals, $row->{$_} foreach @cols;
# special case: insert new s1styles into s1stylemap
if ($do_stylemap) {
push @map_bind, "(?,?)";
push @map_vals, ($row->{'styleid'}, $u->{'userid'});
push @delete_styleids, $row->{'styleid'};
}
# increment the count for this pass, style or overrides
$stats{'move'}->{$pass}->{'ct'}++
unless $src_table eq 's1stylecache';
# flush if we've reached our insert limit
$flush->() if @bind > $BLOCK_INSERT;
}
$flush->();
}
# haven't died yet? everything is still going okay
# update dversion
LJ::update_user($u, { 'dversion' => 5 })
or die "error updating dversion";
$u->{'dversion'} = 5; # update local copy in memory
return 1;
};
my $dbh = $get_db_writer->();
die "Could not connect to global master" unless $dbh;
$dbh->{'RaiseError'} = 1;
my $dbslo = $get_db_slow->();
die "Could not connect to global slow master" unless $dbslo;
$dbslo->{'RaiseError'} = 1;
my $ts = $dbslo->selectrow_hashref("SHOW TABLE STATUS LIKE 'overrides'");
if ($ts->{'Type'} eq 'ISAM') {
die "This script isn't efficient with ISAM tables. Please convert to MyISAM with:\n" .
" mysql> ALTER TABLE overrides TYPE=MyISAM;\n\n" .
"Then re-run this script.\n";
}
print $header->("Moving user data");
# first pass should get everything, second pass will
# get changes made during the first
foreach my $p (1..2) {
# this is strange. perl bug?
$pass = $p;
# get totals from overrides and style so we can do a percentage bar
# there will be overlaps in this when users have both styles and
# overrides, but we'll fix those up as we go
foreach (qw(style overrides)) {
$stats{'move'}->{$pass}->{'total'} += $dbslo->selectrow_array("SELECT COUNT(*) FROM $_");
}
print "Processing $stats{'move'}->{$p}->{'total'} total rows\n";
# 2 passes, so we catch people with styles & overrides,
# styles w/o overrides, and overrides w/o styles
foreach my $table (qw(style overrides)) {
$lastuser = '';
# loop until we have no more users to convert
my $ct;
do {
# get blocks of $BLOCK_MOVE users at a time
my $sth = $dbslo->prepare("SELECT user FROM $table WHERE user>? " .
"ORDER BY user LIMIT $BLOCK_MOVE");
$sth->execute($lastuser);
$ct = 0;
while (my $user = $sth->fetchrow_array) {
$move_user->($user);
$ct++;
}
} while $ct;
}
print $stats{'move'}->{$p}->{'user_ct'}+0 . " users moved\n\n";
}
# now we're confident that all users have had their data moved if
# necessary, so we can just unconditionally change dversions.
print $header->("Updating remaining users");
$stats{'update'}->{'total'} = $dbslo->selectrow_array("SELECT COUNT(*) FROM user WHERE dversion=4");
print "Converting $stats{'update'}->{'total'} users\n";
# now update dversions for users who had no data to move
if ($stats{'update'}->{'total'}) {
my $get_users = sub {
my $sth = $dbslo->prepare("SELECT userid, user FROM user " .
"WHERE dversion=4 LIMIT $BLOCK_UPDATE");
$sth->execute();
my @rows; # [ userid, user ]
while ( my ($userid, $user) = $sth->fetchrow_array) {
push @rows, [ $userid, $user ];
}
return @rows;
};
while (my @rows = $get_users->()) {
# update database
my $bind = join(",", map { "?" } @rows);
my @vals = map { $_->[0] } @rows;
$dbh->do("UPDATE user SET dversion=5 WHERE userid IN ($bind)",
undef, @vals);
# update memcache
foreach (@rows) {
LJ::MemCache::delete([$_->[0], "userid:" . $_->[0]]);
LJ::MemCache::delete([$_->[1], "user:" . $_->[1]]);
}
$stats{'update'}->{'ct'} += @rows;
print $status->($stats{'update'}->{'ct'}, $stats{'update'}->{'total'}, "users");
}
}
my $zeropad = sub {
return sprintf("%d", $_[0]);
};
# calculate total move stats
foreach (1..2) {
$stats{'move'}->{'total_ct'} += $stats{'move'}->{$_}->{'ct'};
$stats{'move'}->{'total_user_ct'} += $stats{'move'}->{$_}->{'user_ct'};
}
print $header->("Dversion 4->5 conversion completed");
print " Rows moved: " . $zeropad->($stats{'move'}->{'total_ct'}) . "\n";
print " Users moved: " . $zeropad->($stats{'move'}->{'total_user_ct'}) . "\n";
print "Users updated: " . $zeropad->($stats{'update'}->{'ct'}) . "\n\n";

View File

@@ -0,0 +1,349 @@
#!/usr/bin/perl
#
use strict;
use Getopt::Long;
$| = 1;
use lib ("$ENV{LJHOME}/cgi-bin");
require "ljlib.pl";
use LJ::User;
use constant DEBUG => 0; # turn on for debugging (mostly db handle crap)
my $BLOCK_MOVE = 5000; # user rows to get at a time before moving
my $BLOCK_INSERT = 25; # rows to insert at a time when moving users
my $BLOCK_UPDATE = 1000; # users to update at a time if they had no data to move
# get options
my %opts;
exit 1 unless
GetOptions("lock=s" => \$opts{locktype},);
# if no locking, notify them about it
die "ERROR: Lock must be of types 'ddlockd' or 'none'\n"
if $opts{locktype} && $opts{locktype} !~ m/^(?:ddlockd|none)$/;
# used for keeping stats notes
my %stats = (); # { 'stat' => 'value' }
my %handle;
# database handle retrieval sub
my $get_db_handles = sub {
# figure out what cluster to load
my $cid = shift(@_) + 0;
my $dbh = $handle{0};
unless ($dbh) {
$dbh = $handle{0} = LJ::get_dbh({ raw => 1 }, "master");
print "Connecting to master ($dbh)...\n";
eval {
$dbh->do("SET wait_timeout=28800");
};
$dbh->{'RaiseError'} = 1;
}
my $dbcm;
$dbcm = $handle{$cid} if $cid;
if ($cid && ! $dbcm) {
$dbcm = $handle{$cid} = LJ::get_cluster_master({ raw => 1 }, $cid);
print "Connecting to cluster $cid ($dbcm)...\n";
return undef unless $dbcm;
eval {
$dbcm->do("SET wait_timeout=28800");
};
$dbcm->{'RaiseError'} = 1;
}
# return one or both, depending on what they wanted
return $cid ? ($dbh, $dbcm) : $dbh;
};
# percentage complete
my $status = sub {
my ($ct, $tot, $units, $user) = @_;
my $len = length($tot);
my $usertxt = $user ? " Moving user: $user" : '';
return sprintf(" \[%6.2f%%: %${len}d/%${len}d $units]$usertxt\n",
($ct / $tot) * 100, $ct, $tot);
};
my $header = sub {
my $size = 50;
return "\n" .
("#" x $size) . "\n" .
"# $_[0] " . (" " x ($size - length($_[0]) - 4)) . "#\n" .
("#" x $size) . "\n\n";
};
my $zeropad = sub {
return sprintf("%d", $_[0]);
};
# mover function
my $move_user = sub {
my $u = shift;
# make sure our user is of the proper dversion
return 0 unless $u->{'dversion'} == 5;
# at this point, try to get a lock for this user
my $lock;
if ($opts{locktype} eq 'ddlockd') {
$lock = LJ::locker()->trylock("d5d6-$u->{user}");
return 1 unless $lock;
}
# get a handle for every user to revalidate our connection?
my ($dbh, $dbcm) = $get_db_handles->($u->{clusterid});
return 0 unless $dbh;
if ($dbcm) {
# assign this dbcm to the user
$u->set_dbcm($dbcm)
or die "unable to set database for $u->{user}: dbcm=$dbcm\n";
}
# verify dversion hasn't changed on us (done by another job?)
my $dversion = $dbh->selectrow_array("SELECT dversion FROM user WHERE userid = $u->{userid}");
return 1 unless $dversion == 5;
# ignore expunged users
if ($u->{'statusvis'} eq "X" || $u->{'clusterid'} == 0) {
LJ::update_user($u, { dversion => 6 })
or die "error updating dversion";
$u->{dversion} = 6; # update local copy in memory
return 1;
}
return 0 unless $dbcm;
# step 1: get all friend groups and move those. safe to just grab with no limit because
# there are limits to how many friend groups you can have (30).
my $rows = $dbh->selectall_arrayref('SELECT groupnum, groupname, sortorder, is_public ' .
'FROM friendgroup WHERE userid = ?', undef, $u->{userid});
if (@$rows) {
# got some rows, create an update statement
my (@bind, @vars);
foreach my $row (@$rows) {
push @bind, "($u->{userid}, ?, ?, ?, ?)";
push @vars, $_ foreach @$row;
}
my $bind = join ',', @bind;
eval {
$u->do("INSERT INTO friendgroup2 (userid, groupnum, groupname, sortorder, is_public) " .
"VALUES $bind", undef, @vars);
};
}
# general purpose flusher for use below
my (@bind, @vars);
my $flush = sub {
return unless @bind;
my ($table, $cols) = @_;
# insert data into cluster master
my $bind = join(",", @bind);
$u->do("REPLACE INTO $table ($cols) VALUES $bind", undef, @vars);
die "error in flush $table: " . $u->errstr . "\n" if $u->err;
# reset values
@bind = ();
@vars = ();
};
# step 1.5: see if the user has any data already? clear it if so.
my $counter = $dbcm->selectrow_array("SELECT max FROM counter WHERE journalid = ? AND area = 'R'",
undef, $u->{userid});
$counter += 0;
if ($counter > 0) {
# yep, so we need to delete stuff, real data first
foreach my $table (qw(memorable2 memkeyword2 userkeywords)) {
$u->do("DELETE FROM $table WHERE userid = ?", undef, $u->{userid});
die "error in clear: " . $u->errstr . "\n" if $u->err;
}
# delete counters used (including memcache of such)
$u->do("DELETE FROM counter WHERE journalid = ? AND area IN ('R', 'K')", undef, $u->{userid});
die "error in clear: " . $u->errstr . "\n" if $u->err;
LJ::MemCache::delete([$u->{userid}, "auc:$u->{userid}:R"]);
LJ::MemCache::delete([$u->{userid}, "auc:$u->{userid}:K"]);
}
# step 2: get all of their memories and move them, creating the oldmemid -> newmemid mapping
# that we can use in later steps to migrate keywords
my %bindings; # ( oldid => newid )
my $sth = $dbh->prepare('SELECT memid, journalid, jitemid, des, security ' .
'FROM memorable WHERE userid = ?');
$sth->execute($u->{userid});
while (my $row = $sth->fetchrow_hashref()) {
# got a row, good
my $newid = LJ::alloc_user_counter($u, 'R');
die "Error: unable to allocate type 'R' counter for $u->{user}($u->{userid})\n"
unless $newid;
$bindings{$row->{memid}} = $newid;
# push data
push @bind, "($u->{userid}, ?, ?, ?, ?, ?)";
push @vars, ($newid, map { $row->{$_} } qw(journalid jitemid des security));
# flush if necessary
$flush->('memorable2', 'userid, memid, journalid, ditemid, des, security')
if @bind > $BLOCK_INSERT;
}
$flush->('memorable2', 'userid, memid, journalid, ditemid, des, security');
# step 3: get the list of keywords that these memories all use
my %kwmap;
if (%bindings) {
my $memids = join ',', map { $_+0 } keys %bindings;
my $rows = $dbh->selectall_arrayref("SELECT memid, kwid FROM memkeyword WHERE memid IN ($memids)");
push @{$kwmap{$_->[1]}}, $_->[0] foreach @$rows; # kwid -> [ memid, memid, memid ... ]
}
# step 4: get the actual keywords associated with these keyword ids
my %kwidmap;
if (%kwmap) {
my $kwids = join ',', map { $_+0 } keys %kwmap;
my $rows = $dbh->selectall_arrayref("SELECT kwid, keyword FROM keywords WHERE kwid IN ($kwids)");
%kwidmap = map { $_->[0] => $_->[1] } @$rows; # kwid -> keyword
}
# step 5: now migrate all keywords into userkeywords table
my %mappings;
while (my ($kwid, $keyword) = each %kwidmap) {
# reallocate counter
my $newkwid = LJ::alloc_user_counter($u, 'K');
die "Error: unable to allocate type 'K' counter for $u->{user}($u->{userid})\n"
unless $newkwid;
$mappings{$kwid} = $newkwid;
# push data
push @bind, "($u->{userid}, ?, ?)";
push @vars, ($newkwid, $keyword);
# flush if necessary
$flush->('userkeywords', 'userid, kwid, keyword')
if @bind > $BLOCK_INSERT;
}
$flush->('userkeywords', 'userid, kwid, keyword');
# step 6: now we have to do some mapping conversions and put new data into memkeyword2 table
while (my ($oldkwid, $oldmemids) = each %kwmap) {
foreach my $oldmemid (@$oldmemids) {
# get new data
my ($newkwid, $newmemid) = ($mappings{$oldkwid}, $bindings{$oldmemid});
# push data
push @bind, "($u->{userid}, ?, ?)";
push @vars, ($newmemid, $newkwid);
# flush?
$flush->('memkeyword2', 'userid, memid, kwid')
if @bind > $BLOCK_INSERT;
}
}
$flush->('memkeyword2', 'userid, memid, kwid');
# delete memcache keys that hold old data
LJ::MemCache::delete([$u->{userid}, "memkwid:$u->{userid}"]);
# haven't died yet? everything is still going okay, so update dversion
LJ::update_user($u, { 'dversion' => 6 })
or die "error updating dversion";
$u->{'dversion'} = 6; # update local copy in memory
return 1;
};
# get dbh handle
my $dbh = LJ::get_db_writer(); # just so we can get users...
die "Could not connect to global master" unless $dbh;
# get user count
my $total = $dbh->selectrow_array("SELECT COUNT(*) FROM user WHERE dversion = 5");
$stats{'total_users'} = $total+0;
# print out header and total we're moving
print $header->("Moving user data");
print "Processing $stats{'total_users'} total users with the old dversion\n";
# loop until we have no more users to convert
my $ct;
while (1) {
# get blocks of $BLOCK_MOVE users at a time
my $sth = $dbh->prepare("SELECT * FROM user WHERE dversion = 5 LIMIT $BLOCK_MOVE");
$sth->execute();
$ct = 0;
my %us;
my %fast; # people to move fast
while (my $u = $sth->fetchrow_hashref()) {
$us{$u->{userid}} = $u;
$ct++;
$fast{$u->{userid}} = 1;
}
# jump out if we got nothing
last unless $ct;
# now that we have %us, we can see who has data
my $ids = join ',', map { $_+0 } keys %us;
my $has_memorable = $dbh->selectcol_arrayref("SELECT DISTINCT userid FROM memorable WHERE userid IN ($ids)");
my $has_fgroups = $dbh->selectcol_arrayref("SELECT DISTINCT userid FROM friendgroup WHERE userid IN ($ids)");
my %uids = ( map { $_ => 1 } (@$has_memorable, @$has_fgroups) );
# these people actually have data to migrate; don't move them fast
delete $fast{$_} foreach keys %uids;
# now see who we can do in a fast way
my @fast_ids = map { $_+0 } keys %fast;
if (@fast_ids) {
print "Converting ", scalar(@fast_ids), " users quickly...\n";
# update stats for counting and print
$stats{'fast_moved'} += @fast_ids;
print $status->($stats{'slow_moved'}+$stats{'fast_moved'}, $stats{'total_users'}, "users");
# block update
LJ::update_user(\@fast_ids, { dversion => 6 });
}
my $slow_todo = scalar keys %uids;
print "Of $BLOCK_MOVE, $slow_todo have to be slow-converted...\n";
my @ids = randlist(keys %uids);
foreach my $id (@ids) {
# this person has memories, move them the slow way
die "Userid $id in \$has_memorable, but not in \%us...fatal error\n" unless $us{$id};
# now move the user
bless $us{$id}, 'LJ::User';
if ($move_user->($us{$id})) {
$stats{'slow_moved'}++;
print $status->($stats{'slow_moved'}+$stats{'fast_moved'}, $stats{'total_users'}, "users", $us{$id}{user});
}
}
}
# ...done?
print $header->("Dversion 5->6 conversion completed");
print " Users moved: " . $zeropad->($stats{'slow_moved'}) . "\n";
print "Users updated: " . $zeropad->($stats{'fast_moved'}) . "\n\n";
# helper function to randomize stuff
sub randlist
{
my @rlist = @_;
my $size = scalar(@rlist);
my $i;
for ($i=0; $i<$size; $i++) {
unshift @rlist, splice(@rlist, $i+int(rand()*($size-$i)), 1);
}
return @rlist;
}

View File

@@ -0,0 +1,352 @@
#!/usr/bin/perl
#
use strict;
use Getopt::Long;
$| = 1;
use lib "$ENV{'LJHOME'}/cgi-bin/";
require "ljlib.pl";
use LJ::Blob;
use LJ::User;
use constant DEBUG => 0; # turn on for debugging (mostly db handle crap)
my $BLOCK_MOVE = 5000; # user rows to get at a time before moving
my $BLOCK_INSERT = 25; # rows to insert at a time when moving users
my $BLOCK_UPDATE = 1000; # users to update at a time if they had no data to move
# get options
my %opts;
exit 1 unless
GetOptions("lock=s" => \$opts{locktype},
"user=s" => \$opts{user},
"total=i" => \$opts{total},);
# if no locking, notify them about it
die "ERROR: Lock must be of types 'ddlockd' or 'none'\n"
if $opts{locktype} && $opts{locktype} !~ m/^(?:ddlockd|none)$/;
# used for keeping stats notes
my %stats = (); # { 'stat' => 'value' }
my %handle;
# database handle retrieval sub
my $get_db_handles = sub {
# figure out what cluster to load
my $cid = shift(@_) + 0;
my $dbh = $handle{0};
unless ($dbh) {
$dbh = $handle{0} = LJ::get_dbh({ raw => 1 }, "master");
print "Connecting to master ($dbh)...\n";
eval {
$dbh->do("SET wait_timeout=28800");
};
$dbh->{'RaiseError'} = 1;
}
my $dbcm;
$dbcm = $handle{$cid} if $cid;
if ($cid && ! $dbcm) {
$dbcm = $handle{$cid} = LJ::get_cluster_master({ raw => 1 }, $cid);
print "Connecting to cluster $cid ($dbcm)...\n";
return undef unless $dbcm;
eval {
$dbcm->do("SET wait_timeout=28800");
};
$dbcm->{'RaiseError'} = 1;
}
# return one or both, depending on what they wanted
return $cid ? ($dbh, $dbcm) : $dbh;
};
# percentage complete
my $status = sub {
my ($ct, $tot, $units, $user) = @_;
my $len = length($tot);
my $usertxt = $user ? " Moving user: $user" : '';
return sprintf(" \[%6.2f%%: %${len}d/%${len}d $units]$usertxt\n",
($ct / $tot) * 100, $ct, $tot);
};
my $header = sub {
my $size = 50;
return "\n" .
("#" x $size) . "\n" .
"# $_[0] " . (" " x ($size - length($_[0]) - 4)) . "#\n" .
("#" x $size) . "\n\n";
};
my $zeropad = sub {
return sprintf("%d", $_[0]);
};
# mover function
my $move_user = sub {
my $u = shift;
# make sure our user is of the proper dversion
return 0 unless $u->{'dversion'} == 6;
# at this point, try to get a lock for this user
my $lock;
if ($opts{locktype} eq 'ddlockd') {
$lock = LJ::locker()->trylock("d6d7-$u->{user}");
return 1 unless $lock;
}
# get a handle for every user to revalidate our connection?
my ($dbh, $dbcm) = $get_db_handles->($u->{clusterid});
return 0 unless $dbh;
# assign this dbcm to the user
if ($dbcm) {
$u->set_dbcm($dbcm)
or die "unable to set database for $u->{user}: dbcm=$dbcm\n";
}
# verify dversion hasn't changed on us (done by another job?)
my $dversion = $dbh->selectrow_array("SELECT dversion FROM user WHERE userid = $u->{userid}");
return 1 unless $dversion == 6;
# ignore expunged users
if ($u->{'statusvis'} eq "X" || $u->{'clusterid'} == 0) {
LJ::update_user($u, { dversion => 7 })
or die "error updating dversion";
$u->{dversion} = 7; # update local copy in memory
return 1;
}
return 0 unless $dbcm;
# step 0.5: delete all the bogus userblob rows for this user
# This is due to the auto_increment for the blobid overflowing
# and thus all entries recieving an id of max id for a mediumint.
# This is lame.
my $domainid = LJ::get_blob_domainid('userpic');
$u->do("DELETE FROM userblob WHERE journalid=$u->{userid} AND domain=$domainid AND blobid>=16777216");
die "error in delete: " . $u->errstr . "\n" if $u->err;
# step 1: get all user pictures and move those. safe to just grab with no limit
# since users can only have a limited number of them
my $rows = $dbh->selectall_arrayref('SELECT picid, userid, contenttype, width, height, state, picdate, md5base64 ' .
'FROM userpic WHERE userid = ?', undef, $u->{userid}) || [];
if (@$rows) {
# got some rows, create an update statement
my (@bind, @vars, @blobids, @blobbind, @picinfo);
foreach my $row (@$rows) {
my $picid = $row->[0];
push @bind, "(?, ?, ?, ?, ?, ?, ?, ?)";
$row->[2] = {'image/gif' => 'G',
'image/jpeg' => 'J',
'image/png' => 'P'}->{$row->[2]};
push @vars, @$row;
# [picid, fmt]
my $fmt = {'G' => 'gif',
'J' => 'jpg',
'P' => 'png'}->{$row->[2]};
push @picinfo, [$picid, $fmt];
# picids
push @blobids, $picid;
push @blobbind, "?";
}
my $bind = join ',', @bind;
$u->do("REPLACE INTO userpic2 (picid, userid, fmt, width, height, state, picdate, md5base64) " .
"VALUES $bind", undef, @vars);
die "error in userpic2 replace: " . $u->errstr . "\n" if $u->err;
# step 1.5: insert missing rows into the userblob table
my $blobbind = join ',', @blobbind;
my $blobrows = $dbcm->selectall_hashref("SELECT blobid FROM userblob WHERE journalid=$u->{userid} AND domain=$domainid " .
"AND blobid IN ($blobbind)", 'blobid', undef, @blobids) || {};
my (@insertbind, @insertvars);
foreach my $pic (@picinfo) {
my ($picid, $fmt) = @$pic;
unless ($blobrows->{$picid}) {
push @insertbind, "(?, ?, ?, ?)";
my $blob = LJ::Blob::get($u, "userpic", $fmt, $picid);
my $length = length($blob);
push @insertvars, $u->{'userid'}, $domainid, $picid, $length;
}
}
if (@insertbind) {
my $insertbind = join ',', @insertbind;
$u->do("INSERT IGNORE INTO userblob (journalid, domain, blobid, length) " .
"VALUES $insertbind", undef, @insertvars);
die "error in userblob insert: " . $u->errstr . "\n" if $u->err;
}
}
# general purpose flusher for use below
my (@bind, @vars);
my $flush = sub {
return unless @bind;
my ($table, $cols) = @_;
# insert data into cluster master
my $bind = join(",", @bind);
$u->do("REPLACE INTO $table ($cols) VALUES $bind", undef, @vars);
die "error in flush $table: " . $u->errstr . "\n" if $u->err;
# reset values
@bind = ();
@vars = ();
};
# step 2: get the mapping of all of their keywords
my $kwrows = $dbh->selectall_arrayref('SELECT picid, kwid FROM userpicmap WHERE userid=?',
undef, $u->{'userid'});
my %kwmap;
if (@$kwrows) {
push @{$kwmap{$_->[1]}}, $_->[0] foreach @$kwrows; # kwid -> [ picid, picid, picid ... ]
}
# step 3: get the actual keywords associated with these keyword ids
my %kwidmap;
if (%kwmap) {
my $kwids = join ',', map { $_+0 } keys %kwmap;
my $rows = $dbh->selectall_arrayref("SELECT kwid, keyword FROM keywords WHERE kwid IN ($kwids)");
%kwidmap = map { $_->[0] => $_->[1] } @$rows; # kwid -> keyword
}
# step 4: now migrate all keywords into userkeywords table
my %mappings;
while (my ($kwid, $keyword) = each %kwidmap) {
# reallocate counter
my $newkwid = LJ::get_keyword_id($u, $keyword);
die "Error: unable to get keyword id for $u->{user}($u->{userid}), keyword '$keyword'\n"
unless $newkwid;
$mappings{$kwid} = $newkwid;
}
# step 5: now we have to do some mapping conversions and put new data into userpicmap2 table
while (my ($oldkwid, $picids) = each %kwmap) {
foreach my $picid (@$picids) {
# get new data
my $newkwid = $mappings{$oldkwid};
# push data
push @bind, "($u->{userid}, ?, ?)";
push @vars, ($picid, $newkwid);
# flush?
$flush->('userpicmap2', 'userid, picid, kwid')
if @bind > $BLOCK_INSERT;
}
}
$flush->('userpicmap2', 'userid, picid, kwid');
# delete memcache keys that hold old data
LJ::MemCache::delete([$u->{userid}, "upicinf:$u->{userid}"]);
# haven't died yet? everything is still going okay, so update dversion
LJ::update_user($u, { 'dversion' => 7 })
or die "error updating dversion";
$u->{'dversion'} = 7; # update local copy in memory
return 1;
};
# get dbh handle
my $dbh = LJ::get_db_writer(); # just so we can get users...
die "Could not connect to global master" unless $dbh;
# get user count
my $total = $opts{total} || $dbh->selectrow_array("SELECT COUNT(*) FROM user WHERE dversion = 6");
$stats{'total_users'} = $total+0;
# print out header and total we're moving
print $header->("Moving user data");
print "Processing $stats{'total_users'} total users with the old dversion\n";
# loop until we have no more users to convert
my $ct;
while (1) {
# get users to move
my $sth;
if ($opts{user}) {
$sth = $dbh->prepare("SELECT * FROM user WHERE user = ? AND dversion = 6");
$sth->execute($opts{user});
} else {
$sth = $dbh->prepare("SELECT * FROM user WHERE dversion = 6 LIMIT $BLOCK_MOVE");
$sth->execute();
}
# get blocks of $BLOCK_MOVE users at a time
$ct = 0;
my (%us, %fast);
while (my $u = $sth->fetchrow_hashref()) {
$us{$u->{userid}} = $u;
$fast{$u->{userid}} = 1;
$ct++;
}
# jump out if we got nothing
last unless $ct;
# now that we have %us, we can see who has data
my $ids = join ',', map { $_+0 } keys %us;
my $has_upics = $dbh->selectcol_arrayref("SELECT DISTINCT userid FROM userpic WHERE userid IN ($ids)");
my %uids = ( map { $_ => 1 } (@$has_upics) );
# remove folks that have userpics from the fast list
delete $fast{$_} foreach keys %uids;
# now see who we can do in a fast way
my @fast_ids = map { $_+0 } keys %fast;
if (@fast_ids) {
# update stats for counting and print
$stats{'fast_moved'} += @fast_ids;
print $status->($stats{'slow_moved'}+$stats{'fast_moved'}, $stats{'total_users'}, "users");
# block update
LJ::update_user(\@fast_ids, { dversion => 7 });
}
my $slow_todo = scalar keys %uids;
print "Of $BLOCK_MOVE, $slow_todo have to be slow-converted...\n";
my @ids = randlist(keys %uids);
foreach my $id (@ids) {
# this person has userpics, move them the slow way
die "Userid $id in \$has_upics, but not in \%us...fatal error\n" unless $us{$id};
# now move the user
bless $us{$id}, 'LJ::User';
if ($move_user->($us{$id})) {
$stats{'slow_moved'}++;
print $status->($stats{'slow_moved'}+$stats{'fast_moved'}, $stats{'total_users'}, "users", $us{$id}{user});
}
}
}
# ...done?
print $header->("Dversion 6->7 conversion completed");
print " Users moved: " . $zeropad->($stats{'slow_moved'}) . "\n";
print "Users updated: " . $zeropad->($stats{'fast_moved'}) . "\n\n";
# helper function to randomize stuff
sub randlist
{
my @rlist = @_;
my $size = scalar(@rlist);
my $i;
for ($i=0; $i<$size; $i++) {
unshift @rlist, splice(@rlist, $i+int(rand()*($size-$i)), 1);
}
return @rlist;
}

View File

@@ -0,0 +1,207 @@
# these get removed if found by texttool.pl
#
general /allpics.bml.edit
general /allpics.bml.nopics.text
general /community/join.bml.label.authpost
general /community/join.bml.label.closedcomm
general /community/manage.bml.actmembers
general /community/manage.bml.actsettings
general /community/manage.bml.commlist.actmoderate
general /community/members.bml.manage
general /community/search.bml.contasmember
general /community/search.bml.userlikes
general /community/settings.bml.label.admconsole
general /community/settings.bml.manage
general /create.bml.aolnotice.head
general /create.bml.aolnotice.text
general /create.bml.error.seebelow
general /create.bml.proceed.head
general /create.bml.proceed.text
general /create.bml.tos.error
general /create.bml.tos.haveread
general /create.bml.tos.p1.2
general /editinfo.bml.allowshocontact.email.if_domainaddy
general /editinfo.bml.allowshowcontact.email.reason
general /editinfo.bml.newemail.body
general /editinfo.bml.settings.about
general /editinfo.bml.showsubjicons.about
general /editinfo.bml.showsubjicons.header
general /editinfo.bml.tm.about
general /editinfo.bml.topicdir.about
general /editinfo.bml.topicdir.header
general /friends/edit.bml.btn.proceed
general /friends/edit.bml.edit.head
general /friends/edit.bml.edit.text
general /editjournal.bml.enterlogin
general /editjournal.bml.lostinfo.head
general /editjournal.bml.lostinfo.text
general /editjournal_do.bml.error.mustlogin
general /editjournal_do.bml.success.edit
general /friends/editgroups.bml.login.header
general /friends/editgroups.bml.login.text
general /interests.bml.findsim.account.notallowed
general /interests.bml.findsim.account.notloggedin
general /interests.bml.findsim.btn.find
general /interests.bml.findsim.head
general /interests.bml.findsim.simtouser
general /interests.bml.findsim.text
general /interests.bml.interests.findsim1
general /interests.bml.interests.findsim2
general /login.bml.error.forgotpass
general /login.bml.error.noaccount
general /manage/index.bml.information.setlang.about
general /manage/index.bml.information.setscheme.about
general /modify.bml.btn.proceed
general /modify.bml.journalstatus.about
general /modify.bml.journalstatus.head
general /modify.bml.journalstatus.select.activated
general /modify.bml.journalstatus.select.deleted
general /modify.bml.journalstatus.select.head
general /modify.bml.journalstatus.select.suspended
general /modify.bml.lostinfo.head
general /modify.bml.lostinfo.text
general /modify.bml.modify.head
general /modify.bml.modify.text
general /modify_do.bml.title
general /multisearch.bml.region.text
general /register.bml.new.body
general /setlang.bml.select
general /setlang.bml.switch
general /setlang.bml.title
general /setscheme.bml.current
general /setscheme.bml.default
general /setscheme.bml.noschemes
general /setscheme.bml.select
general /setscheme.bml.switch
general /setscheme.bml.title
general /support/faqbrowse.bml.title
general /talkpost.bml.label.picturetouse
general /talkpost_do.bml.opt.spellcheck
general /talkread.bml.pageofpages
general /tools/memadd.bml.body.added.body
general /update.bml.update.about
general /update.bml.login.success
general /update.bml.htmlokay
general /uploadpic.bml.success.text
general /uploadpic.bml.btn.proceed
general /uploadpic.bml.error.badurl
general /uploadpic.bml.error.databasedown
general /uploadpic.bml.error.filetoolarge
general /uploadpic.bml.error.imagetoolarge
general /uploadpic.bml.error.invalidauth
general /uploadpic.bml.error.invalidimage
general /uploadpic.bml.error.toomanypics
general /uploadpic.bml.error.unknownmode
general /uploadpic.bml.error.urlerror
general /uploadpic.bml.fromfile
general /uploadpic.bml.fromfile.key
general /uploadpic.bml.fromurl
general /uploadpic.bml.fromurl.key
general /uploadpic.bml.header
general /uploadpic.bml.imagesize.by
general /uploadpic.bml.kilobytes
general /uploadpic.bml.makedefault
general /uploadpic.bml.makedefault.key
general /uploadpic.bml.restriction.fileformat
general /uploadpic.bml.restriction.filesize
general /uploadpic.bml.restriction.imagesize
general /uploadpic.bml.success.editpics
general /uploadpic.bml.success.header
general /uploadpic.bml.success.preview
general /uploadpic.bml.success.upload
general /uploadpic.bml.text
general /uploadpic.bml.title
general /uploadpic_do.bml.error.urlerror
general uploadpic.error.toolarge
general /userinfo.bml.canpost
general /userinfo.bml.closedmembership.body
general /userinfo.bml.fbpictures
general /userinfo.bml.label.viewlabel
general /userinfo.bml.openmembership.body
general /userinfo.bml.posthere
general /userinfo.bml.rpmembership.body
general /userinfo.bml.syn.lastnew
general /register.bml.error.alreadyvalidated
general /tools/memories.bml.entry
general /tools/memories.bml.entries
general /create.bml.tos.p1
general /create.bml.email.text
general /create.bml.email.note
general /syn/index.bml.table.cost
general /syn/index.bml.quota.text
general /syn/index.bml.quota.your
general /syn/index.bml.quota.numbers
general /syn/index.bml.invalid.overquota
general /syn/index.bml.invalid.overquota.text
general /syn/index.bml.invalid.overquota.title
general /syn/index.bml.invalid.overquota.username
general /syn/index.bml.accounttype.notallowed
general /syn/index.bml.add.other.title
general /syn/index.bml.add.other.text
general /syn/index.bml.notused
general /userinfo.bml.syn.cost
general bml.needlogin.body
general /userinfo.bml.label.frsyndication
general /syn/index.bml.invalid.address
general /community/members.bml.key.name
general /community/members.bml.success.addusers
general /userinfo.bml.label.totalfriends
general /community/settings.bml.label.closedmemb
general /talkscreen.bml.title
general /community/members.bml.success.message
general /community/transfer.bml.error.banned
general /create.bml.age.check.question
general /create.bml.age.check.yes
general /create.bml.age.check2.question
general /create.bml.age.check2.yes
general /create.bml.age.head
general /community/members.bml.reinvited
general /community/membres.bml.success.invited
general /customize/index.bml.s1

4676
livejournal/bin/upgrading/en.dat Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,48 @@
#!/usr/bin/perl
# This script goes through all of the files in your include directory
# (LJHOME/htdocs/inc) and then imports ones that are specified by your
# ljconfig.pl file (%LJ::FILEEDIT_VIA_DB) into your database if the file
# on disk is newer than the one in the database.
use strict;
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
# create list of files to check
my $dir = "$ENV{'LJHOME'}/htdocs/inc";
print "searching for files to check against database...";
opendir DIR, $dir
or die "Unable to open $ENV{'LJHOME'}/htdocs/inc for searching.\n";
my @files = grep { $LJ::FILEEDIT_VIA_DB ||
$LJ::FILEEDIT_VIA_DB{$_} } readdir(DIR);
my $count = scalar(@files);
print $count+0 . " found.\n";
# now iterate through and check times
my $dbh = LJ::get_db_writer();
foreach my $file (@files) {
my $path = "$dir/$file";
next unless -f $path;
# now get filetime
my $ftimedisk = (stat($path))[9];
my $ftimedb = $dbh->selectrow_array("SELECT updatetime
FROM includetext WHERE incname=?", undef, $file)+0;
# check
if ($ftimedisk > $ftimedb) {
# load file
open FILE, "<$path";
my $content = join("", <FILE>);
close FILE;
# now do SQL
print "$file newer on disk...updating database...";
$dbh->do("REPLACE INTO includetext (incname, inctext, updatetime)" .
"VALUES (?,?,UNIX_TIMESTAMP())", undef, $file, $content);
print $dbh->err ? "error: " . $dbh->errstr . ".\n" : "done.\n";
} else {
print "$file newer in database, ignored.\n";
}
}
print "all done.\n";

View File

@@ -0,0 +1,53 @@
#!/usr/bin/perl
#
use strict;
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
my $dbh = LJ::get_dbh("master");
print "
This tool will create your LiveJournal 'system' account and
set its password. Or, if you already have a system user, it'll change
its password to whatever you specify.
";
print "Enter password for the 'system' account: ";
my $pass = <STDIN>;
chomp $pass;
print "\n";
print "Creating system account...\n";
unless (LJ::create_account({ 'user' => 'system',
'name' => 'System Account',
'password' => $pass }))
{
print "Already exists.\nModifying 'system' account...\n";
$dbh->do("UPDATE user SET password=? WHERE user='system'",
undef, $pass);
}
my $u = LJ::load_user("system");
unless ($u) {
print "ERROR: can't find newly-created system account.\n";
exit 1;
}
print "Giving 'system' account 'admin' priv on all areas...\n";
if (LJ::check_priv($u, "admin", "*")) {
print "Already has it.\n";
} else {
my $sth = $dbh->prepare("INSERT INTO priv_map (userid, prlid, arg) ".
"SELECT $u->{'userid'}, prlid, '*' ".
"FROM priv_list WHERE privcode='admin'");
$sth->execute;
if ($dbh->err || $sth->rows == 0) {
print "Couldn't grant system account admin privs\n";
exit 1;
}
}
print "Done.\n\n";

View File

@@ -0,0 +1,323 @@
#!/usr/bin/perl
use strict;
use lib "$ENV{LJHOME}/cgi-bin";
require 'ljlib.pl';
use LJ::Blob;
use LJ::User;
use Getopt::Long;
use IPC::Open3;
use Digest::MD5;
# this script is a migrater that will move phone posts from an old storage method
# into mogilefs.
# the basic theory is that we iterate over all clusters, find all phoneposts that
# aren't in mogile right now, and put them there
# determine
my ($one, $besteffort, $dryrun, $user, $verify, $verbose, $clusters, $purge);
my $rv = GetOptions("best-effort" => \$besteffort,
"one" => \$one,
"dry-run" => \$dryrun,
"user=s" => \$user,
"verify" => \$verify,
"verbose" => \$verbose,
"purge-old" => \$purge,
"clusters=s" => \$clusters,);
unless ($rv) {
die <<ERRMSG;
This script supports the following command line arguments:
--clusters=X[-Y]
Only handle clusters in this range. You can specify a single
number, or a range of two numbers with a dash.
--user=username
Only move this particular user.
--one
Only move one user. (But it moves all their phone posts.) This is
used for testing.
--verify
If specified, this option will reload the phonepost from MogileFS and
make sure it's been stored successfully.
--dry-run
If on, do not update the database. This mode will put the phonepost
in MogileFS and give you paths to examine the phone posts and make
sure everything is okay. It will not update the phonepost2 table,
though.
--best-effort
Normally, if a problem is encountered (null phonepost, md5 mismatch,
connection failure, etc) the script will die to make sure
everything goes well. With this flag, we don't die and instead
just print to standard error.
--purge-old
Sometimes we run into data that is for users that have since
moved to a different cluster. Normally we ignore it, but
with this option, we'll clean that data up as we find it.
--verbose
Be very chatty.
ERRMSG
}
# make sure ljconfig is setup right (or so we hope)
die "Please define a 'phoneposts' class in your \%LJ::MOGILEFS_CONFIG\n"
unless defined $LJ::MOGILEFS_CONFIG{classes}->{phoneposts};
die "Unable to find MogileFS object (\%LJ::MOGILEFS_CONFIG not setup?)\n"
unless $LJ::MogileFS;
# setup stderr if we're in best effort mode
if ($besteffort) {
my $oldfd = select(STDERR);
$| = 1;
select($oldfd);
}
# operation modes
if ($user) {
# move a single user
my $u = LJ::load_user($user);
die "No such user: $user\n" unless $u;
handle_userid($u->{userid}, $u->{clusterid});
} else {
# parse the clusters
my @clusters;
if ($clusters) {
if ($clusters =~ /^(\d+)(?:-(\d+))?$/) {
my ($min, $max) = map { $_ + 0 } ($1, $2 || $1);
push @clusters, $_ foreach $min..$max;
} else {
die "Error: --clusters argument not of right format.\n";
}
} else {
@clusters = @LJ::CLUSTERS;
}
# now iterate over the clusters to pick
my $ctotal = scalar(@clusters);
my $ccount = 0;
foreach my $cid (sort { $a <=> $b } @clusters) {
# status report
$ccount++;
print "\nChecking cluster $cid...\n\n";
# get a handle
my $dbcm = get_db_handle($cid);
# get all userids
print "Getting userids...\n";
my $limit = $one ? 'LIMIT 1' : '';
my $userids = $dbcm->selectcol_arrayref
("SELECT DISTINCT userid FROM phonepostentry WHERE (location='blob' OR location IS NULL) $limit");
my $total = scalar(@$userids);
# iterate over userids
my $count = 0;
print "Beginning iteration over userids...\n";
foreach my $userid (@$userids) {
# move this phonepost
my $extra = sprintf("[%6.2f%%, $ccount of $ctotal] ", (++$count/$total*100));
handle_userid($userid, $cid, $extra);
}
# don't hit up more clusters
last if $one;
}
}
print "\n";
print "Updater terminating.\n";
#############################################################################
### helper subs down here
# take a userid and move their phone posts
sub handle_userid {
my ($userid, $cid, $extra) = @_;
# load user to move and do some sanity checks
my $u = LJ::load_userid($userid);
unless ($u) {
LJ::end_request();
LJ::start_request();
$u = LJ::load_userid($userid);
}
die "ERROR: Unable to load userid $userid\n"
unless $u;
# if they're expunged, they might have data somewhere if they were
# copy-moved from A to B, then expunged on B. now we're on A and
# need to delete it ourselves (if purge-old is on)
if ($u->{clusterid} == 0 && $u->{statusvis} eq "X") {
return unless $purge;
# if we get here, the user has indicated they want data purged, get handle
my $to_purge_dbcm = get_db_handle($cid);
my $ct = $to_purge_dbcm->do("DELETE FROM phonepostentry WHERE userid = ?", undef, $u->{userid});
print "\tnotice: purged $ct old rows.\n\n"
if $verbose;
return;
}
# get a handle
my $dbcm = get_db_handle($u->{clusterid});
# print that we're doing this user
print "$extra$u->{user}($u->{userid})\n";
# if a user has been moved to another cluster, but the source data from
# phonepostentry wasn't deleted, we need to ignore the user or purge their data
if ($u->{clusterid} != $cid) {
return unless $purge;
# verify they have some rows on the new side
my $count = $dbcm->selectrow_array
("SELECT COUNT(*) FROM phonepostentry WHERE userid = ?",
undef, $u->{userid});
return unless $count;
# if we get here, the user has indicated they want data purged, get handle
my $to_purge_dbcm = get_db_handle($cid);
# delete the old data
if ($dryrun) {
print "\tnotice: need to delete phonepostentry rows.\n\n"
if $verbose;
} else {
my $ct = $to_purge_dbcm->do("DELETE FROM phonepostentry WHERE userid = ?", undef, $u->{userid});
print "\tnotice: purged $ct old rows.\n\n"
if $verbose;
}
# nothing else to do here
return;
}
# get all their photos that aren't in mogile already
my $rows = $dbcm->selectall_arrayref
("SELECT filetype, blobid FROM phonepostentry WHERE userid = ? ".
"AND (location = 'blob' OR location IS NULL)",
undef, $u->{userid});
return unless @$rows;
# if a user has been moved to another cluster, but the source data from
# phonepost2 wasn't deleted, we need to ignore the user
return unless $u->{clusterid} == $cid;
# now we have a userid and blobids, get the photos from the blob server
foreach my $row (@$rows) {
my ($filetype, $blobid) = @$row;
print "\tstarting move for blobid $blobid\n"
if $verbose;
my $format = { 0 => 'mp3', 1 => 'ogg', 2 => 'wav' }->{$filetype};
my $data = LJ::Blob::get($u, "phonepost", $format, $blobid);
# get length
my $len = length($data);
if (! $len) {
my $has_blob = $dbcm->selectrow_array("SELECT COUNT(*) FROM userblob WHERE ".
"journalid=? AND domain=? AND blobid=?",
undef, $u->{userid},
LJ::get_blob_domainid("phonepost"),
$blobid);
if (! $has_blob) {
$dbcm->do("UPDATE phonepostentry SET location='none' ".
"WHERE userid=? AND blobid=?", undef, $u->{userid}, $blobid);
print "\tnote: changed phonepost entry location to 'none'\n\n"
if $verbose;
next;
}
}
if ($besteffort && !$len) {
print STDERR "empty_phonepost userid=$u->{userid} blobid=$blobid\n";
print "\twarning: empty phonepost.\n\n"
if $verbose;
next;
}
die "Error: data from blob empty ($u->{user}, 'phonepost', $format, $blobid)\n"
unless $len;
# get filehandle to Mogile and put the file there
print "\tdata length = $len bytes, uploading to MogileFS...\n"
if $verbose;
my $fh = $LJ::MogileFS->new_file("pp:$u->{userid}:$blobid", 'phoneposts');
if ($besteffort && !$fh) {
print STDERR "new_file_failed userid=$u->{userid} blobid=$blobid\n";
print "\twarning: failed in call to new_file\n\n"
if $verbose;
next;
}
die "Unable to get filehandle to save file to MogileFS\n"
unless $fh;
# now save the file and close the handles
$fh->print($data);
my $rv = $fh->close;
if ($besteffort && !$rv) {
print STDERR "close_failed userid=$u->{userid} blobid=$blobid reason=$@\n";
print "\twarning: failed in call to cloes: $@\n\n"
if $verbose;
next;
}
die "Unable to save file to MogileFS: $@\n"
unless $rv;
# extra verification
if ($verify) {
my $data2 = $LJ::MogileFS->get_file_data("pp:$u->{userid}:$blobid");
my $eq = ($data2 && $$data2 eq $data) ? 1 : 0;
if ($besteffort && !$eq) {
print STDERR "verify_failed userid=$u->{userid} blobid=$blobid\n";
print "\twarning: verify failed; phone post not updated\n\n"
if $verbose;
next;
}
die "\tERROR: phone post NOT stored successfully, content mismatch\n"
unless $eq;
print "\tverified length = " . length($$data2) . " bytes...\n"
if $verbose;
}
# done moving this phone post
unless ($dryrun) {
print "\tupdating database for this phone post...\n"
if $verbose;
$dbcm->do("UPDATE phonepostentry SET location = 'mogile' WHERE userid = ? AND blobid = ?",
undef, $u->{userid}, $blobid);
}
# get the paths so the user can verify if they want
if ($verbose) {
my @paths = $LJ::MogileFS->get_paths("pp:$u->{userid}:$blobid", 1);
print "\tverify mogile path: $_\n" foreach @paths;
print "\tphone post update complete.\n\n";
}
}
}
# a sub to get a cluster handle and set it up for our use
sub get_db_handle {
my $cid = shift;
my $dbcm = LJ::get_cluster_master({ raw => 1 }, $cid);
unless ($dbcm) {
print STDERR "handle_unavailable clusterid=$cid\n";
die "ERROR: unable to get raw handle to cluster $cid\n";
}
eval {
$dbcm->do("SET wait_timeout = 28800");
die $dbcm->errstr if $dbcm->err;
};
die "Couldn't set wait_timeout on $cid: $@\n" if $@;
$dbcm->{'RaiseError'} = 1;
return $dbcm;
}

View File

@@ -0,0 +1,318 @@
#!/usr/bin/perl
use strict;
use lib "$ENV{LJHOME}/cgi-bin";
require 'ljlib.pl';
use LJ::Blob;
use LJ::User;
use Getopt::Long;
use IPC::Open3;
use Digest::MD5;
# this script is a migrater that will move userpics from an old storage method
# into mogilefs.
# the basic theory is that we iterate over all clusters, find all userpics that
# aren't in mogile right now, and put them there
# determine
my ($one, $besteffort, $dryrun, $user, $verify, $verbose, $clusters, $purge);
my $rv = GetOptions("best-effort" => \$besteffort,
"one" => \$one,
"dry-run" => \$dryrun,
"user=s" => \$user,
"verify" => \$verify,
"verbose" => \$verbose,
"purge-old" => \$purge,
"clusters=s" => \$clusters,);
unless ($rv) {
die <<ERRMSG;
This script supports the following command line arguments:
--clusters=X[-Y]
Only handle clusters in this range. You can specify a
single number, or a range of two numbers with a dash.
--user=username
Only move this particular user.
--one
Only move one user. (But it moves all their pictures.)
This is used for testing.
--verify
If specified, this option will reload the userpic from
MogileFS and make sure it's been stored successfully.
--dry-run
If on, do not update the database. This mode will put the
userpic in MogileFS and give you paths to examine the picture
and make sure everything is okay. It will not update the
userpic2 table, though.
--best-effort
Normally, if a problem is encountered (null userpic, md5
mismatch, connection failure, etc) the script will die to
make sure everything goes well. With this flag, we don't
die and instead just print to standard error.
--purge-old
Sometimes we run into data that is for users that have since
moved to a different cluster. Normally we ignore it, but
with this option, we'll clean that data up as we find it.
--verbose
Be very chatty.
ERRMSG
}
# make sure ljconfig is setup right (or so we hope)
die "Please define a 'userpics' class in your \%LJ::MOGILEFS_CONFIG\n"
unless defined $LJ::MOGILEFS_CONFIG{classes}->{userpics};
die "Unable to find MogileFS object (\%LJ::MOGILEFS_CONFIG not setup?)\n"
unless $LJ::MogileFS;
# setup stderr if we're in best effort mode
if ($besteffort) {
my $oldfd = select(STDERR);
$| = 1;
select($oldfd);
}
# operation modes
if ($user) {
# move a single user
my $u = LJ::load_user($user);
die "No such user: $user\n" unless $u;
handle_userid($u->{userid}, $u->{clusterid});
} else {
# parse the clusters
my @clusters;
if ($clusters) {
if ($clusters =~ /^(\d+)(?:-(\d+))?$/) {
my ($min, $max) = map { $_ + 0 } ($1, $2 || $1);
push @clusters, $_ foreach $min..$max;
} else {
die "Error: --clusters argument not of right format.\n";
}
} else {
@clusters = @LJ::CLUSTERS;
}
# now iterate over the clusters to pick
my $ctotal = scalar(@clusters);
my $ccount = 0;
foreach my $cid (sort { $a <=> $b } @clusters) {
# status report
$ccount++;
print "\nChecking cluster $cid...\n\n";
# get a handle
my $dbcm = get_db_handle($cid);
# get all userids
print "Getting userids...\n";
my $limit = $one ? 'LIMIT 1' : '';
my $userids = $dbcm->selectcol_arrayref
("SELECT DISTINCT userid FROM userpic2 WHERE location <> 'mogile' OR location IS NULL $limit");
my $total = scalar(@$userids);
# iterate over userids
my $count = 0;
print "Beginning iteration over userids...\n";
foreach my $userid (@$userids) {
# move this userpic
my $extra = sprintf("[%6.2f%%, $ccount of $ctotal] ", (++$count/$total*100));
handle_userid($userid, $cid, $extra);
}
# don't hit up more clusters
last if $one;
}
}
print "\n";
print "Updater terminating.\n";
#############################################################################
### helper subs down here
# take a userid and move their pictures. returns 0 on error, 1 on successful
# move of a user's pictures, and 2 meaning the user isn't ready for moving
# (dversion < 7, etc)
sub handle_userid {
my ($userid, $cid, $extra) = @_;
# load user to move and do some sanity checks
my $u = LJ::load_userid($userid);
unless ($u) {
LJ::end_request();
LJ::start_request();
$u = LJ::load_userid($userid);
}
die "ERROR: Unable to load userid $userid\n"
unless $u;
# if they're expunged, they might have data somewhere if they were
# copy-moved from A to B, then expunged on B. now we're on A and
# need to delete it ourselves (if purge-old is on)
if ($u->{clusterid} == 0 && $u->{statusvis} eq "X") {
return unless $purge;
# if we get here, the user has indicated they want data purged, get handle
my $to_purge_dbcm = get_db_handle($cid);
my $ct = $to_purge_dbcm->do("DELETE FROM userpic2 WHERE userid = ?", undef, $u->{userid});
print "\tnotice: purged $ct old rows.\n\n"
if $verbose;
return;
}
# get a handle
my $dbcm = get_db_handle($u->{clusterid});
# print that we're doing this user
print "$extra$u->{user}($u->{userid})\n";
# if a user has been moved to another cluster, but the source data from
# userpic2 wasn't deleted, we need to ignore the user or purge their data
if ($u->{clusterid} != $cid) {
return unless $purge;
# verify they have some rows on the new side
my $count = $dbcm->selectrow_array
("SELECT COUNT(*) FROM userpic2 WHERE userid = ?",
undef, $u->{userid});
return unless $count;
# if we get here, the user has indicated they want data purged, get handle
my $to_purge_dbcm = get_db_handle($cid);
# delete the old data
if ($dryrun) {
print "\tnotice: need to delete userpic2 rows.\n\n"
if $verbose;
} else {
my $ct = $to_purge_dbcm->do("DELETE FROM userpic2 WHERE userid = ?", undef, $u->{userid});
print "\tnotice: purged $ct old rows.\n\n"
if $verbose;
}
# nothing else to do here
return;
}
# get all their photos that aren't in mogile already
my $picids = $dbcm->selectall_arrayref
("SELECT picid, md5base64, fmt FROM userpic2 WHERE userid = ? AND (location <> 'mogile' OR location IS NULL)",
undef, $u->{userid});
return unless @$picids;
# now we have a userid and picids, get the photos from the blob server
foreach my $row (@$picids) {
my ($picid, $md5, $fmt) = @$row;
print "\tstarting move for picid $picid\n"
if $verbose;
my $format = { G => 'gif', J => 'jpg', P => 'png' }->{$fmt};
my $data = LJ::Blob::get($u, "userpic", $format, $picid);
# get length
my $len = length($data);
if ($besteffort && !$len) {
print STDERR "empty_userpic userid=$u->{userid} picid=$picid\n";
print "\twarning: empty userpic.\n\n"
if $verbose;
next;
}
die "Error: data from blob empty ($u->{user}, 'userpic', $format, $picid)\n"
unless $len;
# verify the md5 of this picture with what's in the database
my $blobmd5 = Digest::MD5::md5_base64($data);
if ($besteffort && ($md5 ne $blobmd5)) {
print STDERR "md5_mismatch userid=$u->{userid} picid=$picid dbmd5=$md5 blobmd5=$blobmd5\n";
print "\twarning: md5 mismatch; database=$md5, blobserver=$blobmd5\n\n"
if $verbose;
next;
}
die "\tError: data from blobserver md5 mismatch: database=$md5, blobserver=$blobmd5\n"
unless $md5 eq $blobmd5;
print "\tverified md5; database=$md5, blobserver=$blobmd5\n"
if $verbose;
# get filehandle to Mogile and put the file there
print "\tdata length = $len bytes, uploading to MogileFS...\n"
if $verbose;
my $fh = $LJ::MogileFS->new_file($u->mogfs_userpic_key($picid), 'userpics');
if ($besteffort && !$fh) {
print STDERR "new_file_failed userid=$u->{userid} picid=$picid\n";
print "\twarning: failed in call to new_file\n\n"
if $verbose;
next;
}
die "Unable to get filehandle to save file to MogileFS\n"
unless $fh;
# now save the file and close the handles
$fh->print($data);
my $rv = $fh->close;
if ($besteffort && !$rv) {
print STDERR "close_failed userid=$u->{userid} picid=$picid reason=$@\n";
print "\twarning: failed in call to cloes: $@\n\n"
if $verbose;
next;
}
die "Unable to save file to MogileFS: $@\n"
unless $rv;
# extra verification
if ($verify) {
my $data2 = $LJ::MogileFS->get_file_data($u->mogfs_userpic_key($picid));
my $eq = ($data2 && $$data2 eq $data) ? 1 : 0;
if ($besteffort && !$eq) {
print STDERR "verify_failed userid=$u->{userid} picid=$picid\n";
print "\twarning: verify failed; picture not updated\n\n"
if $verbose;
next;
}
die "\tERROR: picture NOT stored successfully, content mismatch\n"
unless $eq;
print "\tverified length = " . length($$data2) . " bytes...\n"
if $verbose;
}
# done moving this picture
unless ($dryrun) {
print "\tupdating database for this picture...\n"
if $verbose;
$dbcm->do("UPDATE userpic2 SET location = 'mogile' WHERE userid = ? AND picid = ?",
undef, $u->{userid}, $picid);
}
# get the paths so the user can verify if they want
if ($verbose) {
my @paths = $LJ::MogileFS->get_paths($u->mogfs_userpic_key($picid), 1);
print "\tverify mogile path: $_\n" foreach @paths;
print "\tverify site url: $LJ::SITEROOT/userpic/$picid/$u->{userid}\n";
print "\tpicture update complete.\n\n";
}
}
}
# a sub to get a cluster handle and set it up for our use
sub get_db_handle {
my $cid = shift;
my $dbcm = LJ::get_cluster_master({ raw => 1 }, $cid);
unless ($dbcm) {
print STDERR "handle_unavailable clusterid=$cid\n";
die "ERROR: unable to get raw handle to cluster $cid\n";
}
eval {
$dbcm->do("SET wait_timeout = 28800");
die $dbcm->errstr if $dbcm->err;
};
die "Couldn't set wait_timeout on $cid: $@\n" if $@;
$dbcm->{'RaiseError'} = 1;
return $dbcm;
}

View File

@@ -0,0 +1,162 @@
#!/usr/bin/perl
use strict;
use lib "$ENV{'LJHOME'}/cgi-bin";
require 'ljlib.pl';
# so output happens quickly
$| = 1;
# make sure we got a parameter
my $propname = shift;
die "ERROR: no property specified\n" unless $propname;
# verify it's a valid property
my $prop = LJ::get_prop('user', $propname);
# see if we know how to handle this parameter
if ($propname eq 'external_foaf_url' && $prop->{cldversion} == 0) {
# this one is simple; we're moving this one to the clusters 1000 users at a time
print "Beginning initial data migration...\n";
cluster_property($prop);
# update the property to be indexed
print "Updating property data in userproplist...\n";
update_property($prop, { indexed => 0, cldversion => 4 });
# strongly recommend a restart
print "\n";
print "* " x 38 . "\n";
print "WARNING: It is recommended that you restart your web nodes now to cause the\n";
print " updated property to start to take effect. Please press enter when\n";
print " this is done.\n";
print "* " x 38 . "\n";
readline STDIN;
# now let's hope they restarted and let's migrate anybody who is still stuck
print "Beginning final data migration...\n";
cluster_property($prop);
# done
print "Finished migrating external_foaf_url property.\n";
} else {
# don't know how to handle it
die "ERROR: don't know how to handle '$propname' (has it already been handled?)\n";
}
##############################################################################
### helper subs
sub cluster_property {
my $prop = shift;
# some state tracking information
my (%dbcms); # ( clusterid => dbcm )
my (%to_write); # ( clusterid => [ [ userid, value ], [ userid, value ], ... ]
# note: livejournal has only about 7500 external_foaf_urls... those should
# be moved in less time than any database handle will time out, so I've made
# the decision not to worry about handle timeouts right now. all other sites
# are probably no more than this size, so it should be fine for everybody.
# setup our flushing sub that we'll need later
my $flush = sub {
my $cid = shift;
# get the ref from to_write etc
my $aref = $to_write{$cid};
delete $to_write{$cid};
# get handle to database if needed
my $dbcm = $dbcms{$cid} || ($dbcms{$cid} = LJ::get_cluster_master($cid));
# notice that we're flushing data
print "\tflushing " . scalar(@$aref) . " items to cluster $cid...";
# now construct SQL
my $repstr = join(', ', map { "($_->[0], $prop->{upropid}, " .
$dbcm->quote($_->[1]) . ")" } @$aref);
$dbcm->do("REPLACE INTO userproplite2 (userid, upropid, value) VALUES $repstr");
die "ERROR: database: " . $dbcm->errstr . "\n" if $dbcm->err;
# done, status update
print "flushed\n";
};
# start our main loop
while (1) {
# data storage for each loop
my (%users, %values); # ( userid => user object or value )
# clear our handles
$LJ::DBIRole->flush_cache();
# get main database handle
my $dbh = LJ::get_db_writer();
# select up to 1000 userid:value tuples
print "Getting values...";
my $vals = $dbh->selectall_arrayref
('SELECT userid, value FROM userprop WHERE upropid = ? LIMIT 1000',
undef, $prop->{upropid});
die "ERROR: database: " . $dbh->errstr . "\n" if $dbh->err;
print "got " . scalar(@$vals) . " values.\n";
# short circuit if we have 0
return 1 if scalar @$vals == 0;
# get the userids to load
my @to_load;
foreach my $row (@$vals) {
my ($userid, $value) = @$row;
$values{$userid} = $value;
push @to_load, $userid;
}
# now load the users in one big grab
print "Loading users...";
LJ::load_userids_multiple([ map { $_ => \$users{$_} } @to_load ]);
print "loaded.\n";
# now push data onto the cluster lists
while (my ($userid, $value) = each %values) {
my $cid = $users{$userid}->{clusterid};
# clusterid 0 means the user is expunged or somesuch, so we
# don't weant to migrate their settings anywhere and should
# just delete it.
next unless $cid;
# now push this onto the to_write array
$to_write{$cid} ||= [];
push @{$to_write{$cid}}, [ $userid, $value ];
# now, flush this list if it's large (100 or more)
$flush->($cid) if scalar @{$to_write{$cid}} >= 100;
}
# now flush everything that's left
$flush->($_) foreach keys %to_write;
# now delete from the global for items that we've written
print "Deleting " . scalar(keys %values) . " items from global...";
my $instr = join(',', map { $_ + 0 } keys %values);
$dbh->do("DELETE FROM userprop WHERE upropid = $prop->{upropid} AND userid IN ($instr)");
die "ERROR: database: " . $dbh->errstr . "\n" if $dbh->err;
print "deleted.\n";
# last if we had less than 1000 this time
last if scalar @$vals < 1000;
}
}
sub update_property {
my ($prop, $sets) = @_;
die "ERROR: nothing to set\n" unless %$sets;
# now make the updates they want
my $dbh = LJ::get_db_writer();
my $updstr = join(', ', map { "$_ = " . $dbh->quote($sets->{$_}) } keys %$sets);
$dbh->do("UPDATE userproplist SET $updstr WHERE upropid = $prop->{upropid}");
die "ERROR: database: " . $dbh->errstr . "\n" if $dbh->err;
}

View File

@@ -0,0 +1,107 @@
MOOD 1 aggravated 2
MOOD 2 angry 0
MOOD 3 annoyed 2
MOOD 4 anxious 46
MOOD 5 bored 25
MOOD 6 confused 0
MOOD 7 crappy 25
MOOD 8 cranky 2
MOOD 9 depressed 25
MOOD 10 discontent 25
MOOD 11 energetic 0
MOOD 12 enraged 2
MOOD 14 exhausted 74
MOOD 15 happy 0
MOOD 16 high 41
MOOD 18 hungry 74
MOOD 19 infuriated 2
MOOD 20 irate 2
MOOD 21 jubilant 15
MOOD 22 lonely 25
MOOD 23 moody 2
MOOD 25 sad 0
MOOD 26 satisfied 53
MOOD 28 stressed 2
MOOD 30 thoughtful 0
MOOD 31 tired 14
MOOD 32 touched 15
MOOD 33 lazy 61
MOOD 34 drunk 74
MOOD 41 excited 15
MOOD 42 relieved 26
MOOD 43 hopeful 70
MOOD 44 amused 15
MOOD 46 scared 0
MOOD 47 frustrated 2
MOOD 49 sleepy 31
MOOD 51 groggy 31
MOOD 52 hyper 11
MOOD 53 relaxed 15
MOOD 54 restless 74
MOOD 55 disappointed 25
MOOD 56 curious 6
MOOD 61 okay 0
MOOD 68 calm 53
MOOD 70 optimistic 15
MOOD 71 pessimistic 38
MOOD 74 uncomfortable 25
MOOD 79 embarrassed 46
MOOD 80 envious 10
MOOD 81 sympathetic 25
MOOD 82 sick 74
MOOD 83 hot 74
MOOD 84 cold 74
MOOD 85 worried 25
MOOD 86 loved 15
MOOD 87 awake 0
MOOD 88 working 0
MOOD 89 productive 88
MOOD 90 accomplished 88
MOOD 91 busy 88
MOOD 93 full 26
MOOD 95 grumpy 2
MOOD 96 weird 66
MOOD 98 ecstatic 15
MOOD 101 contemplative 30
MOOD 102 nerdy 0
MOOD 103 geeky 102
MOOD 104 cynical 2
MOOD 106 crazy 66
MOOD 107 creative 88
MOOD 109 pleased 15
MOOD 112 irritated 2
MOOD 113 blank 78
MOOD 114 apathetic 78
MOOD 115 dorky 102
MOOD 116 impressed 15
MOOD 117 naughty 36
MOOD 119 dirty 74
MOOD 120 giddy 66
MOOD 121 surprised 15
MOOD 122 shocked 121
MOOD 123 rejected 25
MOOD 124 numb 25
MOOD 125 cheerful 15
MOOD 126 good 15
MOOD 127 distressed 4
MOOD 128 intimidated 46
MOOD 130 devious 0
MOOD 131 thankful 15
MOOD 132 grateful 15
MOOD 133 jealous 25
MOOD 134 nervous 46
MOODTHEME Classic Smileys : The classic little yellow (and other color) smiley faces.
2 /img/mood/classic/angry.gif 15 15
6 /img/mood/classic/confused.gif 19 17
11 /img/mood/classic/energetic.gif 17 17
15 /img/mood/classic/smile.gif 15 15
25 /img/mood/classic/sad.gif 15 15
30 /img/mood/classic/thinking.gif 22 21
31 /img/mood/classic/tired.gif 19 17
34 /img/mood/classic/drunk.gif 15 15
46 /img/mood/classic/shock.gif 15 15
61 /img/mood/classic/blah.gif 15 15
66 /img/mood/classic/wink.gif 15 15
79 /img/mood/classic/blush.gif 15 15
82 /img/mood/classic/sick.gif 15 15
130 /img/mood/classic/devious.gif 15 15

View File

@@ -0,0 +1,886 @@
#!/usr/bin/perl
#
# Moves a user between clusters.
#
use strict;
use Getopt::Long;
my $opt_del = 0;
my $opt_destdel = 0;
my $opt_useslow = 0;
my $opt_slowalloc = 0;
my $opt_verbose = 1;
my $opt_movemaster = 0;
my $opt_prelocked = 0;
my $opt_expungedel = 0;
my $opt_ignorebit = 0;
exit 1 unless GetOptions('delete' => \$opt_del,
'destdelete' => \$opt_destdel,
'useslow' => \$opt_useslow, # use slow db role for read
'slowalloc' => \$opt_slowalloc, # see note below
'verbose=i' => \$opt_verbose,
'movemaster|mm' => \$opt_movemaster,
'prelocked' => \$opt_prelocked,
'expungedel' => \$opt_expungedel,
'ignorebit' => \$opt_ignorebit,
);
my $optv = $opt_verbose;
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
require "$ENV{'LJHOME'}/cgi-bin/ljcmdbuffer.pl";
my $dbh = LJ::get_dbh({raw=>1}, "master");
die "No master db available.\n" unless $dbh;
$dbh->do("SET wait_timeout=28800");
my $dbr = $dbh;
if ($opt_useslow) {
$dbr = LJ::get_dbh({raw=>1}, "slow");
unless ($dbr) { die "Can't get slow db from which to read.\n"; }
}
my $user = LJ::canonical_username(shift @ARGV);
my $dclust = shift @ARGV;
# tables which are dumbly copied by sucking all into memory first.
# use smarter mover code for anything that shouldn't all go into memory.
# also, to use this you have to define the primary keys below
my @manual_move = qw(loginstall ratelog sessions userproplite2
sessions_data userbio userpicblob2 userpropblob
s1usercache modlog modblob counter
s1style s1overrides links userblob clustertrack2);
sub usage {
die "Usage:\n movecluster.pl <user> <destination cluster #>\n";
}
usage() unless defined $user;
usage() unless defined $dclust;
die "Failed to get move lock.\n"
unless ($dbh->selectrow_array("SELECT GET_LOCK('moveucluster-$user', 10)"));
my $u = $dbh->selectrow_hashref("SELECT * FROM user WHERE user=?", undef, $user);
die "Non-existent user $user.\n" unless $u;
die "Can't move back to legacy cluster 0\n" unless $dclust;
my $dbch = LJ::get_cluster_master({raw=>1}, $dclust);
die "Undefined or down cluster \#$dclust\n" unless $dbch;
$dbch->do("SET wait_timeout=28800");
my $separate_cluster = LJ::use_diff_db("master", "cluster$dclust");
$dbh->{'RaiseError'} = 1;
$dbch->{'RaiseError'} = 1;
my $sclust = $u->{'clusterid'};
if ($sclust == $dclust) {
die "User '$user' is already on cluster $dclust\n";
}
if ($sclust) {
verify_movable_tables();
}
# original cluster db handle.
my $dbo;
if ($sclust) {
$dbo = $opt_movemaster ?
LJ::get_dbh({raw=>1}, "cluster$u->{clusterid}movemaster") :
LJ::get_cluster_master({raw=>1}, $u);
die "Can't get source cluster handle.\n" unless $dbo;
$dbo->{'RaiseError'} = 1;
$dbo->do("SET wait_timeout=28800");
}
my $userid = $u->{'userid'};
# find readonly cap class, complain if not found
my $readonly_bit = undef;
foreach (keys %LJ::CAP) {
if ($LJ::CAP{$_}->{'_name'} eq "_moveinprogress" &&
$LJ::CAP{$_}->{'readonly'} == 1) {
$readonly_bit = $_;
last;
}
}
unless (defined $readonly_bit) {
die "Won't move user without %LJ::CAP capability class named '_moveinprogress' with readonly => 1\n";
}
# make sure a move isn't already in progress
if ($opt_prelocked) {
unless (($u->{'caps'}+0) & (1 << $readonly_bit)) {
die "User '$user' should have been prelocked.\n";
}
} else {
if (($u->{'caps'}+0) & (1 << $readonly_bit)) {
die "User '$user' is already in the process of being moved? (cap bit $readonly_bit set)\n"
unless $opt_ignorebit;
}
}
if ($opt_expungedel && $u->{'statusvis'} eq "D" &&
LJ::mysqldate_to_time($u->{'statusvisdate'}) < time() - 86400*31) {
print "Expunging user '$u->{'user'}'\n";
$dbh->do("INSERT INTO clustermove (userid, sclust, dclust, timestart, timedone) ".
"VALUES (?,?,?,UNIX_TIMESTAMP(),UNIX_TIMESTAMP())", undef,
$userid, $sclust, 0);
LJ::update_user($userid, { clusterid => 0,
statusvis => 'X',
raw => "caps=caps&~(1<<$readonly_bit), statusvisdate=NOW()" });
exit 0;
}
print "Moving '$u->{'user'}' from cluster $sclust to $dclust\n" if $optv >= 1;
# mark that we're starting the move
$dbh->do("INSERT INTO clustermove (userid, sclust, dclust, timestart) ".
"VALUES (?,?,?,UNIX_TIMESTAMP())", undef, $userid, $sclust, $dclust);
my $cmid = $dbh->{'mysql_insertid'};
# set readonly cap bit on user
LJ::update_user($userid, { raw => "caps=caps|(1<<$readonly_bit)" })
unless $opt_prelocked;
$dbh->do("SELECT RELEASE_LOCK('moveucluster-$user')");
unless ($opt_prelocked) {
# wait a bit for writes to stop if journal is somewhat active (last week update)
my $secidle = $dbh->selectrow_array("SELECT UNIX_TIMESTAMP()-UNIX_TIMESTAMP(timeupdate) ".
"FROM userusage WHERE userid=$userid");
if ($secidle) {
sleep(2) unless $secidle > 86400*7;
sleep(1) unless $secidle > 86400;
}
}
# make sure slow is caught up:
if ($opt_useslow)
{
my $ms = $dbh->selectrow_hashref("SHOW MASTER STATUS");
my $loop = 1;
while ($loop) {
my $ss = $dbr->selectrow_hashref("SHOW SLAVE STATUS");
$loop = 0;
unless ($ss->{'Log_File'} gt $ms->{'File'} ||
($ss->{'Log_File'} eq $ms->{'File'} && $ss->{'Pos'} >= $ms->{'Position'}))
{
$loop = 1;
print "Waiting for slave ($ss->{'Pos'} < $ms->{'Position'})\n";
sleep 1;
}
}
}
my $last = time();
my $stmsg = sub {
my $msg = shift;
my $now = time();
return if ($now < $last + 1);
$last = $now;
print $msg;
};
my %bufcols = (); # db|table -> scalar "(foo, anothercol, lastcol)" or undef or ""
my %bufrows = (); # db|table -> [ []+ ]
my %bufdbmap = (); # scalar(DBI hashref) -> DBI hashref
my $flush_buffer = sub {
my $dbandtable = shift;
my ($db, $table) = split(/\|/, $dbandtable);
$db = $bufdbmap{$db};
return unless exists $bufcols{$dbandtable};
my $sql = "REPLACE INTO $table $bufcols{$dbandtable} VALUES ";
$sql .= join(", ",
map { my $r = $_;
"(" . join(", ",
map { $db->quote($_) } @$r) . ")" }
@{$bufrows{$dbandtable}});
$db->do($sql);
delete $bufrows{$dbandtable};
delete $bufcols{$dbandtable};
};
my $flush_all = sub {
foreach (keys %bufcols) {
$flush_buffer->($_);
}
};
my $replace_into = sub {
my $db = ref $_[0] ? shift : $dbch; # optional first arg
my ($table, $cols, $max, @vals) = @_;
my $dbandtable = scalar($db) . "|$table";
$bufdbmap{$db} = $db;
if (exists $bufcols{$dbandtable} && $bufcols{$dbandtable} ne $cols) {
$flush_buffer->($dbandtable);
}
$bufcols{$dbandtable} = $cols;
push @{$bufrows{$dbandtable}}, [ @vals ];
if (scalar @{$bufrows{$dbandtable}} > $max) {
$flush_buffer->($dbandtable);
}
};
# assume never tried to move this user before. however, if reported crap
# in the oldids table, we'll revert to slow alloc_id functionality,
# where we do a round-trip to $dbh for everything and see if every id
# has been remapped already. otherwise we do it in perl and batch
# updates to the oldids table, which is the common/fast case.
my $first_move = ! $opt_slowalloc;
my %alloc_data;
my %alloc_arealast;
my $alloc_id = sub {
my ($area, $orig) = @_;
# fast version
if ($first_move) {
my $id = $alloc_data{$area}->{$orig} = ++$alloc_arealast{$area};
$replace_into->($dbh, "oldids", "(area, oldid, userid, newid)", 250,
$area, $orig, $userid, $id);
return $id;
}
# slow version
$dbh->{'RaiseError'} = 0;
$dbh->do("INSERT INTO oldids (area, oldid, userid, newid) ".
"VALUES ('$area', $orig, $userid, NULL)");
my $id;
if ($dbh->err) {
$id = $dbh->selectrow_array("SELECT newid FROM oldids WHERE area='$area' AND oldid=$orig");
} else {
$id = $dbh->{'mysql_insertid'};
}
$dbh->{'RaiseError'} = 1;
$alloc_data{$area}->{$orig} = $id;
return $id;
};
my $bufread;
if ($sclust == 0)
{
# do bio stuff
{
my $bio = $dbr->selectrow_array("SELECT bio FROM userbio WHERE userid=$userid");
my $bytes = length($bio);
$dbch->do("REPLACE INTO dudata (userid, area, areaid, bytes) VALUES ($userid, 'B', 0, $bytes)");
if ($separate_cluster) {
$bio = $dbh->quote($bio);
$dbch->do("REPLACE INTO userbio (userid, bio) VALUES ($userid, $bio)");
}
}
my @itemids = reverse @{$dbr->selectcol_arrayref("SELECT itemid FROM log ".
"WHERE ownerid=$u->{'userid'} ".
"ORDER BY ownerid, rlogtime")};
$bufread = make_buffer_reader("itemid", \@itemids);
my $todo = @itemids;
my $done = 0;
my $stime = time();
print "Total: $todo\n";
# moving time, journal item at a time, and everything recursively under it
foreach my $itemid (@itemids) {
movefrom0_logitem($itemid);
$done++;
my $percent = $done/$todo;
my $elapsed = time() - $stime;
my $totaltime = $elapsed * (1 / $percent);
my $timeremain = int($totaltime - $elapsed);
$stmsg->(sprintf "$user: copy $done/$todo (%.2f%%) +${elapsed}s -${timeremain}s\n", 100*$percent);
}
$flush_all->();
# update their memories. in particular, any memories of their own
# posts need to to be updated from the (0, globalid) to
# (journalid, jitemid) format, to make the memory filter feature
# work. (it checks the first 4 bytes only, not joining the
# globalid on the clustered log table)
print "Fixing memories.\n";
my @fix = @{$dbh->selectall_arrayref("SELECT memid, jitemid FROM memorable WHERE ".
"userid=$u->{'userid'} AND journalid=0")};
foreach my $f (@fix) {
my ($memid, $newid) = ($f->[0], $alloc_data{'L'}->{$f->[1]});
next unless $newid;
my ($newid2, $anum) = $dbch->selectrow_array("SELECT jitemid, anum FROM log2 ".
"WHERE journalid=$u->{'userid'} AND ".
"jitemid=$newid");
if ($newid2 == $newid) {
my $ditemid = $newid * 256 + $anum;
print "UPDATE $memid TO $ditemid\n";
$dbh->do("UPDATE memorable SET journalid=$u->{'userid'}, jitemid=$ditemid ".
"WHERE memid=$memid");
}
}
# fix polls
print "Fixing polls.\n";
@fix = @{$dbh->selectall_arrayref("SELECT pollid, itemid FROM poll ".
"WHERE journalid=$u->{'userid'}")};
foreach my $f (@fix) {
my ($pollid, $newid) = ($f->[0], $alloc_data{'L'}->{$f->[1]});
next unless $newid;
my ($newid2, $anum) = $dbch->selectrow_array("SELECT jitemid, anum FROM log2 ".
"WHERE journalid=$u->{'userid'} AND ".
"jitemid=$newid");
if ($newid2 == $newid) {
my $ditemid = $newid * 256 + $anum;
print "UPDATE $pollid TO $ditemid\n";
$dbh->do("UPDATE poll SET itemid=$ditemid WHERE pollid=$pollid");
}
}
# move userpics
print "Copying over userpics.\n";
my @pics = @{$dbr->selectcol_arrayref("SELECT picid FROM userpic WHERE ".
"userid=$u->{'userid'}")};
foreach my $picid (@pics) {
print " picid\#$picid...\n";
my $imagedata = $dbr->selectrow_array("SELECT imagedata FROM userpicblob ".
"WHERE picid=$picid");
$imagedata = $dbh->quote($imagedata);
$dbch->do("REPLACE INTO userpicblob2 (userid, picid, imagedata) VALUES ".
"($u->{'userid'}, $picid, $imagedata)");
}
$dbh->do("UPDATE userusage SET lastitemid=0 WHERE userid=$userid");
my $dversion = 2;
# if everything's good (nothing's died yet), then delete all from source
if ($opt_del)
{
# before we start deleting, record they've moved servers.
LJ::update_user($userid, { dversion => $dversion, clusterid => $dclust });
$done = 0;
$stime = time();
foreach my $itemid (@itemids) {
deletefrom0_logitem($itemid);
$done++;
my $percent = $done/$todo;
my $elapsed = time() - $stime;
my $totaltime = $elapsed * (1 / $percent);
my $timeremain = int($totaltime - $elapsed);
$stmsg->(sprintf "$user: delete $done/$todo (%.2f%%) +${elapsed}s -${timeremain}s\n", 100*$percent);
}
# delete bio from source, if necessary
if ($separate_cluster) {
$dbh->do("DELETE FROM userbio WHERE userid=$userid");
}
# delete source userpics
print "Deleting cluster0 userpics...\n";
foreach my $picid (@pics) {
print " picid\#$picid...\n";
$dbh->do("DELETE FROM userpicblob WHERE picid=$picid");
}
# unset read-only bit (marks the move is complete, also, and not aborted mid-delete)
LJ::update_user($userid, { raw => "caps=caps&~(1<<$readonly_bit)" });
$dbh->do("UPDATE clustermove SET sdeleted='1', timedone=UNIX_TIMESTAMP() ".
"WHERE cmid=?", undef, $cmid);
}
else
{
# unset readonly and move to new cluster in one update
LJ::update_user($userid, { dversion => $dversion, clusterid => $dclust,
raw => "caps=caps&~(1<<$readonly_bit)" });
$dbh->do("UPDATE clustermove SET sdeleted='0', timedone=UNIX_TIMESTAMP() ".
"WHERE cmid=?", undef, $cmid);
}
exit 0;
}
elsif ($sclust > 0)
{
print "Moving away from cluster $sclust\n" if $optv;
while (my $cmd = $dbo->selectrow_array("SELECT cmd FROM cmdbuffer WHERE journalid=$userid")) {
my $dbcm = LJ::get_cluster_master($sclust);
print "Flushing cmdbuffer for cmd: $cmd\n" if $optv > 1;
LJ::Cmdbuffer::flush($dbh, $dbcm, $cmd, $userid);
}
my $pri_key = {
# flush this first:
'cmdbuffer' => 'journalid',
# this is populated as we do log/talk
'dudata' => 'userid',
# manual
'loginstall' => 'userid',
'ratelog' => 'userid',
'sessions' => 'userid',
'sessions_data' => 'userid',
'userbio' => 'userid',
'userpicblob2' => 'userid',
'userproplite2' => 'userid',
's1usercache' => 'userid',
'modlog' => 'journalid',
'modblob' => 'journalid',
'counter' => 'journalid',
'userblob' => 'journalid',
'userpropblob' => 'userid',
'clustertrack2' => 'userid',
# log
'log2' => 'journalid',
'logsec2' => 'journalid',
'logprop2' => 'journalid',
'logtext2' => 'journalid',
# talk
'talk2' => 'journalid',
'talkprop2' => 'journalid',
'talktext2' => 'journalid',
# no primary key... move up by posttime
'talkleft' => 'userid',
# s1 styles
's1style' => 'userid',
's1overrides' => 'userid',
# link lists
'links' => 'journalid',
};
# ask the local mods if they have any tables to move
my @local_tables;
my $local_tables = LJ::run_hook("moveucluster_local_tables");
if ($local_tables) {
while (my ($tab, $key) = each %$local_tables) {
push @local_tables, $tab;
$pri_key->{$tab} = $key;
}
}
my @existing_data;
print "Checking for existing data on target cluster...\n" if $optv > 1;
foreach my $table (sort keys %$pri_key) {
my $pri = $pri_key->{$table};
my $is_there = $dbch->selectrow_array("SELECT $pri FROM $table WHERE $pri=$userid LIMIT 1");
next unless $is_there;
if ($opt_destdel) {
while ($dbch->do("DELETE FROM $table WHERE $pri=$userid LIMIT 500") > 0) {
print " deleted from $table\n" if $optv;
}
} else {
push @existing_data, $table;
}
}
if (@existing_data) {
die " Existing data in tables: @existing_data\n";
}
my %pendreplace; # "logprop2:(col,col)" => { 'values' => [ [a, b, c], [d, e, f] ],
# 'bytes' => 3043, 'recs' => 35 }
my $flush = sub {
my $dest = shift;
return 1 unless $pendreplace{$dest};
my ($table, $cols) = split(/:/, $dest);
my $vals;
foreach my $v (@{$pendreplace{$dest}->{'values'}}) {
$vals .= "," if $vals;
$vals .= "(" . join(',', map { $dbch->quote($_) } @$v) . ")";
}
print " flushing write to $table\n" if $optv > 1;
$dbch->do("REPLACE INTO $table $cols VALUES $vals");
die $dbh->errstr if $dbch->err;
delete $pendreplace{$dest};
return 1;
};
my $write = sub {
my $dest = shift;
my @values = @_;
my $new_bytes = 0; foreach (@values) { $new_bytes += length($_); }
push @{$pendreplace{$dest}->{'values'}}, \@values;
$pendreplace{$dest}->{'bytes'} += $new_bytes;
$pendreplace{$dest}->{'recs'}++;
if ($pendreplace{$dest}->{'bytes'} > 1024*500 ||
$pendreplace{$dest}->{'recs'} > 500) { $flush->($dest); }
};
my @styleids = ();
# manual moving (dumb copies)
foreach my $table (@manual_move, @local_tables) {
next if ($table eq "modlog" || $table eq "modblob") && $u->{journaltype} eq "P";
print " moving $table ...\n" if $optv > 1;
my @cols;
my $sth = $dbo->prepare("DESCRIBE $table");
$sth->execute;
my $styleidcolnum = -1;
my $colnum = 0;
while ($_ = $sth->fetchrow_hashref) {
push @cols, $_->{'Field'};
$styleidcolnum = $colnum if $_->{'Field'} eq 'styleid';
$colnum++;
}
my $cols = join(',', @cols);
my $dest = "$table:($cols)";
my $pri = $pri_key->{$table};
$sth = $dbo->prepare("SELECT $cols FROM $table WHERE $pri=$userid");
$sth->execute;
while (my @vals = $sth->fetchrow_array) {
$write->($dest, @vals);
if ($styleidcolnum > -1 && $table eq 's1style') {
push @styleids, $vals[$styleidcolnum];
}
}
}
# size of bio
my $bio_size = $dbch->selectrow_array("SELECT LENGTH(bio) FROM userbio WHERE userid=$userid");
$write->("dudata:(userid,area,areaid,bytes)", $userid, 'B', 0, $bio_size) if $bio_size;
# journal items
{
my $maxjitem = $dbo->selectrow_array("SELECT MAX(jitemid) FROM log2 WHERE journalid=$userid");
my $load_amt = 1000;
my ($lo, $hi) = (1, $load_amt);
my $sth;
my $cols = "security,allowmask,journalid,jitemid,posterid,eventtime,logtime,compressed,anum,replycount,year,month,day,rlogtime,revttime"; # order matters. see indexes below
while ($lo <= $maxjitem) {
print " log ($lo - $hi, of $maxjitem)\n" if $optv > 1;
# log2/logsec2
$sth = $dbo->prepare("SELECT $cols FROM log2 ".
"WHERE journalid=$userid AND jitemid BETWEEN $lo AND $hi");
$sth->execute;
while (my @vals = $sth->fetchrow_array) {
$write->("log2:($cols)", @vals);
if ($vals[0] eq "usemask") {
$write->("logsec2:(journalid,jitemid,allowmask)",
$userid, $vals[3], $vals[1]);
}
}
# logprop2
$sth = $dbo->prepare("SELECT journalid,jitemid,propid,value ".
"FROM logprop2 WHERE journalid=$userid AND jitemid BETWEEN $lo AND $hi");
$sth->execute;
while (my @vals = $sth->fetchrow_array) {
$write->("logprop2:(journalid,jitemid,propid,value)", @vals);
}
# logtext2
$sth = $dbo->prepare("SELECT journalid,jitemid,subject,event ".
"FROM logtext2 WHERE journalid=$userid AND jitemid BETWEEN $lo AND $hi");
$sth->execute;
while (my @vals = $sth->fetchrow_array) {
my $size = length($vals[2]) + length($vals[3]);
LJ::text_compress(\$vals[3]);
$write->("logtext2:(journalid,jitemid,subject,event)", @vals);
$write->("dudata:(userid,area,areaid,bytes)", $userid, 'L', $vals[1], $size);
}
$hi += $load_amt; $lo += $load_amt;
}
}
# comments
{
my $maxtalkid = $dbo->selectrow_array("SELECT MAX(jtalkid) FROM talk2 WHERE journalid=$userid");
my $load_amt = 1000;
my ($lo, $hi) = (1, $load_amt);
my $sth;
my %cols = ('talk2' => 'journalid,jtalkid,nodetype,nodeid,parenttalkid,posterid,datepost,state',
'talkprop2' => 'journalid,jtalkid,tpropid,value',
'talktext2' => 'journalid,jtalkid,subject,body');
while ($lo <= $maxtalkid) {
print " talk ($lo - $hi, of $maxtalkid)\n" if $optv > 1;
foreach my $table (keys %cols) {
$sth = $dbo->prepare("SELECT $cols{$table} FROM $table ".
"WHERE journalid=$userid AND jtalkid BETWEEN $lo AND $hi");
$sth->execute;
while (my @vals = $sth->fetchrow_array) {
LJ::text_compress(\$vals[3]) if $table eq "talktext2";
$write->("$table:($cols{$table})", @vals);
}
}
$hi += $load_amt; $lo += $load_amt;
}
}
# talkleft table.
{
# no primary key... delete all of target first.
while ($dbch->do("DELETE FROM talkleft WHERE userid=$userid LIMIT 1000") > 0) {
print " deleted from talkleft\n" if $optv > 1;
}
my $last_max = 0;
my $cols = "userid,posttime,journalid,nodetype,nodeid,jtalkid,publicitem";
while (defined $last_max) {
print " talkleft: $last_max\n" if $optv > 1;
my $sth = $dbo->prepare("SELECT $cols FROM talkleft WHERE userid=$userid ".
"AND posttime > $last_max ORDER BY posttime LIMIT 1000");
$sth->execute;
undef $last_max;
while (my @vals = $sth->fetchrow_array) {
$write->("talkleft:($cols)", @vals);
$last_max = $vals[1];
}
}
}
# flush remaining items
foreach (keys %pendreplace) { $flush->($_); }
# unset readonly and move to new cluster in one update
LJ::update_user($userid, { clusterid => $dclust, raw => "caps=caps&~(1<<$readonly_bit)" });
print "Moved.\n" if $optv;
# delete from source cluster
if ($opt_del) {
print "Deleting from source cluster...\n" if $optv;
foreach my $table (sort keys %$pri_key) {
my $pri = $pri_key->{$table};
while ($dbo->do("DELETE FROM $table WHERE $pri=$userid LIMIT 500") > 0) {
print " deleted from $table\n" if $optv;
}
}
# s1stylecache table
if (@styleids) {
my $styleids_in = join(",", map { $dbo->quote($_) } @styleids);
if ($dbo->do("DELETE FROM s1stylecache WHERE styleid IN ($styleids_in)") > 0) {
print " deleted from s1stylecache\n" if $optv;
}
}
} else {
# at minimum, we delete the clustertrack2 row so it doesn't get
# included in a future ljumover.pl query from that cluster.
$dbo->do("DELETE FROM clustertrack2 WHERE userid=$userid");
}
$dbh->do("UPDATE clustermove SET sdeleted=?, timedone=UNIX_TIMESTAMP() ".
"WHERE cmid=?", undef, $opt_del ? 1 : 0, $cmid);
exit 0;
}
sub deletefrom0_logitem
{
my $itemid = shift;
# delete all the comments
my $talkids = $dbh->selectcol_arrayref("SELECT talkid FROM talk ".
"WHERE nodetype='L' AND nodeid=$itemid");
my $talkidin = join(",", @$talkids);
if ($talkidin) {
foreach my $table (qw(talktext talkprop talk)) {
$dbh->do("DELETE FROM $table WHERE talkid IN ($talkidin)");
}
}
$dbh->do("DELETE FROM logsec WHERE ownerid=$userid AND itemid=$itemid");
foreach my $table (qw(logprop logtext log)) {
$dbh->do("DELETE FROM $table WHERE itemid=$itemid");
}
}
sub movefrom0_logitem
{
my $itemid = shift;
my $item = $bufread->(100, "SELECT * FROM log", $itemid);
my $itemtext = $bufread->(50, "SELECT itemid, subject, event FROM logtext", $itemid);
return 1 unless $item && $itemtext; # however that could happen.
# we need to allocate a new jitemid (journal-specific itemid) for this item now.
my $jitemid = $alloc_id->('L', $itemid);
unless ($jitemid) {
die "ERROR: could not allocate a new jitemid\n";
}
$dbh->{'RaiseError'} = 1;
$item->{'jitemid'} = $jitemid;
$item->{'anum'} = int(rand(256));
# copy item over:
$replace_into->("log2", "(journalid, jitemid, posterid, eventtime, logtime, ".
"compressed, security, allowmask, replycount, year, month, day, ".
"rlogtime, revttime, anum)",
50, map { $item->{$_} } qw(ownerid jitemid posterid eventtime
logtime compressed security allowmask replycount
year month day rlogtime revttime anum));
$replace_into->("logtext2", "(journalid, jitemid, subject, event)", 10,
$userid, $jitemid, map { $itemtext->{$_} } qw(subject event));
# add disk usage info! (this wasn't in cluster0 anywhere)
my $bytes = length($itemtext->{'event'}) + length($itemtext->{'subject'});
$replace_into->("dudata", "(userid, area, areaid, bytes)", 50, $userid, 'L', $jitemid, $bytes);
# add the logsec item, if necessary:
if ($item->{'security'} ne "public") {
$replace_into->("logsec2", "(journalid, jitemid, allowmask)", 50,
map { $item->{$_} } qw(ownerid jitemid allowmask));
}
# copy its logprop over:
while (my $lp = $bufread->(50, "SELECT itemid, propid, value FROM logprop", $itemid)) {
next unless $lp->{'value'};
$replace_into->("logprop2", "(journalid, jitemid, propid, value)", 50,
$userid, $jitemid, $lp->{'propid'}, $lp->{'value'});
}
# copy its talk shit over:
my %newtalkids = (0 => 0); # 0 maps back to 0 still
my $talkids = $dbr->selectcol_arrayref("SELECT talkid FROM talk ".
"WHERE nodetype='L' AND nodeid=$itemid");
my @talkids = sort { $a <=> $b } @$talkids;
my $treader = make_buffer_reader("talkid", \@talkids);
foreach my $t (@talkids) {
movefrom0_talkitem($t, $jitemid, \%newtalkids, $item, $treader);
}
}
sub movefrom0_talkitem
{
my $talkid = shift;
my $jitemid = shift;
my $newtalkids = shift;
my $logitem = shift;
my $treader = shift;
my $item = $treader->(100, "SELECT *, UNIX_TIMESTAMP(datepost) AS 'datepostunix' FROM talk", $talkid);
my $itemtext = $treader->(50, "SELECT talkid, subject, body FROM talktext", $talkid);
return 1 unless $item && $itemtext; # however that could happen.
# abort if this is a stranded entry. (shouldn't happen, anyway. even if it does, it's
# not like we're losing data: the UI (talkread.bml) won't show it anyway)
return unless defined $newtalkids->{$item->{'parenttalkid'}};
# we need to allocate a new jitemid (journal-specific itemid) for this item now.
my $jtalkid = $alloc_id->('T', $talkid);
unless ($jtalkid) {
die "ERROR: could not allocate a new jtalkid\n";
}
$newtalkids->{$talkid} = $jtalkid;
$dbh->{'RaiseError'} = 1;
# copy item over:
$replace_into->("talk2", "(journalid, jtalkid, parenttalkid, nodeid, ".
"nodetype, posterid, datepost, state)", 50,
$userid, $jtalkid, $newtalkids->{$item->{'parenttalkid'}},
$jitemid, 'L', map { $item->{$_} } qw(posterid datepost state));
$replace_into->("talktext2", "(journalid, jtalkid, subject, body)",
20, $userid, $jtalkid, map { $itemtext->{$_} } qw(subject body));
# copy its logprop over:
while (my $lp = $treader->(50, "SELECT talkid, tpropid, value FROM talkprop", $talkid)) {
next unless $lp->{'value'};
$replace_into->("talkprop2", "(journalid, jtalkid, tpropid, value)", 50,
$userid, $jtalkid, $lp->{'tpropid'}, $lp->{'value'});
}
# note that poster commented here
if ($item->{'posterid'}) {
my $pub = $logitem->{'security'} eq "public" ? 1 : 0;
my ($table, $db) = ("talkleft_xfp", $dbh);
($table, $db) = ("talkleft", $dbch) if $userid == $item->{'posterid'};
$replace_into->($db, $table, "(userid, posttime, journalid, nodetype, ".
"nodeid, jtalkid, publicitem)", 50,
$item->{'posterid'}, $item->{'datepostunix'}, $userid,
'L', $jitemid, $jtalkid, $pub);
}
}
sub make_buffer_reader
{
my $pricol = shift;
my $valsref = shift;
my %bfd; # buffer read data. halfquery -> { 'rows' => { id => [] },
# 'remain' => [], 'loaded' => { id => 1 } }
return sub
{
my ($amt, $hq, $pid) = @_;
if (not defined $bfd{$hq}->{'loaded'}->{$pid})
{
if (not exists $bfd{$hq}->{'remain'}) {
$bfd{$hq}->{'remain'} = [ @$valsref ];
}
my @todo;
for (1..$amt) {
next unless @{$bfd{$hq}->{'remain'}};
my $id = shift @{$bfd{$hq}->{'remain'}};
push @todo, $id;
$bfd{$hq}->{'loaded'}->{$id} = 1;
}
if (@todo) {
my $sql = "$hq WHERE $pricol IN (" . join(",", @todo) . ")";
my $sth = $dbr->prepare($sql);
$sth->execute;
while (my $r = $sth->fetchrow_hashref) {
push @{$bfd{$hq}->{'rows'}->{$r->{$pricol}}}, $r;
}
}
}
return shift @{$bfd{$hq}->{'rows'}->{$pid}};
};
}
# this function needs to die loudly if moveucluster.pl is unable to move
# any type of table that exists on this installation
sub verify_movable_tables {
my %table; # tablename -> unhandled flag
# first, assume everything's unhandled
foreach my $t (@LJ::USER_TABLES, @LJ::USER_TABLES_LOCAL) {
$table{$t} = 1;
}
# now, clear things we know how to move
foreach my $t (qw(cmdbuffer dudata log2 logsec2 logprop2 logtext2
talk2 talkprop2 talktext2 talkleft
), @manual_move) {
delete $table{$t};
}
# local stuff
my $local_tables = LJ::run_hook("moveucluster_local_tables");
if ($local_tables) {
while (my ($tab, $key) = each %$local_tables) {
delete $table{$tab};
}
}
# things we list as active tables but don't use yet
delete $table{"events"};
# things we don't move because it doesn't really matter
delete $table{"s1stylecache"};
delete $table{"captcha_session"};
if (%table) {
die "ERROR. Won't try to move user, because this mover script can't move all live tables for this user. List of tables without mover code available: \n -- " . join("\n -- ", sort keys %table), "\n";
}
}
1; # return true;

View File

@@ -0,0 +1,84 @@
#!/usr/bin/perl
#
# This script converts from dversion 3 to dversion 4,
# which makes most userprops clustered
#
use strict;
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
my $fromver = shift;
die "Usage: pop-clusterprops.pl <fromdversion>\n\t(where fromdversion is one of: 3)\n"
unless $fromver == 3;
my $dbh = LJ::get_db_writer();
my $todo = $dbh->selectrow_array("SELECT COUNT(*) FROM user WHERE dversion=$fromver");
my $done = 0;
unless ($todo) {
print "Nothing to convert.\n";
exit 0;
}
sub get_some {
my @list;
my $sth = $dbh->prepare("SELECT * FROM user WHERE dversion=$fromver LIMIT 200");
$sth->execute;
push @list, $_ while $_ = $sth->fetchrow_hashref;
@list;
}
my $tover = $fromver + 1;
print "Converting $todo users from data version $fromver to $tover...\n";
my @props;
my $sth = $dbh->prepare("SELECT upropid FROM userproplist WHERE cldversion=?");
$sth->execute($tover);
push @props, $_ while $_ = $sth->fetchrow_array;
my $in = join(',', @props);
die "No values?" unless $in;
my $start = time();
while (my @list = get_some()) {
LJ::start_request();
my %cluster; # clusterid -> [ $u* ]
foreach my $u (@list) {
push @{$cluster{$u->{'clusterid'}}}, $u;
}
foreach my $cid (keys %cluster) {
my $dbcm = LJ::get_cluster_master($cid);
next unless $dbcm;
my $uid_in = join(',', map { $_->{'userid'} } @{$cluster{$cid}});
my @vals;
foreach my $table (qw(userprop userproplite)) {
$sth = $dbh->prepare("SELECT userid, upropid, value FROM $table ".
"WHERE userid IN ($uid_in) AND upropid IN ($in)");
$sth->execute();
while (my ($uid, $pid, $v) = $sth->fetchrow_array) {
push @vals, "($uid,$pid," . $dbh->quote($v) . ")";
}
}
if (@vals) {
my $sql = "REPLACE INTO userproplite2 VALUES " . join(',', @vals);
$dbcm->do($sql);
if ($dbcm->err) {
die "Error: " . $dbcm->errstr . "\n\n(Do you need to --runsql on your clusters first?)\n";
}
$dbh->do("DELETE FROM userprop WHERE userid IN ($uid_in) AND upropid IN ($in)");
$dbh->do("DELETE FROM userproplite WHERE userid IN ($uid_in) AND upropid IN ($in)");
}
$dbh->do("UPDATE user SET dversion=$tover WHERE userid IN ($uid_in) AND dversion=$fromver");
$done += scalar @{$cluster{$cid}};
}
my $perc = $done/$todo;
my $elapsed = time() - $start;
my $total_time = $elapsed / $perc;
my $min_remain = int(($total_time - $elapsed) / 60);
printf "%d/%d complete (%.02f%%) minutes_remain=%d\n", $done, $todo, ($perc*100), $min_remain;
}

View File

@@ -0,0 +1,68 @@
#!/usr/bin/perl
#
# This script converts from dversion 2 (clustered + userpicblobs clustered)
# to dversion 3, which adds weekuserusage population.
#
use strict;
require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
die "This script is no longer useful.\n";
my $dbh = LJ::get_db_writer();
my $todo = $dbh->selectrow_array("SELECT COUNT(*) FROM user WHERE dversion=2");
my $done = 0;
unless ($todo) {
print "Nothing to convert.\n";
exit 0;
}
sub get_some {
my @list;
my $sth = $dbh->prepare("SELECT * FROM user WHERE dversion=2 LIMIT 200");
$sth->execute;
push @list, $_ while $_ = $sth->fetchrow_hashref;
@list;
}
print "Converting $todo users from data version 2 to 3...\n";
my $start = time();
while (my @list = get_some()) {
LJ::start_request();
foreach my $u (@list) {
my $dbcm = LJ::get_cluster_master($u);
next unless $dbcm;
my %week;
my $sth = $dbcm->prepare("SELECT rlogtime FROM log2 ".
"WHERE journalid=? AND rlogtime < 2147483647");
$sth->execute($u->{'userid'});
while (my $t = $sth->fetchrow_array) {
my ($week, $uafter, $ubefore) = LJ::weekuu_parts($t);
if (! $week{$week}) {
$week{$week} = [ $uafter, $ubefore ];
} elsif ($ubefore < $week{$week}->[1]) {
$week{$week}->[1] = $ubefore;
}
}
if (%week) {
my $sql = "REPLACE INTO weekuserusage (wknum,userid,uafter,ubefore) VALUES " .
join(",", map { "($_,$u->{'userid'},$week{$_}->[0],$week{$_}->[1])" } keys %week);
my $rv = $dbh->do($sql);
die $dbh->errstr if $dbh->err;
next unless $rv; # error? try later.
}
$dbh->do("UPDATE user SET dversion=3 WHERE userid=?", undef, $u->{'userid'});
$done++;
}
my $perc = $done/$todo;
my $elapsed = time() - $start;
my $total_time = $elapsed / $perc;
my $min_remain = int(($total_time - $elapsed) / 60);
printf "%d/%d complete (%.02f%%) minutes_remain=%d\n", $done, $todo, ($perc*100), $min_remain;
}

View File

@@ -0,0 +1,85 @@
#!/usr/bin/perl
#
# Library to read/write s1styles.dat
#
sub s1styles_read
{
my $ss = {};
open (F, "$ENV{'LJHOME'}/bin/upgrading/s1styles.dat");
my $uniq;
my $entry;
my $read_entry = 0;
my $line = 0;
while (<F>)
{
$line++;
if ($read_entry && $entry)
{
if ($_ eq ".\n") {
chop $entry->{'formatdata'}; # we added a newline
$read_entry = 0;
undef $entry;
next;
}
s!^\.!!;
$entry->{'formatdata'} .= $_;
next;
}
if (m!^Style:\s*(\w+?)/(.+?)\s*$!) {
$uniq = "$1/$2";
die "Repeat style in s1styles.dat at line $line!"
if exists $ss->{$uniq};
$entry = $ss->{$uniq} = {
'type' => $1,
'styledes' => $2,
};
$read_entry = 0;
next;
}
if ($entry && $_ eq "\n") {
$read_entry = 1;
next;
}
next unless $entry;
if (/^(\w+):\s*(.+?)\s*$/) {
$entry->{$1} = $2;
next;
}
die "s1styles.dat:$line: bogus line\n" if /\S/;
}
close F;
return $ss;
}
sub s1styles_write
{
my $ss = shift;
open (F, ">$ENV{'LJHOME'}/bin/upgrading/s1styles.dat")
or die "Can't open s1styles.dat for writing.\n";
foreach my $uniq (sort keys %$ss) {
my $s = $ss->{$uniq};
print F "Style: $uniq\n";
foreach (qw(is_public is_embedded is_colorfree opt_cache lastupdate)) {
next unless exists $s->{$_};
print F "$_: $s->{$_}\n";
}
my $formatdata = $s->{'formatdata'};
$formatdata =~ s/\r//g; # die, DOS line endings!
$formatdata =~ s/\n\./\n\.\./g;
print F "\n$formatdata\n.\n\n";
}
close F;
}
1;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,54 @@
################################################################
# base filename layer type parent
core1 core -
i18nc/da1 i18nc core1
i18nc/de1 i18nc core1
i18nc/en1 i18nc core1
i18nc/eo1 i18nc core1
i18nc/fi1 i18nc core1
i18nc/fr1 i18nc core1
i18nc/ja1 i18nc core1
i18nc/ru1 i18nc core1
classic/layout layout core1
classic/en i18n classic/layout
classic/themes theme+ classic/layout
cleansimple/layout layout core1
cleansimple/en i18n cleansimple/layout
cleansimple/themes theme+ cleansimple/layout
digitalmultiplex/layout layout core1
digitalmultiplex/en i18n digitalmultiplex/layout
haven/layout layout core1
haven/themes theme+ haven/layout
generator/layout layout core1
generator/en i18n generator/layout
generator/themes theme+ generator/layout
magazine/layout layout core1
magazine/en i18n magazine/layout
magazine/themes theme+ magazine/layout
notepad/layout layout core1
notepad/en i18n notepad/layout
#notepad/themes theme+ notepad/layout
punquin/layout layout core1
punquin/en i18n punquin/layout
punquin/themes theme+ punquin/layout
tabularindent/layout layout core1
tabularindent/en i18n tabularindent/layout
tabularindent/themes theme+ tabularindent/layout
sturdygesture/layout layout core1
sturdygesture/themes theme+ sturdygesture/layout
variableflow/layout layout core1
# include local file
s2layers-local.dat INCLUDE

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -0,0 +1,16 @@
# -*-s2-*-
layerinfo type = "i18n";
layerinfo name = "English";
layerinfo redist_uniq = "classic/en";
set text_meta_music = "Current Music";
set text_meta_mood = "Current Mood";
set text_permalink = "Link";
set text_post_comment = "Comment on This";
set text_post_comment_friends = "Comment on This";
set text_read_comments = "1 comment // # comments";
set text_read_comments_friends = "1 comment // # comments";

View File

@@ -0,0 +1,785 @@
# -*-s2-*-
layerinfo type = "layout";
layerinfo name = "Classic";
layerinfo redist_uniq = "classic/layout";
layerinfo previews = "classic/classic.jpg";
propgroup colors {
property Color body_bgcolor {
des = "Background color of page";
s1color = "stronger_back";
}
property Color main_bgcolor {
des = "Background color of main text area";
s1color = "page_back";
}
property Color main_fgcolor {
des = "Color of text on main text areas";
s1color = "page_text";
}
property Color headerbar_bgcolor {
des = "Background color of header bars";
s1color = "strong_back";
}
property Color headerbar_fgcolor {
des = "Color of text on header bars";
s1color = "strong_text";
}
property Color metabar_bgcolor {
des = "Background color of side bar";
s1color = "weak_back";
}
property Color metabar_fgcolor {
des = "Color of text on side bar";
s1color = "weak_text";
}
property Color page_title_color {
des = "Text color of the page's main title";
s1color = "page_text_title";
}
property Color page_subtitle_color {
des = "Text color of the page's subtitles";
s1color = "page_text_em";
}
property Color link_color {
des = "Text color of links";
s1color = "page_link";
}
property Color vlink_color {
des = "Text color of visited links";
s1color = "page_vlink";
}
property Color alink_color {
des = "Text color of active links";
s1color = "page_alink";
}
property Color comment_bar_one_bgcolor {
des = "Alternating background color for comment bars (one)";
}
property Color comment_bar_two_fgcolor {
des = "Text color on alternating comment bars (one)";
}
property Color comment_bar_two_bgcolor {
des = "Alternating background color for comment bars (two)";
}
property Color comment_bar_one_fgcolor {
des = "Text color on alternating comment bars (two)";
}
property Color comment_bar_screened_bgcolor {
des = "Background bar color for screened comments";
}
property Color comment_bar_screened_fgcolor {
des = "Text color on background bar for screened comments";
}
}
set body_bgcolor = "#6666cc";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set headerbar_bgcolor = "#c0c0ff";
set headerbar_fgcolor = "#000000";
set metabar_bgcolor = "#eeeeff";
set metabar_fgcolor = "#000000";
set page_title_color = "#8b1a1a";
set page_subtitle_color = "#c00000";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#ff00c0";
set comment_bar_one_bgcolor = "#c0c0ff";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#eeeeff";
set comment_bar_two_fgcolor = "#000000";
set comment_bar_screened_bgcolor = "#dddddd";
set comment_bar_screened_fgcolor = "#000000";
set tags_aware = true;
propgroup presentation {
property bool show_entry_userpic {
des = "Show your userpic with your journal's entries?";
}
property use font_base;
property use font_fallback;
property use page_recent_items;
property use page_friends_items;
property use view_entry_disabled;
property use use_shared_pic;
property bool show_entrynav_icons {
des = "Toggle to show the next, memory, edit, etc icons on the entry view page";
}
property string page_background_image {
des = "URL to an image to be used for the page background";
}
property use external_stylesheet;
}
set show_entry_userpic = false;
set font_base = "Arial, Helvetica";
set font_fallback = "sans-serif";
set page_recent_items = 20;
set page_friends_items = 25;
set view_entry_disabled = false;
set show_entrynav_icons = true;
set page_background_image = "";
propgroup text {
property use text_post_comment;
property use text_read_comments;
property use text_post_comment_friends;
property use text_read_comments_friends;
property use text_website_default_name;
}
function print_stylesheet ()
{
print clean_url($*page_background_image) != "" ? "body { background-image: url($*page_background_image); }" : "";
var string font;
if ($*font_base) {
$font = "\"$*font_base\"";
if ($*font_fallback != "none") {
$font = "$font, ";
}
}
if ($*font_fallback != "none") {
$font = "$font $*font_fallback";
}
if ($font != "") {
"""
body, table, td, th, .page_title, #yearheader {
font-family: $font;
}
""";
}
"""
body,.body {
background-color: $*body_bgcolor;
color: $*main_fgcolor;
padding: 5pt;
}
a, a:link {
color: $*link_color;
}
a:vlink {
color: $*vlink_color;
}
a:alink {
color: $*alink_color;
}
table.main {
background-color: $*main_bgcolor;
color: $*main_fgcolor;
}
.page_title {
color: $*page_title_color;
font-size: 18pt;
}
.view_links {
font-family: monospace;
white-space: nowrap;
}
.view_links2 {
font-family: monospace;
font-size: 9pt;
}
th.headerbar {
background-color: $*headerbar_bgcolor;
color: $*headerbar_fgcolor;
font-weight: bold;
font-size: 16pt;
text-align: left;
}
td.metabar {
text-align: right;
white-space: nowrap;
background-color: $*metabar_bgcolor;
color: $*metabar_fgcolor;
}
.subject {
color: $*page_subtitle_color;
font-weight: bold;
}
.comments {
text-align: right;
}
#yearheader {
color: $*page_subtitle_color;
font-weight: bold;
font-style: italic;
font-size: 14pt;
}
th.monthheader {
background-color: $*headerbar_bgcolor;
font-size: 12pt;
}
th.daysheader {
background-color: $*metabar_bgcolor;
font-weight: normal;
}
td.weekday_empty {
background-color: $*metabar_bgcolor;
}
.day_id {
font-weight: bold;
font-size: 10pt;
}
#archiveyearpage_nav {
font-size: 14pt;
font-weight: bold;
}
""";
}
function Page::lay_nav_blurb() { }
function Page::lay_primary_userpic() : Image {
return $.journal.default_pic;
}
function EntryPage::lay_primary_userpic() : Image {
return $.entry.userpic;
}
function Page::print_linklist() {
if (size $.linklist <= 0) {
return;
}
var bool section_open = false;
println "<span class='view_links2'>";
foreach var UserLink l ($.linklist) {
if ($l.title) {
if ($l.is_heading) {
if ($section_open) {
println "<br />";
}
println """<span style="font-weight: bold;">$l.title</span> """;
$section_open = true;
} else {
println """[<a href="$l.url">$l.title</a>]""";
}
}
}
if ($section_open) {
println "</span><br /><br />";
}
println "";
}
function Page::print ()
{
var string title = $this->title();
var string userpic;
var Image default_userpic = $this->lay_primary_userpic();
if (defined $default_userpic)
{
$userpic = "<img align='right' style='padding: 2px' src='$default_userpic.url' "+
"width='$default_userpic.width' height='$default_userpic.height' alt='' />";
}
var string website_name = $.journal.website_name ? $.journal.website_name : $*text_website_default_name;
var string website = $.journal.website_url ?
"""<td><a href="$.journal.website_url">$website_name</a></td><td class="body">&nbsp;</td>""" :
"";
var string links;
foreach var string v ($.views_order) {
$links = $links + ($.view == $v ?
"["+lang_viewname($v)+"]" :
"[<a href='$.view_url{$v}'>"+lang_viewname($v)+"</a>]");
}
"""
<html>
<head>
""";
if ($*external_stylesheet) {
println """<link rel="stylesheet" href="$.stylesheet_url" type="text/css" />""";
} else {
println """<style type="text/css">"""; print_stylesheet(); "</style>";
}
$this->print_head();
"""
<title>$title</title>
</head>
<body>
<table class="main" width='100%'><tr><td>
$userpic
<span class="page_title">$title</span>
<p class="view_links">$links</p>
""";
if (size $.linklist > 0 and $*linklist_support) {
$this->print_linklist();
}
$this->lay_nav_blurb();
$this->print_body();
"</td></tr></table>\n";
### Affliations
"<table class='main' align='right'><tr>";
print $website; "<td>"; server_sig(); "</td></tr>";
"</table>\n</body>\n</html>";
}
function print_entry (Page p, Entry e, Color bgcolor, Color fgcolor, bool hide_text)
{
var string time = $e.time->time_format();
var string userpic = "";
if (defined $e.userpic)
{
$userpic = "<img src='$e.userpic.url' alt='[User Picture]' height='$e.userpic.height' width='$e.userpic.width' />";
}
if ($e.new_day or $p.view == "entry")
{
"<tr><th colspan='2' align='left' class='headerbar'>";
print $e.time->date_format("%%month%% %%dayord%%, %%yyyy%%");
"</th></tr>\n";
} elseif ($p.view == "day") {
"<tr><th class='headerbar'>Time</td><td class='headerbar' style='width: 100%'>Event</th></tr>";
}
"<tr valign='top'>";
# Metabar
"<td style='background-color: $bgcolor;' class='metabar'>";
# Time
"<em>$time</em><br />";
# Altposter crap
if ($p.view == "friends")
{
"<strong><a style='color: $fgcolor' href='" + $e.journal->base_url() + "/'>";
print $e.journal.username;
"</a></strong><br />";
}
if ($e.journal.username != $e.poster.username)
{
"[<a href='" + $e.poster->base_url() + "/'>";
print $e.poster.username;
"</a>]<br />";
}
if ($userpic != "" and ($p.view == "friends" or $*show_entry_userpic == true))
{
print $userpic;
}
# Security icon
if ($e.security) { print $e.security_icon; }
# Permalink
"<p>[<a href='$e.permalink_url'>$*text_permalink</a>]</p>";
"</td>";
# Entry
"<td style='text-align:left'>";
if ($p.view == "entry" and $*show_entrynav_icons)
{
print "<div style='text-align: center'>";
$e->print_linkbar();
print "</div>";
}
if ($e.subject) { "\n\n<span class='subject'>$e.subject</span><br />"; }
if (not $hide_text) {
print $e.text; "\n\n";
if (size $e.metadata or size $e.tags)
{
"<p>";
foreach var string k ($e.metadata)
{
var string key = $k;
var string val = $e.metadata{$k};
if ($k == "mood") { $key = $*text_meta_mood; }
if ($k == "music") { $key = $*text_meta_music; }
if ($k == "mood" and defined $e.mood_icon)
{
var Image i = $e.mood_icon;
$val = "<img src='$i.url' width='$i.width' height='$i.height' alt='' /> $val";
}
"<strong>$key:</strong> $val<br />";
}
if ($e.tags) {
var int tcount = 0;
"<strong>Tags:</strong> ";
foreach var Tag t ($e.tags) {
"""<a rel="tag" href="$t.url">$t.name</a>""";
$tcount++;
if ($tcount != size $e.tags) { ", "; }
}
"<br />";
}
"</p>";
}
}
$e.comments->print();
"</td>";
"</tr>\n";
}
function Page::print_entry (Entry e)
{
print_entry($this, $e, $*metabar_bgcolor, $*metabar_fgcolor, false);
}
function FriendsPage::print_entry (Entry e)
{
var Friend f = $.friends{$e.journal.username};
print_entry($this, $e, $f.bgcolor, $f.fgcolor, false);
}
function RecentPage::lay_nav_blurb ()
{
var string user = "<a href='$.base_url/info'>$.journal.name</a>";
if ($.nav.skip > 0)
{
"Below are $.nav.count entries, after skipping $.nav.skip most recent ones in the \"$user\" journal:";
} else {
"Below are the $.nav.count most recent journal entries recorded in the \"$user\" journal:";
}
}
function RecentPage::print_body ()
{
var string nav = "";
if ($.nav.forward_url != "" or $.nav.backward_url != "")
{
if ($.nav.backward_url != "")
{
$nav = "<a href='$.nav.backward_url'>&lt;&lt; Previous $.nav.backward_count entries</a>";
}
if ($.nav.backward_url != "" and $.nav.forward_url != "")
{
$nav = "$nav --";
}
if ($.nav.forward_url != "")
{
$nav = "$nav <a href='$.nav.forward_url'>Next $.nav.forward_count entries &gt;&gt;</a>";
}
$nav = "<p align='center'>[$nav]</p>";
}
if ($nav != "") { print $nav; }
"<table style='margin-left: 30px'>\n";
foreach var Entry e ($.entries) { $this->print_entry($e); }
"</table>\n";
if ($nav != "") { print $nav; }
}
function FriendsPage::lay_nav_blurb ()
{
var int total = size $.entries;
if ($.nav.skip > 0)
{
"Below are $total friends entries, after skipping $.nav.skip most recent ones:";
} else {
"Below are the $total most recent friends journal entries:";
}
}
function CommentInfo::print ()
{
if (not $.enabled) { return; }
"<p class='comments'>(";
if ($.count > 0 or $.screened) {
$this->print_readlink();
"&nbsp;|&nbsp;";
}
$this->print_postlink();
")</p>";
}
function YearPage::lay_nav_blurb()
{
"<p id='yearpage_nav'>";
$this->print_year_links();
"</p>";
}
function YearPage::print_body
{
"<p id='yearheader'>$.year&hellip;</p>\n";
foreach var YearMonth m ($.months) {
$this->print_month($m);
}
}
function YearPage::print_year_links ()
{
foreach var YearYear y ($.years) {
if ($y.displayed) {
"[ $y.year ]";
} else {
"[ <a href=\"$y.url\">$y.year</a> ]";
}
}
}
function YearPage::print_month(YearMonth m)
{
if (not $m.has_entries) { return; }
# Table Wrapper
"<center><p><table border='1' cellpadding='4' width='80%'>\n";
# Month Header
"<tr align='center'><th colspan='7' class='monthheader'>\n";
print $m->month_format();
"</th></tr>\n";
# Weekdays Header
"<tr align='center'>\n";
foreach var int d (weekdays()) {
"<th class='daysheader'>"+$*lang_dayname_short[$d]+"</th>\n";
}
"</tr>\n";
# Weeks
foreach var YearWeek w ($m.weeks) {
$w->print();
}
# Footer
"<tr><td colspan='7'><div style='text-align: center'><a href='$m.url'>$*text_view_month</a></div></td></tr>\n";
# End Table
"</table></p></center>\n";
}
function YearWeek::print ()
{
"<tr>";
if ($.pre_empty) { "<td colspan='$.pre_empty' class='weekday_empty'>&nbsp;</td>"; }
foreach var YearDay d ($.days) {
"<td valign='top'><span class='day_id'>$d.day</span><div style='text-align: center'>";
if ($d.num_entries) {
"<a href='$d.url'>$d.num_entries</a>";
} else {
"&nbsp;";
}
"</div></td>\n";
}
if ($.post_empty) { "<td colspan='$.post_empty' class='weekday_empty'>&nbsp;</td>"; }
"</tr>";
}
function DayPage::print_body ()
{
"<h2 class='daypage_header'>"; print $.date->date_format("%%month%% %%dayord%%, %%yyyy%%"); "</h2>";
if (not $.has_entries)
{
"<blockquote><em>"; print ehtml($*text_noentries_day); "</em></blockquote>";
} else {
"<table style='margin-left: 30px'>";
foreach var Entry e ($.entries) { $this->print_entry($e); }
"</table>";
}
var string tprev = ehtml($*text_day_prev);
var string tnext = ehtml($*text_day_next);
"<table align='center'><tr align='middle'>\n";
"<td width='33%' align='left'><a href='$.prev_url'>$tprev</a></td>\n";
"<td align='center' width='33%'>";
"<strong>"; print $.date->date_format("%%yyyy%%/%%mm%%/%%dd%%"); "</strong><br />";
"[<a href='"; print $this.journal->base_url(); "/calendar'>$*text_view_archive</a>]</td>\n";
"<td width='33%' align='right'><a href='$.next_url'>$tnext</a></td>\n";
"</tr></table>";
}
function EntryPage::print_body () {
set_handler("unscreen_comment_#", [
[ "style_bgcolor", "cmtbar#", "$*comment_bar_one_bgcolor", ],
[ "style_color", "cmtbar#", "$*comment_bar_one_fgcolor", ],
]);
set_handler("screen_comment_#", [
[ "style_bgcolor", "cmtbar#", "$*comment_bar_screened_bgcolor", ],
[ "style_color", "cmtbar#", "$*comment_bar_screened_fgcolor", ],
]);
"<table style='margin-left: 30px'>\n";
print_entry($this, $.entry, $*metabar_bgcolor, $*metabar_fgcolor, $.viewing_thread);
if ($.entry.comments.enabled and $.comment_pages.total_subitems > 0)
{
$this->print_multiform_start();
"<tr valign='top'><th class='headerbar' colspan='2'>Comments</th></tr>";
"<tr valign='top'><td style='background-color: $*metabar_bgcolor'>&nbsp;</td><td style='width: 100%'>";
if ($.comment_pages.total_subitems > 0) {
$.comment_pages->print();
$this->print_comments($.comments);
}
"</td></tr>";
if ($this.multiform_on) {
"<tr valign='top'><th class='headerbar' colspan='2'>Mass Action</th></tr>";
"<tr valign='top'><td style='background-color: $*metabar_bgcolor'>&nbsp;</td><td style='width: 100%'>";
$this->print_multiform_actionline();
$this->print_multiform_end();
"</td></tr>";
}
}
"</table>\n";
}
function EntryPage::print_comment (Comment c) {
var Color background; var Color color;
if ($c.screened) {
$background = $*comment_bar_screened_bgcolor;
$color = $*comment_bar_screened_fgcolor;
} elseif ($c.depth % 2) {
$background = $*comment_bar_one_bgcolor;
$color = $*comment_bar_one_fgcolor;
} else {
$background = $*comment_bar_two_bgcolor;
$color = $*comment_bar_two_fgcolor;
}
var string poster = defined $c.poster ? $c.poster->as_string() : "<i>(Anonymous)</i>";
var string sub_icon;
if (defined $c.subject_icon) {
$sub_icon = $c.subject_icon->as_string();
}
"<a name='$c.anchor'></a><div id='cmtbar$c.talkid' style='background-color: $background; color: $color; margin-top: 10px; width: 100%'>";
"<table cellpadding='2' cellspacing='0' summary='0' style='width: 100%'><tr valign='top'>";
if (defined $c.userpic and $*comment_userpic_style != "off") {
var int w = $c.userpic.width;
var int h = $c.userpic.height;
# WARNING: this will later be done by the system (it'll be a
# constructional property), so don't copy this hack into your
# layout layers or you'll be messed up later.
if ($*comment_userpic_style == "small") {
$w = $w / 2;
$h = $h / 2;
}
print "<td style='width: 102px'><img src='$c.userpic.url' width='$w' height='$h' alt='[User Picture]' /></td>";
}
"<td style='width: 100%'><table style='width: 100%'><tr>";
### From, date, etc
"<td align='left' style='width: 50%'>";
print "<table>";
print "<tr><th align='right'>From:</th><td>$poster</td></tr>\n";
print "<tr><th align='right'>Date:</th><td style='white-space: nowrap'>";
print $c.time->date_format("long") + " - " + $c.time->time_format() + "</td></tr>";
if ($c.metadata{"poster_ip"}) { print "<tr><th align='right'>IP Address:</th><td>(" + $c.metadata{"poster_ip"} + ")</td></tr>"; }
"</table></td>";
### Gadgets
"<td align='right' style='width: 50%'>";
if ($this.multiform_on) {
" <label for='ljcomsel_$c.talkid'>$*text_multiform_check</label>";
$c->print_multiform_check();
}
$c->print_linkbar();
"</td></tr>";
### Subject / icon
print "<tr valign='top'><td style='width: 50%'>";
print (defined $c.subject_icon or $c.subject != "") ? "<h3>$c.subject_icon $c.subject</h3>" : "";
print "</td>";
### Permalink
print "<td style='width: 50%' align='right'><strong>(<a href='$c.permalink_url'>Link</a>)</strong></td></tr>";
print "</table></td></tr></table></div>";
print "<div style='margin-left: 5px'>$c.text</div>";
print "<div style='margin-top: 3px; font-size: smaller'>";
if ($c.frozen) {
print "(Replies frozen) ";
} else {
print "(<a href='$c.reply_url'>Reply to this</a>) ";
}
if ($c.parent_url != "") { "(<a href='$c.parent_url'>Parent</a>) "; }
if ($c.thread_url != "") { "(<a href='$c.thread_url'>Thread</a>) "; }
"</div>";
}
function ReplyPage::print_body()
{
"<table style='margin-left: 30px'>\n";
if (not $.entry.comments.enabled) {
print "<tr><th class='headerbar'>$*text_reply_nocomments_header</th></tr><tr><td>$*text_reply_nocomments</td></tr></table>";
return;
}
var string time = $.replyto.time->time_format();
var string userpic = "";
if (defined $.replyto.userpic)
{
$userpic = "<img src='$.replyto.userpic.url' />";
}
"<tr><th class='headerbar'>Time</td><th class='headerbar' style='width: 100%'>Text</th></tr>";
"<tr valign='top'>";
# Metabar
"<td style='background-color: $*metabar_bgcolor;' class='metabar'>";
# Time
"<em>$time</em><br />";
if ($userpic)
{
print $userpic + "<br />\n";
}
print defined $.replyto.poster ? $.replyto.poster->as_string() : "<i>(Anonymous)</i>";
# Permalink
"<p>[<a href='$.replyto.permalink_url'>$*text_permalink</a>]</p>";
"</td>";
# Text
"<td style='text-align:left'>";
if ($.replyto.subject != "") { "\n\n<span class='subject'>$.replyto.subject</span><br />"; }
print $.replyto.text; "\n\n";
"</td></tr>\n";
"<div align='center'><a href='$.entry.comments.read_url'>( Read Comments )</a></div>";
"<tr valign='top'><th class='headerbar' colspan='2'>Reply:</th></tr>";
"<tr valing='top'><td style='background-color: $*metabar_bgcolor'>&nbsp;</td><td>";
$.form->print();
"</td></tr></table>";
}
function print_theme_preview ()
{
"""
<table width='100%' style='background-color: $*body_bgcolor'>
<tr><td>
<table height='95%' cellpadding='5' width='100%' bgcolor='$*main_bgcolor'>
<tr><td>
<span style='font: normal bold 16pt $*font_base, $*font_fallback; color: $*page_title_color'>John Doe</span>
<ul><table>
<tr><td align="left" style="background-color: $*headerbar_bgcolor; color: $*headerbar_fgcolor" colspan="2">
<span style='font: normal bold 14pt $*font_base, $*font_fallback'>Friday, November 15th, 2002</span>
</td></tr>
<tr valign="top"><td style="text-align: right; background-color: $*metabar_bgcolor; white-space: nowrap">
<span style="font: italic normal 10pt $*font_base, $*font_fallback; color: $*metabar_fgcolor">
10:21 pm</span>
</td><td>
<p style="text-align:left">
<span style="font: italic bold 10pt $*font_base, $*font_fallback; color: $*page_subtitle_color">
Neque porro quisquam est&hellip;
</span><br />
Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit
Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit
Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit
Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit
Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit
Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit
</p><p style="text-align:right; font-size: 8pt">
(<a href="#" style="font-weight: bold; color: $*link_color">1 Comment</a> |
<a href="#" style="color: $*vlink_color">Comment on this</a>)
</p>
</td></tr>
</table></ul>
</td></tr>
</table>
</td></tr>
</table>
""";
}

View File

@@ -0,0 +1,419 @@
#NEWLAYER: classic/calmfire
layerinfo type = theme;
layerinfo name = "Calm Fire";
layerinfo redist_uniq = "classic/calmfire";
set body_bgcolor = "#9e0610";
set main_bgcolor = "#7d7d7d";
set main_fgcolor = "#ffffff";
set headerbar_bgcolor = "#ff6c1d";
set headerbar_fgcolor = "#000000";
set metabar_bgcolor = "#ff9364";
set metabar_fgcolor = "#000000";
set page_title_color = "#8b1a1a";
set page_subtitle_color = "#c00000";
set link_color = "#ff1010";
set vlink_color = "#f10707";
set alink_color = "#ff1d1d";
set comment_bar_one_bgcolor = "#ff6c1d";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#ff9364";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: classic/shrinkvio
layerinfo type = theme;
layerinfo name = "Shrinking Violet";
layerinfo redist_uniq = "classic/shrinkvio";
set body_bgcolor = "#ad22e7";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set headerbar_bgcolor = "#5d0383";
set headerbar_fgcolor = "#ffffff";
set metabar_bgcolor = "#5d0343";
set metabar_fgcolor = "#ffffff";
set page_title_color = "#d9a1f1";
set page_subtitle_color = "#d9a1f1";
set link_color = "#2e053f";
set vlink_color = "#611627";
set alink_color = "#ff00c0";
set comment_bar_one_bgcolor = "#5d0383";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#5d0343";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: classic/pistmint
layerinfo type = theme;
layerinfo name = "Pistachio Mint";
layerinfo redist_uniq = "classic/pistmint";
set body_bgcolor = "#133422";
set main_bgcolor = "#a7c4b4";
set main_fgcolor = "#000000";
set headerbar_bgcolor = "#096d36";
set headerbar_fgcolor = "#ffffff";
set metabar_bgcolor = "#096d36";
set metabar_fgcolor = "#ffffff";
set page_title_color = "#096d36";
set page_subtitle_color = "#096d36";
set link_color = "#8afabc";
set vlink_color = "#1da65a";
set alink_color = "#f9f5f5";
set comment_bar_one_bgcolor = "#096d36";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#096d36";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: classic/mexicanfood
layerinfo type = theme;
layerinfo name = "Mexican Food";
layerinfo redist_uniq = "classic/mexicanfood";
set body_bgcolor = "#ff0000";
set main_bgcolor = "#f8ff3e";
set main_fgcolor = "#f15601";
set headerbar_bgcolor = "#bdbf3e";
set headerbar_fgcolor = "#ff0000";
set metabar_bgcolor = "#ffc664";
set metabar_fgcolor = "#000000";
set page_title_color = "#ff0000";
set page_subtitle_color = "#e15a18";
set link_color = "#f49e08";
set vlink_color = "#b05403";
set alink_color = "#ff7405";
set comment_bar_one_bgcolor = "#bdbf3e";
set comment_bar_one_fgcolor = "#ff0000";
set comment_bar_two_bgcolor = "#ffc664";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: classic/ashfire
layerinfo type = theme;
layerinfo name = "Ash and Fire";
layerinfo redist_uniq = "classic/ashfire";
set body_bgcolor = "#b5b5b5";
set main_bgcolor = "#ffb6af";
set main_fgcolor = "#000000";
set headerbar_bgcolor = "#e75454";
set headerbar_fgcolor = "#ffffff";
set metabar_bgcolor = "#ff9696";
set metabar_fgcolor = "#ffffff";
set page_title_color = "#ff1106";
set page_subtitle_color = "#f06c88";
set link_color = "#f70208";
set vlink_color = "#b0161d";
set alink_color = "#d70106";
set comment_bar_one_bgcolor = "#e75454";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#ff9696";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: classic/desktop
layerinfo type = theme;
layerinfo name = "Classic Desktop";
layerinfo redist_uniq = "classic/desktop";
set body_bgcolor = "#00545c";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set headerbar_bgcolor = "#ff7b05";
set headerbar_fgcolor = "#ffeddd";
set metabar_bgcolor = "#ffffff";
set metabar_fgcolor = "#000000";
set page_title_color = "#ff7b05";
set page_subtitle_color = "#ffeddd";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#5a76ff";
set comment_bar_one_bgcolor = "#ff7b05";
set comment_bar_one_fgcolor = "#ffeddd";
set comment_bar_two_bgcolor = "#ffffff";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: classic/satinhandshake
layerinfo type = theme;
layerinfo name = "Satin Handshake";
layerinfo redist_uniq = "classic/satinhandshake";
set body_bgcolor = "#480c0c";
set main_bgcolor = "#d06464";
set main_fgcolor = "#00001d";
set headerbar_bgcolor = "#aaaaaa";
set headerbar_fgcolor = "#000000";
set metabar_bgcolor = "#dddddd";
set metabar_fgcolor = "#000000";
set page_title_color = "#9d0404";
set page_subtitle_color = "#9d0404";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#ff00c0";
set comment_bar_one_bgcolor = "#aaaaaa";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#dddddd";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: classic/deepmelodrama
layerinfo type = theme;
layerinfo name = "Deep MeloDrama";
layerinfo redist_uniq = "classic/deepmelodrama";
set body_bgcolor = "#872d89";
set main_bgcolor = "#719cff";
set main_fgcolor = "#8e48b2";
set comment_bar_one_bgcolor = "#3794b3";
set comment_bar_one_fgcolor = "#84b8e7";
set metabar_bgcolor = "#65b2c1";
set metabar_fgcolor = "#f5d3ff";
set page_title_color = "#8e48b2";
set page_subtitle_color = "#65b2c1";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#dfd3ff";
set comment_bar_one_bgcolor = "#3794b3";
set comment_bar_one_fgcolor = "#84b8e7";
set comment_bar_two_bgcolor = "#65b2c1";
set comment_bar_two_fgcolor = "#f5d3ff";
#NEWLAYER: classic/everwhite
layerinfo type = theme;
layerinfo name = "Everwhite";
layerinfo redist_uniq = "classic/everwhite";
set body_bgcolor = "#ffffff";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set comment_bar_one_bgcolor = "#ffffff";
set comment_bar_one_fgcolor = "#000000";
set metabar_bgcolor = "#ffffff";
set metabar_fgcolor = "#000000";
set page_title_color = "#000000";
set page_subtitle_color = "#ff0000";
set link_color = "#e60000";
set vlink_color = "#c10602";
set alink_color = "#ff0600";
set comment_bar_one_bgcolor = "#ffffff";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#ffffff";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: classic/everblue
layerinfo type = theme;
layerinfo name = "Everblue with Greys";
layerinfo redist_uniq = "classic/everblue";
set body_bgcolor = "#0f0c6d";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set headerbar_bgcolor = "#000000";
set headerbar_fgcolor = "#ffffff";
set metabar_bgcolor = "#aaaaaa";
set metabar_fgcolor = "#000000";
set page_title_color = "#000000";
set page_subtitle_color = "#aaaaaa";
set link_color = "#2f00f2";
set vlink_color = "#060667";
set alink_color = "#6691ff";
set comment_bar_one_bgcolor = "#000000";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#aaaaaa";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: classic/brownleather
layerinfo type = theme;
layerinfo name = "Brown Leather Coat";
layerinfo redist_uniq = "classic/brownleather";
set body_bgcolor = "#d2b48c";
set main_bgcolor = "#ffebcd";
set main_fgcolor = "#8b4513";
set headerbar_bgcolor = "#d48050";
set headerbar_fgcolor = "#ffffff";
set metabar_bgcolor = "#d48014";
set metabar_fgcolor = "#d48014";
set page_title_color = "#d48014";
set page_subtitle_color = "#ffe1a1";
set link_color = "#000050";
set vlink_color = "#867a55";
set alink_color = "#fffab3";
set comment_bar_one_bgcolor = "#d48014";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#d48050";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: classic/bruise
layerinfo type = theme;
layerinfo name = "Bruise";
layerinfo redist_uniq = "classic/bruise";
set body_bgcolor = "#000000";
set main_bgcolor = "#bcbcbc";
set main_fgcolor = "#000000";
set headerbar_bgcolor = "#1114a0";
set headerbar_fgcolor = "#ffffff";
set metabar_bgcolor = "#21c2f1";
set metabar_fgcolor = "#ffffff";
set page_title_color = "#1114a0";
set page_subtitle_color = "#21c2f1";
set link_color = "#0000cc";
set vlink_color = "#000088";
set alink_color = "#0000ff";
set comment_bar_one_bgcolor = "#1114a0";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#21c2f1";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: classic/ranchhand
layerinfo type = theme;
layerinfo name = "Ranch Hand";
layerinfo redist_uniq = "classic/ranchhand";
set body_bgcolor = "#2999c2";
set main_bgcolor = "#cfe0ff";
set main_fgcolor = "#000000";
set headerbar_bgcolor = "#54442c";
set headerbar_fgcolor = "#ffffff";
set metabar_bgcolor = "#bababa";
set metabar_fgcolor = "#000000";
set page_title_color = "#9d995d";
set page_subtitle_color = "#704400";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#6a20ff";
set comment_bar_one_bgcolor = "#54442c";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#bababa";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: classic/victim
layerinfo type = theme;
layerinfo name = "Victim";
layerinfo redist_uniq = "classic/victim";
set body_bgcolor = "#2cd0ff";
set main_bgcolor = "#505050";
set main_fgcolor = "#ffffff";
set headerbar_bgcolor = "#166bac";
set headerbar_fgcolor = "#ffffff";
set metabar_bgcolor = "#2098f3";
set metabar_fgcolor = "#ffffff";
set page_title_color = "#26b6ff";
set page_subtitle_color = "#353535";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#ff00c0";
set comment_bar_one_bgcolor = "#166bac";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#2098f3";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: classic/forest
layerinfo type = theme;
layerinfo name = "Forest";
layerinfo redist_uniq = "classic/forest";
set body_bgcolor = "#778e64";
set main_bgcolor = "#9b9ba5";
set main_fgcolor = "#000000";
set headerbar_bgcolor = "#72784c";
set headerbar_fgcolor = "#ffffff";
set metabar_bgcolor = "#72781c";
set metabar_fgcolor = "#ffffff";
set page_title_color = "#a0ac62";
set page_subtitle_color = "#73777a";
set link_color = "#3811e1";
set vlink_color = "#310cbb";
set alink_color = "#4e7bef";
set comment_bar_one_bgcolor = "#72784c";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#72781c";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: classic/drone
layerinfo type = theme;
layerinfo name = "Drone";
layerinfo redist_uniq = "classic/drone";
set body_bgcolor = "#395f82";
set main_bgcolor = "#f9fcfe";
set main_fgcolor = "#000000";
set headerbar_bgcolor = "#904094";
set headerbar_fgcolor = "#ffffff";
set metabar_bgcolor = "#f56efc";
set metabar_fgcolor = "#ffffff";
set page_title_color = "#ff93ff";
set page_subtitle_color = "#eeeeff";
set link_color = "#395f82";
set vlink_color = "#395f82";
set alink_color = "#5266ce";
set comment_bar_one_bgcolor = "#904094";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#f56efc";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: classic/lowercurtain
layerinfo type = theme;
layerinfo name = "Lower the Curtain";
layerinfo redist_uniq = "classic/lowercurtain";
set body_bgcolor = "#000000";
set main_bgcolor = "#6b6b6b";
set main_fgcolor = "#ffffff";
set headerbar_bgcolor = "#363636";
set headerbar_fgcolor = "#f0f5fb";
set metabar_bgcolor = "#c6c6c6";
set metabar_fgcolor = "#222222";
set page_title_color = "#363636";
set page_subtitle_color = "#c5c8ca";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#3314ba";
set comment_bar_one_bgcolor = "#363636";
set comment_bar_one_fgcolor = "#f0f5fb";
set comment_bar_two_bgcolor = "#c6c6c6";
set comment_bar_two_fgcolor = "#222222";
#NEWLAYER: classic/sunny
layerinfo type = theme;
layerinfo name = "Sunny Day";
layerinfo redist_uniq = "classic/sunny";
set body_bgcolor = "#55e0f9";
set main_bgcolor = "#e38202";
set main_fgcolor = "#ffffff";
set headerbar_bgcolor = "#fff500";
set headerbar_fgcolor = "#e38202";
set metabar_bgcolor = "#fff5c5";
set metabar_fgcolor = "#e38202";
set page_title_color = "#efe052";
set page_subtitle_color = "#ffba03";
set link_color = "#df0d12";
set vlink_color = "#ac1b25";
set alink_color = "#fe3b3b";
set comment_bar_one_bgcolor = "#fff500";
set comment_bar_one_fgcolor = "#e38202";
set comment_bar_two_bgcolor = "#fff5c5";
set comment_bar_two_fgcolor = "#e38202";
#NEWLAYER: classic/valentine
layerinfo type = theme;
layerinfo name = "Be Mine";
layerinfo redist_uniq = "classic/valentine";
set body_bgcolor = "#6f104a";
set main_bgcolor = "#f2bce9";
set main_fgcolor = "#000000";
set headerbar_bgcolor = "#ff37ff";
set headerbar_fgcolor = "#ffffff";
set metabar_bgcolor = "#df2096";
set metabar_fgcolor = "#ffffff";
set page_title_color = "#ae1774";
set page_subtitle_color = "#df2096";
set link_color = "#ffffff";
set vlink_color = "#a51014";
set alink_color = "#ed8188";
set comment_bar_one_bgcolor = "#ff37ff";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#df2096";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: classic/stripes
layerinfo type = theme;
layerinfo name = "Stripes";
layerinfo redist_uniq = "classic/stripes";
set body_bgcolor = "#ffffff";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set headerbar_bgcolor = "#e7212a";
set headerbar_fgcolor = "#ffffff";
set metabar_bgcolor = "#ffffff";
set metabar_fgcolor = "#000000";
set page_title_color = "#ffffff";
set page_subtitle_color = "#ffcfdc";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#ffafc1";
set comment_bar_one_bgcolor = "#e7212a";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#ffffff";
set comment_bar_two_fgcolor = "#000000";

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -0,0 +1,11 @@
# -*-s2-*-
layerinfo type = "i18n";
layerinfo name = "English";
layerinfo redist_uniq = "cleansimple/en";
set text_meta_music = "music";
set text_meta_mood = "mood";
set text_post_comment = "Comment on this";
set text_post_comment_friends = "Comment on this";

View File

@@ -0,0 +1,932 @@
# -*-s2-*-
layerinfo type = "layout";
layerinfo name = "Clean and Simple";
layerinfo redist_uniq = "cleansimple/layout";
layerinfo author_name = "Martin Atkins";
layerinfo previews = "cleansimple/cleansimple.jpg";
propgroup colors {
property Color body_bgcolor {
des = "Page border color";
note = "If you set the border size to 'None', this won't show up.";
s1color = "stronger_back";
}
property Color entry_bgcolor {
des = "Background of entries";
s1color = "page_back";
}
property Color entry_fgcolor {
des = "Text color of entries";
s1color = "page_text";
}
property Color meta_color {
des = "Color of entry headings and meta-information";
s1color = "page_text_em";
}
property Color link_color {
des = "Link color";
s1color = "page_link";
}
property Color vlink_color {
des = "Visited link color";
s1color = "page_vlink";
}
property Color alink_color {
des = "Active link color";
s1color = "page_alink";
}
property Color topbar_bgcolor {
des = "Background color of titlebar and userpic";
s1color = "strong_back";
}
property Color topbar_fgcolor {
des = "Titlebar text color";
s1color = "strong_text";
}
property Color navbar_bgcolor {
des = "Background color of sidebar";
s1color = "weak_back";
}
property Color navbar_fgcolor {
des = "Sidebar text color";
s1color = "weak_text";
}
property string opt_navbar_pos {
des = "Side Navbar Position";
values = "left|Left|right|Right";
}
property Color comment_bar_one_bgcolor {
des = "Alternating background color for comment bars (one)";
}
property Color comment_bar_two_fgcolor {
des = "Text color on alternating comment bars (one)";
}
property Color comment_bar_two_bgcolor {
des = "Alternating background color for comment bars (two)";
}
property Color comment_bar_one_fgcolor {
des = "Text color on alternating comment bars (two)";
}
property Color comment_bar_screened_bgcolor {
des = "Background bar color for screened comments";
}
property Color comment_bar_screened_fgcolor {
des = "Text color on background bar for screened comments";
}
}
set body_bgcolor = "#6666cc";
set entry_bgcolor = "#ffffff";
set entry_fgcolor = "#000000";
set meta_color = "#c00000";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#00ffff";
set topbar_bgcolor = "#c0c0ff";
set topbar_fgcolor = "#000000";
set navbar_bgcolor = "#eeeeff";
set navbar_fgcolor = "#000000";
set comment_bar_one_bgcolor = "#c0c0ff";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#eeeeff";
set comment_bar_two_fgcolor = "#000000";
set comment_bar_screened_bgcolor = "#dddddd";
set comment_bar_screened_fgcolor = "#000000";
set tags_aware = true;
propgroup fonts {
property use font_base;
property use font_fallback;
property string font_topbar_base {
des = "Preferred font for top bar";
note = "As with the main font, leave blank if you don't care.";
}
property string font_topbar_fallback {
des = "Alternative font style for top bar";
values = "sans-serif|Sans-serif|serif|Serif|cursive|Cursive|monospace|Monospaced|none|Use browser's default";
}
property string font_sidebar_base {
des = "Preferred font for side navigation bar";
note = "As with the main font, leave blank if you don't care.";
}
property string font_sidebar_fallback {
des = "Alternative font style for side navigation bar";
values = "sans-serif|Sans-serif|serif|Serif|cursive|Cursive|monospace|Monospaced|none|Use browser's default";
}
}
set font_topbar_fallback = "none";
set font_sidebar_fallback = "none";
propgroup presentation {
property string opt_daylines_style {
des = "Style of Lines Around Day Headings";
values = "solid|Solid|dashed|Dashed|dotted|Dotted|double|Double|hidden|Invisible";
}
property use page_recent_items;
property use page_friends_items;
property string opt_margin_size {
des = "Size of page border";
values = "0|None|5px|Tiny|25px|Small|50px|Medium|75px|Large|100px|Extra Large";
}
property use view_entry_disabled;
property use use_shared_pic;
property bool show_entrynav_icons {
des = "Toggle to show the next, memory, edit, etc icons on the entry view page";
}
property string page_background_image {
des = "URL to an image to be used for the page background";
}
property use linklist_support;
property use external_stylesheet;
}
set opt_navbar_pos = "left";
set opt_daylines_style = "dashed";
set opt_margin_size = "50px";
set view_entry_disabled = false;
set show_entrynav_icons = true;
set page_background_image = "";
set linklist_support = false;
propgroup text {
property use text_post_comment;
property use text_read_comments;
property use text_post_comment_friends;
property use text_read_comments_friends;
}
function css_fontspec(string base, string fallback)
"Prints a CSS font-family specification based on the base and fallback given"
{
if ($base != "" or $fallback != "none") {
"font-family: ";
if ($base != "") {
"\"$base\"";
if ($fallback != "none") {
", ";
}
}
if ($fallback != "none") {
print $fallback;
}
";";
}
}
function print_stylesheet ()
{
var string bgimg = clean_url($*page_background_image) != "" ? "url($*page_background_image)" : "none";
"""
body {
background: $*body_bgcolor $bgimg;
color: $*entry_fgcolor;
padding: $*opt_margin_size;
margin: 0;
""";
css_fontspec($*font_base,$*font_fallback);
"""
}
a:link {
color: $*link_color;
background: transparent;
}
a:visited {
color: $*vlink_color;
background: transparent;
}
a:active {
color: $*alink_color;
background: transparent;
}
img {
vertical-align: absmiddle;
}
table {
width: 100%;
}
pre {
text-align: left;
}
#topbar {
background: $*topbar_bgcolor none;
color: $*topbar_fgcolor;
""";
css_fontspec($*font_topbar_base,$*font_topbar_fallback);
"""
}
#topbar h1 {
margin-top: 5px;
margin-bottom: 0;
text-align: center;
font-size: 1.5em;
}
#topbar h2 {
margin-top: 0;
margin-bottom: 5px;
text-align: center;
font-size: 1.25em;
}
#navbar {
background: $*navbar_bgcolor none;
color: $*navbar_fgcolor;
width: 25%;
""";
css_fontspec($*font_sidebar_base,$*font_sidebar_fallback);
"""
}
#navbar ul {
list-style: none;
margin: 10px;
}
#navbar ul li {
margin: 0;
}
#navbar ul li.active {
font-weight: bold;
}
#navbar a:link, #navbar a:active, #navbar a:visited {
background: $*navbar_bgcolor none;
color: $*navbar_fgcolor;
text-decoration: none;
}
#navbar a:hover {
text-decoration: underline;
}
#userlinklist ul {
margin-top: 0;
margin-bottom: 0;
}
#mainstuff {
width: 75%;
background: $*entry_bgcolor none;
color: $*entry_fgcolor;
}
#userpic {
text-align: center;
margin: 10px;
}
#userpic img {
border: 2px solid $*topbar_bgcolor;
background: $*topbar_bgcolor none;
color: $*topbar_fgcolor;
}
#entries {
margin: 10px;
}
#range {
margin-bottom: 0.5em;
}
.day {
border-top: 1px $*opt_daylines_style $*entry_fgcolor;
clear: both;
}
.day h3 {
border-bottom: 1px $*opt_daylines_style $*entry_fgcolor;
padding: 2px;
margin: 0;
font-size: 1.1em;
text-align: center;
}
address {
text-align: center;
font-style: normal;
font-size: 0.95em;
}
/* entries */
.entrytext {
padding: 2px;
text-align: justify;
}
.entry {
clear: both;
}
.entrytext p, .entrytext ul, .entrytext ol, .entrytext table {
margin-top: 0.5em;
margin-bottom: 0.5em;
}
.entryheading {
font-weight: bold;
}
.timestamp, .subject, .altposter {
font-weight: bold;
color: $*meta_color;
background: $*entry_bgcolor;
}
.altposter a {
color: $*meta_color;
background: $*entry_bgcolor;
text-decoration: underline;
}
.altposter img {
border: 2px $*navbar_fgcolor solid;
background: $*navbar_bgcolor none;
color: $*navbar_fgcolor;
}
.talklinks {
font-size: 0.75em;
text-align: right;
margin-bottom: 2px;
clear: right;
}
.frienduserpic {
border: 2px solid $*topbar_bgcolor;
background: $*topbar_bgcolor none;
color: $*topbar_fgcolor;
}
""";
}
function Page::lay_viewspec_nav() {
# Intentionally blank
}
function RecentPage::lay_viewspec_nav() {
# FIXME: There is currently no decent way to i18nize this
if ($.nav.forward_url != "" or $.nav.backward_url != "") {
"<ul id=\"skiplinks\">";
if ($.nav.forward_url != "") {
println """<li><a href="$.nav.forward_url">Next</a></li>""";
}
if ($.nav.backward_url != "") {
println """<li><a href="$.nav.backward_url">Previous</a></li>""";
}
"</ul>";
}
}
# This DEFINITELY should be in core
function Page::lay_view_name(string view) : string
"Don't bother overriding this, because it'll be deleted as soon as core can do it" {
if ($view == "recent") {
return $*text_view_recent;
} elseif ($view == "friends") {
return $*text_view_friends;
} elseif ($view == "userinfo") {
return $*text_view_userinfo;
} elseif ($view == "archive") {
return $*text_view_archive;
} else {
return "Something";
}
}
function Page::lay_viewspec_heading() : string
"Returns some text to display under the main heading. Overridden in subclasses." {
return "";
}
function RecentPage::lay_viewspec_heading() : string {
return $*text_view_recent;
}
function FriendsPage::lay_viewspec_heading() : string {
if ($.journal.journal_type == "C") {
return $*text_view_friends_comm;
} else {
return $*text_view_friends;
}
}
function DayPage::lay_viewspec_heading() : string {
return $*text_view_archive;
}
function YearPage::lay_viewspec_heading() : string {
return $*text_view_archive;
}
function MonthPage::lay_viewspec_heading() : string {
return $*text_view_archive;
}
function Page::print_linklist() {
if (size $.linklist <= 0) {
return;
} elseif (not $*linklist_support) {
return;
}
var bool section_open = false;
println "<ul id='userlinklist'>";
foreach var UserLink l ($.linklist) {
if ($l.title) {
if ($l.is_heading) {
if ($section_open) {
println "</ul></li>";
}
println """<li><span style="font-style: italic;">$l.title</span>\n<ul>""";
$section_open = true;
} else {
println """<li><a href="$l.url">$l.title</a></li>""";
}
}
}
if ($section_open) {
println "</ul></li>";
}
println "</ul>";
}
function Page::lay_print_navbar() {
var string userpic;
var Image up_img = $.journal.default_pic;
if (defined $up_img) {
$userpic = """<div id="userpic"><img border="0" src="$up_img.url" height="$up_img.height" width="$up_img.width" alt="" /></div>""";
}
var string website_name = $.journal.website_name ? $.journal.website_name : $*text_website_default_name;
var string website;
if ($.journal.website_url != "") {
$website = """<li><a href="$.journal.website_url">$website_name</a></li>""";
}
"""<td id="navbar" valign="top">
<ul id="viewlinks">
""";
foreach var string v ($.views_order) {
if ($v == $.view) {
println """<li class="active">"""+
$this->lay_view_name($v)+
"""</li>""";
} else {
println """<li><a href="$.view_url{$v}">"""+
$this->lay_view_name($v)+
"""</a></li>""";
}
}
"""
$website
</ul>
""";
$this->lay_viewspec_nav();
"$userpic";
$this->print_linklist();
"</td>";
}
function Page::print ()
{
var string title = $this->title();
"""<html>\n<head>\n""";
if ($*external_stylesheet) {
println """<link rel="stylesheet" href="$.stylesheet_url" type="text/css" />""";
} else {
println """<style type="text/css">"""; print_stylesheet(); "</style>";
}
$this->print_head();
"""<title>$title</title>
</head>
<body>
<table border="0" cellpadding="0" cellspacing="0">
<tr><td colspan="2" id="topbar" valign="top">
""";
"<h1>$.journal.name</h1>";
"<h2>" + $this->lay_viewspec_heading() + "</h2>";
"""
</td></tr>
<tr>
""";
if ($*opt_navbar_pos == "left") {
$this->lay_print_navbar();
}
"""<td id="mainstuff" valign="top">
<div id="entries">
""";
$this->print_body();
"""
</div>
<address>"""; server_sig(); """</address>
</td>
""";
if ($*opt_navbar_pos == "right") {
$this->lay_print_navbar();
}
"""</tr>
</table>
</body>
</html>
""";
}
function print_entry (Page p, Entry e, Color bgcolor, Color fgcolor, bool hide_text)
{
var string time = $e.time->time_format();
if ($e.new_day) {
"""<div class="day"><h3>"""+$e.time->date_format("long")+"</h3>";
}
"""<div class="entry" id="entry$e.itemid"><div class="entrytext">""";
if ($p.view == "entry" and $*show_entrynav_icons)
{
print "<div style='text-align: center'>";
$e->print_linkbar();
print "</div>";
}
"""<span class="entryheading">""";
if ($p.view == "friends") {
if ($e.poster.username != $e.journal.username) {
"<span class=\"altposter\"><a href=\"";
print get_url($e.poster,"userinfo");
"\">"+$e.poster.username;
"</a></span>, posting in ";
}
"<a style=\"color: $fgcolor; background: $bgcolor; padding-left: 0.5em; padding-right: 0.5em;\"";
" href=\""+get_url($e.journal,"userinfo")+"\">$e.journal.username</a> @ ";
} else {
if ($e.poster.username != $e.journal.username) {
"<span class=\"altposter\">";
if (defined $e.userpic) {
"""<img src="$e.userpic.url" width="$e.userpic.width"
height="$e.userpic.height" alt="" align="right" />""";
}
"<a href=\""+
get_url($e.poster,"userinfo")+
"\">$e.poster.username</a></span> @ ";
}
}
"<span class=\"timestamp\">"+$e.time->time_format()+"</span>: ";
if ($e.security) {
$e.security_icon->print();
}
if ($e.subject) {
" <span class=\"subject\">$e.subject</span>";
}
println "</span>"+($e.subject != "" ? "<br />" : "");
if ($p.view == "friends" and defined $e.userpic) {
"""<img src="$e.userpic.url" width="$e.userpic.width"
style="color: $fgcolor; background: $bgcolor; border: 2px solid $bgcolor;"
height="$e.userpic.height" alt="" align="right" class="frienduserpic" />""";
}
if (not $hide_text) {
print "$e.text<br /><br />";
if (size $e.metadata) {
"""<div class="currents">""";
foreach var string k ($e.metadata) {
var string text = $k;
var string val = $e.metadata{$k};
if ($k == "mood") {
$text = $*text_meta_mood;
} elseif ($k == "music") {
$text = $*text_meta_music;
}
if ($k == "mood" and defined $e.mood_icon) {
var Image i = $e.mood_icon;
$val = "<img src='$i.url' width='$i.width' height='$i.height' align='absmiddle'> $val";
}
"""<div class="current$k"><strong>$text:</strong> $val</div>""";
}
"</div>\n";
}
if ($e.tags) {
var int tcount = 0;
"<strong>Tags:</strong> ";
foreach var Tag t ($e.tags) {
"""<a rel="tag" href="$t.url">$t.name</a>""";
$tcount++;
if ($tcount != size $e.tags) { ", "; }
}
"<br />";
}
}
$e.comments->print(); "\n";
"</div>";
if ($e.end_day) {
"</div>";
}
}
function Page::print_entry (Entry e)
{
print_entry($this, $e, null Color, null Color, false);
}
function FriendsPage::print_entry (Entry e) {
var Friend f = $.friends{$e.journal.username};
print_entry($this, $e, $f.bgcolor, $f.fgcolor, false);
}
function CommentInfo::print ()
{
if (not $.enabled) { return; }
"""<div class="talklinks" clear="all">""";
if ($.count > 0 or $.screened) {
$this->print_readlink();
" - ";
}
$this->print_postlink();
"</div>";
}
# This should really be provided in core
function RecentPage::lay_range_text() : string {
if ($.nav.skip == 0) {
return "You are viewing the most recent "+(size $.entries)+" entries";
} else {
return "You are viewing "+(size $.entries)+" entries, $.nav.skip into the past";
}
}
function RecentPage::print_body ()
{
"""<p id="range">"""+$this->lay_range_text()+"""</p>""";
foreach var Entry e ($.entries) {
$this->print_entry($e);
}
}
function YearPage::print_year_links ()
{
"""<ul id="skiplinks">""";
foreach var YearYear y ($.years) {
if ($y.displayed) {
println "<li class=\"active\">$y.year</span>";
} else {
println "<li><a href=\"$y.url\">$y.year</a></li>";
}
}
"</ul>";
}
function YearPage::print_month (YearMonth m)
{
if (not $m.has_entries) { return; }
"""<center><table border="0" cellpadding="4" cellspacing="0" style="margin-top: 10px; margin-bottom: 10px;">""";
"""<tr align="center"><td colspan="7" bgcolor="$*topbar_bgcolor"><font color="$*topbar_fgcolor">""";
"<b>"; print $m->month_format(); """</b> (<a href="$m.url">...</a>)</font></td></tr>""";
"""<tr align="center" bgcolor="$*navbar_bgcolor">""";
foreach var int d (weekdays()) {
"""<td><font color="$*navbar_fgcolor">"""; print $*lang_dayname_short[$d]; "</td>\n";
}
"</tr>";
foreach var YearWeek w ($m.weeks) {
$w->print();
}
"</table></center>";
}
function YearPage::lay_viewspec_nav() {
$this->print_year_links();
}
function YearPage::print_body() {
"<h3>$.year</h3>";
foreach var YearMonth m ($.months) {
$this->print_month($m);
}
}
function YearWeek::print () {
"<tr>";
if ($.pre_empty) { "<td colspan='$.pre_empty'>&nbsp;</td>"; }
foreach var YearDay d ($.days) {
"""<td valign="top"><b><font size="-1">$d.day</font></b>""";
if ($d.num_entries) {
"""<center><a href="$d.url">$d.num_entries</a></center>""";
} else {
"<center>&nbsp;</center>";
}
"</td>";
}
if ($.post_empty) { "<td colspan='$.post_empty'>&nbsp;</td>"; }
"</tr>";
}
function DayPage::lay_viewspec_nav() {
"""
<ul id="skiplinks">
<li><a href="$.prev_url">$*text_day_prev</a></li>
<li><a href="$.next_url">$*text_day_next</a></li>
</ul>
""";
}
function DayPage::print_body() {
"""<div class="day"><h3>""" + $.date->date_format("long") + "</h3>";
if (not $.has_entries) {
println $*text_noentries_day;
}
foreach var Entry e ($.entries) {
$this->print_entry($e);
}
println "</div>";
}
function EntryPage::print_body () {
set_handler("unscreen_comment_#", [
[ "style_bgcolor", "cmtbar#", "$*comment_bar_one_bgcolor", ],
[ "style_color", "cmtbar#", "$*comment_bar_one_fgcolor", ],
]);
set_handler("screen_comment_#", [
[ "style_bgcolor", "cmtbar#", "$*comment_bar_screened_bgcolor", ],
[ "style_color", "cmtbar#", "$*comment_bar_screened_fgcolor", ],
]);
print_entry($this, $.entry, null Color, null Color, $.viewing_thread);
if ($.entry.comments.enabled and $.comment_pages.total_subitems > 0)
{
$this->print_multiform_start();
"""<div class="day"><h3>Comments</h3></div>""";
if ($.comment_pages.total_subitems > 0) {
$.comment_pages->print();
$this->print_comments($.comments);
}
if ($this.multiform_on) {
"""<div class="day"><h3>Mass Action</h3></div>""";
$this->print_multiform_actionline();
$this->print_multiform_end();
}
}
}
# Clean style. Hate to clutter it up with this:
function EntryPage::print_comment (Comment c) {
var Color background; var Color color;
if ($c.screened) {
$background = $*comment_bar_screened_bgcolor;
$color = $*comment_bar_screened_fgcolor;
} elseif ($c.depth % 2) {
$background = $*comment_bar_one_bgcolor;
$color = $*comment_bar_one_fgcolor;
} else {
$background = $*comment_bar_two_bgcolor;
$color = $*comment_bar_two_fgcolor;
}
var string poster = defined $c.poster ? $c.poster->as_string() : "<i>(Anonymous)</i>";
var string sub_icon;
if (defined $c.subject_icon) {
$sub_icon = $c.subject_icon->as_string();
}
"<a name='$c.anchor'></a><div id='cmtbar$c.talkid' style='background-color: $background; color: $color; margin-top: 10px; width: 100%'>";
"<table cellpadding='2' cellspacing='0' summary='0' style='width: 100%'><tr valign='top'>";
if (defined $c.userpic and $*comment_userpic_style != "off") {
var int w = $c.userpic.width;
var int h = $c.userpic.height;
# WARNING: this will later be done by the system (it'll be a
# constructional property), so don't copy this hack into your
# layout layers or you'll be messed up later.
if ($*comment_userpic_style == "small") {
$w = $w / 2;
$h = $h / 2;
}
print "<td style='width: 102px'><img src='$c.userpic.url' width='$w' height='$h' alt='[User Picture]' /></td>";
}
"<td style='width: 100%'><table style='width: 100%'><tr>";
### From, date, etc
"<td align='left' style='width: 50%'>";
print "<table>";
print "<tr><th align='right'>From:</th><td>$poster</td></tr>\n";
print "<tr><th align='right'>Date:</th><td style='white-space: nowrap'>";
print $c.time->date_format("long") + " - " + $c.time->time_format() + "</td></tr>";
if ($c.metadata{"poster_ip"}) { print "<tr><th align='right'>IP Address:</th><td>(" + $c.metadata{"poster_ip"} + ")</td></tr>"; }
"</table></td>";
### Gadgets
"<td align='right' style='width: 50%'>";
if ($this.multiform_on) {
" <label for='ljcomsel_$c.talkid'>$*text_multiform_check</label>";
$c->print_multiform_check();
}
$c->print_linkbar();
"</td></tr>";
### Subject / icon
print "<tr valign='top'><td style='width: 50%'>";
print (defined $c.subject_icon or $c.subject != "") ? "<h3>$c.subject_icon $c.subject</h3>" : "";
print "</td>";
### Permalink
print "<td style='width: 50%' align='right'><strong>(<a href='$c.permalink_url'>Link</a>)</strong></td></tr>";
print "</table></td></tr></table></div>";
print "<div style='margin-left: 5px'>$c.text</div>";
print "<div style='margin-top: 3px; font-size: smaller'>";
if ($c.frozen) {
print "(Replies frozen) ";
} else {
print "(<a href='$c.reply_url'>Reply to this</a>) ";
}
if ($c.parent_url != "") { "(<a href='$c.parent_url'>Parent</a>) "; }
if ($c.thread_url != "") { "(<a href='$c.thread_url'>Thread</a>) "; }
"</div>";
}
function ReplyPage::print_body () {
var string time = $.replyto.time->time_format();
"""
<div class="entry">
<div class="entrytext">
<span class="entryheading">
""";
if (not $.entry.comments.enabled)
{
print "<span class='subject'>$*text_reply_nocomments_header</span></span><br />
$*text_reply_nocomments</div></div>";
return;
}
"<span style='padding-left: 0.5em; padding-right: 0.5em;'>";
print defined $.replyto.poster ? $.replyto.poster->as_string() : "<i>(Anonymous)</i>";
"</span> @ ";
"<span class='timestamp'>$time</span>: ";
if ($.replyto.subject) {
" <span class=\"subject\">$.replyto.subject</span>";
}
println "</span>"+($.replyto.subject ? "<br />" : "");
if (defined $.replyto.userpic) {
"""<img src="$.replyto.userpic.url" width="$.replyto.userpic.width"
style="border: 2px solid $*entry_fgcolor;"
height="$.replyto.userpic.height" alt="" align="right" class="frienduserpic" />""";
}
print $.replyto.text;
"""<div class="talklinks" clear="all"><a href='$.entry.comments.read_url'>Read Comments</a></div>""";
"</div>";
"""<div class="day"><h3>Reply</h3></div>""";
$.form->print();
}
function print_theme_preview ()
{
print """
<div style="background: $*body_bgcolor none; color: $*entry_fgcolor;
padding-left: 50px; padding-right: 50px; padding-top: 10px;
padding-bottom: 10px; margin: 0;">
<table border="0" cellpadding="0" cellspacing="0">
<tr><td colspan="2" style="background: $*topbar_bgcolor none; color: $*topbar_fgcolor" valign="top">
<h1 style="margin-top: 5px; margin-bottom: 5px; text-align: center; font-size: 1.5em;">John Doe</h1>
<h2 style="margin-top: 0; margin-bottom: 5px; text-align: center; font-size: 1.25em;">Recent Entries</h2>
</td></tr>
<tr><td style="background: $*navbar_bgcolor none; color: $*navbar_fgcolor; width: 25%;" valign="top">
<ul style="list-style: none; margin: 10px">
<li style="margin: 0; font-weight: bold;">Recent Entries</li>
<li><a style="background: $*navbar_bgcolor none; color: $*navbar_fgcolor;" href="#">Archive</a></li>
<li><a style="background: $*navbar_bgcolor none; color: $*navbar_fgcolor;" href="#">Friends</a></li>
<li><a style="background: $*navbar_bgcolor none; color: $*navbar_fgcolor;" href="#">User Info</a></li>
</ul>
</td><td style="width: 75%; background: $*entry_bgcolor none; color: $*entry_fgcolor" valign="top">
<div style="margin: 10px;">
<div style="border-top: 1px dashed $*entry_fgcolor; clear: both;">
<h3 style="border-bottom: 1px dashed $*entry_fgcolor; padding: 2px; margin: 0; font-size: 1.1em; text-align: center;">December 17th, 2002</h3>
<div style="clear: both;" id="entry2839"><div style="padding: 2px; text-align: justify">
<span style="font-weight: bold;">
<span style="font-weight: bold; color: $*meta_color; background: $*entry_bgcolor none;">06:42 pm</span>:
<span style="font-weight: bold; color: $*meta_color; background: $*entry_bgcolor none;">Neque porro quisquam&hellip;</span>
</span>
Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit
Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit
Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit
Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit
Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit
<div style="font-size: 0.75em; text-align: right; margin-bottom: 2px; clear: right;" >
<a href="#" style="color: $*link_color;">2 Comments Posted</a> | <a href="#" style="color: $*vlink_color">Leave a comment</a></div>
</div></div></div></div>
</td></tr></table>
</div>
""";
}

View File

@@ -0,0 +1,420 @@
#NEWLAYER: cleansimple/purpleblues
layerinfo type = theme;
layerinfo name = "Purples and Blues";
layerinfo redist_uniq = "cleansimple/purpleblues";
set body_bgcolor = "#660099";
set entry_bgcolor = "#9966cc";
set entry_fgcolor = "#ffff00";
set meta_color = "#003399";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#00ffff";
set topbar_bgcolor = "#c0c0ff";
set topbar_fgcolor = "#000000";
set navbar_bgcolor = "#eeeeff";
set navbar_fgcolor = "#000000";
set comment_bar_one_bgcolor = "#c0c0ff";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#eeeeff";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: cleansimple/flesh
layerinfo type = "theme";
layerinfo name = "Flesh";
layerinfo redist_uniq = "cleansimple/flesh";
set body_bgcolor = "#eeeeff";
set entry_bgcolor = "#ffffff";
set entry_fgcolor = "#000000";
set meta_color = "#ff0000";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#00ffff";
set topbar_bgcolor = "#fa83d7";
set topbar_fgcolor = "#000000";
set navbar_bgcolor = "#f677ad";
set navbar_fgcolor = "#000000";
set comment_bar_one_bgcolor = "#fa83d7";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#f677ad";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: cleansimple/shrinkvio
layerinfo type = theme;
layerinfo name = "Shrinking Violet";
layerinfo redist_uniq = "cleansimple/shrinkvio";
set body_bgcolor = "#ad22e7";
set entry_bgcolor = "#ffffff";
set entry_fgcolor = "#000000";
set meta_color = "#381a45";
set topbar_bgcolor = "#5d0383";
set topbar_fgcolor = "#ffffff";
set navbar_bgcolor = "#d9a1f1";
set navbar_fgcolor = "#000000";
set link_color = "#2e053f";
set vlink_color = "#611627";
set alink_color = "#ff00c0";
set comment_bar_one_bgcolor = "#5d0383";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#d9a1f1";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: cleansimple/pistmint
layerinfo type = theme;
layerinfo name = "Pistachio Mint";
layerinfo redist_uniq = "cleansimple/pistmint";
set body_bgcolor = "#133422";
set entry_bgcolor = "#a7c4b4";
set entry_fgcolor = "#000000";
set meta_color = "#096d36";
set topbar_bgcolor = "#096d36";
set topbar_fgcolor = "#ffffff";
set navbar_bgcolor = "#094f36";
set navbar_fgcolor = "#000000";
set link_color = "#8afabc";
set vlink_color = "#1da65a";
set alink_color = "#f9f5f5";
set comment_bar_one_bgcolor = "#096d36";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#094f36";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: cleansimple/mexicanfood
layerinfo type = theme;
layerinfo name = "Mexican Food";
layerinfo redist_uniq = "cleansimple/mexicanfood";
set body_bgcolor = "#ff0000";
set entry_bgcolor = "#f8ff3e";
set entry_fgcolor = "#f15601";
set meta_color = "#f50701";
set topbar_bgcolor = "#bdbf3e";
set topbar_fgcolor = "#ff0000";
set navbar_bgcolor = "#e15a18";
set navbar_fgcolor = "#ffffff";
set link_color = "#f49e08";
set vlink_color = "#b05403";
set alink_color = "#ff7405";
set comment_bar_one_bgcolor = "#bdbf3e";
set comment_bar_two_fgcolor = "#ff0000";
set comment_bar_two_bgcolor = "#e15a18";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: cleansimple/ashfire
layerinfo type = theme;
layerinfo name = "Ash and Fire";
layerinfo redist_uniq = "cleansimple/ashfire";
set body_bgcolor = "#b5b5b5";
set entry_bgcolor = "#ffb6af";
set entry_fgcolor = "#000000";
set meta_color = "#d90308";
set topbar_bgcolor = "#e75454";
set topbar_fgcolor = "#ffffff";
set navbar_bgcolor = "#f06c88";
set navbar_fgcolor = "#000000";
set link_color = "#f70208";
set vlink_color = "#b0161d";
set alink_color = "#d70106";
set comment_bar_one_bgcolor = "#e75454";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#f06c88";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: cleansimple/desktop
# for layout: 13 (cleansimple/layout)
layerinfo type = theme;
layerinfo name = "Classic Desktop";
layerinfo redist_uniq = "cleansimple/desktop";
set body_bgcolor = "#00545c";
set entry_bgcolor = "#ffffff";
set entry_fgcolor = "#000000";
set meta_color = "#000000";
set topbar_bgcolor = "#ff7b05";
set topbar_fgcolor = "#ffeddd";
set navbar_bgcolor = "#ffeddd";
set navbar_fgcolor = "#000000";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#5a76ff";
set comment_bar_one_bgcolor = "#ff7b05";
set comment_bar_one_fgcolor = "#ffeddd";
set comment_bar_two_bgcolor = "#ffeddd";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: cleansimple/satinhandshake
layerinfo type = theme;
layerinfo name = "Satin Handshake";
layerinfo redist_uniq = "cleansimple/satinhandshake";
set body_bgcolor = "#480c0c";
set entry_bgcolor = "#d06464";
set entry_fgcolor = "#00001d";
set meta_color = "#000000";
set topbar_bgcolor = "#aaaaaa";
set topbar_fgcolor = "#000000";
set navbar_bgcolor = "#9d0404";
set navbar_fgcolor = "#000000";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#ff00c0";
set comment_bar_one_bgcolor = "#aaaaaa";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#9d0404";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: cleansimple/deepmelodrama
layerinfo type = theme;
layerinfo name = "Deep MeloDrama";
layerinfo redist_uniq = "cleansimple/deepmelodrama";
set body_bgcolor = "#872d89";
set entry_bgcolor = "#719cff";
set entry_fgcolor = "#8e48b2";
set meta_color = "#8e48b2";
set topbar_bgcolor = "#3794b3";
set topbar_fgcolor = "#84b8e7";
set navbar_bgcolor = "#65b2c1";
set navbar_fgcolor = "#f5d3ff";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#dfd3ff";
set comment_bar_one_bgcolor = "#3794b3";
set comment_bar_one_fgcolor = "#84b8e7";
set comment_bar_two_bgcolor = "#65b2c1";
set comment_bar_two_fgcolor = "#f5d3ff";
#NEWLAYER: cleansimple/everwhite
layerinfo type = theme;
layerinfo name = "Everwhite";
layerinfo redist_uniq = "cleansimple/everwhite";
set body_bgcolor = "#ffffff";
set entry_bgcolor = "#ffffff";
set entry_fgcolor = "#000000";
set meta_color = "#000000";
set topbar_bgcolor = "#ffffff";
set topbar_fgcolor = "#000000";
set navbar_bgcolor = "#ffffff";
set navbar_fgcolor = "#000000";
set link_color = "#e60000";
set vlink_color = "#c10602";
set alink_color = "#ff0600";
set comment_bar_one_bgcolor = "#ffffff";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#ffffff";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: cleansimple/everblue
layerinfo type = theme;
layerinfo name = "Everblue with Greys";
layerinfo redist_uniq = "cleansimple/everblue";
set body_bgcolor = "#0f0c6d";
set entry_bgcolor = "#ffffff";
set entry_fgcolor = "#000000";
set meta_color = "#000000";
set topbar_bgcolor = "#000000";
set topbar_fgcolor = "#ffffff";
set navbar_bgcolor = "#aaaaaa";
set navbar_fgcolor = "#000000";
set link_color = "#2f00f2";
set vlink_color = "#060667";
set alink_color = "#6691ff";
set comment_bar_one_bgcolor = "#000000";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#aaaaaa";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: cleansimple/brownleather
layerinfo type = theme;
layerinfo name = "Brown Leather Coat";
layerinfo redist_uniq = "cleansimple/brownleather";
set body_bgcolor = "#d2b48c";
set entry_bgcolor = "#ffebcd";
set entry_fgcolor = "#8b4513";
set meta_color = "#000000";
set topbar_bgcolor = "#d48014";
set topbar_fgcolor = "#ffffff";
set navbar_bgcolor = "#ffe1a1";
set navbar_fgcolor = "#000000";
set link_color = "#000050";
set vlink_color = "#867a55";
set alink_color = "#fffab3";
set comment_bar_one_bgcolor = "#d48014";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#ffe1a1";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: cleansimple/bruise
layerinfo type = theme;
layerinfo name = "Bruise";
layerinfo redist_uniq = "cleansimple/bruise";
set body_bgcolor = "#000000";
set entry_bgcolor = "#bcbcbc";
set entry_fgcolor = "#000000";
set meta_color = "#000000";
set topbar_bgcolor = "#1114a0";
set topbar_fgcolor = "#ffffff";
set navbar_bgcolor = "#21c2f1";
set navbar_fgcolor = "#0000ff";
set link_color = "#0000cc";
set vlink_color = "#000088";
set alink_color = "#0000ff";
set comment_bar_one_bgcolor = "#1114a0";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#21c2f1";
set comment_bar_two_fgcolor = "#0000ff";
#NEWLAYER: cleansimple/ranchhand
layerinfo type = theme;
layerinfo name = "Ranch Hand";
layerinfo redist_uniq = "cleansimple/ranchhand";
set body_bgcolor = "#2999c2";
set entry_bgcolor = "#cfe0ff";
set entry_fgcolor = "#000000";
set meta_color = "#060667";
set topbar_bgcolor = "#54442c";
set topbar_fgcolor = "#ffffff";
set navbar_bgcolor = "#704400";
set navbar_fgcolor = "#bababa";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#6a20ff";
set comment_bar_one_bgcolor = "#54442c";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#704400";
set comment_bar_two_fgcolor = "#bababa";
#NEWLAYER: cleansimple/victim
layerinfo type = theme;
layerinfo name = "Victim";
layerinfo redist_uniq = "cleansimple/victim";
set body_bgcolor = "#2cd0ff";
set entry_bgcolor = "#505050";
set entry_fgcolor = "#ffffff";
set meta_color = "#000000";
set topbar_bgcolor = "#166bac";
set topbar_fgcolor = "#ffffff";
set navbar_bgcolor = "#353535";
set navbar_fgcolor = "#ffffff";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#ff00c0";
set comment_bar_one_bgcolor = "#166bac";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#353535";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: cleansimple/forest
layerinfo type = theme;
layerinfo name = "Forest";
layerinfo redist_uniq = "cleansimple/forest";
set body_bgcolor = "#778e64";
set entry_bgcolor = "#9b9ba5";
set entry_fgcolor = "#000000";
set meta_color = "#ffffff";
set topbar_bgcolor = "#72784c";
set topbar_fgcolor = "#ffffff";
set navbar_bgcolor = "#73777a";
set navbar_fgcolor = "#000000";
set link_color = "#3811e1";
set vlink_color = "#310cbb";
set alink_color = "#4e7bef";
set comment_bar_one_bgcolor = "#72784c";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#73777a";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: cleansimple/drone
layerinfo type = theme;
layerinfo name = "Drone";
layerinfo redist_uniq = "cleansimple/drone";
set body_bgcolor = "#395f82";
set entry_bgcolor = "#f9fcfe";
set entry_fgcolor = "#000000";
set meta_color = "#000000";
set topbar_bgcolor = "#904094";
set topbar_fgcolor = "#ffffff";
set navbar_bgcolor = "#eeeeff";
set navbar_fgcolor = "#000000";
set link_color = "#395f82";
set vlink_color = "#395f82";
set alink_color = "#5266ce";
set comment_bar_one_bgcolor = "#904094";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#eeeeff";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: cleansimple/lowercurtain
layerinfo type = theme;
layerinfo name = "Lower the Curtain";
layerinfo redist_uniq = "cleansimple/lowercurtain";
set body_bgcolor = "#000000";
set entry_bgcolor = "#6b6b6b";
set entry_fgcolor = "#ffffff";
set meta_color = "#ffffff";
set topbar_bgcolor = "#363636";
set topbar_fgcolor = "#f0f5fb";
set navbar_bgcolor = "#c5c8ca";
set navbar_fgcolor = "#000000";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#3314ba";
set comment_bar_one_bgcolor = "#363636";
set comment_bar_one_fgcolor = "#f0f5fb";
set comment_bar_two_bgcolor = "#c5c8ca";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: cleansimple/sunny
layerinfo type = theme;
layerinfo name = "Sunny Day";
layerinfo redist_uniq = "cleansimple/sunny";
set body_bgcolor = "#55e0f9";
set entry_bgcolor = "#e38202";
set entry_fgcolor = "#ffffff";
set meta_color = "#000000";
set topbar_bgcolor = "#ffba03";
set topbar_fgcolor = "#ffffff";
set navbar_bgcolor = "#ffba55";
set navbar_fgcolor = "#ffffff";
set link_color = "#df0d12";
set vlink_color = "#ac1b25";
set alink_color = "#fe3b3b";
set comment_bar_one_bgcolor = "#ffba03";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#ffba55";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: cleansimple/valentine
layerinfo type = theme;
layerinfo name = "Be Mine";
layerinfo redist_uniq = "cleansimple/valentine";
set body_bgcolor = "#6f104a";
set entry_bgcolor = "#f2bce9";
set entry_fgcolor = "#000000";
set meta_color = "#ff24ab";
set topbar_bgcolor = "#ff37ff";
set topbar_fgcolor = "#ffffff";
set navbar_bgcolor = "#df2096";
set navbar_fgcolor = "#000000";
set link_color = "#ffffff";
set vlink_color = "#a51014";
set alink_color = "#ed8188";
set comment_bar_one_bgcolor = "#ff37ff";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#df2096";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: cleansimple/stripes
layerinfo type = theme;
layerinfo name = "Stripes";
layerinfo redist_uniq = "cleansimple/stripes";
set body_bgcolor = "#ffffff";
set entry_bgcolor = "#ffffff";
set entry_fgcolor = "#000000";
set meta_color = "#ff0000";
set topbar_bgcolor = "#e7212a";
set topbar_fgcolor = "#ffffff";
set navbar_bgcolor = "#ffcfdc";
set navbar_fgcolor = "#000000";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#ffafc1";
set comment_bar_one_bgcolor = "#e7212a";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#ffcfdc";
set comment_bar_two_fgcolor = "#000000";

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -0,0 +1,10 @@
# -*-s2-*-
layerinfo type = "i18n";
layerinfo name = "English";
layerinfo redist_uniq = "digitalmultiplex/en";
set text_meta_music = "Music";
set text_meta_mood = "Mood";
set text_sidebar_link_separator = "&nbsp;&nbsp;&raquo;&nbsp;&nbsp;";

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,17 @@
# -*-s2-*-
layerinfo type = "i18n";
layerinfo name = "English";
layerinfo redist_uniq = "generator/en";
set text_meta_music = "music";
set text_meta_mood = "mood";
set text_permalink = "link";
set text_post_comment = "post comment";
set text_post_comment_friends = "post comment";
set text_read_comments = "1 comment // # comments";
set text_read_comments_friends = "1 comment // # comments";

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

@@ -0,0 +1,945 @@
# -*-s2-*-
layerinfo type = "layout";
layerinfo name = "Generator";
layerinfo redist_uniq = "generator/layout";
layerinfo previews = "generator/generator.jpg";
propgroup colors {
property Color entry_back {
des = "Entry background";
s1color = "page_back";
}
property Color entry_text {
des = "Entry text color";
s1color = "page_text";
}
property Color page_link {
des = "Link color";
s1color = "page_link";
}
property Color page_vlink {
des = "Visited link color";
s1color = "page_vlink";
}
property Color page_alink {
des = "Active link color";
s1color = "page_alink";
}
property Color page_back {
des = "Page background color (and around userpics)";
s1color = "strong_back";
}
property Color stronger_back {
des = "Background color for the bar above entries";
s1color = "strong_back";
}
property Color stronger_text {
des = "Text color for the bar above entries";
s1color = "stronger_text";
}
property Color weak_back {
des = "Background color for the bar below entries";
s1color = "weak_back";
}
property Color weak_text {
des = "Text color for the bar below entries";
s1color = "weak_text";
}
property Color comment_bar_one_bgcolor {
des = "Alternating background color for comment bars (one)";
}
property Color comment_bar_two_fgcolor {
des = "Text color on alternating comment bars (one)";
}
property Color comment_bar_two_bgcolor {
des = "Alternating background color for comment bars (two)";
}
property Color comment_bar_one_fgcolor {
des = "Text color on alternating comment bars (two)";
}
property Color comment_bar_screened_bgcolor {
des = "Background bar color for screened comments";
}
property Color comment_bar_screened_fgcolor {
des = "Text color on background bar for screened comments";
}
}
propgroup fonts {
property use font_base;
property use font_fallback;
}
propgroup presentation {
property use page_recent_items;
property use page_friends_items;
property int box_width {
des = "Box width (pixels)";
}
property use view_entry_disabled;
property use use_shared_pic;
property use comment_userpic_style;
property bool show_entrynav_icons {
des = "Toggle to show the next, memory, edit, etc icons on the entry view page";
}
property string page_background_image {
des = "URL to an image to be used for the page background";
}
property use external_stylesheet;
property use linklist_support;
}
propgroup text {
property use text_post_comment;
property use text_read_comments;
property use text_post_comment_friends;
property use text_read_comments_friends;
property use text_meta_music;
property use text_meta_mood;
property string text_website {
des = "The label for the 'website' field";
noui = 1;
}
}
# Set default colors
set entry_back = "#ffffff";
set entry_text = "#000000";
set page_link = "#0000ff";
set page_vlink = "#0000ff";
set page_alink = "#00ffff";
set page_back = "#2d4f89";
set stronger_back = "#000000";
set stronger_text = "#ffffff";
set weak_back = "#aaaaaa";
set weak_text = "#000000";
set comment_bar_one_bgcolor = "#aaaaaa";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#dddddd";
set comment_bar_two_fgcolor = "#000000";
set comment_bar_screened_bgcolor = "#5f6f99";
set comment_bar_screened_fgcolor = "#000000";
set box_width = 600;
set show_entrynav_icons = true;
set page_background_image = "";
set font_base = "Verdana";
set font_fallback = "sans-serif";
# Customize the view names to be short and lowercase
# (Sorry translators, you'll have to do these again - keep them short!)
set text_view_recent = "entries";
set text_view_friends = "friends";
set text_view_archive = "archive";
set text_view_userinfo = "userinfo";
set tags_aware = true;
set text_website = "website";
function print_stylesheet () {
print clean_url($*page_background_image) != "" ? "body { background-image: url($*page_background_image); }" : "";
"""body, td {
""";
if ($*font_base != "" or $*font_fallback != "none") {
"font-family: ";
if ($*font_base != "") {
"\"$*font_base\"";
if ($*font_fallback != "none") {
", ";
}
}
if ($*font_fallback != "none") {
print $*font_fallback;
}
";\n";
}
"""font-size: 10pt;
}
tt, pre {
font-family: monospace;
}
a {
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
.shadowed {
font-size: 8pt;
background: $*weak_back;
}
.meta {
font-size: 8pt;
}
.index {
font-size: 8pt;
}
.caption, .index {
color: $*stronger_text;
}
.comments {
font-size: 8pt;
}
""";
}
function Page::lay_top_userpic () {
var Image up_img = $.journal.default_pic;
if (defined $up_img) {
"""<td><table cellpadding="2" bgcolor="$*entry_back" cellspacing="0" border="0" summary="">
<tr><td bgcolor="$*stronger_back" align="center"><img border="0" src="$up_img.url" height="$up_img.height" width="$up_img.width" alt=""></td></tr>
</table></td>
""";
}
}
function FriendsPage::lay_top_userpic () { }
function Page::print_linklist() {
if (size $.linklist <= 0) {
return;
}
println """
<p>
<table width='$*box_width' cellpadding='2' cellspacing='0'
border='0'
summary=''>
<tr><td bgcolor='$*stronger_back' align='center'>
<table width='100%' cellpadding='3' cellspacing='0'
border='0'
summary=''>
<tr class='caption'>
<td class='caption' align='left'><b>Links</b></td>
</tr></table>
<table width='100%' cellpadding='3' cellspacing='0'
border='0'
summary=''>
<tr class='shadowed'>
<td align='center'>
<table cellspacing='5'
cellpadding='0'
border='0'
summary=''>
""";
var bool section_open = false;
if (not $.linklist[0].is_heading) {
println """<tr><td class="meta">[</td><td class="meta" align="right"><b>Links:</b></td><td class="meta" align="center">|</td><td class="meta">""";
$section_open = true;
}
foreach var UserLink l ($.linklist) {
if ($l.title) {
if ($l.is_heading) {
if ($section_open) {
println """</td><td class="meta">]</td></tr>""";
}
println """<tr><td class="meta">[</td><td class="meta" align="right"><b>$l.title</b></td><td class="meta" align="center">|</td><td class="meta">""";
$section_open = true;
} else {
println """<a href="$l.url">$l.title</a> """;
}
}
}
println """</td><td class="meta">]</td></tr>""";
"</table>
</td>
</tr>
</table>
</td>
</tr></table>
</p>
";
}
function Page::print ()
{
var string title = $this->title();
var string website_name = $.journal.website_name ? $.journal.website_name : $*text_website_default_name;
var string website;
if ($.journal.website_url != "") {
$website = """<tr><td class="meta">[</td>
<td class="meta" align="right"><b>$*text_website</b></td>
<td class="meta" align="center">|</td>
<td class="meta" align="left"><a href="$.journal.website_url">$website_name</a></td>
<td class="meta">]</td></tr>""";
}
var string links;
var bool firstlink = true;
foreach var string v ($.views_order) {
if ($firstlink == false) {
$links = "$links|";
}
else {
$firstlink = false;
}
$links = $links + ($.view == $v ?
"<b>"+lang_viewname($v)+"</b>" :
"<a class='index' href='$.view_url{$v}'>"+lang_viewname($v)+"</a>");
}
"""<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n<html>\n<head>\n""";
if ($*external_stylesheet) {
println """<link rel="stylesheet" href="$.stylesheet_url" type="text/css" />""";
} else {
println """<style type="text/css">"""; print_stylesheet(); "</style>";
}
$this->print_head();
"""<title>$title</title>
</head>
<body bgcolor="$*page_back" text="$*entry_text" link="$*page_link" vlink="$*page_vlink" alink="$*page_alink">
<div align="center">
<table width="$*box_width" cellpadding="2" cellspacing="0"
border="0"
summary="">
<tr><td bgcolor="$*stronger_back" align="center">
<table width="100%" cellpadding="3" cellspacing="0"
border="0"
summary="">
<tr class="caption">
<td class="caption" align="left"><b>$title</b></td>
<td class="index" align="right">[$links]</td>
</tr></table>
<table width="100%" cellpadding="3" cellspacing="0"
border="0"
summary="">
<tr>
<td class="shadowed" align="center">
<table cellspacing="5"
cellpadding="0"
border="0"
summary="" style="margin-left: auto; margin-right: auto;">
<tr>""";
$this->lay_top_userpic();
var string sitename_lc = $*SITENAMESHORT->lower();
"""<td>
<div align="center"><b>$.journal.name</b></div><p>
<table cellspacing="0"
cellpadding="0"
border="0"
summary="">
$website
<tr>
<td class="meta">[</td>
<td class="meta" align="right"><b>"""+lang_viewname("userinfo")+"""</b></td>
<td class="meta" align="center">|</td>
<td class="meta" align="left"><a href="$.view_url{"userinfo"}">$sitename_lc userinfo</a></td>
<td class="meta">]</td>
</tr>
<tr>
<td class="meta">[</td>
<td class="meta" align="right"><b>"""+lang_viewname("archive")+"""</b></td>
<td class="meta" align="center">|</td>
<td class="meta" align="left"><a href="$.view_url{"archive"}">journal archive</a></td>
<td class="meta">]</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr></table>
</td></tr>
</table>
""";
if (size $.linklist > 0 and $*linklist_support) {
$this->print_linklist();
}
"""
<p>
""";
$this->print_body();
"""
</div>
<p>
</body>
</html>
""";
}
function print_entry (Page p, Entry e, Color bgcolor, Color fgcolor, bool hide_text)
{
var string datetime;
$datetime = $e.time->date_format("med")+"|<b>"
+ $e.time->time_format() + "</b>";
"""
<table width="$*box_width" cellpadding="2" cellspacing="0" border="0" summary="" class="entrybox">
<tr align='left'>
<td bgcolor="$*stronger_back" align="center">
<table width="100%" cellpadding="5" cellspacing="0" border="0" summary="">
<tr align='left'>
<td class="caption">""";
if ($e.security != "") {
$e.security_icon->print();
}
""" $e.subject</td>
<td align="right" class="index">[$datetime]</td>
</tr>
<tr align='left'>
<td colspan="2" bgcolor="$*entry_back">
""";
if ($p.view == "entry" and $*show_entrynav_icons)
{
print "<div style='text-align: center'>";
$e->print_linkbar();
print "</div>";
}
if ($p.view == "friends" or
$p.journal_type == "C" or
$e.poster.username != $e.journal.username)
{
var UserLite linkto;
var bool showposter;
if ($p.view == "recent" and $p.journal_type == "C") {
$linkto = $e.poster;
$showposter = false;
} else {
$linkto = $e.journal;
$showposter = true;
}
"""<table cellpadding="1" align="right" cellspacing="0" border="0" summary=""><tr align='left'><td bgcolor="$*stronger_back">""";
"""<table cellpadding="2" align="center" cellspacing="0" border="0" summary="">""";
"""<tr align='left'><td bgcolor="$bgcolor" align="center"><a class="index" href=\"""" + $linkto->base_url() + "\">";
if (defined $e.userpic) {
"""<img border="0" src="$e.userpic.url" width="$e.userpic.width" height="$e.userpic.height" alt=""><br>""";
}
"<font color=\"$fgcolor\">$linkto.username</font></a>";
if ($e.poster.username != $e.journal.username and $showposter) {
"<br>[<a class=\"index\" href=\"" +
$e.poster->base_url() + "/\"><font color=\"$fgcolor\">$e.poster.username</font></a>]";
}
"</td></tr></table></td></tr></table>";
}
var string metadata;
if ($e.metadata) {
$metadata = """<table cellspacing="0" cellpadding="0" border="0" summary="">""";
foreach var string k ($e.metadata) {
var string text = $k;
var string val = $e.metadata{$k};
if ($k == "mood") {
$text = $*text_meta_mood;
} elseif ($k == "music") {
$text = $*text_meta_music;
}
if ($k == "mood" and defined $e.mood_icon) {
var Image i = $e.mood_icon;
$val = "<img src='$i.url' width='$i.width' height='$i.height' align='absmiddle'> $val";
}
$metadata = """$metadata\n<tr><td class="meta">[</td><td class="meta" align="right"><b>$text</b></td>
<td class="meta" align="center">|</td><td class="meta">$val</td><td class="meta">]</td></tr>""";
}
$metadata = """$metadata</table>""";
}
var string tags;
if ($e.tags) {
var int tcount = 0;
$tags = """<table cellspacing="0" cellpadding="0" border="0" summary=""><tr><td class="meta" align="right">[<b>Tags</b></td>""";
$tags = """$tags<td class="meta" align="center">|</td><td class="meta">""";
foreach var Tag t ($e.tags) {
$tags = """$tags<a rel="tag" href="$t.url">$t.name</a>""";
$tcount++;
if ($tcount != size $e.tags) { $tags = """$tags, """; }
}
$tags = """$tags</td><td class="meta">]</td></tr></table>""";
}
if (not $hide_text) {
if ($tags or $metadata) {
print $tags;
print $metadata;
print "<br />";
}
print $e.text;
}
"""</td></tr>
<tr bgcolor="$*weak_back"><td align='left' class='comments'>
<a href="$e.permalink_url">$*text_permalink</a></td>""";
if ($p.view != "entry" and $p.view != "reply") {
"<td align='right' class='comments'>"; $e.comments->print(); "</td>";
} elseif ($e.comments.enabled) {
"<td align='right' class='comments'>"; $e.comments->print_postlink(); "</td>";
} else {
"<td></td>";
}
"""</tr></table></td></tr></table><p>""";
} # print_entry(Page,Entry,Color,Color,bool)
function Page::print_entry (Entry e) {
print_entry($this, $e, null Color, null Color, false);
}
function FriendsPage::print_entry (Entry e) {
var Friend f = $.friends{$e.journal.username};
print_entry($this, $e, $f.bgcolor, $f.fgcolor, false);
}
function RecentPage::print_body ()
{
foreach var Entry e ($.entries) {
$this->print_entry($e);
}
var string range = "most recent entries";
if ($.nav.skip > 0) {
$range = "$.nav.skip entries back";
}
"""
<table cellpadding="2" cellspacing="0"
border="0"
summary="">
<tr><td bgcolor="$*stronger_back">
<table cellpadding="3" cellspacing="0"
border="0"
summary="">
<tr>
<td align="center" class="index">navigation</td>
</tr>
<tr>
<td bgcolor="$*entry_back" align="center">
<table cellspacing="0"
cellpadding="0"
border="0"
summary="">
<tr>
<td class="meta">[</td>
<td class="meta" align="right"><b>viewing</b></td>
<td class="meta" align="center">|</td>
<td class="meta">$range</td>
<td class="meta">]</td>
</tr>
""";
# go forward/backward if possible
if ($.nav.forward_url != "" or $.nav.backward_url != "") {
var string sep;
var string back;
var string forward;
if ($.nav.backward_url != "") {
$back = """<a href="$.nav.backward_url">earlier</a>""";
}
if ($.nav.forward_url != "") {
$forward = """<a href="$.nav.forward_url">later</a>""";
}
if ($back != "" and $forward != "") { $sep = "/"; }
"""<tr>
<td class="meta">[</td>
<td class="meta" align="right"><b>go</b></td>
<td class="meta" align="center">|</td>
<td class="meta">$back$sep$forward</td>
<td class="meta">]</td>
</tr>""";
}
"</table></td></tr></table></table>";
}
function CommentInfo::print ()
{
if (not $.enabled) { return; }
if ($.count > 0 or $.screened) {
"<b>"; $this->print_readlink(); "</b>";
"|";
}
$this->print_postlink();
}
function YearPage::print_year_links ()
{
"""<table cellpadding="2" cellspacing="0" border="0" summary="">
<tr><td bgcolor="$*stronger_back" align="center">
<table cellpadding="5" cellspacing="0" border="0" summary="">
<tr><td class="caption">Years</td></tr><tr>
<td colspan="2" bgcolor="$*entry_back">""";
foreach var YearYear y ($.years) {
if ($y.displayed) {
"<b>$y.year</b>&nbsp;";
} else {
"<a href=\"$y.url\">$y.year</a>&nbsp;";
}
}
"""</td></tr></table></td></tr></table><p>""";
}
function YearPage::print_month (YearMonth m)
{
if (not $m.has_entries) { return; }
"""<table cellpadding="2" cellspacing="0" border="0" summary="">
<tr><td bgcolor="$*stronger_back" align="center">
<table cellpadding="5" cellspacing="0" border="0" summary="">
<tr>
<td class="caption">""";
print $m->month_format();
"""</td>
<td class="caption" align="right">[<a href="$m.url" class="index">subjects</a>]</td>
</tr>
<tr>
<td colspan="2" bgcolor="$*entry_back">
<!-- now the headings for the week -->
<table width="100%" cellpadding="5" cellspacing="0" border="0" summary="">
<tr align="center">
""";
foreach var int d (weekdays()) {
"<td>"+$*lang_dayname_short[$d]+"</td>\n";
}
"</tr>";
foreach var YearWeek w ($m.weeks) {
$w->print();
}
"""</table></td></tr></table></td></tr></table><p>""";
}
function YearWeek::print () {
"<tr valign='top'>";
if ($.pre_empty) { "<td colspan='$.pre_empty'></td>"; }
foreach var YearDay d ($.days) {
"""<td><div class="meta">$d.day</div>""";
if ($d.num_entries) {
"""<div align="center"><a href="$d.url">$d.num_entries</a></div>""";
} else {
"&nbsp;";
}
"</td>";
}
if ($.post_empty) { "<td colspan='$.post_empty'></td>"; }
"</tr>";
}
function DayPage::print_body() {
"""<table cellpadding="2" cellspacing="0" border="0" summary="">
<tr><td bgcolor="$*stronger_back" align="center">
<table cellpadding="5" cellspacing="0" border="0" summary="">
<tr><td bgcolor="$*entry_back">""";
if ($.has_entries) {
print $.date->date_format("long");
} else {
print ehtml($*text_noentries_day);
}
"""</td></tr></table></td></tr></table><p>""";
foreach var Entry e ($.entries) {
$this->print_entry($e);
}
var string tprev = ehtml($*text_day_prev);
var string tnext = ehtml($*text_day_next);
var string daylong = $.date->date_format("long");
"""<table cellpadding="2" cellspacing="0" border="0" summary="">
<tr><td bgcolor="$*stronger_back">
<table cellpadding="3" cellspacing="0" border="0" summary="">
<tr>
<td align="center" class="index">navigation</td>
</tr>
<tr>
<td bgcolor="$*entry_back" align="center">
<table cellspacing="0" cellpadding="0" border="0" summary="">
<tr>
<td class="meta">[</td>
<td class="meta" align="right"><b>viewing</b></td>
<td class="meta" align="center">|</td>
<td class="meta">$daylong</td>
<td class="meta">]</td>
</tr>
<tr>
<td class="meta">[</td>
<td class="meta" align="right"><b>go</b></td>
<td class="meta" align="center">|</td>
<td class="meta"><a href="$.prev_url">$tprev</a>|<a href="$.next_url">$tnext</a></td>
<td class="meta">]</td>
</tr>
</table>
</td>
</tr>
</table>
</table>""";
}
function MonthPage::print_body () {
"""<table width="$*box_width" cellpadding="2" cellspacing="0" border="0" summary="" class="entrybox">
<tr align='left'>
<td bgcolor="$*stronger_back" align="center">
<table width="100%" cellpadding="5" cellspacing="0" border="0" summary="">
<tr align='left'>
<td class="caption" colspan='2'>""";
print $.date->date_format($*lang_fmt_month_long);
"""</td></tr>
<tr align='left'>
<td colspan="2" bgcolor="$*entry_back">""";
#Lifted from core, looks decent:
"<form method='post' action='$.redir.url'><center>";
$.redir->print_hiddens();
if ($.prev_url != "") { "[<a href='$.prev_url'>&lt;&lt;&lt;</a>]\n"; }
if (size $.months > 1) {
"<select name='redir_key'>\n";
foreach var MonthEntryInfo mei ($.months) {
var string sel;
if ($mei.date.year == $.date.year and $mei.date.month == $.date.month) {
$sel = " selected='selected'";
}
"<option value='$mei.redir_key'$sel>" + $mei.date->date_format($*lang_fmt_month_long) + "</option>";
}
"</select>\n<input type='submit' value='View' />";
}
if ($.next_url != "") { "\n[<a href='$.next_url'>&gt;&gt;&gt;</a>]\n"; }
"</center></form>\n<dl>";
foreach var MonthDay d ($.days) {
if ($d.has_entries) {
"<dt><a href=\"$d.url\"><b>";
print lang_ordinal($d.day);
"</b></a></dt>\n<dd>";
$d->print_subjectlist();
"</dd>\n";
}
}
"</dl>\n";
"""</td></tr></table>
</td></tr></table><p>""";
}
function EntryPage::print_body () {
print_entry($this, $.entry, null Color, null Color, $.viewing_thread);
if ($.entry.comments.enabled and $.comment_pages.total_subitems > 0)
{
$this->print_multiform_start();
"""<table width="$*box_width" cellpadding="2" cellspacing="0" border="0" summary="" class="entrybox">
<tr align='left'>
<td bgcolor="$*stronger_back" align="center">
<table width="100%" cellpadding="5" cellspacing="0" border="0" summary="">
<tr align='left'>
<td class="caption" colspan='2'>Comments:</td></tr>""";
"""<tr align='left'><td colspan="2" bgcolor="$*entry_back">""";
$.comment_pages->print();
set_handler("unscreen_comment_#", [
[ "style_bgcolor", "cmtbar#", "$*comment_bar_one_bgcolor", ],
[ "style_color", "cmtbar#", "$*comment_bar_one_fgcolor", ],
]);
set_handler("screen_comment_#", [
[ "style_bgcolor", "cmtbar#", "$*comment_bar_screened_bgcolor", ],
[ "style_color", "cmtbar#", "$*comment_bar_screened_fgcolor", ],
]);
$this->print_comments($.comments);
$.comment_pages->print();
"""</td></tr></table></td></tr></table><p>""";
if ($this.multiform_on) {
"""<table width="$*box_width" cellpadding="2" cellspacing="0" border="0" summary="" class="entrybox">
<tr align='left'>
<td bgcolor="$*stronger_back" align="center">
<table width="100%" cellpadding="5" cellspacing="0" border="0" summary="">
<tr align='left'>
<td class="caption" colspan='2'>Mass Action:</td></tr>""";
"""<tr align='left'><td colspan="2" bgcolor="$*entry_back">""";
$this->print_multiform_actionline();
"""</td></tr></table></td></tr></table><p>""";
$this->print_multiform_end();
}
}
}
function EntryPage::print_comment (Comment c) {
var Color background; var Color color;
if ($c.screened) {
$background = $*comment_bar_screened_bgcolor;
$color = $*comment_bar_screened_fgcolor;
} elseif ($c.depth % 2) {
$background = $*comment_bar_one_bgcolor;
$color = $*comment_bar_one_fgcolor;
} else {
$background = $*comment_bar_two_bgcolor;
$color = $*comment_bar_two_fgcolor;
}
var string poster = defined $c.poster ? $c.poster->as_string() : "<i>(Anonymous)</i>";
var string sub_icon;
if (defined $c.subject_icon) {
$sub_icon = $c.subject_icon->as_string();
}
"<a name='$c.anchor'></a><div id='cmtbar$c.talkid' style='background-color: $background; color: $color; margin-top: 10px; width: 100%;'>";
"<table cellpadding='2' cellspacing='0' summary='0' style='width: 100%'><tr valign='top'>";
if (defined $c.userpic and $*comment_userpic_style != "off") {
var int w = $c.userpic.width;
var int h = $c.userpic.height;
# WARNING: this will later be done by the system (it'll be a
# constructional property), so don't copy this hack into your
# layout layers or you'll be messed up later.
if ($*comment_userpic_style == "small") {
$w = $w / 2;
$h = $h / 2;
}
print "<td style='width: 102px'><img src='$c.userpic.url' width='$w' height='$h' alt='[User Picture]' /></td>";
}
"<td style='width: 100%'><table style='width: 100%'><tr>";
### From, date, etc
"<td align='left' style='width: 50%'>";
print "<table>";
print "<tr><th align='right' style='white-space: nowrap'>From:</th><td style='white-space: nowrap'>$poster</td></tr>\n";
print "<tr><th align='right' style='white-space: nowrap'>Date:</th><td style='white-space: nowrap'>";
print $c.time->date_format("long") + " - " + $c.time->time_format() + "</td></tr>";
if ($c.metadata{"poster_ip"}) { print "<tr><th align='right' style='white-space: nowrap'>IP Address:</th><td>(" + $c.metadata{"poster_ip"} + ")</td></tr>"; }
"</table></td>";
### Gadgets
"<td align='right' style='width: 50%'>";
if ($this.multiform_on) {
" <label for='ljcomsel_$c.talkid'>$*text_multiform_check</label>";
$c->print_multiform_check();
}
$c->print_linkbar();
"</td></tr>";
### Subject / icon
print "<tr valign='top'><td style='width: 50%'>";
print (defined $c.subject_icon or $c.subject != "") ? "<h3>$c.subject_icon $c.subject</h3>" : "";
print "</td>";
### Permalink
print "<td style='width: 50%' align='right'><strong>(<a href='$c.permalink_url'>Link</a>)</strong></td></tr>";
print "</table></td></tr></table></div>";
print "<div style='margin-left: 5px'>$c.text</div>";
print "<div style='margin-top: 3px; font-size: smaller'>";
"<span class='commentlinks'>";
if ($c.frozen) {
"(Replies frozen) ";
} else {
"(<a href='$c.reply_url'>Reply to this</a>) ";
}
"</span>";
if ($c.parent_url != "") { "(<a href='$c.parent_url'>Parent</a>) "; }
if ($c.thread_url != "") { "(<a href='$c.thread_url'>Thread</a>) "; }
"</div>";
}
function ReplyPage::print_body () {
if (not $.entry.comments.enabled) {
"""<table width="$*box_width" cellpadding="2" cellspacing="0" border="0" summary="" class="entrybox">
<tr align='left'>
<td bgcolor="$*stronger_back" align="center">
<table width="100%" cellpadding="5" cellspacing="0" border="0" summary="">
<tr align='left'>
<td class="caption" colspan='2'>$*text_reply_nocomments_header</td></tr>
<tr align='left'>
<td colspan="2" bgcolor="$*entry_back">""";
print "<p>$*text_reply_nocomments</p>";
"""</td></tr></table></td></tr></table><p>""";
return;
}
var string datetime;
$datetime = $.replyto.time->date_format("med")+"|<b>" + $.replyto.time->time_format() + "</b>";
"""<table width="$*box_width" cellpadding="2" cellspacing="0" border="0" summary="" class="entrybox">
<tr align='left'>
<td bgcolor="$*stronger_back" align="center">
<table width="100%" cellpadding="5" cellspacing="0" border="0" summary="">
<tr align='left'>
<td class="caption">$.replyto.subject</td>
<td class="index" align="right">$datetime</td></tr>
<tr align='left'>
<td colspan="2" bgcolor="$*entry_back">
<table cellpadding="1" align="right" cellspacing="0" border="0" summary="">
<tr align='left'><td bgcolor="$*stronger_back">
<table cellpadding="2" align="center" cellspacing="0" border="0" summary="">
<tr align='left'><td align="center" style="color: $*stronger_text">""";
if (defined $.replyto.poster) {
"<a href='" + $.replyto.poster->base_url() + "/'>";
if (defined $.replyto.userpic) {
"""<img border="0" src="$.replyto.userpic.url" width="$.replyto.userpic.width" """;
"""height="$.replyto.userpic.height" alt=""><br />""";
}
"$.replyto.poster.username</a>";
} else {
print "<i>Anonymous</i>";
}
"""</td></tr></table></td></tr></table>$.replyto.text</td></tr>
<tr bgcolor="$*weak_back"><td align='left' class='comments'>
<a href="$.replyto.permalink_url">$*text_permalink</a></td>
<td align='right' class='comments'><a href='$.entry.comments.read_url'>Read Comments</a></td>
</tr></table></td></tr></table><p>""";
"""<table width="$*box_width" cellpadding="2" cellspacing="0" border="0" summary="" class="entrybox">
<tr align='left'>
<td bgcolor="$*stronger_back" align="center">
<table width="100%" cellpadding="5" cellspacing="0" border="0" summary="">
<tr align='left'>
<td class="caption" colspan='2'>Reply:</td></tr>
<tr align='left'>
<td colspan="2" bgcolor="$*entry_back">""";
$.form->print();
"""</td></tr></table></td></tr></table><p>""";
}
function print_theme_preview () {
"""<table width='100%' bgcolor='$*page_back' cellpadding=10><tr><td align='center'>
<table width='400' cellpadding='2' cellspacing='2'>
<tr align='left'><td bgcolor="$*stronger_back" align="center">
<table width="100%" cellpadding="5" cellspacing="0" border="0" summary="">
<tr align='left'><td style="color: $*stronger_text">Preview Subject</td><td align="right" style="font-size: 8pt; color: $*stronger_text">[Feb. 5th, 2002|<b>8:46 pm</b>]</td></tr>
<tr align='left'>
<td colspan="2" bgcolor="$*entry_back" style='color: $*entry_text'>
Preview text, preview text, etc, etc..... words, words and more words.
</td></tr>
<tr bgcolor="$*weak_back"><td align='left' class='style: font-size: 8pt'>
<a style='text-decoration:none;color: $*page_link' href="#">$*text_permalink</a>
</td><td align='right' style='font-size: 8pt'>
<a href='#' style='text-decoration:none;color:$*page_vlink'><b>1 comment</b></a>|<a href='#' style='text-decoration:none;color:$*page_link'>post comment</a>
</td></tr></table>
</td></tr></table>
</td></tr></table>
""";
}

View File

@@ -0,0 +1,369 @@
#NEWLAYER: generator/mintchoc
layerinfo "type" = "theme";
layerinfo "name" = "Mint Chocolate Chip";
layerinfo "redist_uniq" = "generator/mintchoc";
layerinfo "author_name" = "Andrea Hartmann";
layerinfo "author_email" = "mullenkamp@livejournal.com";
set entry_back = "#ddffee";
set entry_text = "#330000";
set page_link = "#993333";
set page_vlink = "#663333";
set page_alink = "#000000";
set page_back = "#ccffdd";
set stronger_back = "#663333";
set stronger_text = "#ccffdd";
set weak_back = "#88ffdd";
set weak_text = "#663333";
set comment_bar_one_bgcolor = "#88ffdd";
set comment_bar_one_fgcolor = "#663333";
set comment_bar_two_fgcolor = "#663333";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: generator/purple
layerinfo "type" = "theme";
layerinfo "name" = "Purple";
layerinfo "redist_uniq" = "generator/purple";
layerinfo "author_name" = "Andrea Hartmann";
layerinfo "author_email" = "mullenkamp@livejournal.com";
set entry_back = "#9933cc";
set entry_text = "#ddccff";
set page_link = "#ffffff";
set page_vlink = "#330033";
set page_alink = "#ffccff";
set page_back = "#bb55ee";
set stronger_back = "#660099";
set stronger_text = "#f5eeff";
set weak_back = "#bb88dd";
set weak_text = "#ddccff";
set comment_bar_one_bgcolor = "#660099";
set comment_bar_one_fgcolor = "#f5eeff";
set comment_bar_two_bgcolor = "#bb88dd";
set comment_bar_two_fgcolor = "#ddccff";
#NEWLAYER: generator/ocean
layerinfo "type" = "theme";
layerinfo "name" = "Deep Blue Xenogears Ocean";
layerinfo "redist_uniq" = "generator/ocean";
layerinfo "author_name" = "Andrea Hartmann";
layerinfo "author_email" = "mullenkamp@livejournal.com";
set entry_back = "#1100dd";
set entry_text = "#ccccff";
set page_link = "#ffffff";
set page_vlink = "#ddddff";
set page_alink = "#ffffff";
set page_back = "#3333ff";
set stronger_back = "#aabbff";
set stronger_text = "#0033cc";
set weak_back = "#3399ff";
set weak_text = "#0033cc";
set comment_bar_one_bgcolor = "#aabbff";
set comment_bar_one_fgcolor = "#0033cc";
set comment_bar_two_bgcolor = "#3399ff";
set comment_bar_two_fgcolor = "#0033cc";
#NEWLAYER: generator/harvest
layerinfo "type" = "theme";
layerinfo "name" = "Harvest";
layerinfo "redist_uniq" = "generator/harvest";
layerinfo "author_name" = "Andrea Hartmann";
layerinfo "author_email" = "mullenkamp@livejournal.com";
set entry_back = "#ff9900";
set entry_text = "#663333";
set page_link = "#ffeeaa";
set page_vlink = "#993300";
set page_alink = "#ffcc88";
set page_back = "#ffaa11";
set stronger_back = "#ffcc33";
set stronger_text = "#663333";
set weak_back = "#cc6600";
set weak_text = "#ffcc88";
set comment_bar_one_bgcolor = "#ffcc33";
set comment_bar_one_fgcolor = "#663333";
set comment_bar_two_bgcolor = "#cc6600";
set comment_bar_two_fgcolor = "#ffcc88";
#NEWLAYER: generator/jeweled
layerinfo "type" = "theme";
layerinfo "name" = "Jeweled";
layerinfo "redist_uniq" = "generator/jeweled";
layerinfo "author_name" = "Andrea Hartmann";
layerinfo "author_email" = "mullenkamp@livejournal.com";
set entry_back = "#aa6699";
set entry_text = "#330066";
set page_link = "#ccddee";
set page_vlink = "#cc99cc";
set page_alink = "#cceecc";
set page_back = "#881188";
set stronger_back = "#006699";
set stronger_text = "#ceecc";
set weak_back = "#008888";
set weak_text = "#002222";
set comment_bar_one_bgcolor = "#006699";
set comment_bar_one_fgcolor = "#ceecc";
set comment_bar_two_bgcolor = "#008888";
set comment_bar_two_fgcolor = "#002222";
#NEWLAYER: generator/darkgreens
layerinfo type = "theme";
layerinfo name = "Dark Greens";
layerinfo redist_uniq = "generator/darkgreens";
layerinfo author_name = "Ryan Fitzpatrick";
set entry_back = "#020202";
set entry_text = "#fbfbfb";
set page_link = "#9aff8d";
set page_vlink = "#e3ee39";
set page_alink = "#ff0220";
set page_back = "#117218";
set stronger_back = "#38e616";
set stronger_text = "#020100";
set weak_back = "#020100";
set weak_text = "#000000";
set comment_bar_one_bgcolor = "#38e616";
set comment_bar_one_fgcolor = "#020100";
set comment_bar_two_bgcolor = "#117218";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: generator/satin
layerinfo type = theme;
layerinfo name = "Satin Handshake";
layerinfo redist_uniq = "generator/satin";
set entry_back = "#d06464";
set entry_text = "#000000";
set page_link = "#ffffff";
set page_vlink = "#6f2222";
set page_alink = "#333333";
set page_back = "#480c0c";
set stronger_back = "#9d0404";
set stronger_text = "#ffffff";
set weak_back = "#d06464";
set weak_text = "#ffffff";
set comment_bar_one_bgcolor = "#9d0404";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#d06464";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: generator/sunset
layerinfo type = theme;
layerinfo name = "Sunset";
layerinfo redist_uniq = "generator/sunset";
set entry_back = "#ff7301";
set entry_text = "#fdb54f";
set page_link = "#ffe65e";
set page_vlink = "#ff9879";
set page_alink = "#ffb866";
set page_back = "#070494";
set stronger_back = "#f8a402";
set stronger_text = "#ffd510";
set weak_back = "#f51700";
set weak_text = "#f77603";
set comment_bar_one_bgcolor = "#f8a402";
set comment_bar_one_fgcolor = "#ffd510";
set comment_bar_two_bgcolor = "#f51700";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: generator/redbliss
layerinfo type = theme;
layerinfo name = "Red Bliss";
layerinfo redist_uniq = "generator/redbliss";
set entry_back = "#ffcccc";
set entry_text = "#000000";
set page_link = "#ffffff";
set page_vlink = "#ffcccc";
set page_alink = "#00ffff";
set page_back = "#ff3300";
set stronger_back = "#cc3333";
set stronger_text = "#ffffff";
set weak_back = "#cc3333";
set weak_text = "#fafafa";
set comment_bar_one_bgcolor = "#cc3333";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#ff3333";
set comment_bar_two_fgcolor = "#fafafa";
#NEWLAYER: generator/pastelneons
layerinfo type = theme;
layerinfo name = "Pastel Neons";
layerinfo redist_uniq = "generator/pastelneons";
set entry_back = "#ffffff";
set entry_text = "#1a6b6a";
set page_link = "#330f42";
set page_vlink = "#033339";
set page_alink = "#9923ca";
set page_back = "#00ffff";
set stronger_back = "#60d2cb";
set stronger_text = "#000000";
set weak_back = "#d385f3";
set weak_text = "#000000";
set comment_bar_one_bgcolor = "#60d2cb";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#d385f3";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: generator/classdesk
layerinfo type = "theme";
layerinfo name = "Classic Desktop";
layerinfo redist_uniq = "generator/classdesk";
set page_link = "#ff7b05";
set page_vlink = "#ce4900";
set page_alink = "#ff9e2b";
set page_back = "#007782";
set stronger_back = "#00545c";
set stronger_text = "#ffffff";
set weak_back = "#ffeddd";
set weak_text = "#ffffff";
set comment_bar_one_bgcolor = "#00545c";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#ffeddd";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: generator/everwhite
layerinfo type = theme;
layerinfo name = "Everwhite";
layerinfo redist_uniq = "generator/everwhite";
set entry_back = "#ffffff";
set entry_text = "#000000";
set page_link = "#ff0000";
set page_vlink = "#ff0000";
set page_alink = "#ffffff";
set page_back = "#ffffff";
set stronger_back = "#ffffff";
set stronger_text = "#ff0000";
set weak_back = "#ffffff";
set weak_text = "#ffffff";
set comment_bar_one_bgcolor = "#dddddd";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#aaaaaa";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: generator/everblue
layerinfo type = theme;
layerinfo name = "Everblue with Grey";
layerinfo redist_uniq = "generator/everblue";
set entry_back = "#ffffff";
set entry_text = "#000000";
set page_link = "#0000ff";
set page_vlink = "#060667";
set page_alink = "#ffffff";
set page_back = "#0f0c6d";
set stronger_back = "#000000";
set stronger_text = "#ffffff";
set weak_back = "#aaaaaa";
set weak_text = "#000000";
set comment_bar_one_bgcolor = "#000000";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#aaaaaa";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: generator/purplesky
layerinfo type = theme;
layerinfo name = "Purple Sky";
layerinfo redist_uniq = "generator/purplesky";
set entry_back = "#24d8df";
set entry_text = "#0424e4";
set page_link = "#a917c4";
set page_vlink = "#9911e8";
set page_alink = "#ea09ff";
set page_back = "#99e3e2";
set stronger_back = "#8802fa";
set stronger_text = "#ffffff";
set weak_back = "#89e5e9";
set weak_text = "#000000";
set comment_bar_one_bgcolor = "#8802fa";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#89e5e9";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: generator/bruise
layerinfo type = theme;
layerinfo name = "Bruise";
layerinfo redist_uniq = "generator/bruise";
set entry_back = "#bcbcbc";
set entry_text = "#000000";
set page_link = "#0000ff";
set page_vlink = "#0000ff";
set page_alink = "#0000ff";
set page_back = "#000000";
set stronger_back = "#1114a0";
set stronger_text = "#ffffff";
set weak_back = "#21c2f1";
set weak_text = "#000000";
set comment_bar_one_bgcolor = "#1114a0";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#21c2f1";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: generator/elegant
layerinfo type = theme;
layerinfo name = "Elegant";
layerinfo redist_uniq = "generator/elegant";
set entry_back = "#ffffff";
set entry_text = "#000000";
set page_link = "#e91822";
set page_vlink = "#bf1418";
set page_alink = "#f71e28";
set page_back = "#ffffff";
set stronger_back = "#777777";
set stronger_text = "#000000";
set weak_back = "#e6e6e6";
set weak_text = "#000000";
set comment_bar_one_bgcolor = "#777777";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#e6e6e6";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: generator/bananapeel
layerinfo type = theme;
layerinfo name = "Banana Peel";
layerinfo redist_uniq = "generator/bananapeel";
set entry_back = "#f2f688";
set entry_text = "#ee2914";
set page_link = "#db9129";
set page_vlink = "#c58f1b";
set page_alink = "#ffc518";
set page_back = "#ffffff";
set stronger_back = "#f0f905";
set stronger_text = "#000000";
set weak_back = "#dcdf02";
set weak_text = "#000000";
set comment_bar_one_bgcolor = "#f0f905";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#dcdf02";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: generator/melodrama
layerinfo type = theme;
layerinfo name = "Deep MeloDrama";
layerinfo redist_uniq = "generator/melodrama";
set entry_back = "#719cff";
set entry_text = "#9348a1";
set page_link = "#f5d3ff";
set page_vlink = "#e2ffe3";
set page_alink = "#e2ffe3";
set page_back = "#872d89";
set stronger_back = "#3794b3";
set stronger_text = "#a4b8ff";
set weak_back = "#65b2c1";
set weak_text = "#98bac5";
set comment_bar_one_bgcolor = "#3794b3";
set comment_bar_one_fgcolor = "#a4b8ff";
set comment_bar_two_bgcolor = "#65b2c1";
set comment_bar_two_fgcolor = "#872d89";
#NEWLAYER: generator/iceburg
layerinfo type = theme;
layerinfo name = "Iceburg";
layerinfo redist_uniq = "generator/iceburg";
set entry_back = "#ffffff";
set entry_text = "#000000";
set page_link = "#0000ff";
set page_vlink = "#0000ff";
set page_alink = "#387bf7";
set page_back = "#c6c2f5";
set stronger_back = "#7c6ccd";
set stronger_text = "#ffffff";
set weak_back = "#eef0fd";
set weak_text = "#000000";
set comment_bar_one_bgcolor = "#7c6ccd";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#eef0fd";
set comment_bar_two_fgcolor = "#000000";

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,392 @@
#NEWLAYER: haven/bluemonochromatic
layerinfo "type" = "theme";
layerinfo "name" = "Adaywien";
layerinfo "redist_uniq" = "haven/bluemonochromatic";
set color_scheme_base = "#1575C7";
set color_scheme = "monochromatic";
#NEWLAYER: haven/blueanalogous
layerinfo "type" = "theme";
layerinfo "name" = "Gwirasien";
layerinfo "redist_uniq" = "haven/blueanalogous";
set color_scheme_base = "#1575C7";
set color_scheme = "analogous";
#NEWLAYER: haven/bluecomplementary
layerinfo "type" = "theme";
layerinfo "name" = "Etaella";
layerinfo "redist_uniq" = "haven/bluecomplementary";
set color_scheme_base = "#1575C7";
set color_scheme = "complementary";
#NEWLAYER: haven/bluesplit_complementary
layerinfo "type" = "theme";
layerinfo "name" = "Sevaeviel";
layerinfo "redist_uniq" = "haven/bluesplit_complementary";
set color_scheme_base = "#1575C7";
set color_scheme = "split_complementary";
#NEWLAYER: haven/bluedouble_complementary
layerinfo "type" = "theme";
layerinfo "name" = "Glirewen";
layerinfo "redist_uniq" = "haven/bluedouble_complementary";
set color_scheme_base = "#1575C7";
set color_scheme = "double_complementary";
#NEWLAYER: haven/bluetriadic
layerinfo "type" = "theme";
layerinfo "name" = "Uloewiel";
layerinfo "redist_uniq" = "haven/bluetriadic";
set color_scheme_base = "#1575C7";
set color_scheme = "triadic";
#NEWLAYER: haven/bluetetradic
layerinfo "type" = "theme";
layerinfo "name" = "Yberawen";
layerinfo "redist_uniq" = "haven/bluetetradic";
set color_scheme_base = "#1575C7";
set color_scheme = "tetradic";
#NEWLAYER: haven/orangemonochromatic
layerinfo "type" = "theme";
layerinfo "name" = "Olerassa";
layerinfo "redist_uniq" = "haven/orangemonochromatic";
set color_scheme_base = "#F3904E";
set color_scheme = "monochromatic";
#NEWLAYER: haven/orangeanalogous
layerinfo "type" = "theme";
layerinfo "name" = "Vardothiel";
layerinfo "redist_uniq" = "haven/orangeanalogous";
set color_scheme_base = "#F3904E";
set color_scheme = "analogous";
#NEWLAYER: haven/orangecomplementary
layerinfo "type" = "theme";
layerinfo "name" = "Cadelaviel";
layerinfo "redist_uniq" = "haven/orangecomplementary";
set color_scheme_base = "#F3904E";
set color_scheme = "complementary";
#NEWLAYER: haven/orangesplit_complementary
layerinfo "type" = "theme";
layerinfo "name" = "Eriralle";
layerinfo "redist_uniq" = "haven/orangesplit_complementary";
set color_scheme_base = "#F3904E";
set color_scheme = "split_complementary";
#NEWLAYER: haven/orangedouble_complementary
layerinfo "type" = "theme";
layerinfo "name" = "Bemeth";
layerinfo "redist_uniq" = "haven/orangedouble_complementary";
set color_scheme_base = "#F3904E";
set color_scheme = "double_complementary";
#NEWLAYER: haven/orangetriadic
layerinfo "type" = "theme";
layerinfo "name" = "Welamma";
layerinfo "redist_uniq" = "haven/orangetriadic";
set color_scheme_base = "#F3904E";
set color_scheme = "triadic";
#NEWLAYER: haven/orangetetradic
layerinfo "type" = "theme";
layerinfo "name" = "Jerodia";
layerinfo "redist_uniq" = "haven/orangetetradic";
set color_scheme_base = "#F3904E";
set color_scheme = "tetradic";
#NEWLAYER: haven/greenmonochromatic
layerinfo "type" = "theme";
layerinfo "name" = "Cendarien";
layerinfo "redist_uniq" = "haven/greenmonochromatic";
set color_scheme_base = "#48C754";
set color_scheme = "monochromatic";
#NEWLAYER: haven/greenanalogous
layerinfo "type" = "theme";
layerinfo "name" = "Wicarede";
layerinfo "redist_uniq" = "haven/greenanalogous";
set color_scheme_base = "#48C754";
set color_scheme = "analogous";
#NEWLAYER: haven/greencomplementary
layerinfo "type" = "theme";
layerinfo "name" = "Laylla";
layerinfo "redist_uniq" = "haven/greencomplementary";
set color_scheme_base = "#48C754";
set color_scheme = "complementary";
#NEWLAYER: haven/greensplit_complementary
layerinfo "type" = "theme";
layerinfo "name" = "Dwiama";
layerinfo "redist_uniq" = "haven/greensplit_complementary";
set color_scheme_base = "#48C754";
set color_scheme = "split_complementary";
#NEWLAYER: haven/greendouble_complementary
layerinfo "type" = "theme";
layerinfo "name" = "Missi";
layerinfo "redist_uniq" = "haven/greendouble_complementary";
set color_scheme_base = "#48C754";
set color_scheme = "double_complementary";
#NEWLAYER: haven/greentriadic
layerinfo "type" = "theme";
layerinfo "name" = "Gwuwien";
layerinfo "redist_uniq" = "haven/greentriadic";
set color_scheme_base = "#48C754";
set color_scheme = "triadic";
#NEWLAYER: haven/greentetradic
layerinfo "type" = "theme";
layerinfo "name" = "Gerrathien";
layerinfo "redist_uniq" = "haven/greentetradic";
set color_scheme_base = "#48C754";
set color_scheme = "tetradic";
#NEWLAYER: haven/violetmonochromatic
layerinfo "type" = "theme";
layerinfo "name" = "Erudith";
layerinfo "redist_uniq" = "haven/violetmonochromatic";
set color_scheme_base = "#9D1EC7";
set color_scheme = "monochromatic";
#NEWLAYER: haven/violetanalogous
layerinfo "type" = "theme";
layerinfo "name" = "Narwen";
layerinfo "redist_uniq" = "haven/violetanalogous";
set color_scheme_base = "#9D1EC7";
set color_scheme = "analogous";
#NEWLAYER: haven/violetcomplementary
layerinfo "type" = "theme";
layerinfo "name" = "Yballan";
layerinfo "redist_uniq" = "haven/violetcomplementary";
set color_scheme_base = "#9D1EC7";
set color_scheme = "complementary";
#NEWLAYER: haven/violetsplit_complementary
layerinfo "type" = "theme";
layerinfo "name" = "Araymwen";
layerinfo "redist_uniq" = "haven/violetsplit_complementary";
set color_scheme_base = "#9D1EC7";
set color_scheme = "split_complementary";
#NEWLAYER: haven/violetdouble_complementary
layerinfo "type" = "theme";
layerinfo "name" = "Cydia";
layerinfo "redist_uniq" = "haven/violetdouble_complementary";
set color_scheme_base = "#9D1EC7";
set color_scheme = "double_complementary";
#NEWLAYER: haven/violettriadic
layerinfo "type" = "theme";
layerinfo "name" = "Eowiresa";
layerinfo "redist_uniq" = "haven/violettriadic";
set color_scheme_base = "#9D1EC7";
set color_scheme = "triadic";
#NEWLAYER: haven/violettetradic
layerinfo "type" = "theme";
layerinfo "name" = "Waedith";
layerinfo "redist_uniq" = "haven/violettetradic";
set color_scheme_base = "#9D1EC7";
set color_scheme = "tetradic";
#NEWLAYER: haven/yellowmonochromatic
layerinfo "type" = "theme";
layerinfo "name" = "Vauwen";
layerinfo "redist_uniq" = "haven/yellowmonochromatic";
set color_scheme_base = "#F3EAA0";
set color_scheme = "monochromatic";
#NEWLAYER: haven/yellowanalogous
layerinfo "type" = "theme";
layerinfo "name" = "Praressi";
layerinfo "redist_uniq" = "haven/yellowanalogous";
set color_scheme_base = "#F3EAA0";
set color_scheme = "analogous";
#NEWLAYER: haven/yellowcomplementary
layerinfo "type" = "theme";
layerinfo "name" = "Lelivia";
layerinfo "redist_uniq" = "haven/yellowcomplementary";
set color_scheme_base = "#F3EAA0";
set color_scheme = "complementary";
#NEWLAYER: haven/yellowsplit_complementary
layerinfo "type" = "theme";
layerinfo "name" = "Afalewen";
layerinfo "redist_uniq" = "haven/yellowsplit_complementary";
set color_scheme_base = "#F3EAA0";
set color_scheme = "split_complementary";
#NEWLAYER: haven/yellowdouble_complementary
layerinfo "type" = "theme";
layerinfo "name" = "Umoenna";
layerinfo "redist_uniq" = "haven/yellowdouble_complementary";
set color_scheme_base = "#F3EAA0";
set color_scheme = "double_complementary";
#NEWLAYER: haven/yellowtriadic
layerinfo "type" = "theme";
layerinfo "name" = "Trirwen";
layerinfo "redist_uniq" = "haven/yellowtriadic";
set color_scheme_base = "#F3EAA0";
set color_scheme = "triadic";
#NEWLAYER: haven/yellowtetradic
layerinfo "type" = "theme";
layerinfo "name" = "Jerilisien";
layerinfo "redist_uniq" = "haven/yellowtetradic";
set color_scheme_base = "#F3EAA0";
set color_scheme = "tetradic";
#NEWLAYER: haven/redmonochromatic
layerinfo "type" = "theme";
layerinfo "name" = "Ethowiel";
layerinfo "redist_uniq" = "haven/redmonochromatic";
set color_scheme_base = "#F35951";
set color_scheme = "monochromatic";
#NEWLAYER: haven/redanalogous
layerinfo "type" = "theme";
layerinfo "name" = "Dwyweth";
layerinfo "redist_uniq" = "haven/redanalogous";
set color_scheme_base = "#F35951";
set color_scheme = "analogous";
#NEWLAYER: haven/redcomplementary
layerinfo "type" = "theme";
layerinfo "name" = "Bylind";
layerinfo "redist_uniq" = "haven/redcomplementary";
set color_scheme_base = "#F35951";
set color_scheme = "complementary";
#NEWLAYER: haven/redsplit_complementary
layerinfo "type" = "theme";
layerinfo "name" = "Qiradia";
layerinfo "redist_uniq" = "haven/redsplit_complementary";
set color_scheme_base = "#F35951";
set color_scheme = "split_complementary";
#NEWLAYER: haven/reddouble_complementary
layerinfo "type" = "theme";
layerinfo "name" = "Kairawen";
layerinfo "redist_uniq" = "haven/reddouble_complementary";
set color_scheme_base = "#F35951";
set color_scheme = "double_complementary";
#NEWLAYER: haven/redtriadic
layerinfo "type" = "theme";
layerinfo "name" = "Piliwien";
layerinfo "redist_uniq" = "haven/redtriadic";
set color_scheme_base = "#F35951";
set color_scheme = "triadic";
#NEWLAYER: haven/redtetradic
layerinfo "type" = "theme";
layerinfo "name" = "Gwiradia";
layerinfo "redist_uniq" = "haven/redtetradic";
set color_scheme_base = "#F35951";
set color_scheme = "tetradic";
#NEWLAYER: haven/indigomonochromatic
layerinfo "type" = "theme";
layerinfo "name" = "Elirethiel";
layerinfo "redist_uniq" = "haven/indigomonochromatic";
set color_scheme_base = "#6F60C7";
set color_scheme = "monochromatic";
#NEWLAYER: haven/indigoanalogous
layerinfo "type" = "theme";
layerinfo "name" = "Oneawia";
layerinfo "redist_uniq" = "haven/indigoanalogous";
set color_scheme_base = "#6F60C7";
set color_scheme = "analogous";
#NEWLAYER: haven/indigocomplementary
layerinfo "type" = "theme";
layerinfo "name" = "Gwicia";
layerinfo "redist_uniq" = "haven/indigocomplementary";
set color_scheme_base = "#6F60C7";
set color_scheme = "complementary";
#NEWLAYER: haven/indigosplit_complementary
layerinfo "type" = "theme";
layerinfo "name" = "Grabeth";
layerinfo "redist_uniq" = "haven/indigosplit_complementary";
set color_scheme_base = "#6F60C7";
set color_scheme = "split_complementary";
#NEWLAYER: haven/indigodouble_complementary
layerinfo "type" = "theme";
layerinfo "name" = "Alalicien";
layerinfo "redist_uniq" = "haven/indigodouble_complementary";
set color_scheme_base = "#6F60C7";
set color_scheme = "double_complementary";
#NEWLAYER: haven/indigotriadic
layerinfo "type" = "theme";
layerinfo "name" = "Legeinia";
layerinfo "redist_uniq" = "haven/indigotriadic";
set color_scheme_base = "#6F60C7";
set color_scheme = "triadic";
#NEWLAYER: haven/indigotetradic
layerinfo "type" = "theme";
layerinfo "name" = "Olowen";
layerinfo "redist_uniq" = "haven/indigotetradic";
set color_scheme_base = "#6F60C7";
set color_scheme = "tetradic";

View File

@@ -0,0 +1,161 @@
#-*-s2-*- ;; -*- coding: utf-8 -*-
layerinfo "type" = "i18nc";
layerinfo "redist_uniq" = "i18nc/da1";
layerinfo "name" = "Danish";
layerinfo "langcode" = "da";
layerinfo "author_name" = "LiveJournal Danish Translation Team";
layerinfo "author_email" = "lj_dansk@livejournal.com";
layerinfo "source_viewable" = 1;
set lang_current = "da";
#[[ date and time l12n ]]
# Kort datoformat
set lang_fmt_date_short = "%%d%%/%%m%%/%%yy%%";
# Mellem dato
set lang_fmt_date_med = "%%dayord%% %%mon%%., %%yyyy%%";
# Mellem dato med forkortet ugedag
set lang_fmt_date_med_day = "%%da%%, d. %%dayord%% %%mon%%., %%yyyy%%";
# Lang dato
set lang_fmt_date_long = "%%dayord%% %%month%%, %%yyyy%%";
# Lang dato med ugedag
set lang_fmt_date_long_day = "%%day%%, d. %%dayord%% %%month%%, %%yyyy%%";
# Tidsformat
set lang_fmt_time_short = "%%HH%%:%%min%%";
# Kort månedsformat (samme som engelsk)
set lang_fmt_month_short = "%%m%%/%%yy%%";
# Mellem måned (samme som engelsk)
set lang_fmt_month_med = "%%mon%% %%yyyy%%";
# Lang måned (samme som engelsk)
set lang_fmt_month_long = "%%month%% %%yyyy%%";
# Årets måneder, lang
set lang_monthname_long = [ "", "Januar", "Februar", "Marts",
"April", "Maj", "Juni",
"Juli", "August", "September",
"Oktober", "November", "December" ];
# Årets måneder, kort
set lang_monthname_short = [ "", "Jan", "Feb", "Mar",
"Apr", "Maj", "Jun",
"Jul", "Aug", "Sep",
"Okt", "Nov", "Dec" ];
# Ugens dage, lang
set lang_dayname_long = [ "", "Søndag", "Mandag", "Tirsdag", "Onsdag",
"Torsdag", "Fredag", "Lørdag" ];
# Ugens dage, kort
set lang_dayname_short = [ "", "Søn", "Man", "Tirs", "Ons",
"Tors", "Fre", "Lør" ];
set reg_firstdayofweek = "monday";
#[[ texttranslation ]]
# Currents
set text_meta_music = "Nuværende musik";
set text_meta_mood = "Nuværende humør";
# Comments
set text_post_comment = "Skriv kommentar";
set text_read_comments = "1 kommentar // # kommentarer";
set text_post_comment_friends = "Skriv kommentar";
set text_read_comments_friends = "1 kommentar // # kommentarer";
# Skiplinks
set text_skiplinks_back="Forrige #";
set text_skiplinks_forward="Næste #";
# Views
set text_view_recent = "Seneste poster";
set text_view_friends = "Venner";
set text_view_archive = "Arkiv";
set text_view_userinfo = "Brugerinfo";
set text_view_month = "Vis emner"; # "Vis overskrifter"?
# Misc. texts
set text_nosubject = "(intet emne)";
set text_noentries_recent = "Der er ingen poster at vise.";
set text_noentries_day = "Der blev ikke skrevet nogle poster denne dag.";
set text_permalink = "Link";
set text_month_screened_comments = "m. skærmede";
set text_multiform_check = "Vælg:";
set text_multiform_des = "Massehandling på valgte kommentarer:";
set text_multiform_btn = "Udfør handling";
set text_multiform_opt_unscreen = "Afskærm";
set text_multiform_opt_screen = "Skærm";
set text_multiform_opt_delete = "Slet";
set text_multiform_conf_delete = "Slet valgte kommentarer?";
set text_day_prev = "Forrige dag";
set text_day_next = "Næste dag";
set text_comment_from = "Fra:";
set text_comment_date = "Dato:";
set text_comment_ipaddr = "IP adresse:";
set text_comment_reply = "Svar";
set text_comment_parent = "Forælder";
set text_comment_thread = "Tråd";
set text_reply_back = "Læs kommentarer";
set text_reply_nocomments_header = "Kommentarer slået fra:";
set text_reply_nocomments = "Kommentarer til denne post er blevet slået fra.";
set text_poster_anonymous = "(Anonym)";
set text_website_default_name = "Mit websted";
#[[ function translations ]]
# Samme som engelsk:
#function lang_map_plural (int n) : int {
# if ($n == 1) { return 0; } # singular
# return 1; # plural
#}
function lang_page_of_pages (int pg, int pgs) [notags] : string {
return "Side $pg af $pgs";
}
function lang_ordinal(int num) [notags] : string {
return $num+".";
}
function lang_user_wrote(UserLite u) : string
"Returns text describing that the user wrote something. i18nc layers should override this."
{
if (defined $u) {
return $u->as_string()+" skrev";
}
else {
return "En anonym bruger skrev";
}
}
function lang_at_datetime(DateTime d) : string
"Returns a string saying \"at {the data and time given}\". Used in the core implementation of EntryPage and ReplyPage. i18nc layers should override this."
{
# return "d. 1. Januar, 2004, kl. 23:01";
return "d. " + $d->date_format("long") + ", kl. " + $d->time_format();
}
### Ovenstående skal testes i brug ASAP. ###
function lang_viewname(string viewid) [notags] : string
"Get some words representing a view"
{
if ($viewid == "recent") { return $*text_view_recent; }
if ($viewid == "archive") { return $*text_view_archive; }
if ($viewid == "friends") { return $*text_view_friends; }
if ($viewid == "day") { return "Dag"; }
if ($viewid == "month") { return "Måned"; }
if ($viewid == "userinfo") { return $*text_view_userinfo; }
if ($viewid == "entry") { return "Læs kommentarer"; }
if ($viewid == "reply") { return "Skriv kommentar"; }
return "Ukendt visningstype";
}
function server_sig() {
"""Kørt af <a href="$*SITEROOT/">$*SITENAME</a>""";
}
function ReplyPage::view_title() : string {
return "Skriv kommentar";
}
function Page::print_entry_poster(Entry e) {
$e.poster->print();
if ($.view == "friends" and $e.poster.username != $e.journal.username) {
" skrev i ";
$e.journal->print();
}
}

View File

@@ -0,0 +1,147 @@
#-*-s2-*- ;; -*- coding: utf-8 -*-
layerinfo "type" = "i18nc";
layerinfo "redist_uniq" = "i18nc/de1";
layerinfo "name" = "German";
layerinfo "langcode" = "de";
layerinfo "author_name" = "Timwi";
layerinfo "author_email" = "timwi@livejournal.com";
layerinfo "source_viewable" = 1;
set lang_current = "de";
# Kurzes Datumsformat
set lang_fmt_date_short = "%%d%%.%%m%%.%%yy%%";
# Mittellanges Datumsformat
set lang_fmt_date_med = "%%dayord%% %%mon%% %%yyyy%%";
# Mittellanges Datumsformat mit Wochentag
set lang_fmt_date_med_day = "%%da%%, %%dayord%% %%mon%% %%yyyy%%";
# Langes Datumsformat
set lang_fmt_date_long = "%%dayord%% %%month%% %%yyyy%%";
# Langes Datumsformat mit Wochentag
set lang_fmt_date_long_day = "%%day%%, %%dayord%% %%month%% %%yyyy%%";
# Zeitformat
set lang_fmt_time_short = "%%HH%%:%%min%%";
# Kurzes Monatsformat
#set lang_fmt_month_short = "%%mon%% %%yy%%";
# Mittleres Monatsformat
#set lang_fmt_month_med = "%%mon%% %%yyyy%%";
# Langes Monatsformat
#set lang_fmt_month_long = "%%month%% %%yyyy%%";
# Monatsnamen
set lang_monthname_long = [ "", "Januar", "Februar", "März",
"April", "Mai", "Juni",
"Juli", "August", "September",
"Oktober", "November", "Dezember" ];
# Monatsabkürzungen
set lang_monthname_short = [ "", "Jan", "Feb", "Mär",
"Apr", "Mai", "Jun",
"Jul", "Aug", "Sep",
"Okt", "Nov", "Dez" ];
# Wochentagnamen
set lang_dayname_long = [ "", "Sonntag", "Montag", "Dienstag", "Mittwoch",
"Donnerstag", "Freitag", "Samstag" ];
# Wochentagabkürzungen
set lang_dayname_short = [ "", "So", "Mo", "Di", "Mi",
"Do", "Fr", "Sa" ];
set reg_firstdayofweek = "monday";
#[[ texttranslation ]]
# Currents
set text_meta_music = "Aktuelle Musik";
set text_meta_mood = "Aktuelle Stimmung";
# Comments
set text_post_comment = "Kommentar hinterlassen";
set text_read_comments = "1 Kommentar // # Kommentare";
set text_post_comment_friends = "Kommentar hinterlassen";
set text_read_comments_friends = "1 Kommentar // # Kommentare";
# Skiplinks
set text_skiplinks_back="Vorherige #";
set text_skiplinks_forward="Nächste #";
# Views
set text_view_recent = "Neueste Einträge";
set text_view_friends = "Freunde";
set text_view_archive = "Archiv";
set text_view_userinfo = "Benutzerprofil";
set text_view_month = "Monatsansicht"; # "Vis overskrifter"?
# Misc. texts
set text_nosubject = "(kein Betreff)";
set text_noentries_recent = "Keine Einträge.";
set text_noentries_day = "An diesem Tag wurden keine Einträge gemacht.";
set text_permalink = "Link";
set text_month_screened_comments = "zzgl. verdeckte";
set text_multiform_check = "Auswählen:";
set text_multiform_des = "Alle ausgewählten Kommentare:";
set text_multiform_btn = "Ausführen";
set text_multiform_opt_unscreen = "Aufdecken";
set text_multiform_opt_screen = "Verdecken";
set text_multiform_opt_delete = "Löschen";
set text_multiform_conf_delete = "Bist du dir sicher, dass du die ausgewählten Kommentare löschen möchtest?";
set text_day_prev = "Vorheriger Tag";
set text_day_next = "Nächster Tag";
set text_comment_from = "Von:";
set text_comment_date = "Datum:";
set text_comment_ipaddr = "IP-Adresse:";
set text_comment_reply = "Darauf antworten";
set text_comment_parent = "Kommentar davor";
set text_comment_thread = "Nachfolgende Kommentare";
set text_reply_back = "Kommentare lesen";
set text_reply_nocomments_header = "Kommentarfunktion deaktiviert:";
set text_reply_nocomments = "Für diesen Eintrag wurde die Kommentarfunktion deaktiviert.";
set text_website_default_name = "Meine Webseite";
set text_poster_anonymous = "(Anonym)";
#[[ function translations ]]
function lang_page_of_pages (int pg, int pgs) [notags] : string {
return "Seite $pg von $pgs";
}
function lang_ordinal(int num) [notags] : string {
return $num+".";
}
function lang_viewname(string viewid) [notags] : string
"Get some words representing a view"
{
if ($viewid == "recent") { return $*text_view_recent; }
if ($viewid == "archive") { return $*text_view_archive; }
if ($viewid == "friends") { return $*text_view_friends; }
if ($viewid == "day") { return "Tag"; }
if ($viewid == "month") { return "Monat"; }
if ($viewid == "userinfo") { return $*text_view_userinfo; }
if ($viewid == "entry") { return "Kommentare lesen"; }
if ($viewid == "reply") { return "Kommentar hinterlassen"; }
return "Unbekannte Ansicht";
}
function ReplyPage::view_title() : string {
return "Kommentar hinterlassen";
}
function server_sig() {
"""Gehostet von <a href="$*SITEROOT/">$*SITENAME</a>""";
}
function Page::print_entry_poster(Entry e) {
$e.poster->print();
if ($.view == "friends" and $e.poster.username != $e.journal.username) {
" schrieb in ";
$e.journal->print();
}
}
function lang_user_wrote(UserLite u) : string "Returns text describing that the user wrote something. i18nc layers should override this." {
if (defined $u) {
return $u->as_string()+" schrieb";
}
else {
return "Ein anonymer Benutzer schrieb";
}
}
function lang_at_datetime(DateTime d) : string "Returns a string saying \"at {the date and time given}\". Used in the core implementation of EntryPage and ReplyPage. i18nc layers should override this." {
return "am " + $d->date_format("long") + " um " + $d->time_format();
}

View File

@@ -0,0 +1,9 @@
#-*-s2-*-
layerinfo "type" = "i18nc";
layerinfo "redist_uniq" = "i18nc/en1";
layerinfo "name" = "English";
layerinfo "langcode" = "en";
# Note: this file doesn't actually override anything, since the core
# is in English

View File

@@ -0,0 +1,139 @@
#-*-s2-*- ;; -*- coding: utf-8 -*-
layerinfo "type" = "i18nc";
layerinfo "redist_uniq" = "i18nc/eo1";
layerinfo "name" = "Esperanto";
layerinfo "langcode" = "eo";
layerinfo "author_name" = "Timwi, Amuzulo";
layerinfo "author_email" = "timwi@livejournal.com, amuzulo@livejournal.com";
layerinfo "source_viewable" = 1;
set lang_current = "eo";
set lang_fmt_date_short = "%%yyyy%%-%%mm%%-%%dd%%";
set lang_fmt_date_med = "%%dayord%% de %%mon%% %%yyyy%%";
set lang_fmt_date_med_day = "%%da%%, la %%dayord%% de %%mon%% %%yyyy%%";
set lang_fmt_date_long = "la %%dayord%% de %%month%% %%yyyy%%";
set lang_fmt_date_long_day = "%%day%%, la %%dayord%% de %%month%% %%yyyy%%";
set lang_fmt_time_short = "%%HH%%:%%min%%";
set lang_fmt_month_short = "%%mon%% %%yy%%";
set lang_fmt_month_med = "%%mon%% %%yyyy%%";
set lang_fmt_month_long = "%%month%% %%yyyy%%";
set lang_monthname_long = [ "", "januaro", "februaro", "marto",
"aprilo", "majo", "junio",
"julio", "aŭgusto", "septembro",
"oktobro", "novembro", "decembro" ];
set lang_monthname_short = [ "", "jan", "feb", "mar",
"apr", "maj", "jun",
"jul", "aŭg", "sep",
"okt", "nov", "dec" ];
set lang_dayname_long = [ "", "dimanĉo", "lundo", "mardo", "merkredo",
"ĵaŭdo", "vendredo", "sabato" ];
set lang_dayname_short = [ "", "di", "lu", "ma", "me",
"ĵa", "ve", "sa" ];
set reg_firstdayofweek = "monday";
#[[ texttranslation ]]
# Currents
set text_meta_music = "Nuna muziko";
set text_meta_mood = "Nuna humoro";
# Comments
set text_post_comment = "Afiŝu novan komenton";
set text_read_comments = "1 komento // # komentoj";
set text_post_comment_friends = "Afiŝu novan komenton";
set text_read_comments_friends = "1 komento // # komentoj";
# Skiplinks
set text_skiplinks_back="# antaŭaj komentoj";
set text_skiplinks_forward="# sekvontaj komentoj";
# Views
set text_view_recent = "Lastatempaj enskribojn";
set text_view_friends = "Geamikoj";
set text_view_archive = "Arĥivo";
set text_view_userinfo = "Uzantinformoj";
set text_view_month = "Monataj temoj";
# Misc. texts
set text_nosubject = "(neniu temo)";
set text_noentries_recent = "Neniuj enskriboj.";
set text_noentries_day = "Ekzistas neniuj enskriboj en tiu tago.";
set text_permalink = "Ligilo";
set text_month_screened_comments = "+ kaŝitoj";
set text_multiform_check = "Elektu:";
set text_multiform_des = "Amasagado por elektitaj komentoj:";
set text_multiform_btn = "Agu";
set text_multiform_opt_unscreen = "Malkaŝu";
set text_multiform_opt_screen = "Kaŝu";
set text_multiform_opt_delete = "Forigu";
set text_multiform_conf_delete = "Ĉu vi certas ke vi viŝas forigi la elektitajn komentojn?";
set text_day_prev = "Antaŭa tago";
set text_day_next = "Sekvonta tago";
set text_comment_from = "De:";
set text_comment_date = "Dato:";
set text_comment_ipaddr = "IP-adreso:";
set text_comment_reply = "Respondu al ĉi tiu";
set text_comment_parent = "Patro";
set text_comment_thread = "Fadeno";
set text_reply_back = "Legu komentojn";
set text_reply_nocomments_header = "Komentoj malebligitaj:";
set text_reply_nocomments = "La uzanto malebligis komentojn por ĉi tiu enskribo.";
set text_website_default_name = "Mia TTT-ejo";
set text_poster_anonymous = "(sennoma)";
#[[ function translations ]]
function lang_page_of_pages (int pg, int pgs) [notags] : string {
return "Paĝo $pg da $pgs";
}
function lang_ordinal(int num) [notags] : string {
return $num + "-a";
}
function lang_viewname(string viewid) [notags] : string
"Get some words representing a view"
{
if ($viewid == "recent") { return $*text_view_recent; }
if ($viewid == "archive") { return $*text_view_archive; }
if ($viewid == "friends") { return $*text_view_friends; }
if ($viewid == "day") { return "Tago"; }
if ($viewid == "month") { return "Monato"; }
if ($viewid == "userinfo") { return $*text_view_userinfo; }
if ($viewid == "entry") { return "Legu komentojn"; }
if ($viewid == "reply") { return "Afiŝu komenton"; }
return "Nekonata vido";
}
function ReplyPage::view_title() : string {
return "Afiŝu komenton";
}
function server_sig() {
"""Funkciigita de <a href="$*SITEROOT/">$*SITENAME</a>""";
}
function Page::print_entry_poster(Entry e) {
$e.poster->print();
if ($.view == "friends" and $e.poster.username != $e.journal.username) {
" skribis en ";
$e.journal->print();
}
}
function lang_user_wrote(UserLite u) : string "Returns text describing that the user wrote something. i18nc layers should override this." {
if (defined $u) {
return $u->as_string()+" skribis";
}
else {
return "Sennoma uzanto skribis";
}
}
function lang_at_datetime(DateTime d) : string "Returns a string saying \"at {the date and time given}\". Used in the core implementation of EntryPage and ReplyPage. i18nc layers should override this." {
return "je " + $d->date_format("long") + " je " + $d->time_format();
}

View File

@@ -0,0 +1,171 @@
#-*-s2-*- ;; -*- coding: utf-8 -*-
layerinfo "type" = "i18nc";
layerinfo "redist_uniq" = "i18nc/fi1";
layerinfo "name" = "Finnish";
layerinfo "langcode" = "fi";
layerinfo "author_name" = "shiningkianna, zell_d";
layerinfo "source_viewable" = 1;
set lang_current = "fi";
# Ajat ja päiväykset
# Viikonpäivät
set lang_dayname_long = [ "", "sunnuntai", "maanantai", "tiistai", "keskiviikko", "torstai", "perjantai", "lauantai" ];
set lang_dayname_short = [ "", "su", "ma", "ti", "ke", "to", "pe", "la" ];
# Pitkä päiväys
set lang_fmt_date_long = "%%dayord%% %%month%%ta %%yyyy%%";
# Pitkä päiväys viikonpäivällä
set lang_fmt_date_long_day = "%%day%%, %%dayord%% %%month%%ta %%yyyy%%";
# Keskipitkä päiväys
set lang_fmt_date_med = "%%d%%. %%mon%%. %%yyyy%%";
# Keskipitkä päiväys viikonpäivällä
set lang_fmt_date_med_day = "%%da%%, %%dayord%% %%mon%%. %%yyyy%%";
# Lyhyt päiväys
set lang_fmt_date_short = "%%d%%.%%m%%.%%yyyy%%";
# Pitkä kuukausipäiväys
set lang_fmt_month_long = "%%month%% %%yyyy%%";
# Keskipitkä kuukausipäiväys
set lang_fmt_month_med = "%%mon%% %%yyyy%%";
# Lyhyt kuukausipäiväys
set lang_fmt_month_short = "%%m%%/%%yyyy%%";
# Aika
set lang_fmt_time_short ="%%HH%%:%%min%%";
# Kuukaudet
set lang_monthname_long = [ "", "tammikuu", "helmikuu", "maaliskuu", "huhtikuu", "toukokuu", "kesäkuu", "heinäkuu", "elokuu", "syyskuu", "lokakuu", "marraskuu", "joulukuu" ];
set lang_monthname_short = [ "", "tammik", "helmik", "maalisk", "huhtik", "toukok", "kesäk", "heinäk", "elok", "syysk", "lokak", "marrask", "jouluk" ];
# Viikko alkaa maanantaista
set reg_firstdayofweek = "monday";
# Tekstit
# Tämänhetkinen musiikki ja mieliala
set text_meta_mood = "Mieliala";
set text_meta_music = "Musiikki";
# Kommentit
set text_post_comment = "Jätä vastaus tähän";
set text_post_comment_friends = "Jätä vastaus tähän";
set text_read_comments = "1 kommentti // # kommenttia";
set text_read_comments_friends = "1 kommentti // # kommenttia";
# Linkit, joilla hypätään viestien yli
set text_skiplinks_back = "Edelliset #";
set text_skiplinks_forward = "Seuraavat #";
# Näkymät
set text_view_archive = "Arkisto";
set text_view_friends = "Kaverit";
set text_view_friends_comm = "Jäsenet";
set text_view_friends_filter = "Kaverit (mukautettu suodatin)";
set text_view_friendsfriends = "Kavereiden kaverit";
set text_view_friendsfriends_filter = "Kavereiden kaverit (mukautettu suodatin)";
set text_view_month = "Otsikot";
set text_view_recent = "Merkinnät";
set text_view_userinfo = "Käyttäjätiedot";
# Sekalaisia tekstejä
set text_comment_date = "Päiväys:";
set text_comment_from = "Lähettäjä:";
set text_comment_frozen = "Jäädytetty";
set text_comment_ipaddr = "IP-osoite:";
set text_comment_parent = "Ylempi";
set text_comment_reply = "Vastaa";
set text_comment_thread = "Viestiketju";
set text_day_next = "Seuraava päivä";
set text_day_prev = "Edellinen päivä";
set text_max_comments = "Maksimimäärä kommentteja saatu";
set text_month_screened_comments = "ja peitettyjä kommentteja";
set text_multiform_btn = "Muokkaa";
set text_multiform_check = "Valitse:";
set text_multiform_conf_delete = "Poista valitut kommentit?";
set text_multiform_des = "Muokkaa kaikkia valittuja kommentteja:";
set text_multiform_opt_delete = "Poista";
set text_multiform_opt_freeze = "Jäädytä";
set text_multiform_opt_screen = "Peitä";
set text_multiform_opt_unfreeze = "Poista jäädytys";
set text_multiform_opt_unscreen = "Poista peitto";
set text_noentries_day = "Kyseisenä päivänä ei tehty merkintöjä";
set text_noentries_recent = "Ei merkintöjä";
set text_nosubject = "(ei otsikkoa)";
set text_permalink = "Linkki";
set text_poster_anonymous = "(tuntematon)";
set text_reply_back = "Lue kommentteja";
set text_reply_nocomments = "Kommentointi on estetty tämän merkinnän kohdalla";
set text_reply_nocomments_header = "Kommentointi estetty:";
set text_website_default_name = "Kotisivut";
# Funktiot
# Antaa eri tuloksen riippuen siitä tuleeko tekstiä käsitellä yksikkönä vai monikkona
function lang_map_plural (int n) : int {
if ($n == 1) { return 0; } # singular
return 1; # plural
}
# Palauttaa tekstin "Sivu X/Y", esim. Sivu 3/5
function lang_page_of_pages (int pg, int pgs) [notags] : string {
return "Sivu $pg/$pgs";
}
# Tekee numerosta järjestysnumeron, eli laittaa numeron perään pisteen
function lang_ordinal(int num) : string {
return $num+".";
}
# Palauttaa tekstin joka kertoo millainen näkymä on kyseessä
function lang_viewname(string viewid) [notags] : string "Get some words representing a view" {
if ($viewid == "recent") { return $*text_view_recent; }
if ($viewid == "archive") { return $*text_view_archive; }
if ($viewid == "friends") { return $*text_view_friends; }
if ($viewid == "day") { return "Päivä"; }
if ($viewid == "month") { return "Kuukausi"; }
if ($viewid == "userinfo") { return $*text_view_userinfo; }
if ($viewid == "entry") { return "Lue kommentteja"; }
if ($viewid == "reply") { return "Jätä kommentti"; }
return "Tuntematon näkymä";
}
# Vastaussivun otsikko
function ReplyPage::view_title() : string {
return "Jätä kommentti";
}
# Kirjoittaa palvelimen allekirjoituksen,
# Esim. "Sivun tarjoaa LiveJournal.com"
function server_sig() {
"""Sivun tarjoaa <a href="$*SITEROOT/">$*SITENAME</a>""";
}
# Kirjoittaa kaverisivulla tekstin, joka kertoo missä yhteisössä joku kirjoitti jotakin,
# Esim. "Esimerkkilähettäjä kirjoitti yhteisössä esimerkkiyhteisö"
function Page::print_entry_poster(Entry e) {
$e.poster->print();
if ($.view == "friends" and $e.poster.username != $e.journal.username) {
" kirjoitti yhteisössä ";
$e.journal->print();
}
}
# Palauttaa tekstin joka kertoo että joku kirjoitti,
# Esim. "Esimerkkikäyttäjä kirjoitti" tai "Tuntematon käyttäjä kirjoitti"
function lang_user_wrote(UserLite u) : string "Returns text describing that the user wrote something. i18nc layers should override this." {
if (defined $u) {
return $u->as_string()+" kirjoitti";
}
else {
return "Tuntematon käyttäjä kirjoitti";
}
}
# Palauttaa tekstin joka ilmoittaa päiväyksen ja kellonajan,
# Esim. "3. lokakuuta 2004 kello 14:45"
function lang_at_datetime(DateTime d) : string "Returns a string saying \"at {the date and time given}\". Used in the core implementation of EntryPage and ReplyPage. i18nc layers should override this." {
return $d->date_format("long") + " kello " + $d->time_format();
}

View File

@@ -0,0 +1,144 @@
#-*-s2-*- ;; -*- coding: utf-8 -*-
layerinfo "type" = "i18nc";
layerinfo "redist_uniq" = "i18nc/fr1";
layerinfo "name" = "French";
layerinfo "langcode" = "fr";
layerinfo "author_name" = "Timwi, Diziet Sma, Eclips1st";
layerinfo "author_email" = "timwi@livejournal.com, dizietsma@livejournal.com, eclips1st@livejournal.com";
layerinfo "source_viewable" = 1;
set lang_current = "fr";
set lang_fmt_date_short = "%%d%% %%mon%% %%yy%%";
set lang_fmt_date_med = "%%dd%% %%mon%% %%yyyy%%";
set lang_fmt_date_med_day = "%%da%%, le %%dd%% %%mon%% %%yyyy%%";
set lang_fmt_date_long = "le %%dd%% %%month%% %%yyyy%%";
set lang_fmt_date_long_day = "%%day%%, le %%dd%% %%month%% %%yyyy%%";
set lang_fmt_time_short = "%%HH%%:%%min%%";
set lang_fmt_month_short = "%%mon%% %%yy%%";
set lang_fmt_month_med = "%%mon%% %%yyyy%%";
set lang_fmt_month_long = "%%month%% %%yyyy%%";
set lang_monthname_long = [ "", "janvier", "février", "mars",
"avril", "mai", "juin",
"juillet", "août", "septembre",
"octobre", "novembre", "décembre" ];
set lang_monthname_short = [ "", "jan", "fév", "mar",
"avr", "mai", "juin",
"juil", "aoû", "sep",
"oct", "nov", "déc" ];
set lang_dayname_long = [ "", "dimanche", "lundi", "mardi", "mercredi",
"jeudi", "vendredi", "samedi" ];
set lang_dayname_short = [ "", "dim", "lun", "mar", "mer",
"jeu", "ven", "sam" ];
set reg_firstdayofweek = "monday";
#[[ texttranslation ]]
# Currents
set text_meta_music = "Musique actuelle";
set text_meta_mood = "Humeur actuelle";
# Comments
set text_post_comment = "Envoyez un commentaire";
set text_read_comments = "1 commentaire // # commentaires";
set text_post_comment_friends = "Envoyez un commentaire";
set text_read_comments_friends = "1 commentaire // # commentaires";
# Skiplinks
set text_skiplinks_back="# entrées précédentes";
set text_skiplinks_forward="# entrées suivantes";
# Views
set text_view_recent = "Entrées récentes";
set text_view_friends = "Amis";
set text_view_archive = "Archives";
set text_view_userinfo = "Profil";
set text_view_month = "Sujets du mois";
# Misc. texts
set text_nosubject = "(pas de sujets)";
set text_noentries_recent = "Pas d'entrées.";
set text_noentries_day = "Il n'y a aucune entrée cette journée.";
set text_permalink = "Lien";
set text_month_screened_comments = "+ filtrée(s)";
set text_multiform_check = "Cocher&nbsp;:";
set text_multiform_des = "Modifier les commentaires cochés&nbsp;:";
set text_multiform_btn = "Modifier";
set text_multiform_opt_unscreen = "Rendre public";
set text_multiform_opt_screen = "Filtrer";
set text_multiform_opt_delete = "Effacer";
set text_multiform_conf_delete = "Êtes-vous sûr de vouloir supprimer les commentaires sélectionnés?";
set text_day_prev = "Journée précédente";
set text_day_next = "Journée suivante";
set text_comment_from = "De&nbsp;:";
set text_comment_date = "Date&nbsp;:";
set text_comment_ipaddr = "Adresse IP&nbsp;:";
set text_comment_reply = "Répondre";
set text_comment_parent = "Précédent";
set text_comment_thread = "Fil";
set text_reply_back = "Lire les commentaires";
set text_reply_nocomments_header = "Commentaires désactivés&nbsp;:";
set text_reply_nocomments = "L'utilisateur a désactivé les commentaires pour cette entrée.";
set text_website_default_name = "Mon site";
set text_poster_anonymous = "(anonyme)";
#[[ function translations ]]
function lang_page_of_pages (int pg, int pgs) [notags] : string {
return "Page $pg de $pgs";
}
function lang_ordinal(int num) [notags] : string {
if ($num == 1) { return $num+"er"; }
return $num+"e";
}
function lang_map_plural (int n) : int {
if ($n > 1) { return 1; } # plural
return 0; # singular
}
function lang_viewname(string viewid) [notags] : string
"Get some words representing a view"
{
if ($viewid == "recent") { return $*text_view_recent; }
if ($viewid == "archive") { return $*text_view_archive; }
if ($viewid == "friends") { return $*text_view_friends; }
if ($viewid == "day") { return "Journée"; }
if ($viewid == "month") { return "Mois"; }
if ($viewid == "userinfo") { return $*text_view_userinfo; }
if ($viewid == "entry") { return "Lire les commentaires"; }
if ($viewid == "reply") { return "Envoyer un commentaire"; }
return "Affichage inconnue";
}
function ReplyPage::view_title() : string {
return "Envoyer un commentaire";
}
function server_sig() {
"""Actionné par <a href="$*SITEROOT/">$*SITENAME</a>""";
}
function Page::print_entry_poster(Entry e) {
$e.poster->print();
if ($.view == "friends" and $e.poster.username != $e.journal.username) {
" a écrit dans ";
$e.journal->print();
}
}
function lang_user_wrote(UserLite u) : string "Returns text describing that the user wrote something. i18nc layers should override this." {
if (defined $u) {
return $u->as_string()+" a écrit";
}
else {
return "Un utilisateur anonyme a écrit";
}
}
function lang_at_datetime(DateTime d) : string "Returns a string saying \"at {the date and time given}\". Used in the core implementation of EntryPage and ReplyPage. i18nc layers should override this." {
return $d->date_format("long") + " à " + $d->time_format();
}

View File

@@ -0,0 +1,16 @@
#-*-s2-*- ;; -*- coding: utf-8 -*-
layerinfo "type" = "i18nc";
layerinfo "redist_uniq" = "i18nc/ja1";
layerinfo "name" = "Japanese";
layerinfo "langcode" = "ja";
set lang_current = "ja";
# One form (the number is inflected)
function lang_map_plural (int n) : int {
return 0;
}
set text_read_comments = "# コメント";
set text_post_comment = "コメントの送信";
set text_read_comments_friends = "# コメント";
set text_post_comment_friends = "コメントの送信";

View File

@@ -0,0 +1,21 @@
#-*-s2-*- ;; -*- coding: utf-8 -*-
layerinfo "type" = "i18nc";
layerinfo "redist_uniq" = "i18nc/ru1";
layerinfo "name" = "Russian";
layerinfo "langcode" = "ru";
set lang_current = "ru";
# Three forms, special cases for numbers ending in 1 and 2, 3, 4, except those ending in 1[1-4]
function lang_map_plural (int n) : int {
if ($n%10 == 1 and $n%100 != 11) { return 0; }
if ($n%10 >= 2 and $n%10 <= 4 and ($n%100 < 10 or $n%100>=20)) { return 1; }
return 2;
}
set text_post_comment="Оставить комментарий";
set text_read_comments="# комментарий // # комментария // # комментариев";
set text_post_comment_friends="Оставить комментарий";
set text_read_comments_friends="# комментарий // # комментария // # комментариев";

View File

@@ -0,0 +1,14 @@
# -*-s2-*-
layerinfo type = "i18n";
layerinfo name = "English";
layerinfo redist_uniq = "magazine/en";
set text_meta_music = "Music";
set text_meta_mood = "Mood";
set text_post_comment = "comment&nbsp;on&nbsp;this";
set text_read_comments = "#&nbsp;comments";
set text_post_comment_friends = "comment&nbsp;on&nbsp;this";
set text_read_comments_friends = "#&nbsp;comments";

View File

@@ -0,0 +1,699 @@
# -*-s2-*-
layerinfo type = "layout";
layerinfo name = "Magazine";
layerinfo redist_uniq = "magazine/layout";
layerinfo previews = "magazine/magazine.jpg";
propgroup colors {
property Color main_bgcolor {
des = "Main Background color";
s1color = "page_back";
}
property Color main_fgcolor {
des = "Main text color";
s1color = "page_text";
}
property Color sidebar_color {
des = "Sidebar color";
s1color = "stronger_back";
}
property Color headerbar_bgcolor {
des = "Headerbar background color";
s1color = "strong_back";
}
property Color headerbar_fgcolor {
des = "Text color on headerbar";
s1color = "strong_text";
}
property Color headerbar_bevel_color {
des = "Accent line color for headerbar";
s1color = "stronger_back";
}
property Color highlight_bgcolor {
des = "Highlighting color for accented text";
s1color = "weak_back";
}
property Color highlight_fgcolor {
des = "Highlighted text color";
s1color = "weak_text";
}
property Color border_color {
des = "Color of borders";
s1color = "weak_text";
}
property Color title_color {
des = "Text color of top title";
s1color = "page_text_title";
}
property Color meta_color {
des = "Text color of meta descriptions";
s1color = "page_text_em";
}
property Color link_color {
des = "Text color of links";
s1color = "page_link";
}
property Color vlink_color {
des = "Text color of visited links";
s1color = "page_vlink";
}
property Color alink_color {
des = "Text color of active links";
s1color = "page_alink";
}
property Color comment_bar_one_bgcolor {
des = "Alternating background color for comment bars (one)";
}
property Color comment_bar_two_fgcolor {
des = "Text color on alternating comment bars (one)";
}
property Color comment_bar_two_bgcolor {
des = "Alternating background color for comment bars (two)";
}
property Color comment_bar_one_fgcolor {
des = "Text color on alternating comment bars (two)";
}
property Color comment_bar_screened_bgcolor {
des = "Background bar color for screened comments";
}
property Color comment_bar_screened_fgcolor {
des = "Text color on background bar for screened comments";
}
}
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set sidebar_color = "#6666cc";
set headerbar_bgcolor = "#c0c0ff";
set headerbar_fgcolor = "#000000";
set headerbar_bevel_color = "#6666cc";
set highlight_bgcolor = "#eeeeff";
set highlight_fgcolor = "#000000";
set border_color = "#000000";
set title_color = "#8b1a1";
set meta_color = "#c00000";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#ff00c0";
set comment_bar_one_bgcolor = "#c0c0ff";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#eeeeff";
set comment_bar_two_fgcolor = "#000000";
set comment_bar_screened_bgcolor = "#dddddd";
set comment_bar_screened_fgcolor = "#000000";
propgroup presentation {
property bool show_entry_userpic {
des = "Show the userpic on the journal entries? [Excludes friends page]";
}
property use page_recent_items;
property use page_friends_items;
property use use_shared_pic;
property use view_entry_disabled;
property bool show_entrynav_icons {
des = "Toggle to show the next, memory, edit, etc icons on the entry view page";
}
property string page_background_image {
des = "URL to an image to be used for the page background";
}
property use external_stylesheet;
}
set show_entry_userpic = false;
set view_entry_disabled = false;
set show_entrynav_icons = true;
set page_background_image = "";
propgroup text {
property use text_post_comment;
property use text_read_comments;
property use text_post_comment_friends;
property use text_read_comments_friends;
}
set tags_aware = true;
function Page::lay_skip_navigation() {}
function Page::lay_bottom_navigation() {}
function print_stylesheet ()
{
print clean_url($*page_background_image) != "" ? "body { background-image: url($*page_background_image); }" : "";
"""HTML {
border-left: 1cm solid $*sidebar_color;
padding: 1cm;
}
BODY {
line-height: 1.3;
margin: 0;
background-color: $*main_bgcolor;
color: $*main_fgcolor;
}
P {
margin-top: 0;
text-align: justify;
}
H1 {
font: x-large Verdana, sans-serif; text-align: center;
letter-spacing: -0.09em;
color: $*title_color;
}
H2 {
background-color: $*headerbar_bgcolor;
color: $*headerbar_fgcolor;
border-bottom: thin solid $*headerbar_bevel_color;
font: normal 1.3em Georgia, serif;
}
H3 {
color: $*highlight_fgcolor;
font: medium sans-serif;
}
H3 SPAN {
background-color: $*highlight_bgcolor;
border-right: thin solid $*border_color;
border-bottom: thin solid $*border_color;
padding-right: 0.5ex;
}
H3 EM {
color: $*meta_color;
font-style: normal;
}
.H3Holder {
clear: both;
padding-left: 2ex;
border-left: thin solid $*border_color;
border-bottom: thin solid $*border_color;
margin-bottom: 1em;
}
A:link {
color: $*link_color;
}
A:visited {
color: $*vlink_color;
}
A:active {
color: $*alink_color;
}
.Navigation {
text-align: center;
font-family: sans-serif;
}
.Comment {
font-size: 0.7em;
margin-top: -1em;
text-align: right;
}
.Comment, .Current {
margin-bottom: 1em;
clear: right;
}
.Picture {
border-left: thin solid $*border_color;
border-top: thin solid $*border_color;
float: right;
margin: 0 0 0.5em 0.5em;
padding: 0.2em;
}
.Picture DIV {
text-align: center;
}
.Active {
background-color: $*highlight_bgcolor;
}
ACRONYM {
border-bottom: thin dashed $*border_color;
cursor: help;
}
.Bottom {
border-top: thin solid $*border_color;
text-align: center;
}
.Empty {
background-color: $*highlight_bgcolor;
}
.Month {
margin-top: 1em;
}
.MonthHeader {
color: $*headerbar_fgcolor;
background-color: $*headerbar_bgcolor ! important;
line-height: 1.5;
}
.Month TD {
color: $*highlight_fgcolor;
width: 14%;
border: thin outset;
}
.Month TH {
background-color: $*highlight_bgcolor;
font-family: Verdana, sans-serif;
border: thin outset;
}""";
}
function Page::print () {
var string title = $this->title();
"""<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n<html>\n<head>\n""";
if ($*external_stylesheet) {
println """<link rel="stylesheet" href="$.stylesheet_url" type="text/css" />""";
} else {
println """<style type="text/css">"""; print_stylesheet(); "</style>";
}
$this->print_head();
"""<title>$title</title>
</head>
<body>
<h1>$title</h1>""";
var string website_name = $.journal.website_name ? $.journal.website_name : $*text_website_default_name;
var string website = ($.journal.website_url != "" ? "(<a href='$.journal.website_url'>$website_name</a>)" : "");
var string links;
foreach var string v ($.views_order) {
$links = "$links(<span style='white-space: nowrap;'>" + ($.view == $v ?
"<span class='Active'>"+lang_viewname($v)+"</span>" :
"<a href='$.view_url{$v}'>"+lang_viewname($v)+"</a>") + ")</span>\n";
}
"""<p class="Navigation">$links $website<br />""";
$this->lay_skip_navigation();
"</p>";
$this->print_body();
$this->lay_bottom_navigation();
"</body></html>";
}
function print_entry (Page p, Entry e, Color bgcolor, Color fgcolor, bool hide_text)
{
var string time = $e.time->time_format();
var string userpic = (defined $e.userpic ? "<img src='$e.userpic.url' />" : "");
if (($p.view != "entry" and $e.new_day) or $p.view == "entry")
{
"<h2>" + $e.time->date_format("med") + "</h2>";
}
"<div class='H3Holder'>";
# Altposter / friends / lastn userpic
if ($p.view == "friends" or
$p.view == "entry" or
$*show_entry_userpic == true or
$e.journal.username != $e.poster.username)
{
"<div class='Picture' style='background-color: $bgcolor;'>";
if ($p.view == "friends")
{
"<div><a href='";
print $e.journal->base_url() + "/";
"' style='color: $fgcolor;'><small>$e.journal.username</small></a></div>";
}
if ($*show_entry_userpic == true or $p.view == "friends" or $p.view == "entry")
{
if (defined $e.userpic) { "<div><img src='$e.userpic.url' /></div>"; }
}
if ($e.journal.username != $e.poster.username)
{
"<div><a href='";
print $e.poster->base_url() + "/";
"'>$e.poster.username</a></div>";
}
"</div>";
}
# Time / Subject / Security
var string subject = ($e.subject != "" ? " - <em>$e.subject</em>" : "");
"<h3><span>$time$subject</span> $e.security_icon</h3>";
if ($p.view == "entry" and $*show_entrynav_icons)
{
print "<div style='text-align: center'>";
$e->print_linkbar();
print "</div>";
}
if (not $hide_text)
{
# Entry
"<p>$e.text</p>";
# Tags
if ($e.tags) {
var int tcount = 0;
"<div class='ljtags'><strong>Tags:</strong> ";
foreach var Tag t ($e.tags) {
"""<a rel="tag" href="$t.url">$t.name</a>""";
$tcount++;
if ($tcount != size $e.tags) { ", "; }
}
"</div>";
}
# Metadata
if (size $e.metadata) {
foreach var string k ($e.metadata) {
"<div class='Currents'>";
var string key = $k;
var string val = $e.metadata{$k};
if ($k == "mood") {
$key = $*text_meta_mood;
} elseif ( $k == "music" ) {
$key = $*text_meta_music;
}
if ($k == "mood" and defined $e.mood_icon) {
var Image i = $e.mood_icon;
$val = "<img src='$i.url' width='$i.width' height='$i.height' align='absmiddle' alt='[mood icon]' /> $val";
}
"<div><strong>$key:</strong> $val</div>";
"</div>";
}
}
}
# Comments
$e.comments->print();
"</div>";
}
function CommentInfo::print()
{
if (not $.enabled) { return; }
"<div class='Comment'>(";
if ($.count > 0 or $.screened) {
$this->print_readlink(); "&nbsp;|&nbsp;";
}
$this->print_postlink();
")</div>";
}
function Page::print_entry (Entry e)
{
print_entry($this, $e, null Color, null Color, false);
}
function RecentPage::lay_skip_navigation()
{
var int total = size $.entries;
var string nav = "";
if ($.nav.backward_url != "") {
$nav = """<a href="$.nav.backward_url">Previous $total Entries</a>""";
}
if ($.nav.forward_url != "" and $.nav.backward_url != "") {
$nav = "$nav&nbsp;|&nbsp;";
}
if ($.nav.forward_url != "") {
$nav = """$nav<a href="$.nav.forward_url">Next $total Entries</a>""";
}
if ($nav != "") { print "Navigate: ($nav)"; }
}
function RecentPage::lay_bottom_navigation()
{
"<p class='Bottom'>"; $this->lay_skip_navigation(); "</p>";
}
function RecentPage::print_body
{
foreach var Entry e ($.entries) {
$this->print_entry($e);
}
}
function FriendsPage::lay_skip_navigation()
{
var int total = size $.entries;
var string nav = "";
if ($.nav.backward_url != "") {
$nav = """<a href="$.nav.backward_url">Previous $total Friends</a>""";
}
if ($.nav.forward_url != "" and $.nav.backward_url != "") {
$nav = "$nav&nbsp;|&nbsp;";
}
if ($.nav.forward_url != "") {
$nav = """$nav<a href="$.nav.forward_url">Next $total Friends</a>""";
}
if ($nav != "") { print "Navigate: ($nav)"; }
}
function FriendsPage::print_entry (Entry e)
{
var Friend f = $.friends{$e.journal.username};
print_entry($this, $e, $f.bgcolor, $f.fgcolor, false);
}
function FriendsPage::print_body
{
foreach var Entry e ($.entries) {
$this->print_entry($e);
}
}
function YearPage::lay_skip_navigation ()
{
$this->print_year_links();
}
function YearPage::lay_bottom_navigation() { }
function YearPage::print_body() {
"<h2>$.year</h2>";
foreach var YearMonth m ($.months) {
$this->print_month($m);
}
}
function YearPage::print_year_links ()
{
"Navigate: ";
foreach var YearYear y ($.years) {
if ($y.displayed) {
" (<span class='Active'>$y.year</span>) ";
} else {
" (<a href='$y.url'>$y.year</a>) ";
}
}
}
function YearPage::print_month(YearMonth m)
{
if (not $m.has_entries) { return; }
"<table class='Month'>";
"<tr><th class='MonthHeader' colspan='7'>";
"<a href='$m.url'>"; print $m->month_format(); "</a></th></tr>\n";
"<tr>";
foreach var int d (weekdays())
{
"<th>"+$*lang_dayname_short[$d]+ "</th>\n";
}
"</tr>";
foreach var YearWeek w ($m.weeks)
{
$w->print();
}
"</table>\n";
}
function YearWeek::print() {
"<tr valign='top'>";
if ($.pre_empty) { "<td class='empty' colspan='$.pre_empty'></td></td>"; }
foreach var YearDay d ($.days)
{
"<td>$d.day";
if ($d.num_entries)
{
"<div align='center'><a href='$d.url'><strong>$d.num_entries</strong></a></div>";
} else {
"<br /><br />";
}
"</td>";
}
if ($.post_empty) { "<td class='empty' colspan='$.post_empty'></td></td>"; }
"</tr>";
}
function DayPage::lay_skip_navigation()
{
"Navigate: (<a href='$.prev_url'>Previous Day</a>&nbsp;|&nbsp;<a href='$.next_url'>Next Day</a>)";
}
function DayPage::lay_bottom_navigation()
{
"""
<table style="border-top: thin solid $*headerbar_bevel_color;" width="100%">
<tr>
<td width="33%">&larr; <a href="$.prev_url">Previous day</a></td>
<td width="34%" align="center">(<a href="$.base_url/calendar">Calendar</a>)</td>
<td width="33%" align="right"><a href="$.next_url">Next day</a> &rarr;</td>
</tr>
</table>
""";
}
function DayPage::print_body ()
{
if (not $.has_entries) {
"<h2>"; print $.date->date_format("med"); "</h2>";
print "<p>(No journal entries for this day.)</p>";
} else {
foreach var Entry e ($.entries) {
$this->print_entry($e);
}
}
}
function EntryPage::print_body ()
{
set_handler("unscreen_comment_#", [
[ "style_bgcolor", "cmtbar#", "$*comment_bar_one_bgcolor", ],
[ "style_color", "cmtbar#", "$*comment_bar_one_fgcolor", ],
]);
set_handler("screen_comment_#", [
[ "style_bgcolor", "cmtbar#", "$*comment_bar_screened_bgcolor", ],
[ "style_color", "cmtbar#", "$*comment_bar_screened_fgcolor", ],
]);
print_entry($this, $.entry, null Color, null Color, $.viewing_thread);
if ($.entry.comments.enabled and $.comment_pages.total_subitems > 0)
{
$this->print_multiform_start();
print "<h2>Comments:</h2><div style='margin-left: 30px;'>";
if ($.comment_pages.total_subitems > 0) {
$.comment_pages->print();
$this->print_comments($.comments);
}
"</div>";
if ($this.multiform_on) {
"<h2>Mass Action</h2><div style='margin-left: 30px;'>";
$this->print_multiform_actionline();
$this->print_multiform_end();
"</div>";
}
}
}
function EntryPage::print_comment (Comment c) {
var Color background; var Color color;
if ($c.screened) {
$background = $*comment_bar_screened_bgcolor;
$color = $*comment_bar_screened_fgcolor;
} elseif ($c.depth % 2) {
$background = $*comment_bar_one_bgcolor;
$color = $*comment_bar_one_fgcolor;
} else {
$background = $*comment_bar_two_bgcolor;
$color = $*comment_bar_two_fgcolor;
}
var string poster = defined $c.poster ? $c.poster->as_string() : "<i>(Anonymous)</i>";
var string sub_icon;
if (defined $c.subject_icon) {
$sub_icon = $c.subject_icon->as_string();
}
"<a name='$c.anchor'></a><div id='cmtbar$c.talkid' style='background-color: $background; color: $color; margin-top: 10px; width: 100%'>";
"<table cellpadding='2' cellspacing='0' summary='0' style='width: 100%'><tr valign='top'>";
if (defined $c.userpic and $*comment_userpic_style != "off") {
var int w = $c.userpic.width;
var int h = $c.userpic.height;
# WARNING: this will later be done by the system (it'll be a
# constructional property), so don't copy this hack into your
# layout layers or you'll be messed up later.
if ($*comment_userpic_style == "small") {
$w = $w / 2;
$h = $h / 2;
}
print "<td style='width: 102px'><img src='$c.userpic.url' width='$w' height='$h' alt='[User Picture]' /></td>";
}
"<td style='width: 100%'><table style='width: 100%'><tr>";
### From, date, etc
"<td align='left' style='width: 50%'>";
print "<table>";
print "<tr><th align='right'>From:</th><td>$poster</td></tr>\n";
print "<tr><th align='right'>Date:</th><td style='white-space: nowrap'>";
print $c.time->date_format("long") + " - " + $c.time->time_format() + "</td></tr>";
if ($c.metadata{"poster_ip"}) { print "<tr><th align='right'>IP Address:</th><td>(" + $c.metadata{"poster_ip"} + ")</td></tr>"; }
"</table></td>";
### Gadgets
"<td align='right' style='width: 50%'>";
if ($this.multiform_on) {
" <label for='ljcomsel_$c.talkid'>$*text_multiform_check</label>";
$c->print_multiform_check();
}
$c->print_linkbar();
"</td></tr>";
### Subject / icon
print "<tr valign='top'><td style='width: 50%'>";
print (defined $c.subject_icon or $c.subject != "") ? "<h3>$c.subject_icon $c.subject</h3>" : "";
print "</td>";
### Permalink
print "<td style='width: 50%' align='right'><strong>(<a href='$c.permalink_url'>Link</a>)</strong></td></tr>";
print "</table></td></tr></table></div>";
print "<div style='margin-left: 5px'>$c.text</div>";
print "<div style='margin-top: 3px; font-size: smaller'>";
if ($c.frozen) {
print """(Replies frozen) """;
} else {
print """(<a href='$c.reply_url'>Reply to this</a>) """;
}
if ($c.parent_url != "") { "(<a href='$c.parent_url'>Parent</a>) "; }
if ($c.thread_url != "") { "(<a href='$c.thread_url'>Thread</a>) "; }
"</div>";
}
function ReplyPage::print_body ()
{
var string time = $.replyto.time->time_format();
if (not $.entry.comments.enabled)
{
print "<h2>$*text_reply_nocomments_header</h2><p>$*text_reply_nocomments</p>";
return;
}
"<h2>" + $.replyto.time->date_format("med") + "</h2>";
"<div class='H3Holder'>";
"<div class='Picture'>";
print defined $.replyto.poster ? $.replyto.poster->as_string() : "<i>(Anonymous)</i>";
if (defined $.replyto.userpic) { "<div><img src='$.replyto.userpic.url' /></div>"; }
"</div>";
# Time / Subject / Security
var string subject = ($.replyto.subject ? " - <em>$.replyto.subject</em>" : "");
"<h3><span>$time$subject</span></h3>";
"<p>$.replyto.text</p>";
"<div class='Comment'><a href='$.entry.comments.read_url'>Read Comments</a></div>";
"</div>";
print "<h2>Reply:</h2>";
$.form->print();
}
function print_theme_preview ()
{
"""<table width='100%' bgcolor='$*main_bgcolor' cellpadding='3' border='0'><tr valign='top'>
<td width='30' bgcolor='$*sidebar_color'>&nbsp;</td>
<td width='30'>&nbsp;</td>
<td>
<h2 style='background-color: $*headerbar_bgcolor; color: $*headerbar_fgcolor; border-bottom: thin solid $*headerbar_bevel_color; font: normal 1.3em Georgia, serif; line-height: 1.3;'>Dec. 22nd, 2002</h2>
<div style='clear: both; padding-left: 2ex; border-left: thin solid $*border_color; border-bottom: thin solid $*border_color; margin-bottom: 1em; '>
<h3 style='color: $*highlight_fgcolor; font: medium sans-serif'><span style='background-color: $*highlight_bgcolor; border-right: thin solid $*border_color; border-bottom: thin solid $*border_color; padding-right: 0.5ex;'>08:46 pm - <em style='color: $*meta_color; font-style: normal;'>subject</em></span></h3>
<p style='margin-top: 0; text-align: justify; font-family: serif; font-size: 12pt; color: $*main_fgcolor;'>Words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words words</p>
<div style='font-size: 0.7em; margin-top: -1em; text-align: right; font-size: 8pt; color: $*main_fgcolor;'>(<a style='color: $*link_color;' href='#'>1 comment</a>&nbsp;|&nbsp;<a style='color: $*link_color;' href='#'>Leave a comment</a>)</div>
</div>
</td></tr>
</table>""";
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -0,0 +1,459 @@
#NEWLAYER: magazine/wonb
layerinfo "type" = "theme";
layerinfo "name" = "White on Black";
layerinfo "redist_uniq" = "magazine/wonb";
set title_color = "#ffffff";
set main_bgcolor = "#000000";
set main_fgcolor = "#ffffff";
set sidebar_color = "#555555";
set headerbar_bgcolor = "#777777";
set headerbar_fgcolor = "#ffffff";
set headerbar_bevel_color = "#777777";
set link_color = "#eeeeee";
set alink_color = "#ffffff";
set vlink_color = "#dddddd";
set meta_color = "#ffffff";
set highlight_bgcolor = "#666666";
set highlight_fgcolor = "#dddddd";
set border_color = "#ffffff";
set comment_bar_one_bgcolor = "#777777";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#666666";
set comment_bar_two_fgcolor = "#dddddd";
#NEWLAYER: magazine/shrinkvio
layerinfo type = theme;
layerinfo name = "Shrinking Violet";
layerinfo redist_uniq = "magazine/shrinkvio";
set sidebar_color = "#ad22e7";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set border_color = "#381a45";
set headerbar_bgcolor = "#5d0383";
set headerbar_fgcolor = "#ffffff";
set title_color = "#5d0383";
set meta_color = "#ffffff";
set headerbar_bevel_color = "#d9a1f1";
set highlight_bgcolor = "#d9a1f1";
set highlight_fgcolor = "#000000";
set link_color = "#2e053f";
set vlink_color = "#611627";
set alink_color = "#ff00c0";
set comment_bar_one_bgcolor = "#5d0383";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#d9a1f1";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: magazine/pistmint
layerinfo type = theme;
layerinfo name = "Pistachio Mint";
layerinfo redist_uniq = "magazine/pistmint";
set sidebar_color = "#133422";
set main_bgcolor = "#a7c4b4";
set main_fgcolor = "#000000";
set border_color = "#096d36";
set headerbar_bgcolor = "#096d36";
set headerbar_fgcolor = "#ffffff";
set title_color = "#096d36";
set meta_color = "#ffffff";
set headerbar_bevel_color = "#096d36";
set highlight_bgcolor = "#096d36";
set highlight_fgcolor = "#000000";
set link_color = "#8afabc";
set vlink_color = "#1da65a";
set alink_color = "#f9f5f5";
set comment_bar_one_bgcolor = "#096d36";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#093d36";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: magazine/mexicanfood
layerinfo type = theme;
layerinfo name = "Mexican Food";
layerinfo redist_uniq = "magazine/mexicanfood";
set sidebar_color = "#ff0000";
set main_bgcolor = "#f8ff3e";
set main_fgcolor = "#f15601";
set border_color = "#f50701";
set headerbar_bgcolor = "#bdbf3e";
set headerbar_fgcolor = "#ff0000";
set title_color = "#ffc664";
set meta_color = "#000000";
set headerbar_bevel_color = "#f9ff9d";
set highlight_bgcolor = "#e15a18";
set highlight_fgcolor = "#ffffff";
set link_color = "#f49e08";
set vlink_color = "#b05403";
set alink_color = "#ff7405";
set comment_bar_one_bgcolor = "#bdbf3e";
set comment_bar_one_fgcolor = "#ff0000";
set comment_bar_two_bgcolor = "#e15a18";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: magazine/ashfire
layerinfo type = theme;
layerinfo name = "Ash and Fire";
layerinfo redist_uniq = "magazine/ashfire";
set sidebar_color = "#b5b5b5";
set main_bgcolor = "#ffb6af";
set main_fgcolor = "#000000";
set border_color = "#d90308";
set headerbar_bgcolor = "#e75454";
set headerbar_fgcolor = "#ffffff";
set title_color = "#ff9696";
set meta_color = "#ffffff";
set headerbar_bevel_color = "#ff1106";
set highlight_bgcolor = "#f06c88";
set highlight_fgcolor = "#000000";
set link_color = "#f70208";
set vlink_color = "#b0161d";
set alink_color = "#d70106";
set comment_bar_one_bgcolor = "#e75454";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#f06c88";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: magazine/desktop
layerinfo type = theme;
layerinfo name = "Classic Desktop";
layerinfo redist_uniq = "magazine/desktop";
set sidebar_color = "#00545c";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set border_color = "#000000";
set headerbar_bgcolor = "#ff7b05";
set headerbar_fgcolor = "#ffeddd";
set title_color = "#ffffff";
set meta_color = "#000000";
set headerbar_bevel_color = "#ff7b05";
set highlight_bgcolor = "#ffeddd";
set highlight_fgcolor = "#000000";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#5a76ff";
set comment_bar_one_bgcolor = "#ff7b05";
set comment_bar_one_fgcolor = "#ffeddd";
set comment_bar_two_bgcolor = "#ffeddd";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: magazine/satinhandshake
layerinfo type = theme;
layerinfo name = "Satin Handshake";
layerinfo redist_uniq = "magazine/satinhandshake";
set sidebar_color = "#480c0c";
set main_bgcolor = "#d06464";
set main_fgcolor = "#00001d";
set border_color = "#000000";
set headerbar_bgcolor = "#aaaaaa";
set headerbar_fgcolor = "#000000";
set title_color = "#aaaaaa";
set meta_color = "#000000";
set headerbar_bevel_color = "#9d0404";
set highlight_bgcolor = "#9d0404";
set highlight_fgcolor = "#ffffff";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#ff00c0";
set comment_bar_one_bgcolor = "#aaaaaa";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#9d0404";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: magazine/deepmelodrama
layerinfo type = theme;
layerinfo name = "Deep MeloDrama";
layerinfo redist_uniq = "magazine/deepmelodrama";
set sidebar_color = "#872d89";
set main_bgcolor = "#719cff";
set main_fgcolor = "#8e48b2";
set border_color = "#8e48b2";
set headerbar_bgcolor = "#3794b3";
set headerbar_fgcolor = "#84b8e7";
set title_color = "#65b2c1";
set meta_color = "#f5d3ff";
set headerbar_bevel_color = "#8e48b2";
set highlight_bgcolor = "#65b2c1";
set highlight_fgcolor = "#f5d3ff";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#dfd3ff";
set comment_bar_one_bgcolor = "#3794b3";
set comment_bar_one_fgcolor = "#84b8e7";
set comment_bar_two_bgcolor = "#65b2c1";
set comment_bar_two_fgcolor = "#f5d3ff";
#NEWLAYER: magazine/everwhite
layerinfo type = theme;
layerinfo name = "Everwhite";
layerinfo redist_uniq = "magazine/everwhite";
set sidebar_color = "#ffffff";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set border_color = "#000000";
set headerbar_bgcolor = "#ffffff";
set headerbar_fgcolor = "#000000";
set title_color = "#ffffff";
set meta_color = "#000000";
set headerbar_bevel_color = "#ffffff";
set highlight_bgcolor = "#ffffff";
set highlight_fgcolor = "#000000";
set link_color = "#e60000";
set vlink_color = "#c10602";
set alink_color = "#ff0600";
set comment_bar_one_bgcolor = "#dddddd";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#aaaaaa";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: magazine/everblue
layerinfo type = theme;
layerinfo name = "Everblue with Greys";
layerinfo redist_uniq = "magazine/everblue";
set sidebar_color = "#0f0c6d";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set border_color = "#000000";
set headerbar_bgcolor = "#000000";
set headerbar_fgcolor = "#ffffff";
set title_color = "#aaaaaa";
set meta_color = "#000000";
set headerbar_bevel_color = "#000000";
set highlight_bgcolor = "#aaaaaa";
set highlight_fgcolor = "#000000";
set link_color = "#2f00f2";
set vlink_color = "#060667";
set alink_color = "#6691ff";
set comment_bar_one_bgcolor = "#000000";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#aaaaaa";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: magazine/brownleather
layerinfo type = theme;
layerinfo name = "Brown Leather Coat";
layerinfo redist_uniq = "magazine/brownleather";
set sidebar_color = "#d2b48c";
set main_bgcolor = "#ffebcd";
set main_fgcolor = "#8b4513";
set border_color = "#000000";
set headerbar_bgcolor = "#d48014";
set headerbar_fgcolor = "#ffffff";
set title_color = "#d48014";
set meta_color = "#d48014";
set headerbar_bevel_color = "#d48014";
set highlight_bgcolor = "#ffe1a1";
set highlight_fgcolor = "#000000";
set link_color = "#000050";
set vlink_color = "#867a55";
set alink_color = "#fffab3";
set comment_bar_one_bgcolor = "#d48014";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#ffe1a1";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: magazine/bruise
layerinfo type = theme;
layerinfo name = "Bruise";
layerinfo redist_uniq = "magazine/bruise";
set sidebar_color = "#000000";
set main_bgcolor = "#bcbcbc";
set main_fgcolor = "#000000";
set border_color = "#000000";
set headerbar_bgcolor = "#1114a0";
set headerbar_fgcolor = "#ffffff";
set title_color = "#21c2f1";
set meta_color = "#ffffff";
set headerbar_bevel_color = "#1114a0";
set highlight_bgcolor = "#21c2f1";
set highlight_fgcolor = "#0000ff";
set link_color = "#0000cc";
set vlink_color = "#000088";
set alink_color = "#0000ff";
set comment_bar_one_bgcolor = "#1114a0";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#21c2f1";
set comment_bar_two_fgcolor = "#0000ff";
#NEWLAYER: magazine/ranchhand
layerinfo type = theme;
layerinfo name = "Ranch Hand";
layerinfo redist_uniq = "magazine/ranchhand";
set sidebar_color = "#2999c2";
set main_bgcolor = "#cfe0ff";
set main_fgcolor = "#000000";
set border_color = "#060667";
set headerbar_bgcolor = "#54442c";
set headerbar_fgcolor = "#ffffff";
set title_color = "#bababa";
set meta_color = "#000000";
set headerbar_bevel_color = "#9d995d";
set highlight_bgcolor = "#704400";
set highlight_fgcolor = "#bababa";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#6a20ff";
set comment_bar_one_bgcolor = "#54442c";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#704400";
set comment_bar_two_fgcolor = "#bababa";
#NEWLAYER: magazine/victim
layerinfo type = theme;
layerinfo name = "Victim";
layerinfo redist_uniq = "magazine/victim";
set sidebar_color = "#2cd0ff";
set main_bgcolor = "#505050";
set main_fgcolor = "#ffffff";
set border_color = "#000000";
set headerbar_bgcolor = "#166bac";
set headerbar_fgcolor = "#ffffff";
set title_color = "#2098f3";
set meta_color = "#ffffff";
set headerbar_bevel_color = "#26b6ff";
set highlight_bgcolor = "#353535";
set highlight_fgcolor = "#ffffff";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#ff00c0";
set comment_bar_one_bgcolor = "#166bac";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#353535";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: magazine/forest
layerinfo type = theme;
layerinfo name = "Forest";
layerinfo redist_uniq = "magazine/forest";
set sidebar_color = "#778e64";
set main_bgcolor = "#9b9ba5";
set main_fgcolor = "#000000";
set border_color = "#ffffff";
set headerbar_bgcolor = "#72784c";
set headerbar_fgcolor = "#ffffff";
set title_color = "#72784c";
set meta_color = "#ffffff";
set headerbar_bevel_color = "#a0ac62";
set highlight_bgcolor = "#73777a";
set highlight_fgcolor = "#000000";
set link_color = "#3811e1";
set vlink_color = "#310cbb";
set alink_color = "#4e7bef";
set comment_bar_one_bgcolor = "#72784c";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#73777a";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: magazine/drone
layerinfo type = theme;
layerinfo name = "Drone";
layerinfo redist_uniq = "magazine/drone";
set sidebar_color = "#395f82";
set main_bgcolor = "#f9fcfe";
set main_fgcolor = "#000000";
set border_color = "#000000";
set headerbar_bgcolor = "#904094";
set headerbar_fgcolor = "#ffffff";
set title_color = "#f56efc";
set meta_color = "#ffffff";
set headerbar_bevel_color = "#ff93ff";
set highlight_bgcolor = "#eeeeff";
set highlight_fgcolor = "#000000";
set link_color = "#395f82";
set vlink_color = "#395f82";
set alink_color = "#5266ce";
set comment_bar_one_bgcolor = "#904094";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#eeeeff";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: magazine/lowercurtain
layerinfo type = theme;
layerinfo name = "Lower the Curtain";
layerinfo redist_uniq = "magazine/lowercurtain";
set sidebar_color = "#000000";
set main_bgcolor = "#6b6b6b";
set main_fgcolor = "#ffffff";
set border_color = "#ffffff";
set headerbar_bgcolor = "#363636";
set headerbar_fgcolor = "#f0f5fb";
set title_color = "#c6c6c6";
set meta_color = "#222222";
set headerbar_bevel_color = "#363636";
set highlight_bgcolor = "#c5c8ca";
set highlight_fgcolor = "#000000";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#3314ba";
set comment_bar_one_bgcolor = "#363636";
set comment_bar_one_fgcolor = "#f0f5fb";
set comment_bar_two_bgcolor = "#c5c8ca";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: magazine/sunny
layerinfo type = theme;
layerinfo name = "Sunny Day";
layerinfo redist_uniq = "magazine/sunny";
set sidebar_color = "#55e0f9";
set main_bgcolor = "#e38202";
set main_fgcolor = "#ffffff";
set border_color = "#000000";
set headerbar_bgcolor = "#e38202";
set headerbar_fgcolor = "#ffffff";
set title_color = "#fff505";
set meta_color = "#ffffff";
set headerbar_bevel_color = "#efe052";
set highlight_bgcolor = "#ffba03";
set highlight_fgcolor = "#ffffff";
set link_color = "#df0d12";
set vlink_color = "#ac1b25";
set alink_color = "#fe3b3b";
set comment_bar_one_bgcolor = "#e38202";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#ffba03";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: magazine/valentine
layerinfo type = theme;
layerinfo name = "Be Mine";
layerinfo redist_uniq = "magazine/valentine";
set sidebar_color = "#6f104a";
set main_bgcolor = "#f2bce9";
set main_fgcolor = "#000000";
set border_color = "#ff24ab";
set headerbar_bgcolor = "#ff37ff";
set headerbar_fgcolor = "#ffffff";
set title_color = "#df2096";
set meta_color = "#ffffff";
set headerbar_bevel_color = "#ae1774";
set highlight_bgcolor = "#df2096";
set highlight_fgcolor = "#000000";
set link_color = "#ffffff";
set vlink_color = "#a51014";
set alink_color = "#ed8188";
set comment_bar_one_bgcolor = "#ff37ff";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#df2096";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: magazine/stripes
layerinfo type = theme;
layerinfo name = "Stripes";
layerinfo redist_uniq = "magazine/stripes";
set sidebar_color = "#ffffff";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set border_color = "#ff0000";
set headerbar_bgcolor = "#e7212a";
set headerbar_fgcolor = "#ffffff";
set title_color = "#ffffff";
set meta_color = "#000000";
set headerbar_bevel_color = "#ffffff";
set highlight_bgcolor = "#ffcfdc";
set highlight_fgcolor = "#000000";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#ffafc1";
set comment_bar_one_bgcolor = "#e7212a";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#ffcfdc";
set comment_bar_two_fgcolor = "#000000";

View File

@@ -0,0 +1,14 @@
# -*-s2-*-
layerinfo type = "i18n";
layerinfo name = "English";
layerinfo redist_uniq = "notepad/en";
set text_meta_music = "Music";
set text_meta_mood = "Mood";
set text_post_comment = "Make Notes";
set text_read_comments = "Read # Notes";
set text_post_comment_friends = "Make Notes";
set text_read_comments_friends = "Read # Notes";

View File

@@ -0,0 +1,605 @@
# -*-s2-*-
layerinfo type = "layout";
layerinfo name = "Notepad";
layerinfo redist_uniq = "notepad/layout";
layerinfo previews = "notepad/notepad.jpg";
propgroup colors {
property Color body_bgcolor {
des = "Body background color";
}
property Color text_color {
des = "Text color";
}
property Color subject_color {
des = "Text color of subjects";
}
property Color link_color {
des = "Link color";
}
property Color vlink_color {
des = "Visited link color";
}
property Color alink_color {
des = "Active link color";
}
property Color comment_bar_one_bgcolor {
des = "Alternating background color for comment bars (one)";
}
property Color comment_bar_two_fgcolor {
des = "Text color on alternating comment bars (one)";
}
property Color comment_bar_two_bgcolor {
des = "Alternating background color for comment bars (two)";
}
property Color comment_bar_one_fgcolor {
des = "Text color on alternating comment bars (two)";
}
property Color comment_bar_screened_bgcolor {
des = "Background bar color for screened comments";
}
property Color comment_bar_screened_fgcolor {
des = "Text color on background bar for screened comments";
}
}
set body_bgcolor = "#8cd5fe";
set text_color = "#000000";
set subject_color = "#ff0000";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#ff00c0";
set comment_bar_one_bgcolor = "#c0c0ff";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#eeeeff";
set comment_bar_two_fgcolor = "#000000";
set comment_bar_screened_bgcolor = "#dddddd";
set comment_bar_screened_fgcolor = "#000000";
propgroup presentation {
property bool show_entry_userpic {
des = "Show the userpic on the journal entries?";
}
property use page_recent_items;
property use page_friends_items;
property use use_shared_pic;
property use view_entry_disabled;
property string page_background_image {
des = "URL to an image to be used for the page background";
}
property bool show_entrynav_icons {
des = "Toggle to show the next, memory, edit, etc icons on the entry view page";
}
property use external_stylesheet;
}
set show_entry_userpic = false;
set view_entry_disabled = false;
set page_background_image = "";
set show_entrynav_icons = true;
propgroup text {
property use text_post_comment;
property use text_read_comments;
property use text_post_comment_friends;
property use text_read_comments_friends;
}
property string imguri {
noui = 1;
des = "URI to notepad images (no trailing slash)";
}
set imguri = "";
function prop_init()
{
if ($*imguri == "") { $*imguri = "$*SITEROOT/img/style/notepad"; }
}
function Page::lay_bottom_navigation() { }
function print_stylesheet ()
{
var string backgroundurl = clean_url($*page_background_image) != "" ? "background-image: url($*page_background_image);" : "";
"""body {
$backgroundurl
background-color: $*body_bgcolor;
}
td,body,p,div {
color: $*text_color;
text-decoration: none;
font-family: verdana,arial,helvetica;
font-size: 12px;
}
a:link {
color: $*link_color;
text-decoration: underline;
font-family: verdana,arial,helvetica;
font-size: 12px;
}
a:visited {
color: $*vlink_color;
text-decoration: underline;
font-family: verdana,arial,helvetica;
font-size:12px;
}
a:active {
color: $*alink_color;
text-decoration: underline;
font-family: verdana,arial,helvetica;
font-size: 12px;
}
a:hover {
color: $*alink_color;
text-decoration: underline;
font-family: verdana,arial,helvetica;
font-size:12px;
}""";
}
function Page::print()
{
var string title = $this->title();
"""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n<html>\n<head>\n""";
if ($*external_stylesheet) {
println """<link rel="stylesheet" href="$.stylesheet_url" type="text/css" />""";
} else {
println """<style type="text/css">"""; print_stylesheet(); "</style>";
}
$this->print_head();
"""<title>$title</title>
</head>
<body>
<table width="70%" border="0" cellpadding="0" cellspacing="0">
<tr>
<td colspan="2">
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td width="30"><img src="$*imguri/spacer.gif" width="30" height="10" alt='' /></td>
<td width="120" height="18" style="background-image: url($*imguri/tab.jpg)">&nbsp;&nbsp;
<a href="$.base_url/">Journal</a>
</td>
<td width="120" height="18" style="background-image: url($*imguri/tab.jpg)">&nbsp;&nbsp;
<a href="$.base_url/friends">Friends</a>
</td>
<td width="120" height="18" style="background-image: url($*imguri/tab.jpg)">&nbsp;&nbsp;
<a href="$.base_url/calendar">Archive</a>
</td>
<td width="120" height="18" style="background-image: url($*imguri/tab.jpg)">&nbsp;&nbsp;
<a href="$.base_url/info">User Info</a>
</td>
<td width="120" height="18" style="background-image: url($*imguri/tab.jpg)">&nbsp;&nbsp;
<a href="$*SITEROOT/tools/memories.bml?user=$.journal.username">memories</a>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td width="80" height="38" style="background-image: url($*imguri/top-left.jpg)">
<img src="$*imguri/spacer.gif" width="80" height="10" alt='' />
</td>
<td height="38" style="background-image: url($*imguri/middle.jpg)">
<img src="$*imguri/spacer.gif" width="10" height="10" alt='' />
</td>
<td width="10" height="38" style="background-image: url($*imguri/top-right.jpg)">
<img src="$*imguri/spacer.gif" width="10" height="10" alt='' />
</td>
</tr>
<tr>
<td width="80" height="38" style="background-image: url($*imguri/side-left.jpg)">
&nbsp;
</td>
<td width="100%" height="38" style="background-image: url($*imguri/middle.jpg)">
<h1>$title</h1>
<p align="center"><img src="$*imguri/hr.gif" width="345" height="23" alt='' /></p>
""";
$this->print_body();
"<p style='text-align: center; font-size: 115%'>"; $this->lay_bottom_navigation(); "</p>";
"""
</td>
<td width="8" height="38" style="background-image: url($*imguri/side-right.jpg)">
&nbsp;
</td>
</tr>
<tr>
<td width="80" height="12" style="background-image: url($*imguri/bottom-left.jpg)">
<img src="$*imguri/spacer.gif" width="70" height="12" alt='' />
</td>
<td height="12" style="background-image: url($*imguri/bottom-line.jpg)">
<img src="$*imguri/spacer.gif" width="10" height="12" alt='' />
</td>
<td width="8" height="12" style="background-image: url($*imguri/bottom-right.jpg)">
<img src="$*imguri/spacer.gif" width="8" height="12" alt='' />
</td>
</tr>
</table>
</body>
</html>
""";
}
function print_entry (Page p, Entry e, Color bgcolor, Color fgcolor, bool hide_text)
{
"<table border='0'><tr>";
if ($p.view == "friends" or
$*show_entry_userpic == true or
$e.journal.username != $e.poster.username)
{
var string userpic = defined $e.userpic ? "<img src='$e.userpic.url' /><br />" : "";
"<td valign='top' width='100' align='center'>";
if ($p.view == "friends" or $*show_entry_userpic == true) { print $userpic; }
if ($p.view == "friends") { "<strong><a href='"; print $e.journal->base_url(); "/'>$e.journal.username</a></strong>"; }
if ($e.journal.username != $e.poster.username)
{
print ($p.view == "friends" ?
"<br />[ <a href='" + $e.poster->base_url() + "/'>$e.poster.username</a> ]" :
"<strong><a href='" + $e.poster->base_url() + "/'>$e.poster.username</a></strong>");
}
"</td>";
}
"""<td valign="top" width='100%'><font size="+1">"""; print $e.time->date_format("med"); " "; print $e.time->time_format();
if ($e.subject) { " <span style='color: $*subject_color'>$e.subject</span>"; }
" $e.security_icon</font>";
if (not $hide_text)
{
print "<p>$e.text</p>";
if (size $e.metadata) {
"<p>";
foreach var string k ($e.metadata) {
var string key = $k;
var string val = $e.metadata{$k};
if ($k == "mood") {
$key = $*text_meta_mood;
} elseif ($k == "music") {
$key = $*text_meta_music;
}
if ($k == "mood" and defined $e.mood_icon) {
var Image i = $e.mood_icon;
$val = "<img src='$i.url' width='$i.width' height='$i.height' align='absmiddle' alt='' /> $val";
}
"<strong>$key:</strong> $val<br />";
}
"</p>";
}
}
$e.comments->print();
if ($p.view == "entry" and $*show_entrynav_icons)
{
$e->print_linkbar();
}
"""</td></tr><tr><td colspan="2"></td></tr></table>""";
"""<p align="center"><img src="$*imguri/hr.gif" width="345" height="23" alt='' /></p>""";
}
function Page::print_entry (Entry e)
{
print_entry($this, $e, null Color, null Color, false);
}
function RecentPage::print_body ()
{
foreach var Entry e ($.entries) {
$this->print_entry($e);
}
}
function FriendsPage::print_entry (Entry e) {
var Friend f = $.friends{$e.journal.username};
print_entry($this, $e, $f.bgcolor, $f.fgcolor, false);
}
function RecentPage::lay_bottom_navigation ()
{
var string nav = "";
if ($.nav.backward_url != "") {
$nav = """<a href="$.nav.backward_url">Back a Page</a>""";
}
if ($.nav.forward_url != "" and $.nav.backward_url != "") {
$nav = "$nav - ";
}
if ($.nav.forward_url != "") {
$nav = """$nav<a href="$.nav.forward_url">Forward a Page</a>""";
}
if ($nav != "") { print $nav; }
}
function CommentInfo::print()
{
if (not $.enabled) { return; }
if ($.count > 0 or $.screened)
{
$this->print_readlink(); " - ";
}
$this->print_postlink();
}
function YearPage::lay_bottom_navigation ()
{
$this->print_year_links();
}
function YearPage::print_year_links ()
{
if (size $.years <= 0) { return; }
foreach var YearYear y ($.years)
{
if ($y.displayed) {
"$y.year&nbsp;";
} else {
"<a href='$y.url'>$y.year</a>&nbsp;";
}
}
}
function YearPage::print_body ()
{
"<h2>$.year</h2>";
foreach var YearMonth m ($.months)
{
$this->print_month($m);
}
}
function YearPage::print_month(YearMonth m)
{
if (not $m.has_entries) { return; }
"<p align='center'><table border='1' cellpadding='4' width='80%'>";
# Month Header
"<tr align=center><th colspan='7'>"; print $m->month_format(); "</th></tr>";
# Weekdays
"<tr align='center'>";
foreach var int d (weekdays())
{
"<td>" + $*lang_dayname_short[$d] + "</td>\n";
}
"</tr>";
# Weeks
foreach var YearWeek w ($m.weeks)
{
$w->print();
}
"<tr align='center'><td colspan='7'>";
"<a href='$m.url'>$*text_view_month</a>";
"</td></tr></table></p>";
}
function YearWeek::print()
{
"<tr>";
if ($.pre_empty) { "<td colspan='$.pre_empty'>&nbsp;</td>"; }
foreach var YearDay d ($.days)
{
"<td valign='top'><b><font size='-1'>$d.day</font></b><div align='center'>";
if ($d.num_entries)
{
"<a href='$d.url'>$d.num_entries</a>";
} else {
"&nbsp;";
}
"</div></td>";
}
if ($.post_empty) { "<td colspan='$.post_empty'>&nbsp;</td>"; }
}
function DayPage::lay_bottom_navigation()
{
if (not $.has_entries) { "<img src='$*imguri/hr.gif' alt='' /><br />"; }
print "<a href='$.prev_url'>Back a Day</a> - <a href='$.next_url'>Forward a Day</a>";
}
function DayPage::print_body()
{
if (not $.has_entries) {
"<p>No journal entries for this day.</p>";
} else {
foreach var Entry e ($.entries) { $this->print_entry($e); }
}
}
function EntryPage::print_body ()
{
set_handler("unscreen_comment_#", [
[ "style_bgcolor", "cmtbar#", "$*comment_bar_one_bgcolor", ],
[ "style_color", "cmtbar#", "$*comment_bar_one_fgcolor", ],
]);
set_handler("screen_comment_#", [
[ "style_bgcolor", "cmtbar#", "$*comment_bar_screened_bgcolor", ],
[ "style_color", "cmtbar#", "$*comment_bar_screened_fgcolor", ],
]);
print_entry($this, $.entry, null Color, null Color, $.viewing_thread);
if ($.entry.comments.enabled and $.comment_pages.total_subitems > 0)
{
$this->print_multiform_start();
print "<h2>Comments:</h2>";
if ($.comment_pages.total_subitems > 0) {
$.comment_pages->print();
$this->print_comments($.comments);
}
if ($this.multiform_on) {
"<h2>Mass Action:</h2>";
$this->print_multiform_actionline();
$this->print_multiform_end();
}
}
}
function EntryPage::print_comment (Comment c) {
var Color barlight = $*color_comment_bar->clone();
$barlight->lightness(($barlight->lightness() + 255) / 2);
var Color barc = $c.depth % 2 ? $*color_comment_bar : $barlight;
if ($c.screened) {
$barc = $*comment_bar_screened_bgcolor;
}
var string poster = defined $c.poster ? $c.poster->as_string() : "<i>(Anonymous)</i>";
"<a name='$c.anchor'></a><div id='cmtbar$c.talkid' style='background-color: $barc; margin-top: 10px; width: 100%'>";
"<table cellpadding='2' cellspacing='0' summary='0' style='width: 100%'><tr valign='top'>";
if (defined $c.userpic and $*comment_userpic_style != "off") {
var int w = $c.userpic.width;
var int h = $c.userpic.height;
# WARNING: this will later be done by the system (it'll be a
# constructional property), so don't copy this hack into your
# layout layers or you'll be messed up later.
if ($*comment_userpic_style == "small") {
$w = $w / 2;
$h = $h / 2;
}
print "<td style='width: 102px'><img src='$c.userpic.url' width='$w' height='$h' alt='' /></td>";
}
"<td><table style='width: 100%'><tr>";
"<td align='left' style='width: 50%'>";
print "<table>";
print "<tr><th align='right'>$*text_comment_from</th><td>$poster</td></tr>\n";
print "<tr><th align='right'>$*text_comment_date</th><td style='white-space: nowrap'>";
print $c.time->date_format("long") + " - " + $c.time->time_format() + "</td></tr>";
if ($c.metadata{"poster_ip"}) { print "<tr><th align='right'>$*text_comment_ipaddr</th><td>(" + $c.metadata{"poster_ip"} + ")</td></tr>"; }
"</table></td>";
print "<td align='right' style='width: 50%'>";
if ($this.multiform_on) {
" <label for='ljcomsel_$c.talkid'>$*text_multiform_check</label> ";
$c->print_multiform_check();
}
$c->print_linkbar();
"</td></tr>";
print "<tr valign='top'><td style='width: 50%'>";
if (defined $c.subject_icon or $c.subject != "") { "<h3>$c.subject_icon $c.subject</h3>\n"; }
print "</td>";
print "<td style='width:50%;' align='right'><strong>(<a href='$c.permalink_url'>$*text_permalink</a>)</strong></td></tr>\n";
print "</table></td></tr></table></div>";
print "<div style='margin-left: 5px'>$c.text</div>\n";
print "<div style='margin-top: 3px; font-size: smaller'>";
if ($c.frozen) {
print "($*text_comment_frozen) ";
} else {
print "(<a href='$c.reply_url'>$*text_comment_reply</a>) ";
}
if ($c.parent_url != "") { "(<a href='$c.parent_url'>$*text_comment_parent</a>) "; }
if ($c.thread_url != "") { "(<a href='$c.thread_url'>$*text_comment_thread</a>) "; }
"</div>\n";
}
function ReplyPage::print_body ()
{
if (not $.entry.comments.enabled)
{
print "<h2>$*text_reply_nocomments_header</h2><p>$*text_reply_nocomments</p>";
return;
}
"<table border='0'><tr>";
"<td valign='top' width='100' align='center'>";
print defined $.replyto.userpic ? "<img src='$.replyto.userpic.url' alt='' /><br />" : "";
print defined $.replyto.poster ? $.replyto.poster->as_string() : "<i>(Anonymous)</i>";
"</td>";
"""<td valign="top"><font size="+1">"""; print $.replyto.time->date_format("med"); " "; print $.replyto.time->time_format();
if ($.replyto.subject) { " <span style='color: $*subject_color'>$.replyto.subject</span>"; }
"</font>";
print "<p>$.replyto.text</p>";
"<a href='$.entry.comments.read_url'>Read Comments</a>";
"""</td></tr>""";
"""<tr><td colspan="2"><p align="center"><img src="$*imguri/hr.gif" width="345" height="23" alt='' /></p>""";
"</td></tr></table>\n";
print "<h2>Reply</h2>";
$.form->print();
}
function print_theme_preview ()
{
"""
<div style="color: $*text_color; background-color: $*body_bgcolor">
<table width="70%" border="0" cellpadding="0" cellspacing="0">
<tr>
<td colspan="2">
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td width="30"><img src="$*imguri/spacer.gif" width="30" height="10" alt='' /></td>
<td width="120" height="18" style="background-image: url($*imguri/tab.jpg)">&nbsp;&nbsp;
<a href="#" style="color: $*link_color">Tab</a>
</td>
<td width="120" height="18" style="background-image: url($*imguri/tab.jpg)">&nbsp;&nbsp;
<a href="#" style="color: $*link_color">Tab</a>
</td>
<td width="120" height="18" style="background-image: url($*imguri/tab.jpg)">&nbsp;&nbsp;
<a href="#" style="color: $*link_color">Tab</a>
</td>
<td width="120" height="18" style="background-image: url($*imguri/tab.jpg)">&nbsp;&nbsp;
<a href="#" style="color: $*link_color">Tab</a>
</td>
<td width="120" height="18" style="background-image: url($*imguri/tab.jpg)">&nbsp;&nbsp;
<a href="#" style="color: $*link_color">Tab</a>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td width="80" height="38" style="background-image: url($*imguri/top-left.jpg)">
<img src="$*imguri/spacer.gif" width="80" height="10" />
</td>
<td height="38" style="background-image: url($*imguri/middle.jpg)">
<img src="$*imguri/spacer.gif" width="10" height="10" />
</td>
<td width="10" height="38" style="background-image: url($*imguri/top-right.jpg)">
<img src="$*imguri/spacer.gif" width="10" height="10" />
</td>
</tr>
<tr>
<td width="80" height="38" style="background-image: url($*imguri/side-left.jpg)">
&nbsp;
</td>
<td width="100%" height="38" style="background-image: url($*imguri/middle.jpg)">
<h1>John Doe</h1>
<p align="center"><img src="$*imguri/hr.gif" width="345" height="23"></p>
<p align='center'>
<table border='0'><tr><td valign="top">
<h1>Dec. 16th, 2002 06:39 pm <span style='color: $*subject_color'>Neque porro quisquam est qui dolorem ipsum quia dolor sit amet&hellip;</span></h1>
<p>
Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit
Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit
Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit
Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit
Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit
Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit
</p>
<p><a href="#" style="color: $*vlink_color; font-weight: bold">2 Comments</a> | <a href="#" style="color: $*link_color">Leave a comment</a></p></td></tr>
<tr><td colspan="2"><p align="center"><img src="$*imguri/hr.gif" width="345" height="23"></p></td></tr>
</table>
</p>
</td>
<td width="8" height="38" style="background-image: url($*imguri/side-right.jpg)">
&nbsp;
</td>
</tr>
<tr>
<td width="80" height="12" style="background-image: url($*imguri/bottom-left.jpg)">
<img src="$*imguri/spacer.gif" width="70" height="12" alt='' />
</td>
<td height="12" style="background-image: url($*imguri/bottom-line.jpg)">
<img src="$*imguri/spacer.gif" width="10" height="12" alt='' />
</td>
<td width="8" height="12" style="background-image: url($*imguri/bottom-right.jpg)">
<img src="$*imguri/spacer.gif" width="8" height="12" alt='' />
</td>
</tr>
</table>
</div>
""";
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -0,0 +1,27 @@
# Do not modify this file. To set the S2-usage policy for your own
# LiveJournal-based site, create a file beside this one called
# policy-local.dat, based on instructions you find in this document.
# That file will override anything not set here.
#
# 'allow' means all users get access. 'deny' means only users with
# the 's2styles' capability get access.
#
# Default policy for layouts without their own policy section.
layer: *
use allow # can all users use it?
props allow # can all users modify any property of it?
# If you decide to make your site's default policy for * to be 'deny',
# then you'll have to selectively allow access to parts, like so:
#layer: generator/layout
# use allow
# props deny
# prop page_bgcolor allow
# Notes:
# -- allowing/denying access to properties is only valid on
# layout and core layers.
# -- you can't disallow use of a core layer, or i18n layers.
# -- for theme layers, you can only set the 'use' property.

View File

@@ -0,0 +1,11 @@
# -*-s2-*-
layerinfo type = "i18n";
layerinfo name = "English";
layerinfo redist_uniq = "punquin/en";
set text_meta_music = "music";
set text_meta_mood = "mood";
set text_post_comment = "Comment on this";
set text_post_comment_friends = "Comment on this";

View File

@@ -0,0 +1,699 @@
# -*-s2-*-
layerinfo type = "layout";
layerinfo name = "Punquin Elegant";
layerinfo redist_uniq = "punquin/layout";
layerinfo previews = "punquin/punquin.jpg";
# Colors
propgroup colors {
property Color body_bgcolor {
des = "Page background color";
s1color = "stronger_accent";
}
property Color main_bgcolor {
des = "Background of text areas";
s1color = "page_back";
}
property Color main_fgcolor {
des = "Text color";
s1color = "page_text";
}
property Color subject_color {
des = "Color of entry subjects";
s1color = "page_text_em";
}
property Color title_color {
des = "Color of headers and titles";
s1color = "page_text_title";
}
property Color border_color {
des = "Color of borders";
s1color = "weak_back";
}
property Color link_color {
des = "Link color";
s1color = "page_link";
}
property Color vlink_color {
des = "Visited link color";
s1color = "page_vlink";
}
property Color alink_color {
des = "Active link color";
s1color = "page_alink";
}
property Color comment_bar_one_bgcolor {
des = "Alternating background color for comment bars (one)";
}
property Color comment_bar_two_fgcolor {
des = "Text color on alternating comment bars (one)";
}
property Color comment_bar_two_bgcolor {
des = "Alternating background color for comment bars (two)";
}
property Color comment_bar_one_fgcolor {
des = "Text color on alternating comment bars (two)";
}
property Color comment_bar_screened_bgcolor {
des = "Background bar color for screened comments";
}
property Color comment_bar_screened_fgcolor {
des = "Text color on background bar for screened comments";
}
}
set body_bgcolor = "#6666cc";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set subject_color = "#c00000";
set title_color = "#8b1a1a";
set border_color = "#eeeeff";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#ff00c0";
set comment_bar_one_bgcolor = "#c0c0ff";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#eeeeff";
set comment_bar_two_fgcolor = "#000000";
set comment_bar_screened_bgcolor = "#dddddd";
set comment_bar_screened_fgcolor = "#000000";
propgroup presentation {
property bool show_recent_userpic {
des = "Show the userpic on the recent entries page?";
}
property string sidebar_position {
des = "Position of the sidebar relative to the main content";
values = "left|Left|right|Right";
}
property use font_base;
property use font_fallback;
property use page_recent_items;
property use page_friends_items;
property use use_shared_pic;
property use view_entry_disabled;
property bool show_entrynav_icons {
des = "Toggle to show the next, memory, edit, etc icons on the entry view page";
}
property string page_background_image {
des = "URL to an image to be used for the page background";
}
property use linklist_support;
property use external_stylesheet;
}
set font_base = "Verdana, Arial, Helvetica";
set font_fallback = "sans-serif";
set show_recent_userpic = false;
set sidebar_position = "left";
set page_recent_items = 20;
set page_friends_items = 20;
set view_entry_disabled = false;
set show_entrynav_icons = true;
set page_background_image = "";
set linklist_support = false;
propgroup text {
property string text_gotop {
des = "Link text to 'top of the page'";
noui = 1;
}
property use text_post_comment;
property use text_read_comments;
property use text_post_comment_friends;
property use text_read_comments_friends;
property use text_website_default_name;
}
set text_gotop = "Go to Top";
set tags_aware = true;
function print_stylesheet ()
{
var string font = "$*font_base, $*font_fallback";
print clean_url($*page_background_image) != "" ? "body { background-image: url($*page_background_image); }" : "";
print """
body {
background-color: $*body_bgcolor;
color: $*main_fgcolor;
font: normal normal 10pt $font;
}
a {
text-decoration: none;
color: $*link_color;
background: transparent;
font: normal normal 10pt $font;
}
a:visited {
color: $*vlink_color;
background: transparent;
}
a:active {
color: $*alink_color;
background: transparent;
}
#title {
font: normal bold 10pt $font;
color: $*title_color;
text-align: center;
}
.date {
font: normal bold 12pt $font;
color: $*title_color;
text-align: right;
}
.comments {
font: normal normal 8pt $font;
}
hr.separator {
color: $*border_color;
}
.siteplug {
font: normal normal 8pt $font;
}
#yearheader {
text-align: right;
color: $*title_color;
font: normal bold 12pt $font;
}
th.monthheader {
color: $*title_color;
}
th.daysheader {
color: $*subject_color;
}
/* Tables. Fun. */
table#main {
border: solid 0px $*body_bgcolor;
}
table.standard {
border: solid 5px $*border_color;
background-color: $*main_bgcolor;
color: $*main_fgcolor;
font: normal normal 10pt $font;
}
table.standard>td {
background-color: $*main_bgcolor;
color: $*main_fgcolor;
}
table.standard td {
font: normal normal 10pt $font;
}
""";
}
function Page::lay_sidebar_navigation () { }
function print_sidebar(Page p) {
var string title = $p->title();
var string userpic;
var Image up_img = $p.journal.default_pic;
if (defined $up_img) {
$userpic = """<p align="center"><img border="0" src="$up_img.url" height="$up_img.height" width="$up_img.width" alt="" /></p>""";
}
var string website_name = $p.journal.website_name ? $p.journal.website_name : $*text_website_default_name;
var string website;
if ($p.journal.website_url != "") {
$website = """&gt; <a href="$p.journal.website_url">$website_name</a><br />""";
}
var string links;
foreach var string v ($p.views_order) {
$links = "$links&gt; " + ($p.view == $v ?
lang_viewname($v) :
"<a href='$p.view_url{$v}'>"+lang_viewname($v)+"</a>") + "<br />\n";
}
# Table Wrapper
"<!-- Begin Main Sidebar -->\n<td valign='top' align='$*sidebar_position'>";
"<table width='150' class='standard' cellpadding='5' cellspacing='0'>\n";
"<tr valign='top'><td align='left'>";
# Title
"<div style='text-align:center'><span style='color: $*title_color'><strong>$title</strong></span></div>\n";
# Links
"<p>$links\n$website\n";
$p->lay_sidebar_navigation();
# Userpic
"</p>"; if($userpic != "") { "<div style='text-align:center'>$userpic</div>"; }
# Link List
if (size $p.linklist > 0 and $*linklist_support) {
if (not $p.linklist[0].is_heading) {
"<b>Links</b><br />";
}
$p->print_linklist();
}
# End Table
"</td></tr></table>\n<!-- End Main Sidebar -->";
}
function print_gotop (Page p)
{
"<td valign='bottom' align='$*sidebar_position'>\n<!-- Begin Small Sidebar -->\n";
"<table width='150' class='standard' cellpadding='5' cellspacing='0'>\n";
"<tr valign='top'><td align='left'>\n";
$p->lay_sidebar_navigation();
"<br />&gt; <a href='#top'>$*text_gotop</a><br>\n</td></tr></table>\n<!-- End Small Sidebar -->";
}
function Page::print ()
{
var string title = $this->title();
var string main_position = $*sidebar_position == "left" ? "right" : "left";
# Head
println "<html><head>";
if ($*external_stylesheet) {
println """<link rel="stylesheet" href="$.stylesheet_url" type="text/css" />""";
} else {
println """<style type="text/css">"""; print_stylesheet(); "</style>";
}
$this->print_head();
"<title>$title</title>\n</head>\n";
# Body
"<body>\n<a name='top'></a><div align='center'>\n";
# Table wrapper
"<table id='main' cellpadding='5' cellspacing='0' width='90%'>\n<tr>";
if ($*sidebar_position == "left") { print_sidebar($this); }
# Main content
"<td valign='top' align='$main_position' rowspan='2'>\n<!-- Begin Main -->\n";
"<table class='standard' width='100%' height='90%' cellpadding='5' cellspacing='0'><tr valign='top'><td>\n";
$this->print_body();
"</td></tr></table>\n<!-- End Main -->\n</td>";
if ($*sidebar_position == "right") { print_sidebar($this); }
# Go to top
"</tr><tr>";
print_gotop($this);
"</tr><tr>";
# Plug the site!
"<td colspan='2' align='$main_position'>\n";
"<a href='$*SITEROOT/'>$*SITENAME</a></td>\n";
"</tr></table></div></body></html>";
}
function print_entry (Page p, Entry e, Color bgcolor, Color fgcolor, bool hide_text)
{
var string time = $e.time->time_format();
if ($e.new_day or $p.view == "entry") {
"<p class='date'>"; print $e.time->date_format("%%month%% %%dayord%%, %%yyyy%%"); "</p>";
"<hr class='separator' />";
}
if ($p.view == "entry" and $*show_entrynav_icons)
{
print "<div style='text-align: center'>";
$e->print_linkbar();
print "</div>";
}
"<table border='0' cellpadding='2' cellspacing='0'><tr>";
if ($p.view == "friends" or
$e.poster.username != $e.journal.username or
$*show_recent_userpic == true)
{
# Lots of muddled logic. Yay.
"""<td valign=top align="middle" style="background-color: $bgcolor" width="100">""";
if ($p.view == "friends") {
"""<a href='""" + $e.journal->base_url() + """/' style="color: $fgcolor; font-weight: bold">$e.journal.username</a><br />""";
}
if ($e.poster.username != $e.journal.username) {
if ($p.view == "friends") {
"""[<a href='""" + $e.poster->base_url() + """/' style="color: $fgcolor">$e.poster.username</a>]<br />""";
} else {
"""<a href='""" + $e.poster->base_url() + """/' style="color: $fgcolor; font-weight: bold">$e.poster.username</a><br />""";
}
}
if (defined $e.userpic) {
if (($*show_recent_userpic == false) and
($p.view != "friends") and
($p.journal_type != "C") ) { }
else { """<img border="0" src="$e.userpic.url" width="$e.userpic.width" height="$e.userpic.height" alt="" />""";
}
}
"</td>";
}
"<td valign='top'><strong>$time";
if ($e.subject) { " - <span style='color: $*subject_color'>$e.subject</span>"; }
if ($e.security) {
" "; $e.security_icon->print();
}
"</strong><br />";
if (not $hide_text) {
print $e.text; "<br />";
if (size $e.metadata) {
foreach var string k ($e.metadata) {
var string key = $k;
var string val = $e.metadata{$k};
if ($k == "mood") {
$key = $*text_meta_mood;
} elseif ( $k == "music" ) {
$key = $*text_meta_music;
}
if ($k == "mood" and defined $e.mood_icon) {
var Image i = $e.mood_icon;
$val = "<img src='$i.url' width='$i.width' height='$i.height' align='absmiddle' alt='[mood icon]' /> $val";
}
"<strong>$key:</strong> $val<br />";
}
}
if ($e.tags) {
var int tcount = 0;
"<div class='ljtags'><strong>Tags:</strong> ";
foreach var Tag t ($e.tags) {
"""<a rel="tag" href="$t.url">$t.name</a>""";
$tcount++;
if ($tcount != size $e.tags) { ", "; }
}
"</div>";
}
}
"</td></tr></table>";
$e.comments->print();
}
function Page::print_entry (Entry e)
{
print_entry($this, $e, null Color, null Color, false);
}
function FriendsPage::print_entry (Entry e) {
var Friend f = $.friends{$e.journal.username};
print_entry($this, $e, $f.bgcolor, $f.fgcolor, false);
}
function RecentPage::print_body {
foreach var Entry e ($.entries) {
$this->print_entry($e);
}
}
function FriendsPage::print_body {
foreach var Entry e ($.entries) {
$this->print_entry($e);
}
}
function RecentPage::lay_sidebar_navigation () {
var int total = size $.entries;
var string nav = "";
if ($.nav.backward_url != "") {
$nav = """&gt; <a href="$.nav.backward_url">previous $total entries</a>""";
}
if ($.nav.forward_url != "" and $.nav.backward_url != "") {
$nav = "$nav<br />";
}
if ($.nav.forward_url != "") {
$nav = """${nav}&gt; <a href="$.nav.forward_url">next $total entries</a>""";
}
print $nav;
}
function CommentInfo::print ()
{
if (not $.enabled) {
"<p align='right' class='comments'>&nbsp;</p>";
return;
}
"<p align='right' class='comments'>(";
if ($.count > 0 or $.screened) {
$this->print_readlink();
"&nbsp;|&nbsp;";
}
$this->print_postlink();
")</p>";
}
function YearPage::print_body {
"<p id='yearheader'>$.year</p>\n";
foreach var YearMonth m ($.months) {
$this->print_month($m);
}
}
function YearPage::print_year_links ()
{
foreach var YearYear y ($.years) {
if ($y.displayed) {
"&gt; $y.year<br />";
} else {
"&gt; <a href=\"$y.url\">$y.year</a><br />";
}
}
}
function YearPage::lay_sidebar_navigation ()
{
$this->print_year_links();
}
function YearPage::print_month(YearMonth m)
{
if (not $m.has_entries) { return; }
# Table Wrapper
"<center><p><table border='1' cellpadding='4' width='80%'>\n";
# Month Header
"<tr align='center'><th colspan='7' class='monthheader'>\n";
print $m->month_format();
"</th></tr>\n";
# Weekdays Header
"<tr align='center'>\n";
foreach var int d (weekdays()) {
"<th class='daysheader'>"+$*lang_dayname_short[$d]+"</th>\n";
}
"</tr>\n";
# Weeks
foreach var YearWeek w ($m.weeks) {
$w->print();
}
# Footer
"<tr><td colspan='7'><div style='text-align: center'><a href='$m.url'>view subjects</a></div></td></tr>\n";
# End Table
"</table></p></center>\n";
}
function YearWeek::print () {
"<tr>";
if ($.pre_empty) { "<td colspan='$.pre_empty'>&nbsp;</td>"; }
foreach var YearDay d ($.days) {
"<td valign='top'><strong>$d.day</strong><div style='text-align: center'>";
if ($d.num_entries) {
"<a href='$d.url'>$d.num_entries</a>";
} else {
"&nbsp;";
}
"</div></td>\n";
}
if ($.post_empty) { "<td colspan='$.post_empty'>&nbsp;</td>"; }
"</tr>";
}
function DayPage::print_body() {
if (not $.has_entries) {
"<table width='100%'><tr><td><p class='date'>\n";
print $.date->date_format("%%month%% %%dayord%%, %%yyyy%%");
"</p><hr class='separator' width='100%' /></td></tr>";
"<tr><td><blockquote align='center'>"; print ehtml($*text_noentries_day); "</blockquote></td></tr></table>";
} else {
foreach var Entry e ($.entries) {
$this->print_entry($e);
}
}
var string tprev = ehtml($*text_day_prev);
var string tnext = ehtml($*text_day_next);
"<hr class='separator' width='100%' />\n";
"<table width='100%'><tr align='middle'>\n";
"<td width='33%' align='left'><a href='$.prev_url'>$tprev</a></td>\n";
"<td align='center' width='33%'>[<a href='"; print $this.journal->base_url(); "/calendar'>$*text_view_archive</a>]</td>\n";
"<td width='33%' align='right'><a href='$.next_url'>$tnext</a></td>\n";
"</tr></table>";
}
function EntryPage::print_body ()
{
set_handler("unscreen_comment_#", [
[ "style_bgcolor", "cmtbar#", "$*comment_bar_one_bgcolor", ],
[ "style_color", "cmtbar#", "$*comment_bar_one_fgcolor", ],
]);
set_handler("screen_comment_#", [
[ "style_bgcolor", "cmtbar#", "$*comment_bar_screened_bgcolor", ],
[ "style_color", "cmtbar#", "$*comment_bar_screened_fgcolor", ],
]);
print_entry($this, $.entry, null Color, null Color, $.viewing_thread);
if ($.entry.comments.enabled and $.comment_pages.total_subitems > 0)
{
$this->print_multiform_start();
print "<h2 class='date'>Comments:</h2>";
"<hr class='separator' />";
if ($.comment_pages.total_subitems > 0) {
$.comment_pages->print();
$this->print_comments($.comments);
}
if ($this.multiform_on) {
print "<h2 class='date'>Mass Action:</h2>";
"<hr class='separator' />";
$this->print_multiform_actionline();
$this->print_multiform_end();
}
}
}
function EntryPage::print_comment (Comment c) {
var Color background; var Color color;
if ($c.screened) {
$background = $*comment_bar_screened_bgcolor;
$color = $*comment_bar_screened_fgcolor;
} elseif ($c.depth % 2) {
$background = $*comment_bar_one_bgcolor;
$color = $*comment_bar_one_fgcolor;
} else {
$background = $*comment_bar_two_bgcolor;
$color = $*comment_bar_two_fgcolor;
}
var string poster = defined $c.poster ? $c.poster->as_string() : "<i>(Anonymous)</i>";
var string sub_icon;
if (defined $c.subject_icon) {
$sub_icon = $c.subject_icon->as_string();
}
"<a name='$c.anchor'></a><div id='cmtbar$c.talkid' style='background-color: $background; color: $color; margin-top: 10px; width: 100%'>";
"<table cellpadding='2' cellspacing='0' summary='0' style='width: 100%'><tr valign='top'>";
if (defined $c.userpic and $*comment_userpic_style != "off") {
var int w = $c.userpic.width;
var int h = $c.userpic.height;
# WARNING: this will later be done by the system (it'll be a
# constructional property), so don't copy this hack into your
# layout layers or you'll be messed up later.
if ($*comment_userpic_style == "small") {
$w = $w / 2;
$h = $h / 2;
}
print "<td style='width: 102px'><img src='$c.userpic.url' width='$w' height='$h' alt='[User Picture]' /></td>";
}
"<td style='width: 100%'><table style='width: 100%'><tr>";
### From, date, etc
"<td align='left' style='width: 50%'>";
print "<table>";
print "<tr><th align='right' style='font-size: .9em'>From:</th><td>$poster</td></tr>\n";
print "<tr><th align='right' style='font-size: .9em'>Date:</th><td style='white-space: nowrap'>";
print $c.time->date_format("long") + " - " + $c.time->time_format() + "</td></tr>";
if ($c.metadata{"poster_ip"}) { print "<tr><th align='right' style='font-size: .9em'>IP Address:</th><td>(" + $c.metadata{"poster_ip"} + ")</td></tr>"; }
"</table></td>";
### Gadgets
"<td align='right' style='width: 50%'>";
if ($this.multiform_on) {
" <label for='ljcomsel_$c.talkid'>$*text_multiform_check</label>";
$c->print_multiform_check();
}
$c->print_linkbar();
"</td></tr>";
### Subject / icon
print "<tr valign='top'><td style='width: 50%'>";
print (defined $c.subject_icon or $c.subject != "") ? "<h3>$c.subject_icon $c.subject</h3>" : "";
print "</td>";
### Permalink
print "<td style='width: 50%' align='right'><strong>(<a href='$c.permalink_url'>Link</a>)</strong></td></tr>";
print "</table></td></tr></table></div>";
print "<div style='margin-left: 5px'>$c.text</div>";
print "<div style='margin-top: 3px; font-size: smaller'>";
if ($c.frozen) {
print "(Replies frozen)";
} else {
print "(<a href='$c.reply_url'>Reply to this</a>) ";
}
if ($c.parent_url != "") { "(<a href='$c.parent_url'>Parent</a>) "; }
if ($c.thread_url != "") { "(<a href='$c.thread_url'>Thread</a>) "; }
"</div>";
}
function ReplyPage::print_body() {
if (not $.entry.comments.enabled)
{
"<h2 class='date'>$*text_reply_nocomments_header</h2>";
"<hr class='separator' />";
"<p>$*text_reply_nocomments</p>";
return;
}
"<p class='date'>"; print $.replyto.time->date_format("%%month%% %%dayord%%, %%yyyy%%"); "</p>";
"<hr class='separator' />";
"<table border='0' cellpadding='2' cellspacing='0'><tr>";
"""<td valign=top align="middle" width="100">""";
print defined $.replyto.poster ? $.replyto.poster->as_string() : "<i>(Anonymous)</i>";
if (defined $.replyto.userpic) {
print """<img border="0" src="$.replyto.userpic.url" width="$.replyto.userpic.width" height="$.replyto.userpic.height" alt="" />""";
}
"</td>";
"<td valign='top'><strong>"; print $.replyto.time->time_format();
if ($.replyto.subject) { " - <span style='color: $*subject_color'>$.replyto.subject</span>"; }
"</strong><br />";
print $.replyto.text; "<br />";
"</td></tr></table>";
"<p align='right' class='comments'><a href='$.entry.comments.read_url'>Read Comments</a></p>";
"<h2 class='date'>Reply</h2>";
"<hr class='separator' />";
$.form->print();
}
function print_theme_preview ()
{
"""
<table width="100%" style="background-color: $*body_bgcolor; border: solid 1px #000000"><tr><td style="color:$*main_fgcolor">
<table bgcolor="$*border_color" border="0" cellpadding="5" cellspacing="0" width="60%" align="center">
<tr><td valign="center" align="center">
<table width="100%" height=90% bgcolor="$*main_bgcolor" border="0" cellpadding="5" cellspacing="0">
<tr valign="top"><td>
<p align="right"><font color="$*title_color" face="verdana,arial,helvetica" size="3">
<strong>December 18th, 2002</strong></font><hr noshade color="$*border_color" size="1" width="100%" />
</p>
<font face="verdana,arial,helvetica" size="2">
<b>01:22 am - <font color="$*subject_color">Test</font></b><font face="verdana,arial,helvetica" size="2"><br />
Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit.
Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit.</font>
<p align="right">(<a style="color: $*link_color" href="#">Read # Comments</a> | <a style="color: $*vlink_color" href="#">Leave a comment</a>)</p>
</td></tr>
</table>
</td></tr>
</table>
</td></tr></table>
""";
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,450 @@
#NEWLAYER: punquin/bw
layerinfo type = "theme";
layerinfo name = "Black on White";
layerinfo redist_uniq = "punquin/bw";
set body_bgcolor = "#333333";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set subject_color = "#c00000";
set title_color = "#336699";
set border_color = "#dddddd";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#ff00c0";
set comment_bar_one_bgcolor = "#dddddd";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#aaaaaa";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: punquin/autumn
layerinfo type = theme;
layerinfo name = "Autumn";
layerinfo redist_uniq = "punquin/autumn";
layerinfo author = "pumpsnail";
set body_bgcolor = "#660033";
set main_bgcolor = "#990022";
set main_fgcolor = "#ffffff";
set subject_color = "#ffffff";
set title_color = "#ffffff";
set border_color = "#fcc303";
set link_color = "#cc6600";
set vlink_color = "#cc99cc";
set alink_color = "#ffcc33";
set comment_bar_one_bgcolor = "#660033";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#993366";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: punquin/greyslate
layerinfo type = theme;
layerinfo name = "Grey Slate Rain";
layerinfo redist_uniq = "punquin/greyslate";
set body_bgcolor = "#67698f";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set subject_color = "#000000";
set title_color = "#336699";
set border_color = "#dddddd";
set link_color = "#8e80f8";
set vlink_color = "#c780f8";
set alink_color = "#f880dd";
set comment_bar_one_bgcolor = "#dddddd";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#aaaaaa";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: punquin/minimal
layerinfo type = theme;
layerinfo name = "Minimalist";
layerinfo redist_uniq = "punquin/minimal";
set body_bgcolor = "#ffffff";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#333333";
set subject_color = "#333333";
set title_color = "#333333";
set border_color = "#aaaaaa";
set link_color = "#8e80f8";
set vlink_color = "#c780f8";
set alink_color = "#f880dd";
set comment_bar_one_bgcolor = "#dddddd";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#aaaaaa";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: punquin/jewel
layerinfo type = theme;
layerinfo name = "Jewel Toned";
layerinfo redist_uniq = "punquin/jewel";
set body_bgcolor = "#950875";
set main_bgcolor = "#f3a8e2";
set main_fgcolor = "#000000";
set subject_color = "#c00000";
set title_color = "#336699";
set border_color = "#dddddd";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#ff00c0";
set comment_bar_one_bgcolor = "#950875";
set comment_bar_one_fgcolor = "#f3a8e2";
set comment_bar_two_bgcolor = "#b70875";
set comment_bar_two_fgcolor = "#f3a8e2";
#NEWLAYER: punquin/bold
layerinfo type = theme;
layerinfo name = "Bold";
layerinfo redist_uniq = "punquin/bold";
set body_bgcolor = "#2501da";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set subject_color = "#c00453";
set title_color = "#f50930";
set border_color = "#000000";
set link_color = "#5f5cd5";
set vlink_color = "#2a2ab2";
set alink_color = "#4a92eb";
set comment_bar_one_bgcolor = "#2501da";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#2501fc";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: punquin/shrinkvio
layerinfo type = theme;
layerinfo name = "Shrinking Violet";
layerinfo redist_uniq = "punquin/shrinkvio";
set body_bgcolor = "#ad22e7";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set border_color = "#381a45";
set title_color = "#5d0383";
set subject_color = "#d9a1f1";
set link_color = "#2e053f";
set vlink_color = "#611627";
set alink_color = "#ff00c0";
set comment_bar_one_bgcolor = "#5d0383";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#d9a1f1";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: punquin/pistmint
layerinfo type = theme;
layerinfo name = "Pistachio Mint";
layerinfo redist_uniq = "punquin/pistmint";
set body_bgcolor = "#133422";
set main_bgcolor = "#a7c4b4";
set main_fgcolor = "#000000";
set border_color = "#096d36";
set title_color = "#096d36";
set subject_color = "#096d36";
set link_color = "#8afabc";
set vlink_color = "#1da65a";
set alink_color = "#f9f5f5";
set comment_bar_one_bgcolor = "#096d36";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#093d36";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: punquin/mexicanfood
layerinfo type = theme;
layerinfo name = "Mexican Food";
layerinfo redist_uniq = "punquin/mexicanfood";
set body_bgcolor = "#ff0000";
set main_bgcolor = "#f8ff3e";
set main_fgcolor = "#f15601";
set border_color = "#f50701";
set title_color = "#bdbf3e";
set subject_color = "#f9ff9d";
set link_color = "#f49e08";
set vlink_color = "#b05403";
set alink_color = "#ff7405";
set comment_bar_one_bgcolor = "#bdbf3e";
set comment_bar_one_fgcolor = "#ff0000";
set comment_bar_two_bgcolor = "#e15a18";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: punquin/ashfire
layerinfo type = theme;
layerinfo name = "Ash and Fire";
layerinfo redist_uniq = "punquin/ashfire";
set body_bgcolor = "#b5b5b5";
set main_bgcolor = "#ffb6af";
set main_fgcolor = "#000000";
set border_color = "#d90308";
set title_color = "#e75454";
set subject_color = "#ff1106";
set link_color = "#f70208";
set vlink_color = "#b0161d";
set alink_color = "#d70106";
set comment_bar_one_bgcolor = "#e75454";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#f06c88";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: punquin/desktop
layerinfo type = theme;
layerinfo name = "Classic Desktop";
layerinfo redist_uniq = "punquin/desktop";
set body_bgcolor = "#00545c";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set border_color = "#000000";
set title_color = "#ff7b05";
set subject_color = "#ff7b05";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#5a76ff";
set comment_bar_one_bgcolor = "#ff7b05";
set comment_bar_one_fgcolor = "#ffeddd";
set comment_bar_two_bgcolor = "#ffeddd";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: punquin/satinhandshake
layerinfo type = theme;
layerinfo name = "Satin Handshake";
layerinfo redist_uniq = "punquin/satinhandshake";
set body_bgcolor = "#480c0c";
set main_bgcolor = "#d06464";
set main_fgcolor = "#00001d";
set border_color = "#000000";
set title_color = "#aaaaaa";
set subject_color = "#9d0404";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#ff00c0";
set comment_bar_one_bgcolor = "#aaaaaa";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#9d0404";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: punquin/deepmelodrama
layerinfo type = theme;
layerinfo name = "Deep MeloDrama";
layerinfo redist_uniq = "punquin/deepmelodrama";
set body_bgcolor = "#872d89";
set main_bgcolor = "#719cff";
set main_fgcolor = "#8e48b2";
set border_color = "#8e48b2";
set title_color = "#3794b3";
set subject_color = "#8e48b2";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#dfd3ff";
set comment_bar_one_bgcolor = "#3794b3";
set comment_bar_one_fgcolor = "#84b8e7";
set comment_bar_two_bgcolor = "#65b2c1";
set comment_bar_two_fgcolor = "#f5d3ff";
#NEWLAYER: punquin/everwhite
layerinfo type = theme;
layerinfo name = "Everwhite";
layerinfo redist_uniq = "punquin/everwhite";
set body_bgcolor = "#ffffff";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set border_color = "#000000";
set title_color = "#ffffff";
set subject_color = "#ff0000";
set link_color = "#e60000";
set vlink_color = "#c10602";
set alink_color = "#ff0600";
set comment_bar_one_bgcolor = "#dddddd";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#aaaaaa";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: punquin/everblue
layerinfo type = theme;
layerinfo name = "Everblue with Greys";
layerinfo redist_uniq = "punquin/everblue";
set body_bgcolor = "#0f0c6d";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set border_color = "#000000";
set title_color = "#000000";
set subject_color = "#000000";
set link_color = "#2f00f2";
set vlink_color = "#060667";
set alink_color = "#6691ff";
set comment_bar_one_bgcolor = "#000000";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#aaaaaa";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: punquin/brownleather
layerinfo type = theme;
layerinfo name = "Brown Leather Coat";
layerinfo redist_uniq = "punquin/brownleather";
set body_bgcolor = "#d2b48c";
set main_bgcolor = "#ffebcd";
set main_fgcolor = "#8b4513";
set border_color = "#000000";
set title_color = "#d48014";
set subject_color = "#d48014";
set link_color = "#000050";
set vlink_color = "#867a55";
set alink_color = "#fffab3";
set comment_bar_one_bgcolor = "#d48014";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#ffe1a1";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: punquin/bruise
layerinfo type = theme;
layerinfo name = "Bruise";
layerinfo redist_uniq = "punquin/bruise";
set body_bgcolor = "#000000";
set main_bgcolor = "#bcbcbc";
set main_fgcolor = "#000000";
set border_color = "#000000";
set title_color = "#1114a0";
set subject_color = "#1114a0";
set link_color = "#0000cc";
set vlink_color = "#000088";
set alink_color = "#0000ff";
set comment_bar_one_bgcolor = "#1114a0";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#21c2f1";
set comment_bar_two_fgcolor = "#0000ff";
#NEWLAYER: punquin/ranchhand
layerinfo type = theme;
layerinfo name = "Ranch Hand";
layerinfo redist_uniq = "punquin/ranchhand";
set body_bgcolor = "#2999c2";
set main_bgcolor = "#cfe0ff";
set main_fgcolor = "#000000";
set border_color = "#060667";
set title_color = "#54442c";
set subject_color = "#9d995d";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#6a20ff";
set comment_bar_one_bgcolor = "#54442c";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#704400";
set comment_bar_two_fgcolor = "#bababa";
#NEWLAYER: punquin/victim
layerinfo type = theme;
layerinfo name = "Victim";
layerinfo redist_uniq = "punquin/victim";
set body_bgcolor = "#2cd0ff";
set main_bgcolor = "#505050";
set main_fgcolor = "#ffffff";
set border_color = "#000000";
set title_color = "#166bac";
set subject_color = "#26b6ff";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#ff00c0";
set comment_bar_one_bgcolor = "#166bac";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#353535";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: punquin/forest
layerinfo type = theme;
layerinfo name = "Forest";
layerinfo redist_uniq = "punquin/forest";
set body_bgcolor = "#778e64";
set main_bgcolor = "#9b9ba5";
set main_fgcolor = "#000000";
set border_color = "#ffffff";
set title_color = "#72784c";
set subject_color = "#a0ac62";
set link_color = "#3811e1";
set vlink_color = "#310cbb";
set alink_color = "#4e7bef";
set comment_bar_one_bgcolor = "#72784c";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#73777a";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: punquin/drone
layerinfo type = theme;
layerinfo name = "Drone";
layerinfo redist_uniq = "punquin/drone";
set body_bgcolor = "#395f82";
set main_bgcolor = "#f9fcfe";
set main_fgcolor = "#000000";
set border_color = "#000000";
set title_color = "#904094";
set subject_color = "#ff93ff";
set link_color = "#395f82";
set vlink_color = "#395f82";
set alink_color = "#5266ce";
set comment_bar_one_bgcolor = "#904094";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#eeeeff";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: punquin/lowercurtain
layerinfo type = theme;
layerinfo name = "Lower the Curtain";
layerinfo redist_uniq = "punquin/lowercurtain";
set body_bgcolor = "#000000";
set main_bgcolor = "#6b6b6b";
set main_fgcolor = "#ffffff";
set border_color = "#ffffff";
set title_color = "#363636";
set subject_color = "#363636";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#3314ba";
set comment_bar_one_bgcolor = "#363636";
set comment_bar_one_fgcolor = "#f0f5fb";
set comment_bar_two_bgcolor = "#c5c8ca";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: punquin/sunny
layerinfo type = theme;
layerinfo name = "Sunny Day";
layerinfo redist_uniq = "punquin/sunny";
set body_bgcolor = "#55e0f9";
set main_bgcolor = "#e38202";
set main_fgcolor = "#ffffff";
set border_color = "#000000";
set title_color = "#e38202";
set subject_color = "#efe052";
set link_color = "#df0d12";
set vlink_color = "#ac1b25";
set alink_color = "#fe3b3b";
set comment_bar_one_bgcolor = "#e38202";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#ffba03";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: punquin/valentine
layerinfo type = theme;
layerinfo name = "Be Mine";
layerinfo redist_uniq = "punquin/valentine";
set body_bgcolor = "#6f104a";
set main_bgcolor = "#f2bce9";
set main_fgcolor = "#000000";
set border_color = "#ff24ab";
set title_color = "#ff37ff";
set subject_color = "#ae1774";
set link_color = "#ffffff";
set vlink_color = "#a51014";
set alink_color = "#ed8188";
set comment_bar_one_bgcolor = "#ff37ff";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#df2096";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: punquin/stripes
layerinfo type = theme;
layerinfo name = "Stripes";
layerinfo redist_uniq = "punquin/stripes";
set body_bgcolor = "#ffffff";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set border_color = "#ff0000";
set title_color = "#e7212a";
set subject_color = "#ffffff";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#ffafc1";
set comment_bar_one_bgcolor = "#e7212a";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#ffcfdc";
set comment_bar_two_fgcolor = "#000000";

View File

@@ -0,0 +1,850 @@
# -*-s2-*-
layerinfo type = "layout";
layerinfo name = "A Sturdy Gesture";
layerinfo lang = "en";
layerinfo author = "Martin Atkins";
layerinfo author_email = "mart@livejournal.com";
layerinfo redist_uniq = "sturdygesture/layout";
layerinfo previews = "sturdygesture/sturdygesture.jpg";
propgroup colors {
property Color clr_page_back { des = "Page background"; }
set clr_page_back = "#ffffff";
property Color clr_page_text { des = "Box border color"; }
set clr_page_text = "#000000";
property Color clr_box_text { des = "Box content color"; }
set clr_boxhead_text = "#ffffff";
property Color clr_box_back { des = "Box background color"; }
set clr_boxhead_back = "#000000";
property Color clr_boxhead_text { des = "Box heading text color"; }
set clr_boxhead_text = "#ffffff";
property Color clr_boxhead_back { des = "Box heading background color"; }
set clr_boxhead_back = "#000000";
property Color clr_page_link { des = "Link color"; }
set clr_page_link = "#0000ff";
property Color clr_page_vlink { des = "Visited link color"; }
set clr_page_vlink = "#0000ff";
}
propgroup fonts {
property use font_base;
property use font_fallback;
}
propgroup presentation {
property string opt_navbar_pos {
des = "Navigation Bar Location";
values = "left|Left|right|Right";
}
set opt_navbar_pos = "left";
property bool opt_friends_colors {
des = "Use friend colors on friends page";
note = "If this option is on, the titles of friends' entries will use the colors you have selected for each friend.";
}
set opt_friends_colors = true;
property bool opt_always_userpic {
des = "Always show userpics";
note = "With this off, userpics are only shown in the friends view.";
}
set opt_always_userpic = false;
## These have no UI, but S2 generates an empty settings page if they aren't in a group
property string text_page_prev {
des = "Text used to link to the previous page";
noui = 1;
}
property string text_page_next {
des = "Text used to link to the next page";
noui = 1;
}
set text_page_prev = "Previous Page";
set text_page_next = "Next Page";
property string{} text_entry_links {
des = "Captions for Entry Action links";
noui = 1;
}
set text_entry_links = {"edit_entry" => "Edit Entry",
"edit_tags" => "Edit Tags",
"mem_add" => "Add As Memory",
"tell_friend" => "Tell a Friend",
"nav_prev" => "Previous Entry",
"nav_next" => "Next Entry"};
property string{} text_comment_links {
des = "Captions for Comment Action links";
noui = 1;
}
set text_comment_links = {"delete_comment" => "Delete",
"screen_comment" => "Screen",
"unscreen_comment" => "Unscreen",
"freeze_thread" => "Freeze",
"unfreeze_thread" => "Unfreeze", };
property use use_shared_pic;
property use linklist_support;
property use external_stylesheet;
}
set tags_aware = true;
function navheading(RecentNav nav, int entries) : string
"i18n layers should override this to translate the skiplink box heading." {
return ($nav.skip == 0 ? $entries+" most recent" : "skipped back "+$nav.skip);
}
function navlinktext(RecentNav nav, bool next) : string
"i18n layers should override this to translate the skiplinks. If \$next is false, output 'Previous X', else 'Next X'." {
return ($next ? "Next "+$nav.forward_count : "Previous "+$nav.backward_count);
}
function print_stylesheet() {
"""
body {
background: $*clr_page_back;
color: $*clr_page_text;
""";
# Ugliness
if ($*font_base != "" or $*font_fallback != "none") {
"font-family: ";
if ($*font_base != "") {
"\"$*font_base\"";
if ($*font_fallback != "none") {
", ";
}
}
if ($*font_fallback != "none") {
print $*font_fallback;
}
";";
}
"""
}
a {
color: $*clr_page_link;
}
a:visited {
color: $*clr_page_vlink;
}
img {
border: 0;
}
.box {
border: 1px solid $*clr_page_text;
margin: 1em;
background: $*clr_box_back;
color: $*clr_box_text;
}
#navbar {
width: 25%;
}
#body {
width: 75%;
}
#navbar .box h1, .box h2, .box h3 {
font-size: 1em;
background: $*clr_boxhead_back;
color: $*clr_boxhead_text;
padding: 3px;
margin: 0;
}
#navbar .box h1 {
text-align: center;
}
.box h1 a, .box h2 a, .box h3 a {
color: $*clr_boxhead_text;
background: $*clr_boxhead_back;
}
#navbar .box div.userpic {
margin: 1em;
text-align: center;
}
#navbar p {
margin-left: 1em;
margin-right: 1em;
margin-bottom: 0;
}
#navbar ul, #skipbar ul {
list-style: none;
padding: 0;
margin: 0.5em;
}
#navbar ul li.active, #skipbar ul li.active {
font-weight: bold;
}
.box .entry {
margin: 1em;
}
.box .talklinks {
margin: 1em;
text-align: right;
clear: both;
}
.box .talklinks .permalink {
float: left;
}
.box .minicomment {
clear: both;
}
body.day #body h1 {
font-size: 1.1em;
font-weight: bold;
}
table.box, table.box td, table.box th {
border: 1px solid #000000;
}
.metadata {
margin-top: 1em;
}
form#postform table {
background: $*clr_box_back;
color: $*clr_box_text;
}
""";
}
function Page::lay_page_nav() {
}
function RecentPage::lay_page_nav() {
if ($.nav.backward_url == "" and $.nav.forward_url == "") {
return;
}
println "<div class=\"box\">";
println "<h2>"+navheading($.nav,size $.entries)+"</h2>\n<ul>";
if ($.nav.backward_url != "") {
println "<li><a href=\""+$.nav.backward_url+"\">"+
navlinktext($.nav,false)+"</a></li>";
}
if ($.nav.forward_url != "") {
println "<li><a href=\""+$.nav.forward_url+"\">"+
navlinktext($.nav,true)+"</a></li>";
}
println "</ul>\n";
println "</div>\n";
}
function DayPage::lay_page_nav() {
println "<div class=\"box\"><ul>";
println "<li><a href=\"$.prev_url\">"+$.prev_date->date_format("med")+"</a></li>";
println "<li><a href=\"$.next_url\">"+$.next_date->date_format("med")+"</a></li>";
println "</ul></div>";
}
function YearPage::lay_page_nav() {
println "<div class=\"box\"><ul>";
foreach var YearYear y ($.years) {
if ($y.displayed) {
println "<li class=\"active\">$y.year</li>";
} else {
println "<li><a href=\"$y.url\">$y.year</a></li>";
}
}
println "</ul></div>";
}
function MonthPage::lay_page_nav() {
println "<div class=\"box\"><ul>";
if ($.prev_url != "") {
"""<li><a href="$.prev_url">"""+$.prev_date->date_format($*lang_fmt_month_long)+"""</a></li>""";
}
if ($.next_url != "") {
"""<li><a href="$.next_url">"""+$.next_date->date_format($*lang_fmt_month_long)+"""</a></li>""";
}
"</ul>";
"<form method='post' action='$.redir.url'><center>";
$.redir->print_hiddens();
if (size $.months > 1) {
"<select name='redir_key'>\n";
foreach var MonthEntryInfo mei ($.months) {
var string sel;
if ($mei.date.year == $.date.year and $mei.date.month == $.date.month) {
$sel = " selected='selected'";
}
"<option value='$mei.redir_key'$sel>" + $mei.date->date_format($*lang_fmt_month_long) + "</option>";
}
"</select>\n<input type='submit' value='View' />";
}
"</center></form>\n</div>\n";
}
function EntryPage::lay_page_nav() {
println "<div class=\"box\">";
if (size $.comments > 0 and not $.comment_pages.all_subitems_displayed) {
"<h2>"+lang_page_of_pages($.comment_pages.current, $.comment_pages.total)+"</h2>\n";
}
print "<ul>\n";
if ($.entry.comments.enabled) {
"<li>"; $.entry.comments->print_postlink(); "</li>\n";
}
if ($.comment_pages.url_prev != "") {
"""<li><a href="$.comment_pages.url_prev">$*text_page_prev</a></li>\n""";
}
if ($.comment_pages.url_next != "") {
"""<li><a href="$.comment_pages.url_next">$*text_page_next</a></li>\n""";
}
println "<li>&nbsp;</li>";
var Link l = new Link;
$l = $.entry->get_link("nav_next");
println """<li><a href="$l.url">$*text_entry_links{"nav_next"}</a></li>""";
foreach var string ls ($.entry.link_keyseq) {
$l = $.entry->get_link($ls);
if (defined $l) {
println """<li><a href="$l.url">$*text_entry_links{$ls}</a></li>""";
}
}
$l = $.entry->get_link("nav_prev");
println """<li><a href="$l.url">$*text_entry_links{"nav_prev"}</a></li>""";
println "</ul></div>";
}
function Page::lay_show_firstnav() : bool {
return false;
}
function RecentPage::lay_show_firstnav() : bool {
return ((size $.entries) > 5);
}
function DayPage::lay_show_firstnav() : bool {
return ((size $.entries) > 5);
}
function YearPage::lay_show_firstnav() : bool {
return true;
}
function MonthPage::lay_show_firstnav() : bool {
return true;
}
function EntryPage::lay_show_firstnav() : bool {
return ((size $.comments) > 5);
}
function EntryPage::lay_show_firstnav() : bool {
return false;
}
function Page::lay_navbar() {
var string userpic;
var Image up_img = $.journal.default_pic;
if (defined $up_img) {
$userpic = """<div class="userpic">
<img src="$up_img.url"
class="userpic" alt=""
height="$up_img.height" width="$up_img.width" />
</div>
""";
}
var string website;
if ($.journal.website_url != "") {
$website = """<li><a href="$.journal.website_url">$.journal.website_name</a></li>\n""";
}
"""
<td id="navbar" width="25%">
<div class="box">
<h1>$.journal.name</h1>
<ul>
""";
foreach var string v ($.views_order) {
if ($.view == $v) {
println "<li class=\"active\">"+lang_viewname($v)+"</li>";
} else {
println "<li><a href=\""+$.view_url{$v}+"\">"+lang_viewname($v)+"</a></li>";
}
}
"""
$website</ul>
$userpic
</div>
""";
if ($this->lay_show_firstnav()) {
$this->lay_page_nav();
}
if (size $this.linklist > 0 and $*linklist_support) {
println "<div class=\"box\">";
println "<h2>Links</h2>\n";
$this->print_linklist();
println "</div>";
}
"</td>";
}
function Page::print_linklist() {
if (size $.linklist <= 0) {
return;
}
var bool section_open = false;
println "<ul>";
foreach var UserLink l ($.linklist) {
if ($l.title) {
if ($l.is_heading) {
if ($section_open) {
println "</ul></li>";
}
println """<li><span style="font-weight: bold;">$l.title</span>\n<ul>""";
$section_open = true;
} else {
println """<li><a href="$l.url">$l.title</a></li>""";
}
}
}
if ($section_open) {
println "</ul></li>";
}
println "</ul>";
}
function Page::print() {
var string title = $this->title();
"""<html>\n<head>\n""";
if ($*external_stylesheet) {
println """<link rel="stylesheet" href="$.stylesheet_url" type="text/css" />""";
} else {
println """<style type="text/css">"""; print_stylesheet(); "</style>";
}
$this->print_head();
"<title>"+$this->title()+"</title>";
"""
</head>
<body class="$.view">
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr valign="top">
""";
if ($*opt_navbar_pos == "left") {
$this->lay_navbar();
}
"<td rowspan=\"2\" id=\"body\">\n";
$this->print_body();
"</td>\n";
if ($*opt_navbar_pos == "right") {
$this->lay_navbar();
}
"</tr><tr><td valign=\"bottom\" id=\"skipbar\">";
$this->lay_page_nav();
"</td>";
"""
</tr>
</table>
</body>
</html>
""";
}
function print_entry(Page p, Entry e, Color bgcolor, Color fgcolor) {
var string datetime;
if ($p.view != "day") {
$datetime = $e.time->date_format("med_day")+", "+$e.time->time_format();
} else {
$datetime = $e.time->time_format();
}
if (not (defined $bgcolor) or not $*opt_friends_colors) {
$bgcolor = $*clr_boxhead_back;
}
if (not (defined $fgcolor) or not $*opt_friends_colors) {
$fgcolor = $*clr_boxhead_text;
}
"""<div class="box"><h2 style="color: $fgcolor; background: $bgcolor;">$datetime """;
if ($e.security != "") {
print """<img src="$e.security_icon.url" align="right" """+
"""width="$e.security_icon.width" height="$e.security_icon.height" """+
"""alt="[$e.security]" />""";
}
if ($p.view == "friends" or
$e.subject != "" or
$e.poster.username != $p.journal.username) {
print "<br />";
if ($p.view == "friends" or $e.poster.username != $p.journal.username) {
$p->print_entry_poster($e);
print ": ";
}
print $e.subject;
}
"</h2>\n<div class=\"entry\">\n";
if (defined $e.userpic and (
$*opt_always_userpic
or ($e.poster.username != $p.journal.username and $e.userpic.url != $p.journal.default_pic.url)
or $p.view == "friends"
or $p.view == "entry")) {
"""<img src="$e.userpic.url" """;
"""width="$e.userpic.width" height="$e.userpic.height" """;
"""alt="" align="right" style="margin: 5px;" />\n""";
}
"$e.text";
$e->print_metadata();
"""</div><div class="talklinks">""";
"""<div class="permalink"><a href="$e.permalink_url">$*text_permalink</a></div>&nbsp;""";
$e.comments->print();
"</div>";
"</div>";
} # print_entry(Page,Entry,Color,Color)
function Entry::print_metadata() {
var string caption;
var string val;
var Image i;
if (size $.metadata == 0 and size $.tags == 0) { return; }
println """<div class="metadata">""";
if ($this.tags) {
var int tcount = 0;
"<div class='ljtags'><strong>Tags:</strong> ";
foreach var Tag t ($this.tags) {
"""<a rel="tag" href="$t.url">$t.name</a>""";
$tcount++;
if ($tcount != size $this.tags) { ", "; }
}
"</div>";
}
if (size $.metadata != 0) {
foreach var string k ($.metadata) {
$caption = $k;
$val = $.metadata{$k};
if ($k == "music") {
$caption = $*text_meta_music;
}
elseif ($k == "mood") {
$caption = $*text_meta_mood;
if (defined $.mood_icon) {
$i = $.mood_icon;
$val = """<img src="$i.url" width="$i.width" height="$i.height" align="absmiddle"> $val""";
}
}
println """<div class="metadata-$k"><span style="font-weight: bold;">$caption:</span> $val</div>""";
}
}
println "</div>";
}
function Page::print_entry(Entry e) {
print_entry($this, $e, null Color, null Color);
}
function FriendsPage::print_entry(Entry e) {
var Friend f = $.friends{$e.journal.username};
print_entry($this, $e, $f.bgcolor, $f.fgcolor);
}
function colored_ljuser(UserLite u, Color fg, Color bg) : string {
var Image uiimg = userinfoicon($u);
var string dir = $u.journal_type == "C" ? "community" : "users";
return """<span class="ljuser" style="white-space:nowrap;"><a href="$*SITEROOT/userinfo.bml?user=$u.username" style="color: $fg; background: $bg;"><img src="$uiimg.url" alt="[i]" width="$uiimg.width" height="$uiimg.height" style="vertical-align:bottom;border:0;" /></a><a href="$*SITEROOT/$dir/$u.username/" style="color: $fg; background: $bg; font-weight: bold;">$u.username</a></span>""";
}
function FriendsPage::print_entry_poster(Entry e) {
var Friend f = $.friends{$e.journal.username};
var Color fg; var Color bg;
if ($*opt_friends_colors) {
$fg = $f.fgcolor;
$bg = $f.bgcolor;
} else {
$fg = $*clr_boxhead_text;
$bg = $*clr_boxhead_back;
}
print colored_ljuser($e.poster, $fg, $bg);
if ($e.poster.username != $e.journal.username) {
" posting in ";
print colored_ljuser($e.journal, $fg, $bg);
}
}
function RecentPage::print_body() {
foreach var Entry e ($.entries) {
$this->print_entry($e);
}
}
function CommentInfo::print() {
if ($.enabled) {
$this->print_postlink();
if ($.count > 0 or $.screened) {
" | ";
$this->print_readlink();
}
}
}
function DayPage::print_body() {
println """<h1 style="font-size: 1.5em; text-align: center;">"""+$.date->date_format("long")+"</h1>";
if (not $.has_entries) {
print "<p>$*text_noentries_day</p>";
return;
}
foreach var Entry e ($.entries) {
$this->print_entry($e);
}
}
function EntryPage::print_body() {
$this->print_entry($.entry);
if ($this.multiform_on) {
$this->print_multiform_start();
}
if ($.entry.comments.enabled) {
$this->print_comments($.comments);
}
if ($this.multiform_on) {
"<div class='box'><h2>Mass Action on Selected Comments:</h2>";
"<p class='entry'>"; $this->print_multiform_actionline(); "</p>";
"</div>";
$this->print_multiform_end();
}
}
function EntryPage::print_comments(Comment[] cs) {
if (size $cs == 0) { return; }
print "<div style=\"margin-left: 25px;\">";
foreach var Comment c ($cs) {
var int indent = ($c.depth - 1) * 25;
if ($c.full) {
$this->print_comment($c);
} else {
$this->print_comment_partial($c);
}
}
print "</div>";
}
function EntryPage::print_comment(Comment c) {
var string datetime;
$datetime = $c.time->date_format("med_day")+", "+$c.time->time_format();
"""<a name='$c.anchor'></a><div id="$c.dom_id" class="box"><h3 style="color: $*clr_boxhead_text; background: $*clr_boxhead_back;">""";
if ($c.metadata{"poster_ip"}) { print """<div style="float: right; vertical-align: top; font-size: 0.75em;">(""" +
$c.metadata{"poster_ip"} +
""")</div>"""; }
print $datetime;
if (defined $c.subject_icon) {
print """<img src="$c.subject_icon.url" align="right" """+
"""width="$c.subject_icon.width" height="$c.subject_icon.height" """+
"""alt="" />""";
}
var string poster = defined $c.poster ? $c.poster->as_string() : "<i>(Anonymous)</i>";
print "<br />"+$poster;
if ($c.subject != "") {
print ": "+$c.subject;
}
"</h3>\n<div class=\"entry\">\n";
if (defined $c.userpic and $*comment_userpic_style != "off") {
"""<img src="$c.userpic.url" """;
"""width="$c.userpic.width" height="$c.userpic.height" """;
"""alt="" align="right" style="margin: 5px;" />\n""";
}
"$c.text</div>";
"""<div class="talklinks">""";
"""<div class="permalink"><a href="$c.permalink_url">$*text_permalink</a></div>""";
if ($c.parent_url != "") { """<a href="$c.parent_url">$*text_comment_parent</a> - """; }
if ($c.thread_url != "") { """<a href="$c.thread_url">$*text_comment_thread</a> - """; }
var Link l = new Link;
foreach var string ls ($c.link_keyseq) {
$l = $c->get_link($ls);
if (defined $l) {
println """<a href="$l.url">$*text_comment_links{$ls}</a> - """;
}
}
if (not $c.frozen) {
"""<a href="$c.reply_url">$*text_comment_reply</a>""";
} else {
"""$*text_comment_frozen""";
}
# FIXME: better location?
if ($.multiform_on) {
"""<br /><label for="ljcomsel_$c.talkid">$*text_multiform_check</label> """; $c->print_multiform_check();
}
"</div>";
if ((size $c.replies) > 0 and $c.replies[0].full == false) {
"""<div style="margin-top: 5px; margin-bottom: 5px; clear: both;">\n""";
$this->print_comments($c.replies);
"</div>\n";
}
"</div>";
if ((size $c.replies) > 0 and $c.replies[0].full == true) {
$this->print_comments($c.replies);
}
}
function EntryPage::print_comment_partial(Comment c) {
var string poster = defined $c.poster ? $c.poster->as_string() : "<i>(Anonymous)</i>";
var string subj = $c.subject != "" ? $c.subject : $*text_nosubject;
print """<div class="minicomment"><a href="$c.permalink_url">$subj</a> - $poster</div>""";
$this->print_comments($c.replies);
}
function ReplyPage::print_body() {
var EntryLite c = $.replyto;
var string datetime;
$datetime = $c.time->date_format("med_day")+", "+$c.time->time_format();
"""<div class="box"><h2 style="color: $*clr_boxhead_text; background: $*clr_boxhead_back;">$datetime """;
var string poster = defined $c.poster ? $c.poster->as_string() : "<i>(Anonymous)</i>";
print "<br />"+$poster;
if ($c.subject != "") {
print ": "+$c.subject;
}
"</h2>\n<div class=\"entry\">\n";
if (defined $c.userpic and $*comment_userpic_style != "off") {
"""<img src="$c.userpic.url" """;
"""width="$c.userpic.width" height="$c.userpic.height" """;
"""alt="" align="right" style="margin: 5px;" />\n""";
}
"$c.text</div>";
if (defined $c.userpic and $*comment_userpic_style != "off") {
"""<br clear="all" />""";
}
"</div>";
"""<div class="box" style="margin-left: 25px;">\n""";
$.form->print();
"</div>\n";
}
function YearPage::print_body {
foreach var YearMonth m ($.months) {
$this->print_month($m);
}
}
function YearPage::print_month(YearMonth m) {
if (not $m.has_entries) { return; }
"""<table class="box" style="border-collapse: collapse; border: 1px solid; width: 80%; margin-left: 10%; margin-right: 10%;" border="1">\n
<tr><th colspan="7" style="background: $*clr_boxhead_back; color: $*clr_boxhead_text; text-align: center;">""";
print $m->month_format();
"""</th></tr>\n""";
foreach var int d (weekdays()) {
"<th style=\"width: 14%;\">"+$*lang_dayname_short[$d]+"</th>\n";
}
"</tr>\n";
foreach var YearWeek w ($m.weeks) {
$w->print();
}
"""<tr><td colspan="7" style="text-align: center;">
<a href="$m.url">$*text_view_month</a></td></tr>\n""";
"</table>";
}
function YearWeek::print() {
"""<tr valign="top" style="height: 2.75em;">\n""";
if ($.pre_empty > 0) {
"""<td class="emptyday" colspan="$.pre_empty">&nbsp;</td>\n""";
}
foreach var YearDay d ($.days) {
"""<td>\n""";
"""<div style="text-align: right;">$d.day</div>\n""";
if ($d.num_entries > 0) {
"""<div style="text-align: center;"><a href="$d.url">$d.num_entries</a></div>\n""";
}
"""</td>\n""";
}
if ($.post_empty > 0) {
"""<td colspan="$.post_empty">&nbsp;</td>\n""";
}
"</tr>";
}
function MonthPage::print_body {
"""<div class="box"><h2>"""+$.date->date_format($*lang_fmt_month_long)+"</h2>\n";
"<dl style=\"margin: 1em;\">";
foreach var MonthDay d ($.days) {
if ($d.has_entries) {
"<dt><a href=\"$d.url\"><b>";
print lang_ordinal($d.day);
"</b></a></dt>\n<dd>";
$d->print_subjectlist();
"</dd>\n";
}
}
"</dl>\n</div>\n";
}
### Handler for the theme previews
function print_theme_preview() {
"""
<div style="padding: 1em; background: $*clr_page_back; color: $*clr_page_text;">
<div style="border: 1px solid $*clr_page_text; margin: 1em; background: $*clr_box_back; color: $*clr_box_text;">
<h2 style="color: $*clr_boxhead_text; background: $*clr_boxhead_back; font-size: 1em; padding: 4px; margin: 0;">Cir zuta besho cavu mabu</h2>
<div style="margin: 1em;">
Cir zuta besho cavu mabu. Jad dop fugu hige wiju. Jam nek sapu shek noshea, moz lolle jil hattou daz.
Heck mippe giffou tipe pello, govo goof wachou fenu betui, mumu niffo puffu hivoo ziv! Sap gap jozo vem
sushu jiwo peru diche gese zar. Zuk kah rec sok vapui, mumu. Puw wuti mufe bak jivo, zef kazou gipwew cus.
Cev lepp gik fego rer. Tucku mickou jeck helou soopp! Vowa vov fawea pip wok. Heg fum heafsum pele.
Piz kuzu louw rome puir. Pashi jog huku pobi ckush. Zuj bit wido guih biha. Som veh nelo ruh ruju.
Coosh jecko nuh tutt tab. Zutt ckek vano fic der, hivu?
</div>
<div style="margin: 1em; text-align: right; clear: both;">
<div style="float: left;"><span style="color: #0000ff; text-decoration: underline; cursor: hand;">$*text_permalink</span></div>&nbsp;
</div>
</div>
</div>
""";
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -0,0 +1,75 @@
#NEWLAYER: sturdygesture/beansprout
layerinfo "type" = "theme";
layerinfo "name" = "Beansprout";
layerinfo "redist_uniq" = "sturdygesture/beansprout";
set clr_page_link = "#006760";
set clr_boxhead_text = "#ffffff";
set clr_box_text = "#000000";
set clr_page_text = "#ffffff";
set clr_box_back = "#ffffff";
set clr_boxhead_back = "#006760";
set clr_page_back = "#000000";
set clr_page_vlink = "#002C29";
#NEWLAYER: sturdygesture/boxless
layerinfo "type" = "theme";
layerinfo "name" = "Boxless";
layerinfo "redist_uniq" = "sturdygesture/boxless";
set clr_page_link = "#0000ff";
set clr_boxhead_text = "#ffffff";
set clr_box_text = "#000000";
set clr_page_text = "#ffffff";
set clr_box_back = "#ffffff";
set clr_boxhead_back = "#000000";
set clr_page_back = "#ffffff";
set clr_page_vlink = "#00007f";
#NEWLAYER: sturdygesture/martialblue
layerinfo "type" = "theme";
layerinfo "name" = "Martial Blue";
layerinfo "redist_uniq" = "sturdygesture/martialblue";
set clr_page_link = "#0068CF";
set clr_boxhead_text = "#000000";
set clr_box_text = "#000000";
set clr_page_text = "#000000";
set clr_box_back = "#FFFFFF";
set clr_boxhead_back = "#6FB7FF";
set clr_page_back = "#BFD8FF";
set clr_page_vlink = "#003070";
#NEWLAYER: sturdygesture/redmond
layerinfo "type" = "theme";
layerinfo "name" = "Redmond";
layerinfo "redist_uniq" = "sturdygesture/redmond";
set clr_page_link = "#0000ff";
set clr_boxhead_text = "#ffffff";
set clr_box_text = "#000000";
set clr_page_text = "#000000";
set clr_box_back = "#ffffff";
set clr_boxhead_back = "#00007F";
set clr_page_back = "#007F7F";
set clr_page_vlink = "#0000ff";
#NEWLAYER: sturdygesture/shadesofgray
layerinfo "type" = "theme";
layerinfo "name" = "Shades of Gray"; # or, indeed, "grey" :)
layerinfo "redist_uniq" = "sturdygesture/shadesofgray";
set clr_page_link = "#444444";
set clr_boxhead_text = "#ffffff";
set clr_box_text = "#000000";
set clr_page_text = "#7f7f7f";
set clr_box_back = "#cccccc";
set clr_boxhead_back = "#7f7f7f";
set clr_page_back = "#888888";
set clr_page_vlink = "#222222";

View File

@@ -0,0 +1,14 @@
# -*-s2-*-
layerinfo type = "i18n";
layerinfo name = "English";
layerinfo redist_uniq = "tabularindent/en";
set text_meta_music = "Music";
set text_meta_mood = "Mood";
set text_post_comment = "Add Your Own";
set text_read_comments = "Read # Comments";
set text_post_comment_friends = "Add Your Own";
set text_read_comments_friends = "Read # Comments";

View File

@@ -0,0 +1,741 @@
# -*-s2-*-
layerinfo type = "layout";
layerinfo name = "Tabular Indent";
layerinfo redist_uniq = "tabularindent/layout";
layerinfo previews = "tabularindent/tabularindent.jpg";
propgroup colors {
property Color body_bgcolor {
des = "Body background color";
s1color = "page_back";
}
property Color main_bgcolor {
des = "Background of main text areas";
s1color = "page_back";
}
property Color main_fgcolor {
des = "Main text color";
s1color = "page_text";
}
property Color border_color {
des = "Color of borders";
# No s1color equivalent
}
property Color headerbar_bgcolor {
des = "Background color of header bar(s)";
s1color = "stronger_back";
}
property Color headerbar_fgcolor {
des = "Header bar text color";
s1color = "stronger_text";
}
property Color captionbar_mainbox_bgcolor {
des = "Main background color of caption bar";
s1color = "page_back";
}
property Color captionbar_mainbox_fgcolor {
des = "Text color of caption bar";
s1color = "page_text";
}
property Color captionbar_userpicbox_color {
des = "User picture background color of caption bar";
s1color = "strong_back";
}
property Color accent_bgcolor {
des = "Background color of accented areas";
s1color = "weak_back";
}
property Color accent_fgcolor {
des = "Accented area text color";
s1color = "weak_text";
}
property Color link_color {
des = "Link color";
s1color = "page_link";
}
property Color vlink_color {
des = "Visited link color";
s1color = "page_vlink";
}
property Color alink_color {
des = "Active link color";
s1color = "page_alink";
}
property Color comment_bar_one_bgcolor {
des = "Alternating background color for comment bars (one)";
}
property Color comment_bar_two_fgcolor {
des = "Text color on alternating comment bars (one)";
}
property Color comment_bar_two_bgcolor {
des = "Alternating background color for comment bars (two)";
}
property Color comment_bar_one_fgcolor {
des = "Text color on alternating comment bars (two)";
}
property Color comment_bar_screened_bgcolor {
des = "Background bar color for screened comments";
}
property Color comment_bar_screened_fgcolor {
des = "Text color on background bar for screened comments";
}
}
set body_bgcolor = "#ffffff";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set border_color = "#000000";
set headerbar_bgcolor = "#6666cc";
set headerbar_fgcolor = "#ffffff";
set captionbar_mainbox_bgcolor = "#ffffff";
set captionbar_mainbox_fgcolor = "#000000";
set captionbar_userpicbox_color = "#c0c0ff";
set accent_bgcolor = "#eeeeff";
set accent_fgcolor = "#000000";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#ff00c0";
set comment_bar_one_bgcolor = "#c0c0ff";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#eeeeff";
set comment_bar_two_fgcolor = "#000000";
set comment_bar_screened_bgcolor = "#dddddd";
set comment_bar_screened_fgcolor = "#000000";
propgroup presentation {
property bool show_entry_userpic {
des = "Show the userpic on the journal entries?";
}
property use page_recent_items;
property use page_friends_items;
property use use_shared_pic;
property use view_entry_disabled;
property string page_background_image {
des = "URL to an image to be used for the page background";
}
property use external_stylesheet;
}
set show_entry_userpic = true;
set page_recent_items = 20;
set page_friends_items = 20;
set view_entry_disabled = false;
set page_background_image = "";
propgroup text {
property use text_post_comment;
property use text_read_comments;
property use text_post_comment_friends;
property use text_read_comments_friends;
}
set tags_aware = true;
function Page::lay_captionbar_navigation () { }
function captionbar (Page p) {
var string title = $p->title();
var string userpic;
var Image up_img = $p.journal.default_pic;
if (defined $up_img) {
$userpic = """<img src="$up_img.url" height="$up_img.height" width="$up_img.width" alt="[icon]" />""";
}
var string website_name = $p.journal.website_name ? $p.journal.website_name : $*text_website_default_name;
var string website;
if ($p.journal.website_url != "") {
$website = """<tr><td>View:</td><td><a href="$p.journal.website_url">Website ($website_name)</a>.</td></tr>""";
}
var string links;
foreach var string v ($p.views_order) {
$links = "$links<tr><td>View:</td><td>" + ($p.view == $v ?
lang_viewname($v) :
"<a href='$p.view_url{$v}'>"+lang_viewname($v)+"</a>") + ".</td></tr>\n";
}
var string captionbar_userpicbox_style = "background-color: $*captionbar_userpicbox_color";
"""
<table height='100' class='captionbar' cellpadding='5' cellspacing='1'><tr>
<td class="captionbar-userpicbox" align='center' valign='center' width='100' style='$captionbar_userpicbox_style'>$userpic</td>
<td><b>$title</b><br />
<table border='0'>
$links
$website
<tr>
<td colspan='2'>""";
$p->lay_captionbar_navigation();
"
</td>
</tr>
</table>
</td>
</tr></table>";
}
function print_stylesheet ()
{
var string backgroundurl = clean_url($*page_background_image) != "" ? "background-image: url($*page_background_image);" : "";
"""/* Tabular Indent Stylesheet */
body {
$backgroundurl
background-color: $*body_bgcolor;
}
.captionbar {
width: 100%;
border: 1px solid $*border_color;
}
.captionbar, .captionbar td {
background-color: $*captionbar_mainbox_bgcolor;
color: $*captionbar_mainbox_fgcolor;
}
.captionbar-userpicbox {
border-right: 1px solid $*border_color;
background-color: $*captionbar_userpicbox_color;
color: $*captionbar_mainbox_fgcolor;
}
body,td,p {
font-family: verdana, arial, helvetica, sans-serif;
font-size: 8pt;
}
a {
color: $*link_color;
font-family: verdana, arial, helvetica, sans-serif;
font-size: 8pt;
text-decoration: none;
}
a:visited {
color: $*vlink_color;
font-family: verdana, arial, helvetica, sans-serif;
font-size: 8pt;
text-decoration: none;
}
a:active {
color: $*alink_color;
font-family: verdana, arial, helvetica, sans-serif;
font-size: 8pt;
text-decoration: none;
}
a:hover {
color: $*alink_color;
font-family: verdana, arial, helvetica, sans-serif;
font-size: 8pt;
text-decoration: underline;
}
h3.page-header {
font-size: 8pt;
font-family: verdana, arial, helvetica, sans-serif;
font-weight: normal;
background-color: $*headerbar_bgcolor;
color: $*headerbar_fgcolor;
padding: 6px;
border: 1px solid $*border_color;
}
""";
}
function Page::print ()
{
var string title = $this->title();
println "<html>\n<head>\n";
if ($*external_stylesheet) {
println """<link rel="stylesheet" href="$.stylesheet_url" type="text/css" />""";
} else {
println """<style type="text/css">"""; print_stylesheet(); "</style>";
}
$this->print_head();
"""<title>$title</title>
</head>
<body>
""";
"<p>"; captionbar($this); "</p>";
"<p>"; $this->print_body(); "</p>";
"<p>"; captionbar($this); "</p>";
"""
</body>
</html>
""";
}
function print_box (string{} colors, string metapic, string{} meta, string content, string footer, string domid) {
var string bgcolor = $colors{"bgcolor"};
var string fgcolor = $colors{"fgcolor"};
if ($domid != "") { $domid = "id='$domid'"; }
var string style = "background-color: $bgcolor; color: $fgcolor";
"<div align='right'><table $domid border='0' width='95%' cellpadding='5' cellspacing='1' style='$style'>";
"<tr><td><table border='0' width='100%'><tr>";
if ($metapic) {
"<td width='100' valign='top' align='center'>$metapic</td>";
}
"<td valign='top'><table border='0'>";
foreach var string k ($meta) {
var string key = $k;
var string val = $meta{$k};
"<tr><td align='right'>$key</td><td>$val</td></tr>";
}
"</table></td></tr></table></td></tr>";
"<tr><td style='background-color: $*main_bgcolor; color: $*main_fgcolor'>";
print $content;
"</td></tr>";
if ($footer) {
"<tr><td style='white-space: nowrap'>$footer</td></tr>";
}
"</table></div><br />";
}
function print_header (string header)
{
print "<h3 class='page-header'>$header</h3>";
}
function print_genericbox_open () {
"<div align='right'><table border='0' width='95%' cellpadding='5' cellspacing='1' bgcolor='$*accent_bgcolor'>";
"<tr><td style='background-color: $*main_bgcolor; color: $*main_fgcolor'>";
}
function print_genericbox_close ()
{
"</font></td></tr></table></div><br />";
}
function print_entry (Page p, Entry e, Color bgcolor, Color fgcolor, bool hide_text)
{
var string{} colors; var string{} meta; var string content = ""; var string footer = "";
$colors{"bgcolor"} = "$*accent_bgcolor";
$colors{"fgcolor"} = "$*accent_fgcolor";
if ($p.view == "recent") {
if ($e.new_day) {
print_header($e.time->date_format("%%month%% %%dayord%%, %%yyyy%%"));
}
} else {
print_header($e.time->date_format("%%month%% %%dayord%%, %%yyyy%%"));
}
# Userpic
var string metapic = "";
if ($p.view == "friends" or
$*show_entry_userpic == true or
$e.journal.username != $e.poster.username)
{
var string userpic = defined $e.userpic ? "<img src='$e.userpic.url' style='border: 0' />" : "";
var string url = $e.journal->base_url() + "/";
$metapic = "<div style='background-color: $bgcolor'>";
$metapic = "$metapic <a href='$url'>$userpic</a>";
if ($e.journal.username != $e.poster.username) {
var string purl = $e.poster->base_url() + "/";
$metapic = "$metapic<br /><font color='$fgcolor'>[<a href='$purl'>$e.poster.username</a>]</font>";
}
if ($p.view == "friends") { $metapic = "$metapic<br /><font color='$fgcolor'><a href='$url'>$e.journal.username</a></font>"; }
$metapic = "$metapic</div>";
}
# Security Icon
if ($e.security) {
$meta{"Security:"} = "$e.security_icon $e.security";
}
# Subject
if ($e.subject) {
$meta{"Subject:"} = $e.subject;
}
# Time posted
var string time = $e.time->time_format();
$meta{"Time:"} = $time;
# Current
if (size $e.metadata) {
foreach var string k ($e.metadata) {
var string key = $k; var string val = $e.metadata{$k};
if ($k == "mood") {
$key = $*text_meta_mood;
} elseif ($k == "music") {
$key = $*text_meta_music;
}
if ($k == "mood" and defined $e.mood_icon) {
var Image i = $e.mood_icon;
$val = "<img src='$i.url' width='$i.width' height='$i.height' align='absmiddle' alt='[mood icon]' /> $val";
}
$meta{"$key:"} = $val;
}
}
# Tags
if ($e.tags) {
var int tcount = 0;
var string tag;
foreach var Tag t ($e.tags) {
$tag = $tag + """<a rel="tag" href="$t.url">$t.name</a>""";
$tcount++;
if ($tcount != size $e.tags) { $tag = $tag + ", "; }
}
$meta{"Tags:"} = $tag;
}
if (not $hide_text) { $content = $e.text; }
if ($e.comments.enabled) {
$footer = "comments:";
if (($e.comments.count > 0 or $e.comments.screened) and ($p.view != "entry")) {
$footer = "$footer <a href=\"$e.comments.read_url\">"
+ get_plural_phrase($e.comments.count, $p.view == "friends" ?
"text_read_comments_friends" : "text_read_comments")
+ "</a> or";
}
$footer = "$footer <a href=\"$e.comments.post_url\">"
+ ($p.view == "friends" ? $*text_post_comment_friends : $*text_post_comment)
+ "</a>";
}
# Misc Links
var Link link;
if ($p.view == "entry")
{
$link = $e->get_link("nav_prev"); $footer = "$footer $link";
}
$link = $e->get_link("edit_entry"); $footer = "$footer $link";
$link = $e->get_link("edit_tags"); $footer = "$footer $link";
$link = $e->get_link("tell_friend"); $footer = "$footer $link";
$link = $e->get_link("mem_add"); $footer = "$footer $link";
if ($p.view == "entry")
{
$link = $e->get_link("nav_next"); $footer = "$footer $link";
}
# Print
print_box($colors, $metapic, $meta, $content, $footer, "");
}
function Page::print_entry (Entry e)
{
print_entry($this, $e, null Color, null Color, false);
}
function FriendsPage::print_entry (Entry e) {
var Friend f = $.friends{$e.journal.username};
print_entry($this, $e, $f.bgcolor, $f.fgcolor, false);
}
function RecentPage::lay_captionbar_navigation()
{
var int total = size $.entries;
var string nav = "";
if ($.nav.backward_url != "") {
$nav = """<a href="$.nav.backward_url">back $total entries</a>""";
}
if ($.nav.forward_url != "" and $.nav.backward_url != "") {
$nav = "$nav or ";
}
if ($.nav.forward_url != "") {
$nav = """$nav<a href="$.nav.forward_url">forward $total entries</a>""";
}
print "You're looking at the latest ";
print size $.entries;
print ($.nav.skip > 0) ? " entries, after skipping $.nav.skip newer ones." :" entries.";
if ($nav != "") { print "<br />Missed some entries? Then simply jump $nav"; }
}
function RecentPage::print_body {
foreach var Entry e ($.entries) {
$this->print_entry($e);
}
}
function FriendsPage::print_body {
foreach var Entry e ($.entries) {
$this->print_entry($e);
}
}
function CommentInfo::print()
{
if (not $.enabled) { return; }
"<tr><td bgcolor='$*accent_bgcolor'><font color='$*accent_fgcolor'>";
"<nobr>comments: ";
if ($.count > 0 or $.screened) {
$this->print_readlink(); " or ";
}
$this->print_postlink();
"</nobr></font></td></tr>";
}
function YearPage::print_body {
print_header(string($.year));
print_genericbox_open();
foreach var YearMonth m ($.months) {
$this->print_month($m);
}
print_genericbox_close();
}
function YearPage::lay_captionbar_navigation()
{
$this->print_year_links();
}
function YearPage::print_year_links ()
{
foreach var YearYear y ($.years) {
if ($y.displayed) {
"$y.year&nbsp;";
} else {
"<a href=\"$y.url\">$y.year</a>&nbsp;";
}
}
}
function YearPage::print_month(YearMonth m)
{
if (not $m.has_entries) { return; }
"<center><table border='1' cellpadding='4' width='80%'>";
# Month header
"<tr align='center'><td colspan='7' bgcolor='$*headerbar_bgcolor'>";
"<font color='$*headerbar_fgcolor'><b>"; print $m->month_format(); "</b></font></td></tr>";
# Weekdays
"<tr align='center' bgcolor='$*accent_bgcolor'>";
foreach var int d (weekdays()) {
"<td><font color='$*accent_fgcolor'>"+$*lang_dayname_short[$d]+"</font></td>\n";
}
"</tr>";
foreach var YearWeek w ($m.weeks) {
$w->print();
}
"<tr align='center'><td colspan='7'><a href='$m.url'>View Subjects</a>";
"</td></tr></table></center>";
}
function YearWeek::print () {
"<tr>";
if ($.pre_empty) { "<td colspan='$.pre_empty' bgcolor='$*accent_bgcolor'>&nbsp;</td>"; }
foreach var YearDay d ($.days) {
"<td valign='top'><b>$d.day</b>";
"<div align='center'>";
if ($d.num_entries) {
"""<a href="$d.url">$d.num_entries</a>""";
} else {
"&nbsp;";
}
"</div></td>";
}
if ($.post_empty) { "<td colspan='$.post_empty' bgcolor='$*accent_bgcolor'>&nbsp;</td>"; }
"</tr>";
}
function DayPage::lay_captionbar_navigation()
{
print "Missed some entries? Then simply jump to the <a href='$.prev_url'>previous day</a> or the <a href='$.next_url'>next day</a>.";
}
function DayPage::print_body ()
{
if (not $.has_entries) {
"<table border='0' width='100%' cellpadding='5' cellspacing='1' bgcolor='$*border_color'>";
"<tr><td bgcolor='$*headerbar_bgcolor'><font color='$*headerbar_fgcolor'>";
print $.date->date_format("%%month%% %%dayord%%, %%yyyy%%");
"</font></td></tr></table><br />";
print "No journal entries for this day.";
} else {
foreach var Entry e ($.entries) {
$this->print_entry($e);
}
}
}
function MonthPage::print_body {
print_header($.date->date_format("%%month%% %%yyyy%%"));
print_genericbox_open();
"<form method='post' action='$.redir.url'><center>";
$.redir->print_hiddens();
if ($.prev_url != "") { "[<a href='$.prev_url'>&lt;&lt;&lt;</a>]\n"; }
if (size $.months > 1) {
"<select name='redir_key'>\n";
foreach var MonthEntryInfo mei ($.months) {
var string sel;
if ($mei.date.year == $.date.year and $mei.date.month == $.date.month) {
$sel = " selected='selected'";
}
"<option value='$mei.redir_key'$sel>" + $mei.date->date_format($*lang_fmt_month_long) + "</option>";
}
"</select>\n<input type='submit' value='View' />";
}
if ($.next_url != "") { "\n[<a href='$.next_url'>&gt;&gt;&gt;</a>]\n"; }
"</center></form>\n<dl>";
foreach var MonthDay d ($.days) {
if ($d.has_entries) {
"<dt><a href=\"$d.url\"><b>";
print lang_ordinal($d.day);
"</b></a></dt>\n<dd>";
$d->print_subjectlist();
"</dd>\n";
}
}
"</dl>\n";
print_genericbox_close();
}
function EntryPage::print_body () {
set_handler("unscreen_comment_#", [
[ "style_bgcolor", "cmtbar#", "$*comment_bar_one_bgcolor", ],
[ "style_color", "cmtbar#", "$*comment_bar_one_fgcolor", ],
]);
set_handler("screen_comment_#", [
[ "style_bgcolor", "cmtbar#", "$*comment_bar_screened_bgcolor", ],
[ "style_color", "cmtbar#", "$*comment_bar_screened_fgcolor", ],
]);
print_entry($this, $.entry, null Color, null Color, $.viewing_thread);
if ($.entry.comments.enabled and $.comment_pages.total_subitems > 0)
{
$this->print_multiform_start();
print_header("Comments:");
if ($.comment_pages.total_subitems > 0) {
$.comment_pages->print();
$this->print_comments($.comments);
}
if ($this.multiform_on) {
print_header("Mass Action:");
print_genericbox_open();
$this->print_multiform_actionline();
print_genericbox_close();
$this->print_multiform_end();
}
}
}
function EntryPage::print_comment_partial (Comment c) {
var string poster = defined $c.poster ? $c.poster->as_string() : "<i>(Anonymous)</i>";
var string subj = $c.subject != "" ? $c.subject : $*text_nosubject;
print_genericbox_open();
print "<a href='$c.permalink_url'>$subj</a> - $poster";
print_genericbox_close();
}
function EntryPage::print_comment (Comment c) {
var string{} colors; var string{} meta; var string content = ""; var string footer = "";
if ($c.screened) {
$colors{"bgcolor"} = "$*comment_bar_screened_bgcolor";
$colors{"fgcolor"} = "$*comment_bar_screened_fgcolor";
} elseif ($c.depth % 2) {
$colors{"bgcolor"} = "$*comment_bar_one_bgcolor";
$colors{"fgcolor"} = "$*comment_bar_one_fgcolor";
} else {
$colors{"bgcolor"} = "$*comment_bar_two_bgcolor";
$colors{"fgcolor"} = "$*comment_bar_two_fgcolor";
}
# Userpic
var string poster = defined $c.poster ? $c.poster->as_string() : "<i>(Anonymous)</i>";
var string metapic = "";
if (defined $c.userpic and $*comment_userpic_style != "off")
{
var string userpic = defined $c.userpic ? "<img src='$c.userpic.url' style='border: 0' />" : "";
$metapic = "$userpic<br />$poster";
} else {
$metapic = $poster;
}
# Subject
var string sub_icon;
if (defined $c.subject_icon) {
$sub_icon = $c.subject_icon->as_string();
}
if ($c.subject or $sub_icon) {
$meta{"Subject:"} = "$c.subject $sub_icon";
}
# Time posted
$meta{"Time:"} = $c.time->time_format();
# Link
$meta{"Link:"} = "(<a href='$c.permalink_url'>Link</a>)";
# IP Address:
if ($c.metadata{"poster_ip"}) {
$meta{"IP Address:"} = $c.metadata{"poster_ip"};
}
if ($c.frozen) {
$footer = "(Replies frozen) ";
} else {
$footer = "(<a href='$c.reply_url'>Reply to this</a>) ";
}
if ($c.parent_url != "") { $footer = "$footer (<a href='$c.parent_url'>Parent</a>) "; }
if ($c.thread_url != "") { $footer = "$footer (<a href='$c.thread_url'>Thread</a>) "; }
var Link link = new Link;
foreach var string k ($c.link_keyseq) {
$link = $c->get_link($k); $footer = "$footer $link";
}
println "<a name='$c.anchor'></a>";
print_box($colors, $metapic, $meta, $c.text, $footer, "cmtbar$c.talkid");
}
function ReplyPage::print_body () {
if (not $.entry.comments.enabled)
{
print_header($*text_reply_nocomments_header);
print "<p>$*text_reply_nocomments</p>";
return;
}
var string{} meta; var string metapic;
# Userpic
if (defined $.replyto.userpic and $*comment_userpic_style != "off")
{
$metapic = "<img src='$.replyto.userpic.url' />";
}
# Subject
if ($.replyto.subject) {
$meta{"Subject:"} = $.replyto.subject;
}
# Time posted
$meta{"Time:"} = $.replyto.time->time_format();
print_box({ "bgcolor" => "$*accent_bgcolor", "fgcolor" => "$*accent_fgcolor" },
$metapic, $meta, $.replyto.text, "", "");
print_header("Reply:");
print_genericbox_open();
$.form->print();
print_genericbox_close();
}
function print_theme_preview()
{
"<table width='100%' bgcolor='$*body_bgcolor' cellpadding=10><tr><td>";
"<table border='0' width='100%' cellpadding='5' cellspacing='1' bgcolor='$*border_color'>";
"<tr><td bgcolor='$*headerbar_bgcolor'><font color='$*headerbar_fgcolor'>October 29th, 2003";
"</font></td></tr></table><br />";
"<div align='right'><table border='0' width='95%' cellpadding='5' cellspacing='1' bgcolor='$*accent_bgcolor'>";
"<tr><td align='left' bgcolor='$*accent_bgcolor'>";
"<table border='0' width='100%'><tr>";
"<td valign='top'><table border='0'>";
"<tr><td align='right'><font color='$*accent_fgcolor'>Subject:</font>";
"</td><td><font color='$*accent_fgcolor'>Words Words Words</font></td></tr>";
"<tr><td align='right'><font color='$*accent_fgcolor'>Time:</font></td>";
"<td><font color='$*accent_fgcolor'>1:37 pm</font></td></tr>";
"</table></td></tr></table></td></tr>";
"<tr><td align='left' bgcolor='$*main_bgcolor'><font color='$*main_fgcolor'>Preview text, preview text, etc, etc..... words, words and more words.</font></td></tr>";
"""<tr><td align='left' bgcolor='$*accent_bgcolor'><font color='$*accent_fgcolor'><nobr>comments: <a href="#">20 comments</a> or <a href="#">Leave a comment</a></nobr></font></td></tr>""";
"</table></div><br />";
"</td></tr></table>";
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -0,0 +1,437 @@
#NEWLAYER: tabularindent/shrinkvio
layerinfo type = theme;
layerinfo name = "Shrinking Violet";
layerinfo redist_uniq = "tabularindent/shrinkvio";
set body_bgcolor = "#ad22e7";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set border_color = "#381a45";
set headerbar_bgcolor = "#5d0383";
set headerbar_fgcolor = "#ffffff";
set captionbar_mainbox_bgcolor = "#5d0383";
set captionbar_mainbox_fgcolor = "#ffffff";
set captionbar_userpicbox_color = "#d9a1f1";
set accent_bgcolor = "#d9a1f1";
set accent_fgcolor = "#000000";
set link_color = "#2e053f";
set vlink_color = "#611627";
set alink_color = "#ff00c0";
set comment_bar_one_bgcolor = "#5d0383";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#d9a1f1";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: tabularindent/pistmint
layerinfo type = theme;
layerinfo name = "Pistachio Mint";
layerinfo redist_uniq = "tabularindent/pistmint";
set body_bgcolor = "#133422";
set main_bgcolor = "#a7c4b4";
set main_fgcolor = "#000000";
set border_color = "#096d36";
set headerbar_bgcolor = "#096d36";
set headerbar_fgcolor = "#ffffff";
set captionbar_mainbox_bgcolor = "#096d36";
set captionbar_mainbox_fgcolor = "#ffffff";
set captionbar_userpicbox_color = "#096d36";
set accent_bgcolor = "#096d36";
set accent_fgcolor = "#000000";
set link_color = "#8afabc";
set vlink_color = "#1da65a";
set alink_color = "#f9f5f5";
set comment_bar_one_bgcolor = "#096d36";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#093f36";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: tabularindent/mexicanfood
layerinfo type = theme;
layerinfo name = "Mexican Food";
layerinfo redist_uniq = "tabularindent/mexicanfood";
set body_bgcolor = "#ff0000";
set main_bgcolor = "#f8ff3e";
set main_fgcolor = "#f15601";
set border_color = "#f50701";
set headerbar_bgcolor = "#bdbf3e";
set headerbar_fgcolor = "#ff0000";
set captionbar_mainbox_bgcolor = "#ffc664";
set captionbar_mainbox_fgcolor = "#000000";
set captionbar_userpicbox_color = "#f9ff9d";
set accent_bgcolor = "#e15a18";
set accent_fgcolor = "#ffffff";
set link_color = "#f49e08";
set vlink_color = "#b05403";
set alink_color = "#ff7405";
set comment_bar_one_bgcolor = "#bdbf3e";
set comment_bar_one_fgcolor = "#ff0000";
set comment_bar_two_bgcolor = "#e15a18";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: tabularindent/ashfire
layerinfo type = theme;
layerinfo name = "Ash and Fire";
layerinfo redist_uniq = "tabularindent/ashfire";
set body_bgcolor = "#b5b5b5";
set main_bgcolor = "#ffb6af";
set main_fgcolor = "#000000";
set border_color = "#d90308";
set headerbar_bgcolor = "#e75454";
set headerbar_fgcolor = "#ffffff";
set captionbar_mainbox_bgcolor = "#ff9696";
set captionbar_mainbox_fgcolor = "#ffffff";
set captionbar_userpicbox_color = "#ff1106";
set accent_bgcolor = "#f06c88";
set accent_fgcolor = "#000000";
set link_color = "#f70208";
set vlink_color = "#b0161d";
set alink_color = "#d70106";
set comment_bar_one_bgcolor = "#e75454";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#f06c88";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: tabularindent/desktop
# for layout: 13 (tabularindent/layout)
layerinfo type = theme;
layerinfo name = "Classic Desktop";
layerinfo redist_uniq = "tabularindent/desktop";
set body_bgcolor = "#00545c";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set border_color = "#000000";
set headerbar_bgcolor = "#ff7b05";
set headerbar_fgcolor = "#ffeddd";
set captionbar_mainbox_bgcolor = "#ffffff";
set captionbar_mainbox_fgcolor = "#000000";
set captionbar_userpicbox_color = "#ff7b05";
set accent_bgcolor = "#ffeddd";
set accent_fgcolor = "#000000";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#5a76ff";
set comment_bar_one_bgcolor = "#ff7b05";
set comment_bar_one_fgcolor = "#ffeddd";
set comment_bar_two_bgcolor = "#ffeddd";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: tabularindent/satinhandshake
layerinfo type = theme;
layerinfo name = "Satin Handshake";
layerinfo redist_uniq = "tabularindent/satinhandshake";
set body_bgcolor = "#480c0c";
set main_bgcolor = "#d06464";
set main_fgcolor = "#00001d";
set border_color = "#000000";
set headerbar_bgcolor = "#aaaaaa";
set headerbar_fgcolor = "#000000";
set captionbar_mainbox_bgcolor = "#aaaaaa";
set captionbar_mainbox_fgcolor = "#000000";
set captionbar_userpicbox_color = "#9d0404";
set accent_bgcolor = "#9d0404";
set accent_fgcolor = "#000000";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#ff00c0";
set comment_bar_one_bgcolor = "#aaaaaa";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#9d0404";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: tabularindent/deepmelodrama
layerinfo type = theme;
layerinfo name = "Deep MeloDrama";
layerinfo redist_uniq = "tabularindent/deepmelodrama";
set body_bgcolor = "#872d89";
set main_bgcolor = "#719cff";
set main_fgcolor = "#8e48b2";
set border_color = "#8e48b2";
set headerbar_bgcolor = "#3794b3";
set headerbar_fgcolor = "#84b8e7";
set captionbar_mainbox_bgcolor = "#65b2c1";
set captionbar_mainbox_fgcolor = "#f5d3ff";
set captionbar_userpicbox_color = "#8e48b2";
set accent_bgcolor = "#65b2c1";
set accent_fgcolor = "#f5d3ff";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#dfd3ff";
set comment_bar_one_bgcolor = "#3794b3";
set comment_bar_one_fgcolor = "#84b8e7";
set comment_bar_two_bgcolor = "#65b2c1";
set comment_bar_two_fgcolor = "#f5d3ff";
#NEWLAYER: tabularindent/everwhite
layerinfo type = theme;
layerinfo name = "Everwhite";
layerinfo redist_uniq = "tabularindent/everwhite";
set body_bgcolor = "#ffffff";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set border_color = "#000000";
set headerbar_bgcolor = "#ffffff";
set headerbar_fgcolor = "#000000";
set captionbar_mainbox_bgcolor = "#ffffff";
set captionbar_mainbox_fgcolor = "#000000";
set captionbar_userpicbox_color = "#ffffff";
set accent_bgcolor = "#ffffff";
set accent_fgcolor = "#000000";
set link_color = "#e60000";
set vlink_color = "#c10602";
set alink_color = "#ff0600";
set comment_bar_one_bgcolor = "#dddddd";
set comment_bar_one_fgcolor = "#000000";
set comment_bar_two_bgcolor = "#aaaaaa";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: tabularindent/everblue
layerinfo type = theme;
layerinfo name = "Everblue with Greys";
layerinfo redist_uniq = "tabularindent/everblue";
set body_bgcolor = "#0f0c6d";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set border_color = "#000000";
set headerbar_bgcolor = "#000000";
set headerbar_fgcolor = "#ffffff";
set captionbar_mainbox_bgcolor = "#aaaaaa";
set captionbar_mainbox_fgcolor = "#000000";
set captionbar_userpicbox_color = "#000000";
set accent_bgcolor = "#aaaaaa";
set accent_fgcolor = "#000000";
set link_color = "#2f00f2";
set vlink_color = "#060667";
set alink_color = "#6691ff";
set comment_bar_one_bgcolor = "#000000";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#aaaaaa";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: tabularindent/brownleather
layerinfo type = theme;
layerinfo name = "Brown Leather Coat";
layerinfo redist_uniq = "tabularindent/brownleather";
set body_bgcolor = "#d2b48c";
set main_bgcolor = "#ffebcd";
set main_fgcolor = "#8b4513";
set border_color = "#000000";
set headerbar_bgcolor = "#d48014";
set headerbar_fgcolor = "#ffffff";
set captionbar_mainbox_bgcolor = "#d48014";
set captionbar_mainbox_fgcolor = "#d48014";
set captionbar_userpicbox_color = "#d48014";
set accent_bgcolor = "#ffe1a1";
set accent_fgcolor = "#000000";
set link_color = "#000050";
set vlink_color = "#867a55";
set alink_color = "#fffab3";
set comment_bar_one_bgcolor = "#d48014";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#ffe1a1";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: tabularindent/bruise
layerinfo type = theme;
layerinfo name = "Bruise";
layerinfo redist_uniq = "tabularindent/bruise";
set body_bgcolor = "#000000";
set main_bgcolor = "#bcbcbc";
set main_fgcolor = "#000000";
set border_color = "#000000";
set headerbar_bgcolor = "#1114a0";
set headerbar_fgcolor = "#ffffff";
set captionbar_mainbox_bgcolor = "#21c2f1";
set captionbar_mainbox_fgcolor = "#ffffff";
set captionbar_userpicbox_color = "#1114a0";
set accent_bgcolor = "#21c2f1";
set accent_fgcolor = "#0000ff";
set link_color = "#0000cc";
set vlink_color = "#000088";
set alink_color = "#0000ff";
set comment_bar_one_bgcolor = "#1114a0";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#21c2f1";
set comment_bar_two_fgcolor = "#0000ff";
#NEWLAYER: tabularindent/ranchhand
layerinfo type = theme;
layerinfo name = "Ranch Hand";
layerinfo redist_uniq = "tabularindent/ranchhand";
set body_bgcolor = "#2999c2";
set main_bgcolor = "#cfe0ff";
set main_fgcolor = "#000000";
set border_color = "#060667";
set headerbar_bgcolor = "#54442c";
set headerbar_fgcolor = "#ffffff";
set captionbar_mainbox_bgcolor = "#bababa";
set captionbar_mainbox_fgcolor = "#000000";
set captionbar_userpicbox_color = "#9d995d";
set accent_bgcolor = "#704400";
set accent_fgcolor = "#bababa";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#6a20ff";
set comment_bar_one_bgcolor = "#54442c";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#704400";
set comment_bar_two_fgcolor = "#bababa";
#NEWLAYER: tabularindent/victim
layerinfo type = theme;
layerinfo name = "Victim";
layerinfo redist_uniq = "tabularindent/victim";
set body_bgcolor = "#2cd0ff";
set main_bgcolor = "#505050";
set main_fgcolor = "#ffffff";
set border_color = "#000000";
set headerbar_bgcolor = "#166bac";
set headerbar_fgcolor = "#ffffff";
set captionbar_mainbox_bgcolor = "#2098f3";
set captionbar_mainbox_fgcolor = "#ffffff";
set captionbar_userpicbox_color = "#26b6ff";
set accent_bgcolor = "#353535";
set accent_fgcolor = "#ffffff";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#ff00c0";
set comment_bar_one_bgcolor = "#166bac";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#353535";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: tabularindent/forest
layerinfo type = theme;
layerinfo name = "Forest";
layerinfo redist_uniq = "tabularindent/forest";
set body_bgcolor = "#778e64";
set main_bgcolor = "#9b9ba5";
set main_fgcolor = "#000000";
set border_color = "#ffffff";
set headerbar_bgcolor = "#72784c";
set headerbar_fgcolor = "#ffffff";
set captionbar_mainbox_bgcolor = "#72784c";
set captionbar_mainbox_fgcolor = "#ffffff";
set captionbar_userpicbox_color = "#a0ac62";
set accent_bgcolor = "#73777a";
set accent_fgcolor = "#000000";
set link_color = "#3811e1";
set vlink_color = "#310cbb";
set alink_color = "#4e7bef";
set comment_bar_one_bgcolor = "#72784c";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#73777a";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: tabularindent/drone
layerinfo type = theme;
layerinfo name = "Drone";
layerinfo redist_uniq = "tabularindent/drone";
set body_bgcolor = "#395f82";
set main_bgcolor = "#f9fcfe";
set main_fgcolor = "#000000";
set border_color = "#000000";
set headerbar_bgcolor = "#904094";
set headerbar_fgcolor = "#ffffff";
set captionbar_mainbox_bgcolor = "#f56efc";
set captionbar_mainbox_fgcolor = "#ffffff";
set captionbar_userpicbox_color = "#ff93ff";
set accent_bgcolor = "#eeeeff";
set accent_fgcolor = "#000000";
set link_color = "#395f82";
set vlink_color = "#395f82";
set alink_color = "#5266ce";
set comment_bar_one_bgcolor = "#904094";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#eeeeff";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: tabularindent/lowercurtain
layerinfo type = theme;
layerinfo name = "Lower the Curtain";
layerinfo redist_uniq = "tabularindent/lowercurtain";
set body_bgcolor = "#000000";
set main_bgcolor = "#6b6b6b";
set main_fgcolor = "#ffffff";
set border_color = "#ffffff";
set headerbar_bgcolor = "#363636";
set headerbar_fgcolor = "#f0f5fb";
set captionbar_mainbox_bgcolor = "#c6c6c6";
set captionbar_mainbox_fgcolor = "#222222";
set captionbar_userpicbox_color = "#363636";
set accent_bgcolor = "#c5c8ca";
set accent_fgcolor = "#000000";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#3314ba";
set comment_bar_one_bgcolor = "#363636";
set comment_bar_one_fgcolor = "#f0f5fb";
set comment_bar_two_bgcolor = "#c5c8ca";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: tabularindent/sunny
layerinfo type = theme;
layerinfo name = "Sunny Day";
layerinfo redist_uniq = "tabularindent/sunny";
set body_bgcolor = "#55e0f9";
set main_bgcolor = "#e38202";
set main_fgcolor = "#ffffff";
set border_color = "#000000";
set headerbar_bgcolor = "#e38202";
set headerbar_fgcolor = "#ffffff";
set captionbar_mainbox_bgcolor = "#fff505";
set captionbar_mainbox_fgcolor = "#ffffff";
set captionbar_userpicbox_color = "#efe052";
set accent_bgcolor = "#ffba03";
set accent_fgcolor = "#ffffff";
set link_color = "#df0d12";
set vlink_color = "#ac1b25";
set alink_color = "#fe3b3b";
set comment_bar_one_bgcolor = "#ffba03";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#ffba36";
set comment_bar_two_fgcolor = "#ffffff";
#NEWLAYER: tabularindent/valentine
layerinfo type = theme;
layerinfo name = "Be Mine";
layerinfo redist_uniq = "tabularindent/valentine";
set body_bgcolor = "#6f104a";
set main_bgcolor = "#f2bce9";
set main_fgcolor = "#000000";
set border_color = "#ff24ab";
set headerbar_bgcolor = "#ff37ff";
set headerbar_fgcolor = "#ffffff";
set captionbar_mainbox_bgcolor = "#df2096";
set captionbar_mainbox_fgcolor = "#ffffff";
set captionbar_userpicbox_color = "#ae1774";
set accent_bgcolor = "#df2096";
set accent_fgcolor = "#000000";
set link_color = "#ffffff";
set vlink_color = "#a51014";
set alink_color = "#ed8188";
set comment_bar_one_bgcolor = "#ff37ff";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#df2096";
set comment_bar_two_fgcolor = "#000000";
#NEWLAYER: tabularindent/stripes
layerinfo type = theme;
layerinfo name = "Stripes";
layerinfo redist_uniq = "tabularindent/stripes";
set body_bgcolor = "#ffffff";
set main_bgcolor = "#ffffff";
set main_fgcolor = "#000000";
set border_color = "#ff0000";
set headerbar_bgcolor = "#e7212a";
set headerbar_fgcolor = "#ffffff";
set captionbar_mainbox_bgcolor = "#ffffff";
set captionbar_mainbox_fgcolor = "#000000";
set captionbar_userpicbox_color = "#ffffff";
set accent_bgcolor = "#ffcfdc";
set accent_fgcolor = "#000000";
set link_color = "#000050";
set vlink_color = "#500050";
set alink_color = "#ffafc1";
set comment_bar_one_bgcolor = "#e7212a";
set comment_bar_one_fgcolor = "#ffffff";
set comment_bar_two_bgcolor = "#ffcfdc";
set comment_bar_two_fgcolor = "#000000";

View File

@@ -0,0 +1,967 @@
layerinfo "type" = "layout";
layerinfo "name" = "Variable Flow";
layerinfo "author_name" = "Martin Atkins";
layerinfo "des" = "A really simple layout that you can customize like crazy!";
layerinfo "redist_uniq" = "variableflow/layout";
layerinfo "previews" = "variableflow/preview.jpg";
# Originally known as "Cleanly Shaven"
#
# This layout is full of customization options, and is designed
# with code overrides in mind.
# It also uses meaningful markup an CSS, for those who like that
# sort of thing. If you like, you can override the stylesheet
# completely in your user layer to drastically change the
# presentation.
propgroup colors {
property Color clr_margin {
des = "Page Background Color";
}
property Color clr_line {
des = "Color of line separating the entry area from the background";
requires = "opt_page_border";
}
property Color clr_back {
des = "Background Color of Main Content Area";
requires = "opt_page_background";
}
property Color clr_text {
des = "Main Text Color";
}
property Color clr_link {
des = "Color of normal links";
}
property Color clr_vlink {
des = "Color of visited links";
}
property Color clr_alink {
des = "Color of links once clicked on";
}
property Color clr_title {
des = "Journal Title Color";
}
set clr_margin = "#337CCD";
set clr_line = "#000000";
set clr_back = "#33ABCD";
set clr_text = "#000000";
set clr_link = "#261A72";
set clr_vlink = "#190F57";
set clr_alink = "#261A72";
set clr_title = "#190F57";
}
propgroup layout {
property string margin_left {
des = "Page Left Margin Size";
values = "0|None|5px|Tiny|5%|Small|10%|Medium|25%|Large|50%|Massive";
}
property string margin_right {
des = "Page Right Margin Size";
values = "0|None|5px|Tiny|5%|Small|10%|Medium|25%|Large|50%|Massive";
}
property string margin_top {
des = "Page Top Margin Size";
values = "0|None|5px|Tiny|5%|Small|10%|Medium|25%|Large|50%|Massive";
}
property string margin_bottom {
des = "Page Bottom Margin Size";
values = "0|None|5px|Tiny|5%|Small|10%|Medium|25%|Large|50%|Massive";
}
set margin_left = "25%";
set margin_right = "25%";
set margin_top = "5px";
set margin_bottom = "5px";
property string padding_left {
des = "Page Left Inner Padding Size";
values = "0|None|5px|Tiny|5%|Small|10%|Medium|25%|Large|50%|Massive";
}
property string padding_right {
des = "Page Right Inner Padding Size";
values = "0|None|5px|Tiny|5%|Small|10%|Medium|25%|Large|50%|Massive";
}
property string padding_top {
des = "Page Top Inner Padding Size";
values = "0|None|5px|Tiny|5%|Small|10%|Medium|25%|Large|50%|Massive";
}
property string padding_bottom {
des = "Page Bottom Inner Padding Size";
values = "0|None|5px|Tiny|5%|Small|10%|Medium|25%|Large|50%|Massive";
}
set padding_left = "5px";
set padding_right = "5px";
set padding_top = "5px";
set padding_bottom = "5px";
property string align_viewlinks {
des = "Position of links to other journal views";
values = "left|Left|right|Right|center|Center";
}
property string align_title {
des = "Position of journal title";
values = "left|Left|right|Right|center|Center";
}
property string align_talklinks {
des = "Position of comment links";
values = "left|Left|right|Right|center|Center";
}
set align_viewlinks = "right";
set align_title = "left";
set align_talklinks = "right";
# Some "advanced" settings which don't appear in the UI,
# either because they have non-obvious interactions with
# other properties or they have issues in certain browsers.
property string adv_page_max_width {
des = "Maximum Width of Content Area";
note = "If you set this, you should also set margin_left and/or margin_right to 'auto'. Internet Explorer 6 does not support this property.";
noui = 1;
}
property string adv_entry_max_width {
des = "Maximum Width of Entry Text";
note = "Internet Explorer 6 does not support this property, and will present entries full-width.";
noui = 1;
}
property bool adv_enable_print_styles {
des = "Enable Print Stylesheet";
note = "If you disable this, your journal views may be unsuitable for printing.";
noui = 1;
}
property bool adv_enable_projection_styles {
des = "Enable Projection Stylesheet";
note = "With this enabled, browsers which support projection stylesheets will see a different stylesheet.";
noui = 1;
}
property bool adv_horrible_userpic_markup {
des = "Enable horrible userpic markup";
note = "With this enabled, the layout will use a table hack to present userpics. With it disabled, the userpics will just be shown raw with class userpic. You'll have to add your own stylesheet rules for them.";
# See the comment within Page::print_entry for more details
noui = 1;
}
set adv_page_max_width = "";
set adv_entry_max_width = "";
set adv_enable_print_styles = true;
set adv_enable_projection_styles = true;
set adv_horrible_userpic_markup = true;
}
propgroup presentation {
property use font_base;
property use font_fallback;
property string font_size {
des = "Size of text";
values = "0.75em|Tiny|1em|Normal|1.1em|Large";
}
set font_size = "0.75em";
property bool opt_page_border {
des = "Draw Line Around Content Box";
note = "With this disabled, the line color option has no effect";
}
property bool opt_page_background {
des = "Content Box has Background";
note = "With this disabled, the Content Box Background Color and Image options have no effect and the page background will show through instead.";
}
set opt_page_border = true;
set opt_page_background = true;
property string url_background_img_page {
des = "Page Background Image URL";
note = "Leave this blank if you do not wish to use a background image.";
palimg_transform = "tint;*clr_back"; # Doesn't do anything right now
}
set url_background_img_page = "";
property string background_properties_page {
des = "Page Background Image Display Options";
values = "scroll|Scrolling, Tiled|scroll no-repeat|Scrolling, No repeat|scroll repeat-x|Scrolling, tile horizontally|scroll repeat-y|Scrolling, tile vertically|fixed|Fixed, Tiled|fixed no-repeat|Fixed, No repeat|fixed repeat-x|Fixed, tile horizontally|fixed repeat-y|Fixed, tile vertically";
requires = "url_background_img_page";
}
set background_properties_page = "scroll";
property string background_position_page {
des = "Page Background Position";
values = "center|Centered|center left|Centered Vertically, Left|center right|Centered Vertically, Right|top center|Top, Centered Horizontally|top left|Top, Left|top right|Top, Right|bottom center|Bottom, Centered Horizontally|bottom left|Bottom, Left|bottom right|Bottom, Right";
requires = "url_background_img_page";
}
set background_position_page = "top left";
property string url_background_img_box {
des = "Content Box Background Image URL";
note = "Leave this blank if you do not wish to use a background image.";
palimg_transform = "tint;*clr_back"; # Doesn't do anything right now
requires = "opt_page_background";
}
set url_background_img_box = "";
property string background_properties_box {
des = "Content Box Background Image Display Options";
values = "scroll|Scrolling, Tiled|scroll no-repeat|Scrolling, No repeat|scroll repeat-x|Scrolling, tile horizontally|scroll repeat-y|Scrolling, tile vertically|fixed|Fixed, Tiled|fixed no-repeat|Fixed, No repeat|fixed repeat-x|Fixed, tile horizontally|fixed repeat-y|Fixed, tile vertically";
requires = "opt_page_background,url_background_img_box";
}
set background_properties_box = "scroll";
property string background_position_box {
des = "Content Box Background Position";
values = "center|Centered|center left|Centered Vertically, Left|center right|Centered Vertically, Right|top center|Top, Centered Horizontally|top left|Top, Left|top right|Top, Right|bottom center|Bottom, Centered Horizontally|bottom left|Bottom, Left|bottom right|Bottom, Right";
requires = "opt_page_background,url_background_img_box";
}
set background_position_box = "top left";
property bool opt_entry_userpics {
des = "Enable Userpics On Entries";
note = "With this disabled, no entries will show userpics, even on the friends page.";
}
set opt_entry_userpics = true;
property bool opt_own_userpics {
des = "Show Own Userpics";
note = "Enable this to show userpics on your own entries. You must also have the previous option enabled. This option has no effect on community journals.";
requires = "opt_entry_userpics";
}
set opt_own_userpics = false;
# This layout has quite a big stylesheet so let's avoid
# transferring it over and over.
set external_stylesheet = true;
# No good support for EntryPage/ReplyPage yet
set view_entry_disabled = true;
}
propgroup options {
# Some standard constructional properties
property use page_recent_items;
property use page_friends_items;
property use page_year_sortorder;
property use page_day_sortorder;
# Tell the system this layout has no linklist support
# If you add linklist support in a user layer, you should also
# set this property to true in your layer.
set linklist_support = false;
}
propgroup text {
property use text_post_comment;
property use text_read_comments;
property use text_post_comment_friends;
property use text_read_comments_friends;
}
function makefontspec() : string
"Forms a CSS 'font-family' value based on the font-related properties."
{
var string fontspec;
if ($*font_base != "") {
$fontspec="\""+$*font_base+"\"";
if ($*font_fallback != "") {
$fontspec=$fontspec+",";
}
}
$fontspec=$fontspec+$*font_fallback;
return $fontspec;
}
function Page::lay_print_viewlinks()
"If you override this, be sure to still use foreach or your style won't support any future views."
{
# Output a list of textual links in a particular order
var bool first = true;
"<ul class=\"navbar\">\n";
foreach var string vl ($.views_order) {
if ($vl == $.view) {
print "<li class=\"active\">"+lang_viewname($vl)+"</li>\n";
} else {
print "<li><a href=\""+ehtml($.view_url{$vl})+"\">"+lang_viewname($vl)+"</a></li>\n";
}
$first = false;
}
"</ul>\n";
}
function Page::lay_print_heading()
"This can be overridden to change the main page titles to something else."
{
"""<h1>"""+$.global_title+"""</h1>
<div id="viewtitle">""";
if ($.view == "recent" and $.global_subtitle != "") {
print $.global_subtitle;
} else {
print $this->view_title();
}
println """</div>""";
}
function Page::print() {
"""<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
<html>
<head>
<title>"""+$this->title()+"""</title>
""";
if ($*external_stylesheet) {
println """<link rel="stylesheet" href="$.stylesheet_url" type="text/css" />""";
}
else {
println """<style type="text/css">""";
print_stylesheet();
println """</style>""";
}
$this->print_head();
"""
</head>
<body class="$.view">
<div id="page">
"""; $this->lay_print_viewlinks(); """
<div id="title">
"""; $this->lay_print_heading(); """
</div>
"""; $this->print_body(); """
<div id="serversig" style="margin-top: 3em; text-align: center;">"""; server_sig(); """</div>
</div>
</body>
</html>""";
}
function lang_skipped_back(RecentNav nav) : string
"Return short text saying how many entries have been skipped back. i18n layers should override this."
{
return "Skipped Back $nav.skip";
}
## The properties for these links are currently broken
## in core - they were never updated to work with lang_map_plural.
# So, FIXME: When core does them right, remove the hardcoded English
function RecentPage::lay_print_skiplinks() {
if ($.nav.backward_url != "" or $.nav.forward_url != "") {
println """<ul class="viewspecnavbar">""";
if ($.nav.backward_url) {
println """<li><a href="$.nav.backward_url">Previous $.nav.backward_count</a></li>""";
}
if ($.nav.skip > 0) {
println "<li>"+lang_skipped_back($.nav)+"</li>";
}
if ($.nav.forward_url) {
println """<li><a href="$.nav.forward_url">Next $.nav.forward_count</a></li>""";
}
println "</ul>";
}
}
function RecentPage::print_body() {
$this->lay_print_skiplinks();
foreach var Entry e ($.entries) {
if ($e.new_day) {
"""<div class="day" id="day"""+$e.time->date_format("%%yyyy%%%%mm%%%%dd%%")+"\">\n";
}
# Print the entry
$this->print_entry($e);
if ($e.end_day) {
"</div>";
}
}
if (size $.entries > 0) {
$this->lay_print_skiplinks();
}
}
function DayPage::print_body() {
"""<ul class="viewspecnavbar">\n""";
"<li><a href=\"$.prev_url\">$*text_day_prev</a></li>\n";
"<li><a href=\"$.next_url\">$*text_day_next</a></li>\n</ul>";
if ($.has_entries) {
"<div class=\"day\" id=\"dayyymmmmmdddd\">\n";
foreach var Entry e ($.entries) {
$this->print_entry($e);
}
"</div>";
"<div class=\"skiplinks\">\n";
"<a href=\"$.prev_url\">$*text_day_prev</a> - ";
"<a href=\"$.next_url\">$*text_day_next</a>\n</div>";
} else {
"<p>$*text_noentries_day</p>";
}
}
## YearPage Stuff
function YearPage::print_body {
$this->print_year_links();
println """<div id="calendarmonthcontainer">""";
foreach var YearMonth m ($.months) {
$this->print_month($m);
}
println "</div>";
}
function YearPage::print_year_links() {
"""<ul class="viewspecnavbar">\n""";
foreach var YearYear y ($.years) {
if ($y.displayed) {
"""<li class="active">$y.year</li>\n""";
} else {
"""<li><a href="$y.url">$y.year</a></li>\n""";
}
}
"""</ul>\n""";
}
function YearPage::print_month(YearMonth m) {
if (not $m.has_entries) { return; }
"""<table class="calendarmonth">\n
<tr><th colspan="7" style="text-align: center;">""";
print "<h2>"+$m->month_format()+"</h2>\n";
"""</th></tr>\n""";
foreach var int d (weekdays()) {
"<th>"+$*lang_dayname_short[$d]+"</th>\n";
}
"</tr>\n";
foreach var YearWeek w ($m.weeks) {
$w->print();
}
"""<tr><td colspan="7" style="text-align: center;" class="calendarmonthlink">
<a href="$m.url">$*text_view_month</a></td></tr>\n""";
"</table>";
}
function YearWeek::print() {
"""<tr valign="top" style="height: 3em;">\n""";
if ($.pre_empty > 0) {
"""<td class="emptyday" colspan="$.pre_empty">&nbsp;</td>\n""";
}
foreach var YearDay d ($.days) {
"""<td class="calendarday">\n""";
"""<div style="text-align: right;">$d.day</div>\n""";
if ($d.num_entries > 0) {
"""<div style="text-align: center;"><a href="$d.url">$d.num_entries</a></div>\n""";
}
"""</td>\n""";
}
if ($.post_empty > 0) {
"""<td colspan="$.post_empty">&nbsp;</td>\n""";
}
"</tr>";
}
function metadata_title(string which) : string
"Until core provides a function for this, i18n layers should override this."
{
if ($which == "music") {
return "Current Music";
}
elseif ($which == "mood") {
return "Current Mood";
}
else {
return $which;
}
}
# Since there's currently no trusted print_entry_text function
# in core, I have to do this here. Later, when something similar
# is added to core, this can become a wrapper and be deprecated.
function Page::lay_print_entry_text(Entry e) [fixed]
"Don't override this. All it does is print the entry text."
{
print $e.text;
}
# Since the metadata keys have to be hardcoded (bad core design)
# let's separate this out so people can override print_entry
# and still get any new metadata added later.
function Page::lay_print_entry_metadata(Entry e)
"Overriding this is strongly discouraged, since if any new entry metadata is added in the future your overridden version will not support it."
{
if (size $e.metadata > 0) {
# This is horrible and unextensible. We have core to thank.
# C'est la vie.
"<div class=\"metadata\">\n";
if ($e.metadata{"music"} != "") {
"""<div class="currentmusic"><span class="metacaption">"""+metadata_title("music") + ":</span> " +
$e.metadata{"music"}+"</div>\n";
}
if ($e.metadata{"mood"} != "") {
"""<div class="currentmood"><span class="metacaption">"""+metadata_title("mood") + ":</span> ";
if (defined $e.mood_icon) {
print $e.mood_icon->as_string()+" ";
}
print $e.metadata{"mood"}+"</div>\n";
}
"</div>\n";
}
}
function Page::print_entry(Entry e) {
"""<div class="entry" id="entry$e.itemid">\n""";
var bool altposter = $e.poster.username != $e.journal.username;
var bool showpic = $*opt_entry_userpics and (($.view == "friends" or $altposter) or $*opt_own_userpics);
# By default, this layout uses an ugly table hack to present the userpic
# alongside the entry. This is because I've been bitten on many previous
# occasions by a bug with floats in IE causing text to vanish in certain
# cases. You can set the property adv_horrible_userpic_markup to false
# in a user layer to disable this behavior, but there are no CSS rules
# in the stock stylesheet to handle it, so you'll have to supply your
# own.
if ($showpic) {
if ($*adv_horrible_userpic_markup) {
"""<table cellpadding="0" border="0" cellspacing="0" style="margin: 0;" class="uglykludgeuserpic">
<tr valign="top">
<td style="text-align: center;" width="105">""";
}
if (defined $e.userpic) {
println """<img src="$e.userpic.url" width="$e.userpic.width" width="$e.userpic.height" alt="" class="userpic" />""";
} else {
if ($*adv_horrible_userpic_markup) {
print "&nbsp;";
}
}
if ($*adv_horrible_userpic_markup) {
"</td><td>";
}
}
"""<h2 class="entryheading">""";
if ($.view != "day") {
print $e.time->date_format()+" ";
}
print $e.time->time_format();
if ($.view == "friends") {
" - "; $this->print_entry_poster($e);
}
elseif ($altposter) {
" - " + $e.poster->as_string();
}
if ($e.security != "") {
" - " + $e.security_icon->as_string();
}
if ($e.subject != "") {
" - $e.subject";
}
"</h2>\n"; $this->lay_print_entry_text($e);
$this->lay_print_entry_metadata($e);
if ($showpic and $*adv_horrible_userpic_markup) {
"</td></tr></table>";
}
$e.comments->print();
"</div>";
}
function CommentInfo::print {
if (not $.enabled) { return; }
"""<ul class="entryextra">""";
if ($.count > 0) {
print """<li class="entryreadlink">""";
$this->print_readlink();
println "</li>";
}
print """<li class="entrypostlink">""";
$this->print_postlink();
print "</li>";
"</ul>";
}
function EntryPage::print_comment (Comment c) {
var Color barlight = $*color_comment_bar->clone();
$barlight->lightness(($barlight->lightness() + 255) / 2);
var string poster = defined $c.poster ? $c.poster->as_string() : "<i>(Anonymous)</i>";
"<div style='margin-top: 10px; padding: 2px'>";
"<table summary='0' style='width: 100%;'><tr valign='top'>";
if (defined $c.userpic and $*comment_userpic_style != "off") {
var int w = $c.userpic.width;
var int h = $c.userpic.height;
# WARNING: this will later be done by the system (it'll be a
# constructional property), so don't copy this hack into your
# layout layers or you'll be messed up later.
$w = $w / 2;
$h = $h / 2;
print "<td><img src='$c.userpic.url' width='$w' height='$h' alt='' /></td>";
}
"<td align='left'>";
if (defined $c.subject_icon or $c.subject != "") { "<h3>$c.subject_icon $c.subject</h3>\n"; }
print "<strong>$*text_comment_from</strong> $poster<br />\n";
print "<strong>$*text_comment_date</strong> ";
print $c.time->date_format("long") + " - " + $c.time->time_format();
if ($c.metadata{"poster_ip"}) { print " ($*text_comment_ipaddr " + $c.metadata{"poster_ip"} + ")"; }
print " <strong>(<a href='$c.permalink_url'>$*text_permalink</a>)</strong>\n";
var Link link;
foreach var string s (["delete_comment", "screen_comment", "unscreen_comment"]) {
}
$link = $c->get_link("delete_comment"); " $link";
$link = $c->get_link("screen_comment"); " $link";
$link = $c->get_link("unscreen_comment"); " $link";
if ($this.multiform_on) {
" <label for='ljcomsel_$c.talkid'>$*text_multiform_check</label> ";
$c->print_multiform_check();
}
print "</td></tr></table></div>";
print "<div style='margin-left: 5px'>$c.text</div>\n";
print "<div style='margin-top: 3px; font-size: smaller'>(<a href='$c.reply_url'>$*text_comment_reply</a>) ";
if ($c.parent_url != "") { "(<a href='$c.parent_url'>$*text_comment_parent</a>) "; }
if ($c.thread_url != "") { "(<a href='$c.thread_url'>$*text_comment_thread</a>) "; }
"</div>\n";
}
function css_rule_if_set(string prop, string val)
"Print a CSS rule only if val is not an empty string."
{
if ($val != "") {
println " $prop: $val;";
}
}
function custom_stylesheet()
"Override this in your user layer to add new stuff to the stylesheet"
{
# None, by default
}
function print_stylesheet_for_printing()
"If you have printing styles enabled, you can override this function to change how the page is styled for printing."
{
""" body, #page, a, a:link, a:visited, a:active, a:hover, #title, h2 {
background: #ffffff;
color: #000000;
}
body {
margin-top: 1em;
margin-bottom: 1em;
font-size: 12pt;
margin-left: auto;
margin-right: auto;
font-family: "Garamond", "Palatino", "Palatino Linotype", serif;
max-width: 15cm;
}
h1, h2, h3, h4, h5, h6, #title #viewtitle {
font-family: "Frutiger", "Frutiger Linotype", "Helvetica", sans-serif;
page-break-after: avoid;
}
.entry {
page-break-inside: avoid;
text-align: justify;
}
.calendarmonth {
page-break-inside: avoid;
}
#page {
border: 0;
margin: 0;
}
.navbar, .entryextra, .viewspecnavbar {
display: none;
}
#title {
display: block;
}
#title h1, #title #viewtitle {
display: inline;
}
#title #viewtitle {
margin-left: 2em;
font-style: italic;
}
""";
}
function print_stylesheet_for_projection()
"If you have projection styles enabled, you can override this function to change how the page is styled for projection."
{
var string background_body = $*clr_margin;
if ($*url_background_img_page != "" and not $*url_background_img_page->contains(")")) {
$background_body = $background_body + " url($*url_background_img_page)";
if (not $*background_properties_page->contains(";")) {
$background_body = $background_body + " $*background_properties_page";
}
}
else {
$background_body = $background_body + " none";
}
var string background_page = $*clr_back;
if ($*url_background_img_box != "" and not $*url_background_img_box->contains(")")) {
$background_page = $background_page + " url($*url_background_img_box)";
if (not $*background_properties_box->contains(";")) {
$background_page = $background_page + " $*background_properties_box";
}
}
else {
$background_page = $background_page + " none";
}
""" #page {
margin: 10px;
padding: 0;
border: 0;
font-size: 2em;
}
body {
background: $background_body;
color: $*clr_text;
}
.navbar, .viewspecnavbar { display: none; }
.entry, #title {
page-break-after: always;
margin: auto;
padding: 10px;
position: absolute;
top: 10px;
bottom: 10px;
left: 10px;
right: 10px;
""";
if ($*opt_page_border) {
println """ border: 1px solid $*clr_line;""";
}
if ($*opt_page_background) {
println """ background: $background_page;""";
}
" }\n";
}
function print_stylesheet() {
var string fontspec=makefontspec();
if ($fontspec != "") {
$fontspec=" font-family: $fontspec;";
}
var string eextrastyle="";
if ($*align_talklinks != "right") {
$eextrastyle=$eextrastyle+
""".entryextra:after { content: " :."; }\n""";
}
if ($*align_talklinks != "left") {
$eextrastyle=$eextrastyle+
""".entryextra:before { content: ".: "; }\n""";
}
$eextrastyle=$eextrastyle+
""".entryextra { text-align: $*align_talklinks; font-size: 0.9em; }""";
# This tries to do a bit of "sanity" checking to ensure users
# don't inadvertently break the CSS, but it's not brilliant.
var string background_body = $*clr_margin;
if ($*url_background_img_page != "" and not $*url_background_img_page->contains(")")) {
$background_body = $background_body + " url($*url_background_img_page)";
if (not $*background_properties_page->contains(";")) {
$background_body = $background_body + " $*background_properties_page";
}
if (not $*background_position_page->contains(";")) {
$background_body = $background_body + " $*background_position_page";
}
}
else {
$background_body = $background_body + " none";
}
var string background_page = $*clr_back;
if ($*url_background_img_box != "" and not $*url_background_img_box->contains(")")) {
$background_page = $background_page + " url($*url_background_img_box)";
if (not $*background_properties_box->contains(";")) {
$background_page = $background_page + " $*background_properties_box";
}
if (not $*background_position_box->contains(";")) {
$background_page = $background_page + " $*background_position_box";
}
}
else {
$background_page = $background_page + " none";
}
"""
body {
margin: 0;
padding: 0;
border: 0;
background: $background_body;
color: $*clr_text;
$fontspec font-size: $*font_size;
}
table, tr, td, th {
font-size: 1em;
}
#page {
""";
css_rule_if_set("margin-left", $*margin_left);
css_rule_if_set("margin-right", $*margin_right);
css_rule_if_set("margin-top", $*margin_top);
css_rule_if_set("margin-bottom", $*margin_bottom);
css_rule_if_set("padding-left", $*padding_left);
css_rule_if_set("padding-right", $*padding_right);
css_rule_if_set("padding-top", $*padding_top);
css_rule_if_set("padding-bottom", $*padding_bottom);
css_rule_if_set("max-width", $*adv_page_max_width);
if ($*opt_page_border) {
println """ border: 1px solid $*clr_line;""";
}
if ($*opt_page_background) {
println """ background: $background_page;""";
}
"""
}
#title h1 {
font-size: 1.4em;
font-weight: bold;
text-align: $*align_title;
margin: 0;
}
#title #viewtitle {
font-size: 1.1em;
font-weight: bold;
text-align: $*align_title;
margin: 0;
}
.navbar {
text-align: $*align_viewlinks;
list-style: none;
padding: 0;
margin: 0;
display: block;
}
.viewspecnavbar {
text-align: center;
list-style: none;
padding: 0;
margin: 0;
display: block;
margin-top: 1em;
margin-bottom: 1em;
}
.navbar li { display: inline; white-space: nowrap; }
.navbar li.active { display: inline; }
.navbar li:before { content: " :: "; }
.navbar li:first-child:before { content: ""; }
.viewspecnavbar li { display: inline; white-space: nowrap; }
.viewspecnavbar li.active { display: inline; }
.viewspecnavbar li:before { content: " :: "; }
.viewspecnavbar li:first-child:before { content: ""; }
#title {
margin-top: 3em;
margin-bottom: 0.5em;
color: $*clr_title;
background: transparent;
}
a:link { color: $*clr_link; background: transparent; }
a:visited { color: $*clr_vlink; background: transparent; }
a:active, a:hover { color: $*clr_alink; background: transparent; }
.entry {
margin-bottom: 4em;
}
.entryheading {
font-weight: bold; font-size: 1.0em;
}
.entrytext {
"""; css_rule_if_set("max-width", $*adv_entry_max_width);
""" margin-left: auto;
margin-right: auto;
}
.entry .metadata {
margin-top: 0.5em;
margin-bottom: 0;
margin-left: 0;
margin-right: 0;
}
.entryextra {
list-style: none;
padding: 0;
margin-left: 0;
margin-right: 0;
display: block;
}
.entryextra li {
display: inline;
}
.entryextra li.entryreadlink:after {
content: " :: ";
}
.entryextra li.entryreadlink {
font-weight: bold;
}
$eextrastyle
/* IE hack - center the block with text-align! */
.calendarmonthcontainer {
text-align: center;
}
.calendarmonth {
margin-top: 2em;
margin-bottom: 2em;
margin-left: auto;
margin-right: auto;
text-align: left;
}
.calendarmonth h2 {
font-size: 1em;
font-weight: bold;
margin: 0;
}
.calendarday {
width: 3em;
max-width: 3em;
height: 3em;
}
""";
if ($*adv_enable_print_styles) {
"""
@media print {
"""; print_stylesheet_for_printing(); """
}
""";
}
if ($*adv_enable_projection_styles) {
"""
@media projection {
"""; print_stylesheet_for_projection(); """
}
""";
}
custom_stylesheet();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Some files were not shown because too many files have changed in this diff Show More